From d087e12fb0636165b3c6da72078905f15ec8022c Mon Sep 17 00:00:00 2001 From: Rix Date: Wed, 21 Oct 2026 02:15:44 -0700 Subject: [PATCH] Menu bar: check marks for on/off items, dots for a picked option An on/off item that is on (Snap, Orthographic, Boot Logo in Test Runs, the relay, panels) now shows a check mark. A dot is kept for the picked option of a group: the tool, the look, and the console count. menumarkcheck opens View, Build and Players and reads each mark by name and in the screenshot. Fixes #232 --- .github/workflows/build.yml | 3 + src/mockup/main_screen.cpp | 37 ++++++++--- src/ui/icons.h | 1 + tests/menumarkcheck.py | 129 ++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 tests/menumarkcheck.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 422ee53..2f3e965 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -244,6 +244,9 @@ jobs: - name: Debug overlays if: runner.os == 'Linux' run: LIBGL_ALWAYS_SOFTWARE=1 xvfb-run -a -s "-screen 0 1600x960x24" python3 tests/overlaycheck.py build/splashedit + - name: Menu check marks and dots + if: runner.os == 'Linux' + run: LIBGL_ALWAYS_SOFTWARE=1 xvfb-run -a -s "-screen 0 1600x960x24" python3 tests/menumarkcheck.py build/splashedit - name: Boot logo off if: runner.os == 'Linux' run: LIBGL_ALWAYS_SOFTWARE=1 xvfb-run -a -s "-screen 0 1600x960x24" python3 tests/bootlogocheck.py build/splashedit build/emulator_tests diff --git a/src/mockup/main_screen.cpp b/src/mockup/main_screen.cpp index db368c2..f5f5517 100644 --- a/src/mockup/main_screen.cpp +++ b/src/mockup/main_screen.cpp @@ -2596,6 +2596,7 @@ struct MenuEntry { enum Kind { Item, Separator, Heading } kind = Item; std::string label, shortcut; bool enabled = true, checked = false; + bool choice = false; // one of a group: the picked one shows a dot, an on/off item a check mark std::function run; }; @@ -2608,6 +2609,12 @@ static MenuEntry item(std::string label, std::string shortcut, bool enabled, std e.run = std::move(run); return e; } +// One option of a group (tool, look, console count): the picked one shows a dot. +static MenuEntry choice(std::string label, std::string shortcut, std::function run, bool picked) { + MenuEntry e = item(std::move(label), std::move(shortcut), true, std::move(run), picked); + e.choice = true; + return e; +} static MenuEntry separator() { MenuEntry e; e.kind = MenuEntry::Separator; @@ -2742,19 +2749,19 @@ static std::vector menuEntries(int which, State& st, editor::Document case 6: // the Players button's list m.push_back(heading("Consoles Play boots")); for (int n = 1; n <= editor::kMaxPlayers; ++n) - m.push_back(item(n == 1 ? std::string("1 Console") : n == 2 ? std::string("2 Linked Consoles") : std::to_string(n) + " Consoles", - "", true, [&st, n] { setPlayers(st, n); }, st.play.tools.players == n)); + m.push_back(choice(n == 1 ? std::string("1 Console") : n == 2 ? std::string("2 Linked Consoles") : std::to_string(n) + " Consoles", + "", [&st, n] { setPlayers(st, n); }, st.play.tools.players == n)); m.push_back(separator()); m.push_back(item("Use the Relay for 2 Consoles", "", true, [&] { setRelay(st, !st.play.tools.relay); }, st.play.tools.relay)); break; case 4: // View - m.push_back(item("Hand", "Q", true, [&] { st.tool = 0; }, st.tool == 0)); - m.push_back(item("Move", "W", true, [&] { st.tool = 1; }, st.tool == 1)); - m.push_back(item("Rotate", "E", true, [&] { st.tool = 2; }, st.tool == 2)); - m.push_back(item("Scale", "R", true, [&] { st.tool = 3; }, st.tool == 3)); + m.push_back(choice("Hand", "Q", [&] { st.tool = 0; }, st.tool == 0)); + m.push_back(choice("Move", "W", [&] { st.tool = 1; }, st.tool == 1)); + m.push_back(choice("Rotate", "E", [&] { st.tool = 2; }, st.tool == 2)); + m.push_back(choice("Scale", "R", [&] { st.tool = 3; }, st.tool == 3)); m.push_back(separator()); - m.push_back(item("PS1 Look", "", true, [&] { st.viewMode = 0; }, st.viewMode == 0)); - m.push_back(item("Clean Look", "", true, [&] { st.viewMode = 1; }, st.viewMode == 1)); + m.push_back(choice("PS1 Look", "", [&] { st.viewMode = 0; }, st.viewMode == 0)); + m.push_back(choice("Clean Look", "", [&] { st.viewMode = 1; }, st.viewMode == 1)); m.push_back(separator()); m.push_back(item("Snap", "", true, [&] { st.snap = !st.snap; }, st.snap)); m.push_back(item("Orthographic", "", true, [&] { view.setOrtho(!view.ortho()); }, view.ortho())); @@ -2852,7 +2859,19 @@ static std::function menuRows(const std::vector& entries, flo if (!menu.empty()) nameRect(menu + "/" + e.label, ir); const bool on = e.enabled && hit.hover > 0; if (on) dl->AddRectFilled(ir.Min, ir.Max, lerpColor(rgb(0x2a2f39, 0), color::hover, hit.hover), radius::field); - if (e.checked) dl->AddCircleFilled(ImVec2(ir.Min.x + space::md, ir.GetCenter().y), 3.5f, color::accent, 12); + if (e.checked) { + // Scripted checks find the mark as /