Skip to content

Commit 3e491b5

Browse files
committed
refactor(panel): move StartMenu config into StartMenuElement
StartMenuElement now owns its own Options, keyboard shortcut, actions registry, and menu window tracking. Each element is self-contained, enabling multiple independent start menus. - Add Options, ShortcutKey, ShortcutModifiers, RegisterAction/ UnregisterAction/GetActions, Show(), MenuWindow to StartMenuElement - Update StartMenuElementBuilder with WithOptions, WithShortcutKey - Change StartMenuDialog.Show() to accept element instead of reading global state from PanelStateService - InputCoordinator iterates all StartMenuElements for shortcuts - Remove all StartMenu state from PanelStateService - Remove StartMenu/StartMenuShortcutKey/StartMenuShortcutModifiers from ConsoleWindowSystemOptions - Update StartMenuDemo and DemoApp examples
1 parent 8c528ab commit 3e491b5

8 files changed

Lines changed: 245 additions & 215 deletions

File tree

Examples/DemoApp/Program.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,22 @@ static async Task<int> Main(string[] args)
2020
try
2121
{
2222
var options = new ConsoleWindowSystemOptions(
23-
StartMenu: new StartMenuOptions
24-
{
25-
AppName = "SharpConsoleUI Demo",
26-
SidebarStyle = StartMenuSidebarStyle.IconLabel,
27-
BackgroundGradient = new GradientBackground(
28-
ColorGradient.FromColors(new Color(25, 25, 60), new Color(15, 15, 35)),
29-
GradientDirection.Vertical)
30-
},
3123
TopPanelConfig: panel => panel
3224
.Left(Elements.StatusText("[bold cyan]SharpConsoleUI Demo[/]"))
3325
.Left(Elements.Separator())
3426
.Left(Elements.StatusText("[dim]Ctrl+T: Theme[/]"))
3527
.Right(Elements.Performance()),
3628
BottomPanelConfig: panel => panel
37-
.Left(Elements.StartMenu().WithText("\u2630 Start"))
29+
.Left(Elements.StartMenu()
30+
.WithText("\u2630 Start")
31+
.WithOptions(new StartMenuOptions
32+
{
33+
AppName = "SharpConsoleUI Demo",
34+
SidebarStyle = StartMenuSidebarStyle.IconLabel,
35+
BackgroundGradient = new GradientBackground(
36+
ColorGradient.FromColors(new Color(25, 25, 60), new Color(15, 15, 35)),
37+
GradientDirection.Vertical)
38+
}))
3839
.Center(Elements.TaskBar())
3940
.Right(Elements.Clock().WithFormat("HH:mm:ss"))
4041
);

Examples/StartMenuDemo/Program.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using SharpConsoleUI.Helpers;
88
using SharpConsoleUI.Panel;
99
using SharpConsoleUI.Plugins.DeveloperTools;
10+
using SharpConsoleUI.Rendering;
1011

1112
namespace StartMenuDemo;
1213

@@ -20,14 +21,17 @@ static async Task<int> Main(string[] args)
2021

2122
var options = new ConsoleWindowSystemOptions(
2223
EnablePerformanceMetrics: false,
23-
StartMenu: new StartMenuOptions
24-
{
25-
ShowWindowList = true,
26-
SidebarStyle = StartMenuSidebarStyle.IconLabel
27-
},
2824
TopPanelConfig: panel => panel.Left(Elements.StatusText("")),
2925
BottomPanelConfig: panel => panel
30-
.Left(Elements.StartMenu())
26+
.Left(Elements.StartMenu()
27+
.WithOptions(new StartMenuOptions
28+
{
29+
ShowWindowList = true,
30+
SidebarStyle = StartMenuSidebarStyle.IconLabel,
31+
BackgroundGradient = new GradientBackground(
32+
ColorGradient.FromColors(new Color(25, 25, 60), new Color(15, 15, 35)),
33+
GradientDirection.Vertical)
34+
}))
3135
.Center(Elements.TaskBar())
3236
);
3337

@@ -52,8 +56,11 @@ static async Task<int> Main(string[] args)
5256
Console.WriteLine($"\x1b[33mNote: DeveloperTools plugin not available: {ex.Message}\x1b[0m");
5357
}
5458

