Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public class IdeSolutionState
{
public List<OpenTab> OpenTabs { get; set; } = [];
public string LastStartupProject { get; set; } = "";
}

public class OpenTab
Expand Down
51 changes: 51 additions & 0 deletions src/SharpIDE.Godot/Features/Run/CustomRunButton.tscn
Original file line number Diff line number Diff line change
@@ -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 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\"><path fill=\"none\" stroke=\"#b2b2b2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-opacity=\".85\" stroke-width=\"2\" d=\"m2 4 4 4 4-4\"/></svg>
"

[node name="CustomRunButton" type="Button" unique_id=1336831619]
custom_minimum_size = Vector2(143, 0)
offset_right = 143.0
offset_bottom = 31.0
text = "<No Project...>"
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
196 changes: 196 additions & 0 deletions src/SharpIDE.Godot/Features/Run/ProjectOptionButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using Godot;
using System;
using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Godot;
using SharpIDE.Godot.Features.Run;

public partial class ProjectOptionButton : Button
{
[Signal]
public delegate void ProjectChangedEventHandler();

[Signal]
public delegate void ItemAddedEventHandler(int index);

[Signal]
public delegate void RunRequestedEventHandler(RunMenuItem item);

private readonly PackedScene _runMenuItemScene = ResourceLoader.Load<PackedScene>("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<string?>((name) => Text = name).CallDeferred(_currentRunOption?.Name ?? "");
}
}

public List<RunOption> Options = [];

// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
_runMenuPopup = GetNode<Popup>("%RunMenuPopup");
_runOptions = GetNode<VBoxContainer>("%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 indx = Options.Count;
var ro = new RunOption(name, model);
Options.Add(ro);
var item = _runMenuItemScene.Instantiate<RunMenuItem>();
item.Project = model;
item.Pressed += () => HandleOptionPressed(ro);
item.RunRequested += EmitSignalRunRequested;
_runOptions.AddChild(item);
UpdateMinimumSize();
EmitSignalItemAdded(indx);
}

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;

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();
EmitSignalProjectChanged();
}
}


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()
{

}
}
1 change: 1 addition & 0 deletions src/SharpIDE.Godot/Features/Run/ProjectOptionButton.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://nwepdo8njw4l
35 changes: 34 additions & 1 deletion src/SharpIDE.Godot/Features/Run/RunMenuItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@

namespace SharpIDE.Godot.Features.Run;

public partial class RunMenuItem : HBoxContainer
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!;
private Button _runButton = null!;
Expand All @@ -30,6 +36,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()
Expand Down Expand Up @@ -75,6 +106,7 @@ private async void OnStopButtonPressed()
private async void OnRunButtonPressed()
{
SetAttemptingRunState();
EmitSignalRunRequested(this);
await _runService.RunProject(Project).ConfigureAwait(false);
}

Expand All @@ -86,6 +118,7 @@ private async void OnDebugButtonPressed()
DebuggerExecutablePath = Singletons.AppState.IdeSettings.DebuggerExecutablePath
};
SetAttemptingRunState();
EmitSignalRunRequested(this);
await _runService.RunProject(Project, true, debuggerExecutableInfo).ConfigureAwait(false);
}

Expand Down
14 changes: 9 additions & 5 deletions src/SharpIDE.Godot/Features/Run/RunMenuItem.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading