add debug panel

This commit is contained in:
Matt Parker
2025-08-29 18:25:42 +10:00
parent 88b8fbea55
commit 850be02a52
11 changed files with 266 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ namespace SharpIDE.Godot.Features.BottomPanel;
public partial class BottomPanelManager : Panel
{
private Control _runPanel = null!;
private Control _debugPanel = null!;
private Control _buildPanel = null!;
private Control _problemsPanel = null!;
@@ -13,11 +14,14 @@ public partial class BottomPanelManager : Panel
public override void _Ready()
{
_runPanel = GetNode<Control>("%RunPanel");
_debugPanel = GetNode<Control>("%DebugPanel");
_buildPanel = GetNode<Control>("%BuildPanel");
_problemsPanel = GetNode<Control>("%ProblemsPanel");
_panelTypeMap = new Dictionary<BottomPanelType, Control>
{
{ BottomPanelType.Run, _runPanel },
{ BottomPanelType.Debug, _debugPanel },
{ BottomPanelType.Build, _buildPanel },
{ BottomPanelType.Problems, _problemsPanel }
};

View File

@@ -0,0 +1,76 @@
using Godot;
using SharpIDE.Application.Features.Events;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
using SharpIDE.Godot.Features.Run;
namespace SharpIDE.Godot.Features.Debug_;
public partial class DebugPanel : Control
{
private TabBar _tabBar = null!;
private Panel _tabsPanel = null!;
[Export]
public Texture2D RunningIcon { get; set; } = null!;
private PackedScene _runPanelTabScene = GD.Load<PackedScene>("res://Features/Run/RunPanelTab.tscn");
public override void _Ready()
{
_tabBar = GetNode<TabBar>("%TabBar");
_tabBar.ClearTabs();
//_tabBar.TabClosePressed
_tabBar.TabClicked += OnTabBarTabClicked;
_tabsPanel = GetNode<Panel>("%TabsPanel");
GlobalEvents.ProjectStartedRunning += async projectModel =>
{
await this.InvokeAsync(() => ProjectStartedRunning(projectModel));
};
GlobalEvents.ProjectStoppedRunning += async projectModel =>
{
await this.InvokeAsync(() => ProjectStoppedRunning(projectModel));
};
}
private void OnTabBarTabClicked(long idx)
{
var children = _tabsPanel.GetChildren().OfType<RunPanelTab>().ToList();
foreach (var child in children)
{
child.Visible = false;
}
var tab = children.Single(t => t.TabBarTab == idx);
tab.Visible = true;
}
public void ProjectStartedRunning(SharpIdeProjectModel projectModel)
{
var existingRunPanelTab = _tabsPanel.GetChildren().OfType<RunPanelTab>().SingleOrDefault(s => s.Project == projectModel);
if (existingRunPanelTab != null)
{
_tabBar.SetTabIcon(existingRunPanelTab.TabBarTab, RunningIcon);
_tabBar.CurrentTab = existingRunPanelTab.TabBarTab;
OnTabBarTabClicked(existingRunPanelTab.TabBarTab);
existingRunPanelTab.ClearTerminal();
existingRunPanelTab.StartWritingFromProjectOutput();
return;
}
var runPanelTab = _runPanelTabScene.Instantiate<RunPanelTab>();
runPanelTab.Project = projectModel;
_tabBar.AddTab(projectModel.Name);
var tabIdx = _tabBar.GetTabCount() - 1;
runPanelTab.TabBarTab = tabIdx;
_tabBar.SetTabIcon(runPanelTab.TabBarTab, RunningIcon);
_tabBar.CurrentTab = runPanelTab.TabBarTab;
_tabsPanel.AddChild(runPanelTab);
OnTabBarTabClicked(runPanelTab.TabBarTab);
runPanelTab.StartWritingFromProjectOutput();
}
public void ProjectStoppedRunning(SharpIdeProjectModel projectModel)
{
var runPanelTab = _tabsPanel.GetChildren().OfType<RunPanelTab>().Single(s => s.Project == projectModel);
_tabBar.SetTabIcon(runPanelTab.TabBarTab, null);
}
}

View File

@@ -0,0 +1 @@
uid://ddyadu54qitw4

View File

@@ -0,0 +1,66 @@
[gd_scene load_steps=2 format=3 uid="uid://dkjips8oudqou"]
[ext_resource type="Script" uid="uid://ddyadu54qitw4" path="res://Features/Debug_/DebugPanel.cs" id="1_h4rcc"]
[node name="DebugPanel" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_h4rcc")
[node name="Label" type="Label" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -64.0
offset_top = -11.5
offset_right = 64.0
offset_bottom = 11.5
grow_horizontal = 2
grow_vertical = 2
text = "Nothing to show"
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 0
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 0
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/HBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 5
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/MarginContainer"]
layout_mode = 2
text = "Debug"
[node name="TabBar" type="TabBar" parent="VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 0
current_tab = 0
tab_close_display_policy = 2
tab_count = 1
tab_0/title = "WebApi"
[node name="TabsPanel" type="Panel" parent="VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3

View File

@@ -0,0 +1,44 @@
using GDExtensionBindgen;
using Godot;
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
namespace SharpIDE.Godot.Features.Debug_;
public partial class DebugPanelTab : Panel
{
private Terminal _terminal = null!;
private Task _writeTask = Task.CompletedTask;
public SharpIdeProjectModel Project { get; set; } = null!;
public int TabBarTab { get; set; }
public override void _Ready()
{
var terminalControl = GetNode<Control>("%Terminal");
_terminal = new Terminal(terminalControl);
}
public void StartWritingFromProjectOutput()
{
if (_writeTask.IsCompleted is not true)
{
GD.PrintErr("Attempted to start writing from project output, but a write task is already running.");
return;
}
_writeTask = GodotTask.Run(async () =>
{
await foreach (var array in Project.RunningOutputChannel!.Reader.ReadAllAsync().ConfigureAwait(false))
{
//_terminal.Write(array);
//await this.InvokeAsync(() => _terminal.Write(array));
var str = System.Text.Encoding.UTF8.GetString(array);
await this.InvokeAsync(() => _terminal.Write(str));
}
});
}
public void ClearTerminal()
{
_terminal.Clear();
}
}

View File

@@ -0,0 +1 @@
uid://b6gq81odfn8ok

View File

@@ -0,0 +1,43 @@
[gd_scene load_steps=3 format=3 uid="uid://d4d0umsglu2ex"]
[ext_resource type="Script" uid="uid://b6gq81odfn8ok" path="res://Features/Debug_/DebugPanelTab.cs" id="1_yinwn"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dx3i6"]
bg_color = Color(0.129589, 0.120703, 0.112057, 1)
[node name="DebugPanelTab" type="Panel"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_dx3i6")
script = ExtResource("1_yinwn")
[node name="TabContainer" type="TabContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
current_tab = 1
[node name="Threads & Variables" type="Control" parent="TabContainer"]
visible = false
layout_mode = 2
metadata/_tab_index = 0
[node name="Console" type="Control" parent="TabContainer"]
layout_mode = 2
metadata/_tab_index = 1
[node name="Terminal" type="Terminal" parent="TabContainer/Console"]
copy_on_selection = true
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View File

@@ -10,6 +10,7 @@ public partial class LeftSideBar : Panel
private Button _problemsButton = null!;
private Button _runButton = null!;
private Button _buildButton = null!;
private Button _debugButton = null!;
public override void _Ready()
{
@@ -17,10 +18,12 @@ public partial class LeftSideBar : Panel
_problemsButton = GetNode<Button>("%ProblemsButton");
_runButton = GetNode<Button>("%RunButton");
_buildButton = GetNode<Button>("%BuildButton");
_debugButton = GetNode<Button>("%DebugButton");
_problemsButton.Toggled += toggledOn => GodotGlobalEvents.InvokeBottomPanelTabSelected(toggledOn ? BottomPanelType.Problems : null);
_runButton.Toggled += toggledOn => GodotGlobalEvents.InvokeBottomPanelTabSelected(toggledOn ? BottomPanelType.Run : null);
_buildButton.Toggled += toggledOn => GodotGlobalEvents.InvokeBottomPanelTabSelected(toggledOn ? BottomPanelType.Build : null);
_debugButton.Toggled += toggledOn => GodotGlobalEvents.InvokeBottomPanelTabSelected(toggledOn ? BottomPanelType.Debug : null);
GodotGlobalEvents.BottomPanelTabExternallySelected += OnBottomPanelTabExternallySelected;
}
@@ -31,6 +34,7 @@ public partial class LeftSideBar : Panel
switch (arg)
{
case BottomPanelType.Run: _runButton.ButtonPressed = true; break;
case BottomPanelType.Debug: _debugButton.ButtonPressed = true; break;
case BottomPanelType.Build: _buildButton.ButtonPressed = true; break;
case BottomPanelType.Problems: _problemsButton.ButtonPressed = true; break;
default: throw new ArgumentOutOfRangeException(nameof(arg), arg, null);

View File

@@ -70,6 +70,19 @@ icon_alignment = 1
vertical_icon_alignment = 0
expand_icon = true
[node name="DebugButton" type="Button" parent="MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
focus_mode = 0
theme_override_font_sizes/font_size = 13
toggle_mode = true
button_group = ExtResource("2_1aad6")
text = "Debug"
icon = ExtResource("1_6wc7d")
icon_alignment = 1
vertical_icon_alignment = 0
expand_icon = true
[node name="BuildButton" type="Button" parent="MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2

View File

@@ -17,6 +17,7 @@ public static class GodotGlobalEvents
public enum BottomPanelType
{
Run,
Debug,
Build,
Problems
}

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=13 format=3 uid="uid://b2oniigcp5ew5"]
[gd_scene load_steps=14 format=3 uid="uid://b2oniigcp5ew5"]
[ext_resource type="Script" uid="uid://bavypuy7b375x" path="res://IdeRoot.cs" id="1_whawi"]
[ext_resource type="Texture2D" uid="uid://bkty6563cthj8" path="res://Features/Run/Resources/Run.svg" id="2_8x8ub"]
@@ -11,6 +11,7 @@
[ext_resource type="Script" uid="uid://cvvgp42r3nml8" path="res://Features/BottomPanel/BottomPanelManager.cs" id="7_i62lx"]
[ext_resource type="PackedScene" uid="uid://co6dkhdolriej" path="res://Features/Build/BuildPanel.tscn" id="9_rllbf"]
[ext_resource type="PackedScene" uid="uid://tqpmww430cor" path="res://Features/Problems/ProblemsPanel.tscn" id="11_b7c1a"]
[ext_resource type="PackedScene" uid="uid://dkjips8oudqou" path="res://Features/Debug_/DebugPanel.tscn" id="11_s2dv6"]
[sub_resource type="FontVariation" id="FontVariation_y3aoi"]
base_font = ExtResource("2_rk34b")
@@ -153,16 +154,21 @@ item_0/id = 0
layout_mode = 2
script = ExtResource("7_i62lx")
[node name="RunPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("5_y3aoi")]
unique_name_in_owner = true
layout_mode = 1
[node name="BuildPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("9_rllbf")]
[node name="ProblemsPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("11_b7c1a")]
unique_name_in_owner = true
visible = false
layout_mode = 1
[node name="ProblemsPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("11_b7c1a")]
[node name="RunPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("5_y3aoi")]
unique_name_in_owner = true
layout_mode = 1
[node name="DebugPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("11_s2dv6")]
unique_name_in_owner = true
visible = false
layout_mode = 1
[node name="BuildPanel" parent="VBoxContainer/HBoxContainer/InvertedVSplitContainer/BottomPanel" instance=ExtResource("9_rllbf")]
unique_name_in_owner = true
visible = false
layout_mode = 1