diff --git a/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.cs b/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.cs new file mode 100644 index 0000000..92de26d --- /dev/null +++ b/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.cs @@ -0,0 +1,61 @@ +using Godot; +using SharpIDE.Application.Features.SolutionDiscovery; +using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; + +namespace SharpIDE.Godot.Features.CodeEditor; + +public partial class CodeEditorPanel : MarginContainer +{ + [Export] + public Texture2D CsFileTexture { get; set; } = null!; + public SharpIdeSolutionModel Solution { get; set; } = null!; + private PackedScene _sharpIdeCodeEditScene = GD.Load("res://Features/CodeEditor/SharpIdeCodeEdit.tscn"); + private TabContainer _tabContainer = null!; + + public override void _Ready() + { + _tabContainer = GetNode("TabContainer"); + _tabContainer.RemoveChild(_tabContainer.GetChild(0)); // Remove the default tab + _tabContainer.TabClicked += OnTabClicked; + var tabBar = _tabContainer.GetTabBar(); + tabBar.TabCloseDisplayPolicy = TabBar.CloseButtonDisplayPolicy.ShowAlways; + tabBar.TabClosePressed += OnTabClosePressed; + } + + private void OnTabClicked(long tab) + { + var sharpIdeFile = _tabContainer.GetChild((int)tab).SharpIdeFile; + GodotGlobalEvents.InvokeFileExternallySelected(sharpIdeFile); + } + + private void OnTabClosePressed(long tabIndex) + { + var tab = _tabContainer.GetChild((int)tabIndex); + _tabContainer.RemoveChild(tab); + tab.QueueFree(); + } + + public async Task SetSharpIdeFile(SharpIdeFile file) + { + var existingTab = _tabContainer.GetChildren().OfType().FirstOrDefault(t => t.SharpIdeFile == file); + if (existingTab is not null) + { + var existingTabIndex = existingTab.GetIndex(); + if (existingTabIndex == _tabContainer.CurrentTab) return; + await this.InvokeAsync(() => _tabContainer.CurrentTab = existingTabIndex); + return; + } + var newTab = _sharpIdeCodeEditScene.Instantiate(); + newTab.Solution = Solution; + await this.InvokeAsync(() => + { + _tabContainer.AddChild(newTab); + var newTabIndex = _tabContainer.GetTabCount() - 1; + _tabContainer.SetTabIcon(newTabIndex, CsFileTexture); + _tabContainer.SetTabTitle(newTabIndex, file.Name); + _tabContainer.SetTabTooltip(newTabIndex, file.Path); + _tabContainer.CurrentTab = newTabIndex; + }); + await newTab.SetSharpIdeFile(file); + } +} \ No newline at end of file diff --git a/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.cs.uid b/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.cs.uid new file mode 100644 index 0000000..c21f072 --- /dev/null +++ b/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.cs.uid @@ -0,0 +1 @@ +uid://cy7erscaagrtj diff --git a/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.tscn b/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.tscn index b7dcb34..2d004ce 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.tscn +++ b/src/SharpIDE.Godot/Features/CodeEditor/CodeEditorPanel.tscn @@ -1,6 +1,12 @@ -[gd_scene load_steps=2 format=3 uid="uid://c5dlwgcx3ubyp"] +[gd_scene load_steps=6 format=3 uid="uid://c5dlwgcx3ubyp"] +[ext_resource type="Script" uid="uid://cy7erscaagrtj" path="res://Features/CodeEditor/CodeEditorPanel.cs" id="1_eraxv"] [ext_resource type="PackedScene" uid="uid://cinaqbdghcvoi" path="res://Features/CodeEditor/SharpIdeCodeEdit.tscn" id="1_y4okr"] +[ext_resource type="Texture2D" uid="uid://do0edciarrnp0" path="res://Features/SolutionExplorer/Resources/CsharpFile.svg" id="2_dbtmr"] +[ext_resource type="StyleBox" uid="uid://bun830pn1vfxw" path="res://Features/CodeEditor/Resources/TabBarTabStyle.tres" id="2_m4iuw"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_m4iuw"] +bg_color = Color(0.11764706, 0.11764706, 0.11764706, 1) [node name="CodeEditorPanel" type="MarginContainer"] anchors_preset = 15 @@ -8,7 +14,19 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +script = ExtResource("1_eraxv") +CsFileTexture = ExtResource("2_dbtmr") -[node name="SharpIdeCodeEdit" parent="." instance=ExtResource("1_y4okr")] +[node name="TabContainer" type="TabContainer" parent="."] layout_mode = 2 -delimiter_strings = Array[String](["\" \"", "' '"]) +theme_override_constants/side_margin = 0 +theme_override_constants/icon_max_width = 22 +theme_override_font_sizes/font_size = 15 +theme_override_styles/tabbar_background = SubResource("StyleBoxFlat_m4iuw") +theme_override_styles/tab_selected = ExtResource("2_m4iuw") +current_tab = 0 +drag_to_rearrange_enabled = true + +[node name="SharpIdeCodeEdit" parent="TabContainer" instance=ExtResource("1_y4okr")] +layout_mode = 2 +metadata/_tab_index = 0 diff --git a/src/SharpIDE.Godot/Features/CodeEditor/Resources/TabBarTabStyle.tres b/src/SharpIDE.Godot/Features/CodeEditor/Resources/TabBarTabStyle.tres new file mode 100644 index 0000000..2258fe9 --- /dev/null +++ b/src/SharpIDE.Godot/Features/CodeEditor/Resources/TabBarTabStyle.tres @@ -0,0 +1,11 @@ +[gd_resource type="StyleBoxFlat" format=3 uid="uid://bun830pn1vfxw"] + +[resource] +content_margin_left = 10.0 +content_margin_top = 4.0 +content_margin_right = 10.0 +content_margin_bottom = 4.0 +bg_color = Color(0.1, 0.1, 0.1, 0.6) +border_width_bottom = 2 +border_color = Color(1, 1, 1, 0.75) +corner_detail = 1 diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs index d031cdd..991b48d 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs @@ -25,6 +25,7 @@ public partial class SharpIdeCodeEdit : CodeEdit private int _selectionEndCol; public SharpIdeSolutionModel? Solution { get; set; } + public SharpIdeFile SharpIdeFile => _currentFile; private SharpIdeFile _currentFile = null!; private CustomHighlighter _syntaxHighlighter = new(); diff --git a/src/SharpIDE.Godot/Features/SolutionExplorer/SolutionExplorerPanel.cs b/src/SharpIDE.Godot/Features/SolutionExplorer/SolutionExplorerPanel.cs index f92a5f9..46884ea 100644 --- a/src/SharpIDE.Godot/Features/SolutionExplorer/SolutionExplorerPanel.cs +++ b/src/SharpIDE.Godot/Features/SolutionExplorer/SolutionExplorerPanel.cs @@ -49,6 +49,7 @@ public partial class SolutionExplorerPanel : MarginContainer item.UncollapseTree(); _tree.SetSelected(item, 0); _tree.ScrollToItem(item, true); + _tree.QueueRedraw(); }); } } diff --git a/src/SharpIDE.Godot/IdeRoot.cs b/src/SharpIDE.Godot/IdeRoot.cs index c867a41..e4b3bd3 100644 --- a/src/SharpIDE.Godot/IdeRoot.cs +++ b/src/SharpIDE.Godot/IdeRoot.cs @@ -4,6 +4,7 @@ using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.SolutionDiscovery; using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence; using SharpIDE.Godot.Features.BottomPanel; +using SharpIDE.Godot.Features.CodeEditor; using SharpIDE.Godot.Features.CustomControls; using SharpIDE.Godot.Features.Run; using SharpIDE.Godot.Features.SolutionExplorer; @@ -15,7 +16,7 @@ public partial class IdeRoot : Control private Button _openSlnButton = null!; private Button _buildSlnButton = null!; private FileDialog _fileDialog = null!; - private SharpIdeCodeEdit _sharpIdeCodeEdit = null!; + private CodeEditorPanel _codeEditorPanel = null!; private SolutionExplorerPanel _solutionExplorerPanel = null!; private InvertedVSplitContainer _invertedVSplitContainer = null!; private RunPanel _runPanel = null!; @@ -32,7 +33,7 @@ public partial class IdeRoot : Control _buildSlnButton = GetNode