mirror of
https://github.com/skoelle/marcer-gamedvd-launcher.git
synced 2026-09-17 18:50:25 +00:00
ui help function
This commit is contained in:
@@ -12,7 +12,7 @@ The implementation is split into focused modules (files) under the `MarcerGameDv
|
|||||||
- MarcerGameDvdLauncher/ProgramHelpers.cs: Small shared helpers (resolve relative paths, centralized console message helper) used across modules.
|
- MarcerGameDvdLauncher/ProgramHelpers.cs: Small shared helpers (resolve relative paths, centralized console message helper) used across modules.
|
||||||
- MarcerGameDvdLauncher/OverlayDirectoryBrowser.cs: Filesystem overlay and browsing logic — merges root and patch directories, enumerates folders and ZIPs, protects against path traversal and ensures navigation cannot leave the configured roots.
|
- MarcerGameDvdLauncher/OverlayDirectoryBrowser.cs: Filesystem overlay and browsing logic — merges root and patch directories, enumerates folders and ZIPs, protects against path traversal and ensures navigation cannot leave the configured roots.
|
||||||
- MarcerGameDvdLauncher/NavigationController.cs: Encapsulates selection, scrolling and relative-path navigation logic (cursor, page up/down, per-directory remembered selection/state).
|
- MarcerGameDvdLauncher/NavigationController.cs: Encapsulates selection, scrolling and relative-path navigation logic (cursor, page up/down, per-directory remembered selection/state).
|
||||||
- MarcerGameDvdLauncher/MenuRenderer.cs: Console rendering logic — efficient per-line redraw, double-buffering and color selection according to overlay rules.
|
- MarcerGameDvdLauncher/MenuRenderer.cs: Console rendering logic — efficient per-line redraw, double-buffering, color selection according to overlay rules, and the help box overlay.
|
||||||
- MarcerGameDvdLauncher/HatariLauncher.cs: Responsible for validating the Hatari executable and starting Hatari with the configured argument template (replaces `{cfg}` and `{zip}`).
|
- MarcerGameDvdLauncher/HatariLauncher.cs: Responsible for validating the Hatari executable and starting Hatari with the configured argument template (replaces `{cfg}` and `{zip}`).
|
||||||
- MarcerGameDvdLauncher/UIErrorService.cs: Centralized UI error presentation using the console message helper.
|
- MarcerGameDvdLauncher/UIErrorService.cs: Centralized UI error presentation using the console message helper.
|
||||||
|
|
||||||
@@ -57,6 +57,7 @@ The console launcher is meant for browsing a games directory and can launch ZIP
|
|||||||
- Backspace: jump to parent directory (never outside root)
|
- Backspace: jump to parent directory (never outside root)
|
||||||
- ESC: exit the program
|
- ESC: exit the program
|
||||||
- PageUp/PageDown: jump by one page up/down through the file list
|
- PageUp/PageDown: jump by one page up/down through the file list
|
||||||
|
- `?`: show a help box with key bindings
|
||||||
- The file list always shows exactly as many lines as fit the screen – ALWAYS **one line less** than the console height (`Console.WindowHeight - 1`). This avoids overflow at the bottom and ensures the selection never enters the non-visible area.
|
- The file list always shows exactly as many lines as fit the screen – ALWAYS **one line less** than the console height (`Console.WindowHeight - 1`). This avoids overflow at the bottom and ensures the selection never enters the non-visible area.
|
||||||
Rationale: writing to the very last console line can cause the Windows console to auto-scroll or produce visual jumps when the cursor reaches the bottom row. Reserving one line prevents unintended scrolling/flicker and keeps the selection cursor strictly within the visible area.
|
Rationale: writing to the very last console line can cause the Windows console to auto-scroll or produce visual jumps when the cursor reaches the bottom row. Reserving one line prevents unintended scrolling/flicker and keeps the selection cursor strictly within the visible area.
|
||||||
Maintenance: when changing rendering or navigation logic, always compute the displayed page size as `availableLines = Console.WindowHeight - 1` and keep this value consistent across MenuRenderer, NavigationController and any other code that references the console height.
|
Maintenance: when changing rendering or navigation logic, always compute the displayed page size as `availableLines = Console.WindowHeight - 1` and keep this value consistent across MenuRenderer, NavigationController and any other code that references the console height.
|
||||||
|
|||||||
@@ -142,6 +142,15 @@ namespace MarcerGameDvdLauncher
|
|||||||
}
|
}
|
||||||
|
|
||||||
var key = Console.ReadKey(intercept: true);
|
var key = Console.ReadKey(intercept: true);
|
||||||
|
if (key.KeyChar == '?')
|
||||||
|
{
|
||||||
|
_menuRenderer.ShowHelpBox(currentAvailableLines);
|
||||||
|
Console.ReadKey(intercept: true);
|
||||||
|
_menuRenderer.InvalidateCache();
|
||||||
|
_menuRenderer.DrawMenu(_gameEntries, _navigationController.ScrollOffset, _navigationController.SelectedIndex, currentAvailableLines, isFav);
|
||||||
|
ProgramHelpers.FlushInputBuffer();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (key.Key)
|
switch (key.Key)
|
||||||
{
|
{
|
||||||
case ConsoleKey.UpArrow:
|
case ConsoleKey.UpArrow:
|
||||||
|
|||||||
@@ -139,6 +139,93 @@ namespace MarcerGameDvdLauncher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidates the internal line cache so the next DrawMenu call
|
||||||
|
// performs a full redraw of every line. Useful after an overlay
|
||||||
|
// (e.g. help box) has overwritten the console directly.
|
||||||
|
public void InvalidateCache()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _cachedBuffer.Length; i++)
|
||||||
|
_cachedBuffer[i].Text = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders a centered, bordered help box with key bindings inside the
|
||||||
|
// available console area. The caller is responsible for waiting on a
|
||||||
|
// key and redrawing the menu afterwards.
|
||||||
|
public void ShowHelpBox(int availableLines)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int width = Console.WindowWidth;
|
||||||
|
string[] helpLines = GetHelpLines();
|
||||||
|
int boxHeight = Math.Min(helpLines.Length + 2, Math.Max(3, availableLines));
|
||||||
|
int boxWidth = Math.Max(1, width);
|
||||||
|
int topRow = Math.Max(0, (availableLines - boxHeight) / 2);
|
||||||
|
|
||||||
|
Console.BackgroundColor = ConsoleColor.DarkGray;
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
|
||||||
|
string topBorder = "+" + new string('-', Math.Max(0, boxWidth - 2)) + "+";
|
||||||
|
Console.SetCursorPosition(0, topRow);
|
||||||
|
Console.Write(topBorder);
|
||||||
|
|
||||||
|
for (int i = 0; i < boxHeight - 2; i++)
|
||||||
|
{
|
||||||
|
int row = topRow + 1 + i;
|
||||||
|
string content;
|
||||||
|
if (i < helpLines.Length)
|
||||||
|
{
|
||||||
|
content = PadToWidth(helpLines[i], boxWidth - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content = new string(' ', Math.Max(0, boxWidth - 2));
|
||||||
|
}
|
||||||
|
Console.SetCursorPosition(0, row);
|
||||||
|
Console.Write("|" + content + "|");
|
||||||
|
}
|
||||||
|
|
||||||
|
int bottomRow = topRow + boxHeight - 1;
|
||||||
|
if (bottomRow < Console.WindowHeight)
|
||||||
|
{
|
||||||
|
string bottomBorder = "+" + new string('-', Math.Max(0, boxWidth - 2)) + "+";
|
||||||
|
Console.SetCursorPosition(0, bottomRow);
|
||||||
|
Console.Write(bottomBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] GetHelpLines()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
" Help — Key Bindings",
|
||||||
|
" ",
|
||||||
|
" ↑ / ↓ Move selection up / down",
|
||||||
|
" Enter / → Open folder / launch ZIP with Hatari",
|
||||||
|
" ← / BS Go up one directory (never exceeds root)",
|
||||||
|
" ESC / Q Exit the program",
|
||||||
|
" PgUp Jump one page up",
|
||||||
|
" PgDn Jump one page down",
|
||||||
|
" * Toggle favorite on selected ZIP",
|
||||||
|
" ? Show this help",
|
||||||
|
" ",
|
||||||
|
" Navigation is strictly limited to RootDirectory.",
|
||||||
|
" The overlay shows both root and patch layers combined.",
|
||||||
|
" ",
|
||||||
|
" Press any key to continue...",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string PadToWidth(string text, int width)
|
||||||
|
{
|
||||||
|
if (text.Length > width) return text.Substring(0, width);
|
||||||
|
return text + new string(' ', width - text.Length);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns foreground and background colors for an entry depending on selection state
|
// Returns foreground and background colors for an entry depending on selection state
|
||||||
private (ConsoleColor fg, ConsoleColor bg) GetColors(GameEntry e, bool selected)
|
private (ConsoleColor fg, ConsoleColor bg) GetColors(GameEntry e, bool selected)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ A performant, consistent console launcher for the Hatari emulator on Windows. Co
|
|||||||
- ESC or Q: exit the program immediately
|
- ESC or Q: exit the program immediately
|
||||||
- PageUp/PageDown: jump exactly one screen full (window height - 1)
|
- PageUp/PageDown: jump exactly one screen full (window height - 1)
|
||||||
- `*`: toggle favorite on selected ZIP
|
- `*`: toggle favorite on selected ZIP
|
||||||
|
- `?`: show a help box with key bindings
|
||||||
- Display always one line less than console height; no overflow/cut-off
|
- Display always one line less than console height; no overflow/cut-off
|
||||||
- **Cursor position saving per directory:**
|
- **Cursor position saving per directory:**
|
||||||
- The last position/selection of each directory is retained, even after Backspace
|
- The last position/selection of each directory is retained, even after Backspace
|
||||||
|
|||||||
Reference in New Issue
Block a user