59+
// Get the start menu element to register actions on it
60+
var startMenu = windowSystem.BottomPanel!.FindElement<StartMenuElement>("startmenu")!;
61+
5562
// Register user actions - File category
56-
windowSystem.PanelStateService.RegisterStartMenuAction("New Document", () =>
63+
startMenu.RegisterAction("New Document", () =>
5764
{
5865
var window = new Window(windowSystem)
5966
{
@@ -74,7 +81,7 @@ static async Task<int> Main(string[] args)
7481
windowSystem.SetActiveWindow(window);
7582
}, category: "File", order: 10);
7683

77-
windowSystem.PanelStateService.RegisterStartMenuAction("Open File", () =>
84+
startMenu.RegisterAction("Open File", () =>
7885
{
7986
var window = new Window(windowSystem)
8087
{
@@ -94,7 +101,7 @@ static async Task<int> Main(string[] args)
94101
windowSystem.SetActiveWindow(window);
95102
}, category: "File", order: 20);
96103

97-
windowSystem.PanelStateService.RegisterStartMenuAction("Save File", () =>
104+
startMenu.RegisterAction("Save File", () =>
98105
{
99106
windowSystem.NotificationStateService.ShowNotification(
100107
"Save",
@@ -104,7 +111,7 @@ static async Task<int> Main(string[] args)
104111
}, category: "File", order: 30);
105112

106113
// Register user actions - Tools category
107-
windowSystem.PanelStateService.RegisterStartMenuAction("Calculator", () =>
114+
startMenu.RegisterAction("Calculator", () =>
108115
{
109116
var window = new Window(windowSystem)
110117
{

SharpConsoleUI/Configuration/ConsoleWindowSystemOptions.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,6 @@ public record ConsoleWindowSystemOptions(
8080
bool EnableQualityAnalysis = false,
8181
bool EnablePerformanceProfiling = false,
8282

83-
// Start menu configuration
84-
StartMenuOptions? StartMenu = null,
85-
ConsoleKey StartMenuShortcutKey = ConsoleKey.Spacebar,
86-
ConsoleModifiers StartMenuShortcutModifiers = ConsoleModifiers.Control,
87-
8883
// Panel system configuration
8984
Func<SharpConsoleUI.Panel.PanelBuilder, SharpConsoleUI.Panel.PanelBuilder>? TopPanelConfig = null,
9085
Func<SharpConsoleUI.Panel.PanelBuilder, SharpConsoleUI.Panel.PanelBuilder>? BottomPanelConfig = null,

SharpConsoleUI/Core/PanelStateService.cs

Lines changed: 1 addition & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,17 @@
77
// -----------------------------------------------------------------------
88

99
using SharpConsoleUI.Configuration;
10-
using SharpConsoleUI.Dialogs;
1110
using SharpConsoleUI.Logging;
12-
using SharpConsoleUI.Models;
1311

1412
namespace SharpConsoleUI.Core
1513
{
1614
/// <summary>
17-
/// Manages panel state, start menu actions, and panel visibility.
15+
/// Manages panel state and visibility.
1816
/// </summary>
1917
public class PanelStateService
2018
{
2119
private readonly ILogService _logService;
2220
private readonly Func<ConsoleWindowSystem> _getWindowSystem;
23-
private readonly List<StartMenuAction> _startMenuActions = new();
24-
25-
// Start menu window tracking
26-
private Window? _startMenuWindow;
2721

2822
// Panel references
2923
private Panel.Panel? _topPanel;
@@ -33,11 +27,6 @@ public class PanelStateService
3327
private bool _showTopPanel = true;
3428
private bool _showBottomPanel = true;
3529

36-
// Start menu configuration
37-
private StartMenuOptions _startMenuOptions = new();
38-
private ConsoleKey _startMenuShortcutKey = ConsoleKey.Spacebar;
39-
private ConsoleModifiers _startMenuShortcutModifiers = ConsoleModifiers.Control;
40-
4130
/// <summary>
4231
/// Initializes a new instance of the PanelStateService class.
4332
/// </summary>
@@ -68,28 +57,6 @@ public PanelStateService(ILogService logService, Func<ConsoleWindowSystem> getWi
6857
(_topPanel?.IsDirty ?? false)
6958
|| (_bottomPanel?.IsDirty ?? false);
7059

71-
/// <summary>
72-
/// Gets the start menu options configuration.
73-
/// </summary>
74-
public StartMenuOptions StartMenuOptions => _startMenuOptions;
75-
76-
/// <summary>
77-
/// Gets the shortcut key for toggling the start menu.
78-
/// </summary>
79-
public ConsoleKey StartMenuShortcutKey => _startMenuShortcutKey;
80-
81-
/// <summary>
82-
/// Gets the shortcut modifier keys for toggling the start menu.
83-
/// </summary>
84-
public ConsoleModifiers StartMenuShortcutModifiers => _startMenuShortcutModifiers;
85-
86-
/// <summary>
87-
/// Gets whether any panel contains a StartMenuElement.
88-
/// </summary>
89-
public bool HasStartMenu =>
90-
(_topPanel?.HasElement<Panel.StartMenuElement>() ?? false) ||
91-
(_bottomPanel?.HasElement<Panel.StartMenuElement>() ?? false);
92-
9360
/// <summary>
9461
/// Marks both panels as dirty, forcing a re-render on the next frame.
9562
/// </summary>
@@ -175,98 +142,6 @@ public string BottomStatus
175142

176143
#endregion
177144

178-
#region Start Menu Actions
179-
180-
/// <summary>
181-
/// Registers a new action in the Start menu.
182-
/// </summary>
183-
/// <param name="name">Display name of the action.</param>
184-
/// <param name="callback">Callback to execute when action is selected.</param>
185-
/// <param name="category">Optional category for grouping actions.</param>
186-
/// <param name="order">Display order (lower values appear first).</param>
187-
public void RegisterStartMenuAction(string name, Action callback, string? category = null, int order = 0)
188-
{
189-
_logService.LogDebug($"Registering Start menu action: {name}", category: "StartMenu");
190-
var action = new StartMenuAction(name, callback, category, order);
191-
_startMenuActions.Add(action);
192-
}
193-
194-
/// <summary>
195-
/// Removes an action from the Start menu by name.
196-
/// </summary>
197-
/// <param name="name">Name of the action to remove.</param>
198-
public void UnregisterStartMenuAction(string name)
199-
{
200-
_logService.LogDebug($"Unregistering Start menu action: {name}", category: "StartMenu");
201-
_startMenuActions.RemoveAll(a => a.Name == name);
202-
}
203-
204-
/// <summary>
205-
/// Gets all registered Start menu actions.
206-
/// </summary>
207-
/// <returns>Read-only list of actions.</returns>
208-
public IReadOnlyList<StartMenuAction> GetStartMenuActions() => _startMenuActions.AsReadOnly();
209-
210-
#endregion
211-
212-
#region Start Menu Display
213-
214-
/// <summary>
215-
/// Gets or sets the currently open Start menu window, if any.
216-
/// Used for toggle behavior — if non-null, the Start menu is open.
217-
/// </summary>
218-
internal Window? StartMenuWindow
219-
{
220-
get => _startMenuWindow;
221-
set => _startMenuWindow = value;
222-
}
223-
224-
/// <summary>
225-
/// Gets the screen bounds and panel location of the start menu element.
226-
/// Returns null if no start menu element exists in any panel.
227-
/// </summary>
228-
internal (System.Drawing.Rectangle bounds, bool isBottom)? GetStartMenuBounds()
229-
{
230-
var ws = _getWindowSystem();
231-
var screenHeight = ws.DesktopDimensions.Height
232-
+ (_topPanel?.Height ?? 0)
233-
+ (_bottomPanel?.Height ?? 0);
234-
235-
if (_bottomPanel != null)
236-
{
237-
var b = _bottomPanel.GetElementBounds<Panel.StartMenuElement>();
238-
if (b.HasValue)
239-
return (new System.Drawing.Rectangle(b.Value.x, screenHeight - 1, b.Value.width, 1), true);
240-
}
241-
if (_topPanel != null)
242-
{
243-
var b = _topPanel.GetElementBounds<Panel.StartMenuElement>();
244-
if (b.HasValue)
245-
return (new System.Drawing.Rectangle(b.Value.x, 0, b.Value.width, 1), false);
246-
}
247-
return null;
248-
}
249-
250-
/// <summary>
251-
/// Shows the Start menu dialog.
252-
/// </summary>
253-
public void ShowStartMenu()
254-
{
255-
_logService.LogDebug("Showing Start menu", category: "StartMenu");
256-
var windowSystem = _getWindowSystem();
257-
258-
if (windowSystem is ConsoleWindowSystem consoleWindowSystem)
259-
{
260-
StartMenuDialog.Show(consoleWindowSystem);
261-
}
262-
else
263-
{
264-
_logService.LogWarning("Cannot show Start menu: window system is not ConsoleWindowSystem", category: "StartMenu");
265-
}
266-
}
267-
268-
#endregion
269-
270145
#region Panel Initialization
271146

272147
/// <summary>
@@ -279,12 +154,6 @@ public void InitializePanels(ConsoleWindowSystemOptions options)
279154
{
280155
var ws = _getWindowSystem();
281156

282-
// Apply start menu config
283-
if (options.StartMenu != null)
284-
_startMenuOptions = options.StartMenu;
285-
_startMenuShortcutKey = options.StartMenuShortcutKey;
286-
_startMenuShortcutModifiers = options.StartMenuShortcutModifiers;
287-
288157
// Top panel: user config or default (status text + clock)
289158
if (options.TopPanelConfig != null)
290159
{

0 commit comments

Comments
 (0)