QML Themeing
-
The historical approach to theming (Widgets) was a style plugin or style sheets that allowed you to go through a large number of customizable parameters when a QWidget went and drew itself. This was great for the monolithic widgets and for native theming, but I don't think it will work in QML simply because we don't have monolithic widgets. So if no other solution comes up for themability (including platform theming), it shouldn't be too hard to recreate the QWidget library for QML ;) . (side note: since they often have properties already, you'd probably get most of the way there by making QWidget inherit QQuickPaintedItem). But I'm really hopeful that QML empowers a more flexible approach than the monolithic widget set.
So let's list the needs of theming in QML, and brainstorm some solutions that can really take advantage of the new technology. Here are the needs I culled from the mailing list discussion:
One source, multiple target platforms
Change the appearance of standard controls in my application
Style QWidget and QQuickItem UIs with the same code
Inside QML items, draw native controls without using QML
Possible solutions I culled from the mailing list discussion:
Centralized Convention on API
Object with centralized properties
Theme manager like QStyle/Style sheets
Can anyone think of further needs, or other possible solutions?
-
My favorite solution is the API convention, then to style common controls you just reimplement the common API yourself in QML and get complete control over look and feel (without the code using them having to change). It would then not be a leap to have an import Native 1.0 import statement, which imports the native components using version 1.0 of the common API. But I, at least, don't quite understand how this would be accomplished - so I have a few questions to think about.
What would such an API look like? Would it be a defined set of common UI components, much like the QWidget library? What about the desktop/mobile divide (which is growing to be less of a divide and more of a continuum)? Should the common API stay small and only assume a generic 'pointer', or would it need to cater for everything. which is harder to implement?
How would such an API be developed? Could we just wait until several platforms have working component sets, and identify the subset? Is there a clear subset that I've missed? Would it just end up being a convention once enough component sets are written?
The big question: Am I the only person who thinks re-implementing the controls every time is perfectly reasonable? Theoretically, QML is at essence a UI description layer. The full set of properties and behaviors that can be tweaked is the QML description. Aside from cascading, it's as flexible as stylesheets (and it manages the cascading through componentization, it's not gone). It will always be a bit of work to define a platform style for a full set of controls, and re-implementing entirely allows you to do it in C++ where necessary (i.e. using the actual native controls on some platforms). Is there really a description simpler than writing it in QML for non-trivial changes?
-
Hi,
What about having something like
@import Desktop 1.0@
that works similar to the Qt.labs.components.native import for mobile.
- Define a common desktop widget API
- API should be designed so that custom delegates can easily replace the default ones for powerful but simple customization (e.g. a special CheckBox look, special TabWidget tab content, ...)
- create specific plugins for Windows, Mac and Linux (perhaps even multiple ones for KDE/Gnome/...) that strictly follow that API
** probably no need to share qml ui logic
** might make sense to share c++ controller logic
** could make use of whatever theming engine is available to draw stuff
By having separate implementations for each platform we could not only achieve a native platform look but also a real native feel (e.g. how should reordering columns in a listview be visualized). The latter is today partly implemented by querying QStyle here and there but it's not perfect.
Platform specific extensions (e.g. "use small ui control" on Mac) could make use of the "hints" approach (as it is currently already done by the experimental Desktop Components).
Nils
-
At first glance of the problem I totally agree with Nils (njeisecke). I mean, when I first used QtQuick components, I've thought this will be the coding style and the general approach. I think it is elegant and similar to QtWidget system where the compiler determined the theme according to the platform.
And if abnybody needs a different look and feels for his/her emedded system he could just create his/her own set of components and import theme, as QtQuick were originally also designed to unique UIs too. -
My team in INdT has been researching about theming/styling of Qt Components.
I've synthetised what we've been done and some of our aims and ideas:http://codecereal.blogspot.com.br/2012/04/qml-themingstyling.html
-
The main problem with strictly following a cross-platform API is that you end up with a "lowest common denominator" effect:
- Platform-specific features can't be a proper part of the API and end up as hints and the like.
- Expanding the API is hard, since all properties needs to be implemented on all platforms.
- You miss out on components that exists on one platform only.
The list is based on my experience with QMacStyle. Such an API has value, but I think it's important to be aware of the limitations. I addition QStyle has "non-native feel" issues as njeisecke notes.
I propose we proceed by using all of aalpert's suggested solutions:
-
QStyle theme manager: Desktop components will support any QStyle. This is the legacy option based on existing code which will work while we implement a better solution.
-
Centralized properties: We define a nice cross-platform QML theming API which does not try do be native and does not interact with QStyle.
-
Centralized Convention on API: Allows for creating native components (with perfect look-and-feel) which share a common property set but with platform-specific differences.
Having a centralized convention ties it all together: All buttons have a "text" property. Themable buttons have the theme API, Cocoa buttons have the a Mac button type setting, and "QStyle" buttons can be styled with existing QStyles.
-
bq. On Mon, Apr 16, 2012 at 7:26 AM, Daker Fernandes Pinheiro daker.pinheiro@openbossa.org wrote:
My team in INdT has been researching about theming/styling of Qt Components.
I’ve synthetised what we’ve been done and some of our aims and ideas:http://codecereal.blogspot.com.br/2012/04/qml-themingstyling.html
Nice. Impressive serious effort at coming up with a "style-paradigm". I like the design -- it removes the "switch-statement" design issues we have with the existing (QWidget) QStyle, and your design seems quite-a-lot more elegant.
IMHO, this is the first-and-best "most-serious" public effort I have seen for something like this (kudos).
In the event your design became "default convention", I would even support the idea that all QML "Item{}" instances always have a QUiStyle property (e.g., it could be the "system-default", or we can/should be able to assume a "native-system-default" "QUiStyle").
I'll need to think about this. I have half-a-dozen other designs (mentioned in my previous links), but none may be sufficiently "universal" like you describe. For example, several of mine deal with "higher-order" concepts that directly impact "size" and "animations", based on higher-order declarative concepts like "importance" and "Z-order", but I'm uncertain that those are as work-able (as application-universal) as what you demonstrate.
Very nice job -- I'm really looking forward to your (very soon) Qt5 implementation that relies only upon the Qt5 "SceneGraph".
-
[quote author="njeisecke" date="1334315072"]Hi,
What about having something like
@import Desktop 1.0@
that works similar to the Qt.labs.components.native import for mobile.
[/quote]That was kind of the original idea for Qt.labs.components, but I'm not sure this follows all the requirements. There seems to be a desire for a set that transcends the desktop/mobile divide - this divide is what's leading me to believe we really need a new and more flexible solution.
To bridge that gap, you need more than a Qt.labs.components.nativeMobile and a Qt.labs.components.Desktop. You need one native set that switches between all of them.
The other issue is that it seems the style API is used by more than platform implementers. I always thought that QML was so powerful that writing custom UIs from scratch was child's play (but I could never get authorization for those experiments on toddlers ;) ). But when you just want to tweak the styling, for example applying a color theme in your text editor, having to re-write the entire components module seems like overkill.
[quote author="daker.pinheiro" date="1334524700"]My team in INdT has been researching about theming/styling of Qt Components.
I've synthetised what we've been done and some of our aims and ideas:http://codecereal.blogspot.com.br/2012/04/qml-themingstyling.html[/quote]
Kudos to the INdT team, that QtQuickStyles repo is quite impressive! I particularly love how you can implement the styles in QML or C++, making it easy both to create a new style of your own, or to call into native rendering code. I'm hope this makes it into Qt addons or playground soon.
The real test will be how flexible this approach is to wildly varying platforms. I know the meego components will probably never get updated to a new architecture, but it should be theoretically quite possible to redo the existing QtQuick Components sets using a mixture of the style approach (and a platform specific widgets import for widgets that are custom enough not to be styled).
Is it possible to split it up a little more, like moving the plastique folder out of that repo? It makes no sense in the current concepting phase of course, but one thing I would hope for a new platform styling API is the ability for new platform styles to easily come from outside. I got the impression that a lot of styling details went inside QWidget and friends, when it should all be abstracted out. So this new requirement I just realized is that the platform styles need to be a plugin (or import), as easy to write and swap in as the new QPA architecture. Perhaps I should look into the details of QPA more, there could be a lot to learn from it. This is also less of a problem now that it's easy to get code into Qt. I was originally very worried about this point because it would be hard for new platforms to enter our monolith - that's so much easier now with the Qt project.
[quote author="charleyb" date="1334599806"]
In the event your design became "default convention", I would even support the idea that all QML "Item{}" instances always have a QUiStyle property (e.g., it could be the "system-default", or we can/should be able to assume a "native-system-default" "QUiStyle").
[/quote]Item{} is supposed to be a primitive. Really simple. Theming/Styling certainly goes in a higher layer.
That said, a styled API could provide a StyledItem{} variant, which is a subclass of QQuickItem plus a style property, and you can use that instead of Item when you need it (perhaps even always, if you aren't writing a style of your own).
-
[quote author="morten.sorvig" date="1334577434"]The main problem with strictly following a cross-platform API is that you end up with a "lowest common denominator" effect:
- Platform-specific features can't be a proper part of the API and end up as hints and the like.
- Expanding the API is hard, since all properties needs to be implemented on all platforms.
- You miss out on components that exists on one platform only.
The list is based on my experience with QMacStyle. Such an API has value, but I think it's important to be aware of the limitations. I addition QStyle has "non-native feel" issues as njeisecke notes.
[/quote]
But the "lowest common denominator" effect is implicitly acceptable for the use-case of "write once, deploy everywhere". If you want to make an application fit in well with wildly varying platforms, you will need to write at least some bits of wildly varying UI. Half the point of QML is to help with the UI/Logic separation to shrink down the amount you'd have to rewrite. But you'll have to explicitly reach out to use "Mac" widgets if you want to feel truly native on Mac.This is based on my experience hearing people complain about Qt on Mac (which is less direct than yours, I'll grant). No matter how many things Qt tried to transparently Mac-ize, Qt applications would not feel native on Mac until you sat down with a Mac and tried. With the wildly varying form factors and input devices you get between mobile and desktop platforms, this is only going to get harder. The first solution (which is what we're talking about, because QML is starting from scratch) will have to give up on transparently making everything feel native. I think it's far easier to ensure that developers have as easy a time possible making a custom UI for a separate platform, which they will always need to do if they want it to feel like it truly belongs on that platform.
[quote author="morten.sorvig" date="1334577434"]
I propose we proceed by using all of aalpert's suggested solutions:- QStyle theme manager: Desktop components will support any QStyle. This is the legacy option based on existing code which will work while we implement a better solution.
[/quote]
Doing everything at once sounds like a lot of work... I was hoping that the problem could be researched until we find a simple and ideal solution, which cuts out a lot of needless effort.
In particular, we can't have a QStyle theme manager until we have QML widgets. The QtQuick primitive set doesn't contain the complete UI controls that QStyle works on (nor should it). To get existing QStyle code to work with QML means reimplementing QtWidgets for QML and that's a lot of work (I tried to create a QTextEdit like control in QML yesterday, and it saddened me :( ). We shouldn't rewrite Qt widgets in QML unless we're sure that's the correct solution for ultra-cross-platform UI controls. Which I am extremely skeptical of, because it was the inflexibility of Qt Widgets that spawned QML in the first place.
[quote author="morten.sorvig" date="1334577434"]
-
Centralized properties: We define a nice cross-platform QML theming API which does not try do be native and does not interact with QStyle.
-
Centralized Convention on API: Allows for creating native components (with perfect look-and-feel) which share a common property set but with platform-specific differences.
Having a centralized convention ties it all together: All buttons have a "text" property. Themable buttons have the theme API, Cocoa buttons have the a Mac button type setting, and "QStyle" buttons can be styled with existing QStyles.
[/quote]Is the cross-platform QML theming API what eventually replaces QStyle?
Wouldn't themablity be part of the centralized convention on API? i.e. wouldn't a Button {} either have a theme property by convention, or button isn't themable? The point of a theme is that it's automatically applied throughout the app, if you have to replace Button with ThemableButton then you could have, almost as easily (and right now), replaced Button with MyButton, where MyButton is your button using your theme.
Does this suggestion mean that some platforms might implement three different buttons? a Button, a ThemableButton, and a StyledButton, which the application developer chooses from?
-
[quote author="aalpert" date="1334653834"]
That was kind of the original idea for Qt.labs.components, but I'm not sure this follows all the requirements. There seems to be a desire for a set that transcends the desktop/mobile divide - this divide is what's leading me to believe we really need a new and more flexible solution.
To bridge that gap, you need more than a Qt.labs.components.nativeMobile and a Qt.labs.components.Desktop. You need one native set that switches between all of them.
[/quote]
IMHO the UI design for a desktop application is totally different from a mobile application (cell phone target). So no need to strictly follow a common API (e.g. the page stack concept popular in mobile applications is of no use on the desktop).
I'd rather say that a set that transcends the desktop/tablet divide would be great because a well designed tablet interface can also work very nice in a desktop application. Just look at the latest Mac OS X and Windows 8 concepts.
-
bq. My team in INdT has been researching about theming/styling of Qt Components.
I’ve synthetised what we’ve been done and some of our aims and ideas:
http://codecereal.blogspot.com.br/2012/04/qml-themingstyling.htmlHi, the code is now updated and can be downloaded from git://code.openbossa.org/projects/qtquickstyles.git
We have found some bugs that were impeding the module to run properly. We have fixed it and integrated on the master.
Regards
-
[quote author="njeisecke" date="1334655499"][quote author="aalpert" date="1334653834"]
That was kind of the original idea for Qt.labs.components, but I'm not sure this follows all the requirements. There seems to be a desire for a set that transcends the desktop/mobile divide - this divide is what's leading me to believe we really need a new and more flexible solution.
To bridge that gap, you need more than a Qt.labs.components.nativeMobile and a Qt.labs.components.Desktop. You need one native set that switches between all of them.
[/quote]
IMHO the UI design for a desktop application is totally different from a mobile application (cell phone target). So no need to strictly follow a common API (e.g. the page stack concept popular in mobile applications is of no use on the desktop).
I'd rather say that a set that transcends the desktop/tablet divide would be great because a well designed tablet interface can also work very nice in a desktop application. Just look at the latest Mac OS X and Windows 8 concepts.
[/quote]I originally thought that the difference between the 'meta-platforms' was too great for anyone to care either. But remember, the email thread started with a Qt port to Android (presumably, it wasn't just for the tablet androids). I'm getting the impression that people want a component set large enough to create useful UIs, which literally work anywhere. This isn't for creating a commercial quality UI that looks and feels native, this is about hacking up an application and running it on your phones + tablets + desktop immediately. The UI would be a few ugly buttons mashed into a grid ( I get the feeling this was a key selling point of the Qt Layouts) and may even look like baby vomit by comparison with native apps. But you wrote a technically-functional application that runs on all your platforms in five minutes, which is sometimes what's most important.
I'd welcome hearing people's feedback on that directly of course, instead of just making assumptions here about what people what.
There are also some theoretical grounds for truly-cross platform APIs. What if page 'stacks' were tabbed widgets on desktop? What about something more dynamic, like that google fragments API that BogDan pointed too (but simpler, their docs confused me) or perhaps Qt style resizing layouts are needed for rescaling elements (but simpler, and with more smarts than just resizing things to 4x). But I'm not sure of concrete proposals here that would give a basis for a common API.
-
Applications designed for desktop space won't work on the mobile form factor. I've tried that for fun. Not only does it look ugly, the interface is simply unusable. So I really don't see the value of a common component set.
You can develop a very clean interface to your application business logic in C++ and use that from Qml quite naturally. The language gap (C++ -> Qml) forces you to make that clean separation, so creating a totally different UI for the mobile and desktop/tablet use case is now really easy and people should be educated about that.
Of course the API for basic components like buttons, text editors etc. should be compatible between mobile and desktop/tablet. Not for enabling cross platform code but simply to make it easier for the developer to remember stuff.
-
[quote author="aalpert" date="1334731153"]
I originally thought that the difference between the 'meta-platforms' was too great for anyone to care either. But remember, the email thread started with a Qt port to Android (presumably, it wasn't just for the tablet androids). I'm getting the impression that people want a component set large enough to create useful UIs, which literally work anywhere. This isn't for creating a commercial quality UI that looks and feels native, this is about hacking up an application and running it on your phones + tablets + desktop immediately. The UI would be a few ugly buttons mashed into a grid ( I get the feeling this was a key selling point of the Qt Layouts) and may even look like baby vomit by comparison with native apps. But you wrote a technically-functional application that runs on all your platforms in five minutes, which is sometimes what's most important.
[/quote]
[quote author="aalpert" date="1334731153"]
I'd welcome hearing people's feedback on that directly of course, instead of just making assumptions here about what people want.
<snip>
[/quote]We ship (embedded) touch-panel and (non-embedded) desktop applications with the same code, and the same physical Qt style-sheet file. Interface is totally different, but the style sheet establishes "common" settings for colors, fonts, etc. It works. We need this going forward with Qt/QML.
I think two different discussions are trying to take place in this discussion:
(A) A desire for a common styling interface/convention for cross-platform ease-of-development; Ability to style/emulate "Native" is secondary (primary goal is for application-developers to create a common-code-base with minimal effort that "basically-works" on multiple target platforms).
(B) A desire for a styling interface/convention that enables highly-specialized application-specific or platform-specific styling. Primary is the expectation for extremely close "native" presentation (native-to-target-device-and-target-operating-system), or the need for artistic expression or application "branding". Support for lowest-common-denominator (e.g., across-all-target-platforms) is quite "secondary".
Recall that Qt has historically delivered HIGH value in providing (A). The current "fracture" from desktop-into-mobile, and the fracture within mobile (including new paradigms for multi-touch and gesture) also cause real market need for (B).
IMHO, we can design QML styling interfaces or conventions to support both. It's not yet obvious to me how to do that, we have to be smart, but I really believe it can be done. That's why I think these discussions are very important.
[quote author="njeisecke" date="1334735328"]Applications designed for desktop space won't work on the mobile form factor. I've tried that for fun. Not only does it look ugly, the interface is simply unusable. So I really don't see the value of a common component set.
[/quote]This is partly true. However, we are shipping "embedded-touch" and "desktop" with the exact same widgets, so it is partly untrue.
[quote author="njeisecke" date="1334735328"]
You can develop a very clean interface to your application business logic in C++ and use that from Qml quite naturally. The language gap (C++ -> Qml) forces you to make that clean separation, so creating a totally different UI for the mobile and desktop/tablet use case is now really easy and people should be educated about that.Of course the API for basic components like buttons, text editors etc. should be compatible between mobile and desktop/tablet. Not for enabling cross platform code but simply to make it easier for the developer to remember stuff.[/quote]
We agree. This (C++ -> QML) abstraction is a major strength of this paradigm, separating the business-logic-and-APIs from the dynamic (GUI) presentation, and also why we are so interested in the QML direction. This is a "neutral" assertion to my separation of the (A) and (B) expectations (above).
You also make a good point, that if we could establish common-interface/conventions, then code will be "more familiar" to different developers working on different platforms, or in the different arenas of "desktop v. mobile". That has (very) high training/productivity/scaling/adoption value.
The styling issue, IMHO, is absolutely and entirely and totally about "data-density". Some concepts are truly "universal" -- a "hot-spot" that that user can somehow "hit" -- that's a button. A "date" that the user can "modify" -- that's some kind of "date-edit-thingie". These may be "lowest-common-denominator", or presented specific to a given-platform-convention.
QML can do both. It should not be a big deal. We're just talking about the "convention" or "API" where we can describe/extend/customize the presentation for (A) and (B) use cases.
Of course, "build" should not be a big deal either: All you need to do is compile-to-object, then link. How hard can it be? (<joke, we know how hard that can be.>)
It is possible we have one convention/API for (A), and a different for (B). It is possible that while those may be different, that they share a common "root" convention/API. Even better would be if we had the same convention/API for both.
Finally, I think it important to define terms, since IMHO the "solution" MAY be "convention", and MAY be "API":
() "Convention" -- if you tend to do it like this, or name things like this, then your parts will work with other people's parts (think something like "Duck-Typing" where we all just do-and-name-stuff-consistently)
() "API" -- something like INdT's theming/styling of Qt Components, where components are actually made-available-for-use, probably adopted into the common distribution
My guess is we will probably need a little of both "convention" and "API", but it is conceivable that we could use only one-or-the-other for (A) and/or (B).
-
[quote author="aalpert" date="1334653834"]
The real test will be how flexible this approach is to wildly varying platforms. I know the meego components will probably never get updated to a new architecture, but it should be theoretically quite possible to redo the existing QtQuick Components sets using a mixture of the style approach (and a platform specific widgets import for widgets that are custom enough not to be styled).
[/quote]Our main target is to have it working on mobile and desktop platforms, in the future. Currently we are mainly focusing on the Desktop side, due to the lack of desktop components with a native look and feel, but that could also have a different style, implemented by the user, with a minimum effort.
Another motivation was to have Qt5 implementation free of QWidgets.[quote author="aalpert" date="1334653834"]
Is it possible to split it up a little more, like moving the plastique folder out of that repo? It makes no sense in the current concepting phase of course, but one thing I would hope for a new platform styling API is the ability for new platform styles to easily come from outside. I got the impression that a lot of styling details went inside QWidget and friends, when it should all be abstracted out. So this new requirement I just realized is that the platform styles need to be a plugin (or import), as easy to write and swap in as the new QPA architecture.
[/quote]You mean that, if a user wants to use the plastique style, he would write "import PlastiqueStyle 1.0" on his QML file, and would do the same for any other available styles?
If is that what you have meant, I think we could have an hybrid approach, an import that would have all styles and separated imports for each style, that would only load that style.
The big import would have some "default" styles implemented, maybe the same styles that are available trough the QStyle. This way, the user would only make one import and could have all default styles reachable and the application would have the native look and feel. If he wants a different look and feel, he could just use our ApplicationStyle and set the style for each widget, reflecting in all application.
Or he could only import the desired style to his application. -
[quote author="thiago.lacerda" date="1334864314"]
[quote author="aalpert" date="1334653834"]
Is it possible to split it up a little more, like moving the plastique folder out of that repo? It makes no sense in the current concepting phase of course, but one thing I would hope for a new platform styling API is the ability for new platform styles to easily come from outside. I got the impression that a lot of styling details went inside QWidget and friends, when it should all be abstracted out. So this new requirement I just realized is that the platform styles need to be a plugin (or import), as easy to write and swap in as the new QPA architecture.
[/quote]You mean that, if a user wants to use the plastique style, he would write "import PlastiqueStyle 1.0" on his QML file, and would do the same for any other available styles?[/quote]
Actually, no. As a purely hypothetical example, let's suppose that Apple wanted to make iOS a first-tier Qt Platform, complete with a native control set for QML. But then their lawyers forbid putting that code into the qt-project repositories. Could they then ship that with their platform, but not with Qt, while still making "import NativeComponents 1.0" use their platform's native components?
-
[quote author="aalpert" date="1335170025"]
Actually, no. As a purely hypothetical example, let's suppose that Apple wanted to make iOS a first-tier Qt Platform, complete with a native control set for QML. But then their lawyers forbid putting that code into the qt-project repositories. Could they then ship that with their platform, but not with Qt, while still making "import NativeComponents 1.0" use their platform's native components?
[/quote]
With the current implementation, the one that wants to add a new style to the project, can do it just by making his new style class inherits from the QUiStyle base class and return this new style on the getPlatformStyle method (from QUiStyle) when it detects that it is running on such platform.
Since it is on the very beginning of the project, this is the current way. What do you think that could be a more suitable way? -
[quote author="thiago.lacerda" date="1335197206"][quote author="aalpert" date="1335170025"]
Actually, no. As a purely hypothetical example, let's suppose that Apple wanted to make iOS a first-tier Qt Platform, complete with a native control set for QML. But then their lawyers forbid putting that code into the qt-project repositories. Could they then ship that with their platform, but not with Qt, while still making "import NativeComponents 1.0" use their platform's native components?
[/quote]
With the current implementation, the one that wants to add a new style to the project, can do it just by making his new style class inherits from the QUiStyle base class and return this new style on the getPlatformStyle method (from QUiStyle) when it detects that it is running on such platform.
Since it is on the very beginning of the project, this is the current way. What do you think that could be a more suitable way?[/quote]That's certainly fine for the initial prototype. Perhaps later the getPlatformStyle function could check plugin paths for compatible platform styles. But it sounds like this isn't going to be a problem, which is great!
-
I've written an update about our research: http://codecereal.blogspot.com.br/2012/05/qml-themingstyling-update.html