Skip to content

Fix invisible menu bar text in Windows dark mode#105

Merged
beneaze merged 4 commits into
mainfrom
fix/dark-mode-menubar-visibility
Jul 10, 2026
Merged

Fix invisible menu bar text in Windows dark mode#105
beneaze merged 4 commits into
mainfrom
fix/dark-mode-menubar-visibility

Conversation

@beneaze

@beneaze beneaze commented Jul 10, 2026

Copy link
Copy Markdown
Member

Problem

When Windows is in dark mode and Optiverse runs in its light theme, the menu bar items (File, Edit, Insert, …) are invisible — white text on the light menu-bar background.

Root cause

On Windows 11, Qt's native style paints native chrome — most visibly the QMenuBar's top-level items — using the OS color scheme, ignoring both the QSS color (light_theme.qss already sets QMenuBar::item { color: black }) and the application palette. So with the OS in dark mode, Qt draws the menu text white regardless of the light theme the app applied.

Fix

Pin Qt's color scheme to match the applied theme via QStyleHints.setColorScheme() (Qt 6.8+) inside apply_theme(). This keeps native rendering consistent with the theme the app actually applies, in both directions (light app on dark OS, and vice versa).

  • Called on every apply_theme() so it stays correct through in-app theme toggles.
  • Guarded with getattr so older Qt builds (PyQt6>=6.5) degrade to a no-op rather than crashing — QSS/palette still apply as before.

Verification

On a machine with Windows in dark mode (OS scheme reported Dark):

scheme after light: ColorScheme.Light
scheme after dark : ColorScheme.Dark
scheme back to light: ColorScheme.Light

The color scheme now tracks the applied theme, so the light-theme menu bar renders dark text and is legible under OS dark mode.

🤖 Generated with Claude Code

beneaze and others added 4 commits July 10, 2026 10:32
On Windows 11, Qt's native style paints native chrome - most visibly
the QMenuBar's top-level items - using the OS color scheme, ignoring
the QSS `color` and the application palette. When the OS is in dark
mode but Optiverse is in light mode, the menu bar renders white text
on its light background, making "File/Edit/Insert/..." invisible.

Pin Qt's color scheme to match the applied theme via
QStyleHints.setColorScheme (Qt 6.8+) in apply_theme, so native
rendering stays consistent with the theme we actually apply. Guarded
with getattr so older Qt builds degrade to a no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI's mypy (unpinned, newer than the last green run on main) flags three
errors unrelated to the menu-bar fix but which block this PR's pipeline:

- raytracing_math.py: the numba-fallback `def jit` re-defines the name
  imported in the try-branch -> [no-redef]. Suppress with type: ignore.
- refractive.py (x2): refract_vector_snell is annotated to return
  `np.ndarray | None`, but both return paths return a real ndarray (the
  TIR branch returns the reflected direction, not None). The lone caller
  never handles None. Narrow the return type to `tuple[np.ndarray, bool]`
  and correct the docstring, which resolves both call-site errors.

Verified locally: `ruff check .` and `mypy src/` both pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_iter_component_json_files relied on Path.iterdir(), whose order is
filesystem dependent, so get_standard_components() returned components
in a different order per OS. This made test_standard_lens_definition
pass on macOS but fail on Linux/Windows (the "first lens" was
Microscope Objective instead of Standard Lens).

Sort the discovered component folders by name so the order is stable
across platforms. Alphabetical folder order puts lens_standard_1in
("Standard Lens") ahead of objective_standard ("Microscope Objective"),
matching the test's expectation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Windows CI's mypy flags the numba-fallback `def jit` with code `misc`
("All conditional function variants must have identical signatures")
rather than `no-redef` seen on Linux/macOS, because numba's
importability during analysis differs per platform. Suppress both
codes; warn_unused_ignores is off so the inapplicable one is harmless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@beneaze
beneaze merged commit d9ff18b into main Jul 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant