[Development] Dark mode, palettes, styles etc.

Shawn Rutledge Shawn.Rutledge at qt.io
Fri Jul 6 17:08:28 CEST 2018


> On 6 Jul 2018, at 11:47, Jean-Michaël Celerier <jeanmichael.celerier at gmail.com> wrote:
> 
> > Another easy thing I think we could add to QPalette is the set of (16?) most-common colors.  That way, when an application really wants something to be blue, it could use QPalette:Blue, and the theme would be able to control the brightness and the exact shade of blue.  
> 
> A good benchmark for this would be to check how it would work with the Base16 theming framework, based on 16 colors : https://github.com/chriskempson/base16 ; they can be checked there : http://chriskempson.com/projects/base16/

That looks like a similar idea, but each color has a purpose, it’s not just a named color.  Some would overlap with existing QPalette colors, and some would be new to us.  To me it sounds OK to add those that we don’t have yet.

It looks like Chris decided to use yaml files, but we don’t ship a YAML parser in Qt Core, only in Qt Application Manager.  But the parsing looks trivial in this case: just need to look for colons and quotes on each line, that’s all.  e.g. https://github.com/tilal6991/base16-onedark-scheme/blob/master/onedark.yaml

We need to agree on the best way to serialize a QPalette. 

JSON has been suggested.

CBOR ought to be an option now, but you need a tool to edit it.  Not that it would be hard to write one.

It looks like KDE consensus is that QSettings is fine for color palettes.  e.g. for Kvantum Adapta I have /usr/share/Kvantum/Adapta/Adapta.kvconfig and /usr/share/Kvantum/AdaptaNokto/AdaptaNokto.kvconfig; Breeze has /usr/share/color-schemes/Breeze.colors.  Those are all INI files, and it looks like Kvantum’s style/themeconfig/ThemeConfig.cpp uses QSettings to read them.

There’s a command-line tool to switch themes: https://www.reddit.com/r/kde/comments/8207td/change_the_theming_based_on_the_time/

lookandfeeltool --apply org.kde.breeze.desktop
lookandfeeltool --apply org.kde.breezedark.desktop

Fine, so it looks possible to write a plasmoid that has a simple dark/light switch.  And widget apps all use the same theme.  Even QtQuick is OK: system palette colors are updated when I run lookandfeeltool or otherwise change it.  So if an app's Controls style uses palette colors, it should be fine.

Maybe the cross-platform guarantee then should be that on other desktops like macOS, the palette colors will be changed appropriately when the user switches to dark mode, and the event is sent to the application to ensure that it re-renders.  It sounds like that’s what we can expect anyway:

>> On 4 Jul 2018, at 16:19, Morten Sørvig <Morten.Sorvig at qt.io> wrote:
>> Dark appearance: In theory, applications should pick up the dark appearance via
>> the style and palette. In practice, they may not due to incomplete/buggy QPalette
>> and QMacStyle implementations, or hardcoded colors in Qt or the application.


> There's also Kvantum which is a SVG theme engine for Qt (examples: https://store.kde.org/browse/cat/123/) ; it would be nice to have it integrated to Qt directly maybe ? And then use a GPU-based SVG renderer to only have to do the GPU work once (how far is QtQuick.Shapes from rendering full-fledged SVG ?).

Do they use QtSVG to render each widget every time it’s painted, or just use it to generate scaled images that are reused as e.g. 9-patches on each widget, or something else?  If it only generates a set of images when the resolution or the theme changes, the rendering cost might be low enough anyway.  But here https://github.com/tsujan/Kvantum/blob/master/Kvantum/style/rendering.cpp it looks like Style::renderElement() uses QSvgRenderer directly.  Maybe I missed some sort of caching there.

QtQuick.Shapes can render SVG paths (see the tiger example), but general SVG support is complex.  AFAIK we haven’t yet tried to turn Shapes into a general solution… but it seems worth trying to see how far we could get.  It would certainly turn out that some features are too hard, but QtSVG already is limited to SVG Tiny to avoid having to implement everything.  I think it would be better to use private APIs to render a whole SVG directly to scene-graph nodes, not construct all those QObjects using the public API.  (The tiger example instantiates too many objects.)  But even then, it might make every frame more expensive to render; but that could be mitigated by turning on layering I suppose, if it becomes a bottleneck.

To render scalable icons, there are a couple more tools already BTW: one is to use an icon font like FontAwesome.  If you like flat design, it’s fine, because those icons will usually be monochrome… but at least they’re scalable, and antialiased, you benefit from the speed of TrueType rendering, and switching colors is no problem, so that should be a nice solution for “dark mode".  But one feature we are missing is the ability to look up a glyph by name.  You might look up and use the Unicode code point; the easier way for now though is to use the icon itself as a literal in your QML Text element (because unlike C++ files, we assume QML is always UTF-8).  What I would like as an alternative is

Glyph {
	font.family: “FontAwesome"
	name: “address-book” // to pick something at random
	color: palette.buttonText
}

Text layout is expensive, but the Glyph item would be able to bypass that, because it knows all it has to do is insert a single QSGGlyphNode into the scene graph.  But that name lookup bit is the hard part.  Freetype has FT_Get_Name_Index( FT_Face face, FT_String* glyph_name ) which I think we could use to implement that… but we don’t use Freetype on every platform, so making this work cross-platform requires a bit of research.

Thanks to the popularity of emoticons, there can be color fonts now; but out of the three possible standards for that, only one of them does it by allowing you to make colored layers of the same scalable Bezier curves that TrueType normally uses.  Another standard allows the font to contain embedded mipmaps, and another allows it to contain embedded SVG images.  But what if the colored layers in the first case could use named colors, wouldn’t that be cool?

Another alternative is to use PDF for icons.  This is not a way of avoiding software rendering, but PDFium is kindof fast in practice.  And your PDFs could include vector graphics rather than images.  Color even.  So you could use a different “page” for each icon… and to make that nice to use, I need to finish up the patches to allow you to choose the page number or frame number in any QML Image.  (I was thinking it would work equally well for animated image formats as for multi-page formats like PDF and TIFF.)  It’s on my todo list for when Input Handlers are sufficiently “done” that I have time for other things again.

But now we’re off topic for “dark mode”… scalable graphics with their own hard-coded colors don’t really help to accomplish that, it’s only when some sort of color palette lookup could be used that it would help.  Or switching graphics completely, but you can do that with images too.



More information about the Development mailing list