From ecddd47ed3c73bac8e88c7094497d51e160bd184 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 02:43:40 -0500 Subject: [PATCH 01/15] Updated IdeSolutionState with LastStartupProject Added variable to store LastStartupProject for new Run UI. --- src/SharpIDE.Godot/Features/IdeSettings/IdeSolutionState.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SharpIDE.Godot/Features/IdeSettings/IdeSolutionState.cs b/src/SharpIDE.Godot/Features/IdeSettings/IdeSolutionState.cs index f7c1c61f..1f934ab6 100644 --- a/src/SharpIDE.Godot/Features/IdeSettings/IdeSolutionState.cs +++ b/src/SharpIDE.Godot/Features/IdeSettings/IdeSolutionState.cs @@ -3,6 +3,7 @@ public class IdeSolutionState { public List OpenTabs { get; set; } = []; + public string LastStartupProject { get; set; } = ""; } public class OpenTab From 4be3b2fd826145681516c2e5f57159906ca64987 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 02:46:28 -0500 Subject: [PATCH 02/15] Updated RunMenuItem for new Run system Added Pressed event handler for when item is pressed. Added Handlers for MouseEntered and Exited for highlighting of the item. Added GuiInput override to handle Pressed events for Item. Added StyleBoxFlat to Label, to show highlighting feedback of the item. Removed Spacer, as it isn't needed. Updated Label to take full rect of space available for the Label, adjusted Vertical Alignment to be center. --- .../Features/Run/RunMenuItem.cs | 30 ++++++++++++++++++- .../Features/Run/RunMenuItem.tscn | 14 +++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs b/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs index 565aacbd..deb77d17 100644 --- a/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs +++ b/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs @@ -4,8 +4,11 @@ namespace SharpIDE.Godot.Features.Run; -public partial class RunMenuItem : HBoxContainer +public partial class RunMenuItem : Control { + [Signal] + public delegate void PressedEventHandler(); + public SharpIdeProjectModel Project { get; set; } = null!; private Label _label = null!; private Button _runButton = null!; @@ -30,6 +33,31 @@ public override void _Ready() Project.ProjectStartedRunning.Subscribe(OnProjectStartedRunning); Project.ProjectStoppedRunning.Subscribe(OnProjectStoppedRunning); Project.ProjectRunFailed.Subscribe(OnProjectRunFailed); + MouseEntered += HandleMouseEntered; + MouseExited += HandleMouseExited; + } + + public override void _GuiInput(InputEvent @event) + { + if (@event is not InputEventMouseButton iemb) return; + if (iemb is {Pressed: true, ButtonIndex: MouseButton.Left}) + EmitSignalPressed(); + } + + private void HandleMouseEntered() + { + var sb = (StyleBoxFlat)_label.GetThemeStylebox("normal"); + var color = sb.BgColor; + color.A = 255; + sb.BgColor = color; + } + + private void HandleMouseExited() + { + var sb = (StyleBoxFlat)_label.GetThemeStylebox("normal"); + var color = sb.BgColor; + color.A = 0; + sb.BgColor = color; } private async Task OnProjectRunFailed() diff --git a/src/SharpIDE.Godot/Features/Run/RunMenuItem.tscn b/src/SharpIDE.Godot/Features/Run/RunMenuItem.tscn index d4779aee..f669f50a 100644 --- a/src/SharpIDE.Godot/Features/Run/RunMenuItem.tscn +++ b/src/SharpIDE.Godot/Features/Run/RunMenuItem.tscn @@ -6,6 +6,10 @@ [ext_resource type="Texture2D" uid="uid://c7cmou8hipsvc" path="res://Features/Run/Resources/Debug.svg" id="3_cd138"] [ext_resource type="Texture2D" uid="uid://debdmtqgw5dhf" path="res://Features/Run/Resources/Stop.svg" id="3_hxkig"] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8lles"] +resource_local_to_scene = true +bg_color = Color(0.4745098, 0.4745098, 0.4745098, 0) + [sub_resource type="Animation" id="Animation_8lles"] resource_name = "BuildingAnimation" length = 0.8 @@ -45,17 +49,17 @@ _data = { } [node name="RunMenuItem" type="HBoxContainer" unique_id=1305347884] -offset_right = 40.0 +offset_right = 181.0 offset_bottom = 40.0 script = ExtResource("1_syj0f") [node name="Label" type="Label" parent="." unique_id=1727711838] layout_mode = 2 -text = "Project Name" - -[node name="Spacer" type="Control" parent="." unique_id=1831433607] -layout_mode = 2 size_flags_horizontal = 3 +size_flags_vertical = 1 +theme_override_styles/normal = SubResource("StyleBoxFlat_8lles") +text = "Project Name" +vertical_alignment = 1 [node name="AnimatedTextureParentControl" type="Control" parent="." unique_id=1016714895] unique_name_in_owner = true From b90cbe74a1f82d966f3e0f404d325be5b996b815 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 02:47:24 -0500 Subject: [PATCH 03/15] Created new Custom Run Button UI Created new Custom Run Button UI, to handle Selecting a Startup Project to run, while still offering a Menu to allow launching of multiple projects. --- .../Features/Run/CustomRunButton.cs | 203 ++++++++++++++++++ .../Features/Run/CustomRunButton.cs.uid | 1 + .../Features/Run/CustomRunButton.tscn | 51 +++++ 3 files changed, 255 insertions(+) create mode 100644 src/SharpIDE.Godot/Features/Run/CustomRunButton.cs create mode 100644 src/SharpIDE.Godot/Features/Run/CustomRunButton.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Run/CustomRunButton.tscn diff --git a/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs b/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs new file mode 100644 index 00000000..af3a91f5 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs @@ -0,0 +1,203 @@ +using Godot; +using System; +using SharpIDE.Application.Features.SolutionDiscovery; +using SharpIDE.Godot; +using SharpIDE.Godot.Features.Run; + +public partial class CustomRunButton : Button +{ + [Signal] + public delegate void StartupProjectChangedEventHandler(); + + private readonly PackedScene _runMenuItemScene = ResourceLoader.Load("res://Features/Run/RunMenuItem.tscn"); + private Popup _runMenuPopup = null!; + private VBoxContainer _runOptions = null!; + + private RunOption _currentRunOption = null!; + + public RunOption CurrentRunOption + { + get => _currentRunOption; + set + { + _currentRunOption = value; + Callable.From((name) => Text = name).CallDeferred(_currentRunOption?.Name ?? ""); + } + } + + public List Options = []; + + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + _runMenuPopup = GetNode("%RunMenuPopup"); + _runOptions = GetNode("%RunOptions"); + UpdateMinimumSize(); + if (CurrentRunOption != null) + Text = CurrentRunOption.Name; + + foreach (var option in Options) + { + AddOption(option.Model); + } + + Pressed += HandlePopupMenu; + + if (GetParent() is not BoxContainer parent) return; + parent.Resized += HandleSizeChanged; + } + + public void AddOption(SharpIdeProjectModel model) => AddOption(model.Name.Value, model); + + public void AddOption(string name, SharpIdeProjectModel model) + { + var ro = new RunOption(name, model); + Options.Add(ro); + var item = _runMenuItemScene.Instantiate(); + item.Project = model; + item.Pressed += () => HandleOptionPressed(ro); + _runOptions.AddChild(item); + UpdateMinimumSize(); + } + + public void RemoveOption(SharpIdeProjectModel model) + { + RunOption foundOption = null!; + foreach (var option in Options.Where(option => option.Model == model)) + { + foreach (var menuItem in _runOptions.GetChildren()) + { + if (menuItem is not RunMenuItem rmi) continue; + if (rmi.Project != model) continue; + rmi.QueueFree(); + break; + } + foundOption = option; + } + + Options.Remove(foundOption); + UpdateMinimumSize(); + } + + public void RemoveOption(RunOption option) + { + foreach (var menuItem in _runOptions.GetChildren()) + { + if (menuItem is not RunMenuItem rmi) continue; + if (rmi.Project != option.Model) continue; + rmi.QueueFree(); + } + + Options.Remove(option); + UpdateMinimumSize(); + } + + public void RemoveOption(string name) + { + RunOption foundOption = Options.Where(option => option.Name == name).FirstOrDefault(); + if (foundOption != null) + RemoveOption(foundOption); + } + + public void SelectOption(SharpIdeProjectModel model) + { + CurrentRunOption = Options.FirstOrDefault(option => option.Model == model)!; + } + + public void SelectOption(string name = "", string filePath = "") + { + if (name == "" && filePath == "") return; + if (name != "") + CurrentRunOption = Options.FirstOrDefault(option => option.Name == name)!; + else + CurrentRunOption = Options.FirstOrDefault(option => option.Model.FilePath == filePath)!; + } + + public void SelectOption(int index) + { + if (index >= 0 && index < Options.Count) + CurrentRunOption = Options[index]; + } + + public void SelectOption(RunOption option) => CurrentRunOption = option; + + public void RunProject() + { + + } + + public void DebugProject() + { + + } + + public void StopProject() + { + + } + + + private void UpdateMinimumSize() + { + var font = GetThemeDefaultFont(); + var size = GetThemeDefaultFontSize(); + var maxWidth = 0f; + foreach (var option in Options) + { + var measure = font.GetStringSize(option.Name, fontSize: size); + if (measure.X + 42 > maxWidth) + maxWidth = measure.X + 42; + } + + CustomMinimumSize = new Vector2(maxWidth, 0); + } + + private void HandleSizeChanged() + { + if (GetParent() is not Control parent) return; + var space = parent.Size; + var popupSize = new Vector2I((int)space.X+3, _runMenuPopup.Size.Y); + _runMenuPopup.MinSize = popupSize; + _runMenuPopup.Size = popupSize; + } + + private void HandlePopupMenu() + { + var popupMenuPosition = GlobalPosition; + const int buttonHeight = 39; + _runMenuPopup.Position = new Vector2I((int)popupMenuPosition.X, (int)popupMenuPosition.Y + buttonHeight); + _runMenuPopup.Popup(); + } + + private void HandleOptionPressed(RunOption option) + { + CurrentRunOption = option; + Text = option.Name; + _runMenuPopup.Hide(); + EmitSignalStartupProjectChanged(); + } +} + + +public class RunOption +{ + public string Name = null!; + public SharpIdeProjectModel Model = null!; + + public RunOption(SharpIdeProjectModel model) + { + Model = model; + Name = model.Name.Value; + } + + public RunOption(string name, SharpIdeProjectModel model) + { + Model = model; + Name = name; + } + + public RunOption() + { + + } +} \ No newline at end of file diff --git a/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs.uid b/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs.uid new file mode 100644 index 00000000..4c4a4179 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs.uid @@ -0,0 +1 @@ +uid://nwepdo8njw4l diff --git a/src/SharpIDE.Godot/Features/Run/CustomRunButton.tscn b/src/SharpIDE.Godot/Features/Run/CustomRunButton.tscn new file mode 100644 index 00000000..fbe18259 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Run/CustomRunButton.tscn @@ -0,0 +1,51 @@ +[gd_scene format=3 uid="uid://du1371oogv5dj"] + +[ext_resource type="Script" uid="uid://nwepdo8njw4l" path="res://Features/Run/CustomRunButton.cs" id="1_rlcoe"] + +[sub_resource type="DPITexture" id="DPITexture_l37ox"] +_source = " +" + +[node name="CustomRunButton" type="Button" unique_id=1336831619] +custom_minimum_size = Vector2(143, 0) +offset_right = 143.0 +offset_bottom = 31.0 +text = "" +alignment = 0 +script = ExtResource("1_rlcoe") + +[node name="TextureRect" type="TextureRect" parent="." unique_id=256296248] +layout_mode = 1 +anchors_preset = 6 +anchor_left = 1.0 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_left = -21.0 +offset_top = -8.0 +offset_right = -5.0 +offset_bottom = 8.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("DPITexture_l37ox") + +[node name="RunMenuPopup" type="Popup" parent="." unique_id=1494309304] +unique_name_in_owner = true +oversampling_override = 1.0 +position = Vector2i(0, 37) +size = Vector2i(151, 100) + +[node name="MarginContainer" type="MarginContainer" parent="RunMenuPopup" unique_id=2114816769] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 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="RunOptions" type="VBoxContainer" parent="RunMenuPopup/MarginContainer" unique_id=232179440] +unique_name_in_owner = true +layout_mode = 2 From 08d3476bb60ff3ae9dab7d815947655fde1936b7 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 02:49:07 -0500 Subject: [PATCH 04/15] Updated IdeRoot with new Run UI Added new controls for Building, Running, Debugging, and Stopping the Startup project. Implemented logic to handle when there is a Change in the Startup Project, and save it to the IdeSolutionState for the last Startup Project setup. --- src/SharpIDE.Godot/IdeRoot.cs | 30 ++++++++++++++++++++----- src/SharpIDE.Godot/IdeRoot.tscn | 40 ++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/SharpIDE.Godot/IdeRoot.cs b/src/SharpIDE.Godot/IdeRoot.cs index 73b3eb80..e991a1c7 100644 --- a/src/SharpIDE.Godot/IdeRoot.cs +++ b/src/SharpIDE.Godot/IdeRoot.cs @@ -36,6 +36,8 @@ public partial class IdeRoot : Control private InvertedVSplitContainer _invertedVSplitContainer = null!; private Button _runMenuButton = null!; private Popup _runMenuPopup = null!; + private CustomRunButton _projectList = null!; + private readonly PackedScene _runMenuItemScene = ResourceLoader.Load("res://Features/Run/RunMenuItem.tscn"); private TaskCompletionSource _nodeReadyTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -77,6 +79,8 @@ public override void _Ready() _searchWindow = GetNode("%SearchWindow"); _searchAllFilesWindow = GetNode("%SearchAllFilesWindow"); _invertedVSplitContainer = GetNode("%InvertedVSplitContainer"); + _projectList = GetNode("%ProjectList"); + _runMenuButton.Pressed += OnRunMenuButtonPressed; GodotGlobalEvents.Instance.FileSelected.Subscribe(OnSolutionExplorerPanelOnFileSelected); _openSlnButton.Pressed += () => IdeWindow.PickSolution(); @@ -89,6 +93,7 @@ public override void _Ready() _buildService.BuildFinished.Subscribe(OnBuildFinished); GetTree().GetRoot().FocusExited += OnFocusExited; _nodeReadyTcs.SetResult(); + _projectList.StartupProjectChanged += OnStartupProjectChanged; } private async Task OnBuildStarted(BuildStartedFlags flags) => await OnBuildRunningStateChanged(true, flags); @@ -192,21 +197,36 @@ public void SetSlnFilePath(string path) var tasks = solutionModel.AllProjects.Select(p => p.MsBuildEvaluationProjectTask).ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); + var runnableProjects = solutionModel.AllProjects.Where(p => p.IsLoaded && p.IsRunnable).ToList(); + // Startup Project + var cproj = Singletons.AppState.RecentSlns.Single(s => s.FilePath == solutionModel.FilePath).IdeSolutionState.LastStartupProject; + await this.InvokeAsync(() => { - var runMenuPopupVbox = _runMenuPopup.GetNode("MarginContainer/VBoxContainer"); foreach (var project in runnableProjects) { - var runMenuItem = _runMenuItemScene.Instantiate(); - runMenuItem.Project = project; - runMenuPopupVbox.AddChild(runMenuItem); + _projectList.AddOption(project); + if (project.FilePath == cproj) + _projectList.SelectOption(project); } - _runMenuButton.Disabled = false; }); + + if (_projectList.CurrentRunOption == null) + _projectList.SelectOption(0); }); } + private void OnStartupProjectChanged() + { + var solutionModel = _sharpIdeSolutionAccessor.SolutionModel; + var runnableProjects = solutionModel.AllProjects.Where(p => p.IsRunnable).ToList(); + var cproj = _projectList.CurrentRunOption.Model; + if (!runnableProjects.Contains(cproj)) return; + + Singletons.AppState.RecentSlns.Single(s => s.FilePath == solutionModel.FilePath).IdeSolutionState.LastStartupProject = cproj.FilePath; + } + public override void _UnhandledKeyInput(InputEvent @event) { if (@event.IsActionPressed(InputStringNames.FindInFiles)) diff --git a/src/SharpIDE.Godot/IdeRoot.tscn b/src/SharpIDE.Godot/IdeRoot.tscn index d1fb3eef..2cfad21c 100644 --- a/src/SharpIDE.Godot/IdeRoot.tscn +++ b/src/SharpIDE.Godot/IdeRoot.tscn @@ -12,6 +12,7 @@ [ext_resource type="Texture2D" uid="uid://ccj73acbnukyt" path="res://Resources/cancel-disabled.svg" id="5_qo7tr"] [ext_resource type="Texture2D" uid="uid://c0gl3rvabse1f" path="res://Resources/cancel-darker.svg" id="5_uvk4l"] [ext_resource type="PackedScene" uid="uid://c5dlwgcx3ubyp" path="res://Features/CodeEditor/CodeEditorPanel.tscn" id="8_7ptyn"] +[ext_resource type="PackedScene" uid="uid://du1371oogv5dj" path="res://Features/Run/CustomRunButton.tscn" id="9_rl2d5"] [ext_resource type="PackedScene" uid="uid://8lk0qj233a7p" path="res://Features/Search/SearchInFiles/SearchWindow.tscn" id="13_7ptyn"] [ext_resource type="PackedScene" uid="uid://c3ow337fhh1v1" path="res://Features/ToolPanes/ToolPaneContainer.tscn" id="13_tmssf"] [ext_resource type="PackedScene" uid="uid://b8kytk23cfo4x" path="res://Features/Search/SearchAllFiles/SearchAllFilesWindow.tscn" id="15_gh8b1"] @@ -107,19 +108,35 @@ stretch_mode = 5 layout_mode = 2 size_flags_horizontal = 3 -[node name="RunMenuButton" type="Button" parent="VBoxContainer/Panel/HBoxContainer" unique_id=193947069] +[node name="BuildProject" type="Button" parent="VBoxContainer/Panel/HBoxContainer" unique_id=63620535] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +size_flags_vertical = 4 +icon = ExtResource("8_tmssf") +expand_icon = true + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/Panel/HBoxContainer" unique_id=1654824922] +layout_mode = 2 + +[node name="ProjectList" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer" unique_id=1336831619 instance=ExtResource("9_rl2d5")] +unique_name_in_owner = true +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 +size_flags_vertical = 4 + +[node name="RunMenuButton" type="Button" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer" unique_id=193947069] unique_name_in_owner = true layout_mode = 2 size_flags_vertical = 4 -disabled = true icon = ExtResource("2_8x8ub") icon_alignment = 1 -[node name="RunMenuPopup" type="Popup" parent="VBoxContainer/Panel/HBoxContainer/RunMenuButton" unique_id=92504102] +[node name="RunMenuPopup" type="Popup" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer/RunMenuButton" unique_id=92504102] unique_name_in_owner = true size = Vector2i(151, 100) -[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/Panel/HBoxContainer/RunMenuButton/RunMenuPopup" unique_id=911955929] +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer/RunMenuButton/RunMenuPopup" unique_id=911955929] anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 @@ -130,8 +147,21 @@ theme_override_constants/margin_top = 5 theme_override_constants/margin_right = 5 theme_override_constants/margin_bottom = 5 -[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Panel/HBoxContainer/RunMenuButton/RunMenuPopup/MarginContainer" unique_id=1372084780] +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer/RunMenuButton/RunMenuPopup/MarginContainer" unique_id=1372084780] +layout_mode = 2 + +[node name="StopButton" type="Button" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer" unique_id=263543484] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_vertical = 4 +icon = ExtResource("10_r1ap7") + +[node name="DebugButton" type="Button" parent="VBoxContainer/Panel/HBoxContainer/HBoxContainer" unique_id=495543979] +unique_name_in_owner = true layout_mode = 2 +size_flags_vertical = 4 +icon = ExtResource("11_rl2d5") [node name="SettingsButton" parent="VBoxContainer/Panel/HBoxContainer" unique_id=1946991037 instance=ExtResource("5_pm5al")] layout_mode = 2 From 5db69b24a2bb8ef3ea31288ae8e9f494b99c1d89 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 21:49:42 -0500 Subject: [PATCH 05/15] Updated RunMenuItem with RunRequested signal Added signal for when the Run Button is pressed, to sync startup project status. --- src/SharpIDE.Godot/Features/Run/RunMenuItem.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs b/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs index deb77d17..0f21520b 100644 --- a/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs +++ b/src/SharpIDE.Godot/Features/Run/RunMenuItem.cs @@ -8,6 +8,9 @@ public partial class RunMenuItem : Control { [Signal] public delegate void PressedEventHandler(); + + [Signal] + public delegate void RunRequestedEventHandler(RunMenuItem sender); public SharpIdeProjectModel Project { get; set; } = null!; private Label _label = null!; @@ -103,6 +106,7 @@ private async void OnStopButtonPressed() private async void OnRunButtonPressed() { SetAttemptingRunState(); + EmitSignalRunRequested(this); await _runService.RunProject(Project).ConfigureAwait(false); } @@ -114,6 +118,7 @@ private async void OnDebugButtonPressed() DebuggerExecutablePath = Singletons.AppState.IdeSettings.DebuggerExecutablePath }; SetAttemptingRunState(); + EmitSignalRunRequested(this); await _runService.RunProject(Project, true, debuggerExecutableInfo).ConfigureAwait(false); } From 7407e2d199c209888d259262aac2ab0f4f09cb1a Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 21:51:53 -0500 Subject: [PATCH 06/15] Updated signals Renamed signal StartupProjectChanged to ProjectChanged. Added Signal ItemAdded to allow Project signals to be connected up the chain. Added Signal RunRequested to sync UI for Startup Project being launched from menu. Removed empty functions as going a different route for design. --- .../Features/Run/CustomRunButton.cs | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs b/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs index af3a91f5..de4e5233 100644 --- a/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs +++ b/src/SharpIDE.Godot/Features/Run/CustomRunButton.cs @@ -7,7 +7,13 @@ public partial class CustomRunButton : Button { [Signal] - public delegate void StartupProjectChangedEventHandler(); + public delegate void ProjectChangedEventHandler(); + + [Signal] + public delegate void ItemAddedEventHandler(int index); + + [Signal] + public delegate void RunRequestedEventHandler(RunMenuItem item); private readonly PackedScene _runMenuItemScene = ResourceLoader.Load("res://Features/Run/RunMenuItem.tscn"); private Popup _runMenuPopup = null!; @@ -51,13 +57,16 @@ public override void _Ready() public void AddOption(string name, SharpIdeProjectModel model) { + var indx = Options.Count; var ro = new RunOption(name, model); Options.Add(ro); var item = _runMenuItemScene.Instantiate(); item.Project = model; item.Pressed += () => HandleOptionPressed(ro); + item.RunRequested += EmitSignalRunRequested; _runOptions.AddChild(item); UpdateMinimumSize(); + EmitSignalItemAdded(indx); } public void RemoveOption(SharpIdeProjectModel model) @@ -121,22 +130,6 @@ public void SelectOption(int index) public void SelectOption(RunOption option) => CurrentRunOption = option; - public void RunProject() - { - - } - - public void DebugProject() - { - - } - - public void StopProject() - { - - } - - private void UpdateMinimumSize() { var font = GetThemeDefaultFont(); @@ -174,7 +167,7 @@ private void HandleOptionPressed(RunOption option) CurrentRunOption = option; Text = option.Name; _runMenuPopup.Hide(); - EmitSignalStartupProjectChanged(); + EmitSignalProjectChanged(); } } From a08b856069aacf4113746f5a5f3d83c1670f14dc Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Fri, 1 May 2026 21:53:30 -0500 Subject: [PATCH 07/15] Created StartupProject Control Moved HBoxContainer into StartupProject control, to group together the ProjectList Options, with the Run and Debug button controls for startup project. --- .../Features/Run/StartupProject.cs | 132 ++++++++++++++++++ .../Features/Run/StartupProject.cs.uid | 1 + .../Features/Run/StartupProject.tscn | 104 ++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 src/SharpIDE.Godot/Features/Run/StartupProject.cs create mode 100644 src/SharpIDE.Godot/Features/Run/StartupProject.cs.uid create mode 100644 src/SharpIDE.Godot/Features/Run/StartupProject.tscn diff --git a/src/SharpIDE.Godot/Features/Run/StartupProject.cs b/src/SharpIDE.Godot/Features/Run/StartupProject.cs new file mode 100644 index 00000000..40924057 --- /dev/null +++ b/src/SharpIDE.Godot/Features/Run/StartupProject.cs @@ -0,0 +1,132 @@ +using Godot; +using SharpIDE.Application.Features.Run; +using SharpIDE.Application.Features.SolutionDiscovery; +using SharpIDE.Godot; + +public partial class StartupProject : HBoxContainer +{ + [Signal] + public delegate void ProjectChangedEventHandler(); + + private CustomRunButton _projectList = null!; + private Control _spacer = null!; + private Control _animatedBuilding = null!; + private Button _runButton = null!; + private Button _debugButton = null!; + private Button _stopButton = null!; + private AnimationPlayer _buildingAnim = null!; + + public CustomRunButton ProjectList => _projectList; + + [Inject] private readonly RunService _runService = null!; + + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + _projectList = GetNode("%ProjectList"); + _spacer = GetNode("%Spacer"); + _animatedBuilding = GetNode("%AnimatedTextureParentControl"); + _runButton = GetNode