From 850be02a52914dfeb94d7480a255209c8b5c9ca2 Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Fri, 29 Aug 2025 18:25:42 +1000 Subject: [PATCH] add debug panel --- .../BottomPanel/BottomPanelManager.cs | 4 + .../Features/Debug_/DebugPanel.cs | 76 +++++++++++++++++++ .../Features/Debug_/DebugPanel.cs.uid | 1 + .../Features/Debug_/DebugPanel.tscn | 66 ++++++++++++++++ .../Features/Debug_/DebugPanelTab.cs | 44 +++++++++++ .../Features/Debug_/DebugPanelTab.cs.uid | 1 + .../Features/Debug_/DebugPanelTab.tscn | 43 +++++++++++ .../Features/LeftSideBar/LeftSideBar.cs | 4 + .../Features/LeftSideBar/LeftSideBar.tscn | 13 ++++ src/SharpIDE.Godot/GodotGlobalEvents.cs | 1 + src/SharpIDE.Godot/IdeRoot.tscn | 20 +++-- 11 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs create mode 100644 src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Debug_/DebugPanel.tscn create mode 100644 src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs create mode 100644 src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.tscn diff --git a/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs b/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs index 48f374d..d6fe54c 100644 --- a/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs +++ b/src/SharpIDE.Godot/Features/BottomPanel/BottomPanelManager.cs @@ -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("%RunPanel"); + _debugPanel = GetNode("%DebugPanel"); _buildPanel = GetNode("%BuildPanel"); _problemsPanel = GetNode("%ProblemsPanel"); + _panelTypeMap = new Dictionary { { BottomPanelType.Run, _runPanel }, + { BottomPanelType.Debug, _debugPanel }, { BottomPanelType.Build, _buildPanel }, { BottomPanelType.Problems, _problemsPanel } }; diff --git a/src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs b/src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs new file mode 100644 index 0000000..50055c1 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs @@ -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("res://Features/Run/RunPanelTab.tscn"); + public override void _Ready() + { + _tabBar = GetNode("%TabBar"); + _tabBar.ClearTabs(); + //_tabBar.TabClosePressed + _tabBar.TabClicked += OnTabBarTabClicked; + _tabsPanel = GetNode("%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().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().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.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().Single(s => s.Project == projectModel); + _tabBar.SetTabIcon(runPanelTab.TabBarTab, null); + } +} \ No newline at end of file diff --git a/src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs.uid b/src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs.uid new file mode 100644 index 0000000..a428ae3 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Debug_/DebugPanel.cs.uid @@ -0,0 +1 @@ +uid://ddyadu54qitw4 diff --git a/src/SharpIDE.Godot/Features/Debug_/DebugPanel.tscn b/src/SharpIDE.Godot/Features/Debug_/DebugPanel.tscn new file mode 100644 index 0000000..5ba8ff7 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Debug_/DebugPanel.tscn @@ -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 diff --git a/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs b/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs new file mode 100644 index 0000000..89176d3 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs @@ -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("%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(); + } +} \ No newline at end of file diff --git a/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs.uid b/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs.uid new file mode 100644 index 0000000..c4d56de --- /dev/null +++ b/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.cs.uid @@ -0,0 +1 @@ +uid://b6gq81odfn8ok diff --git a/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.tscn b/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.tscn new file mode 100644 index 0000000..6acde03 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Debug_/DebugPanelTab.tscn @@ -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 diff --git a/src/SharpIDE.Godot/Features/LeftSideBar/LeftSideBar.cs b/src/SharpIDE.Godot/Features/LeftSideBar/LeftSideBar.cs index 875111b..4e19a25 100644 --- a/src/SharpIDE.Godot/Features/LeftSideBar/LeftSideBar.cs +++ b/src/SharpIDE.Godot/Features/LeftSideBar/LeftSideBar.cs @@ -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