ui help function

This commit is contained in:
2026-08-10 21:37:05 +02:00
parent 87720e6db4
commit 94b4ed7fb3
4 changed files with 99 additions and 1 deletions
+2 -1
View File
@@ -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/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/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/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)
- ESC: exit the program
- 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.
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.
+9
View File
@@ -142,6 +142,15 @@ namespace MarcerGameDvdLauncher
}
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)
{
case ConsoleKey.UpArrow:
+87
View File
@@ -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
private (ConsoleColor fg, ConsoleColor bg) GetColors(GameEntry e, bool selected)
{
+1
View File
@@ -64,6 +64,7 @@ A performant, consistent console launcher for the Hatari emulator on Windows. Co
- ESC or Q: exit the program immediately
- PageUp/PageDown: jump exactly one screen full (window height - 1)
- `*`: toggle favorite on selected ZIP
- `?`: show a help box with key bindings
- Display always one line less than console height; no overflow/cut-off
- **Cursor position saving per directory:**
- The last position/selection of each directory is retained, even after Backspace