30. napari's styling is copied until napari publishes it¶
Date: 2026-10-09
Status¶
Accepted
Context¶
A Qt session used the style the platform gives every window, and the only
way to change its look was to write a configure_application
hook provider. Many labs run napari beside their
acquisition software, and two windows that look alike are easier to move
between. napari's styling is three Qt stylesheets with placeholders, a set
of SVG icons recoloured for each theme, and the Python that fills them in.
It ships only
inside napari itself, which is far too large a dependency for a look.
napari plans to publish its styling as a package of its own, but that
package doesn't exist yet.
A session file also had no short way to name a provider redsun ships: it
had to spell out the class path.
Decision¶
redsuncopies napari 0.9.2's stylesheets and icons unchanged, with napari's BSD 3-Clause licence, and rewrites the code that fills them in. The result matches napari's own output for both themes.NapariStyleinredsun.qt.styles.napariis aconfigure_applicationprovider. It picks napari's dark or light theme from the colour scheme, and picks again whenever the scheme changes, so the colour scheme button stays the one switch. At shutdown it puts back the stylesheet the application had before.redsun's own manifest gets ahookssection of short names. A session file names a built-in provider asconfigure_application: napari, or asprovider: napariwhen it passeskwargs.- The stylesheet points at the recoloured icons by their file path. napari
registers the folder under a path prefix such as
theme_darkwithQDir.addSearchPath, which adds the folder once more at every call, andQDir.setSearchPaths, which would replace it, refuses a prefix holding an underscore. A file path needs neither, and leaves behind no setting that every window in the process shares. redsun.qt.stylesimports nothing, so a session loads only the style it names.
Before¶
class NapariLike:
def configure_application(self, app: QApplication) -> None:
app.setStyleSheet(Path("napari-dark.qss").read_text())
class MyApp(QtSession):
configure_application: AsHook[NapariLike]
The stylesheet is copied by hand, its images don't load, and it stays dark whatever the colour scheme button says.
After¶
Other options were rejected:
- Depending on
napari. It installs a viewer, its plugins and their dependencies to style one window. - One
redsun.qt.stylesmodule importing every style. A session would import the dependencies of styles it doesn't use. - Styles as factory functions or modules. The hook loader takes a class, and a style keeps the application and its connection to the scheme, which belong to one object per session.
- napari's icons for the built-in views. They have no pause, save or target icon, so the views would need two icon sources kept in step.
Consequences¶
- When napari publishes its styling as a package,
redsundepends on it and deletes the copy. - A second style, built on
qlementine, follows the same pattern: a module underredsun.qt.stylesand a short name in the manifest. - A style and the built-in views' icons stay independent: the icons take the window's text colour, which every style sets.