Details
-
Task
-
Resolution: Done
-
P2: Important
-
6.0
-
None
Description
Problem
After the recent type registration changes, explicit style imports now change which style is in use, whereas previously the only way to set a style was through one of these methods:
https://doc.qt.io/qt-5/qtquickcontrols2-styles.html#using-styles-in-qt-quick-controls
This results in e.g. QTBUG-86263.
For example, consider this code:
import QtQuick.Controls import QtQuick.Controls.Material import QtQuick.Controls.Universal
In Qt 5, this would import QtQuick.Controls, which would cause this function to be called:
This causes each control type to be registered for the style that was set by the user. The types are registered under the QtQuick.Controls import.
The following imports would then cause the style plugins to be loaded, making the API of those plugins available to QML, but would not cause any control types to be registered.
In Qt 6, this will import QtQuick.Controls, and similarly to Qt 5, cause each control type to be registered for the style that was set by the user. It does this by "aliasing" the QtQuick.Controls import to the URI of the style that was set by the user. See the qmlRegisterModuleImport() calls in the code below:
So if the user set "MyStyle", importing "QtQuick.Controls" would be equivalent to importing "MyStyle".
However, since the type registration logic is simplified, it means that the following imports behave like regular QML imports; they will override any types that were previously registered under the same name.
Solutions
Strong requirements:
- Runtime style selection (i.e. most of the techniques described in the documentation above) must continue to work.
Preferable:
- It remains possible to use attached API from different styles in the same file. This avoids the need for the user to resort to file selectors, which are a hassle for such small tasks.
Option 1: move all style APIs under a single "Style" API
E.g.
import QtQuick.Controls.Material import QtQuick.Controls.Universal // ... header: ToolBar { Material.foreground: "white" Universal.foreground: "pink"
would become
import QtQuick.Controls // ... header: ToolBar { Style.foreground: Style.name === "Material ? "white" : "pink"
Q: What about attached properties that don't exist for the current style?
e.g.
Material.elevation: 1
that won't work if we switch to
Style.elevation: 1
and then run the app with Universal
A:
You could have a free form field for extra properties:
Style.properties: { elevation: 1 }
Then, if you know you're going to run material style, you can use the direct form, or otherwise you'd use the "properties" form.
Pros:
- Allows similar code to old approach without resorting to file selectors.
Cons:
- Hurts tooling like auto-completion in Creator.
- The "properties" part is not strongly typed.
- Users still can't import their own styles explicitly if they have some API they need to access.
Option 2: Find a different module name for just the attached properties
import QtQuick.Controls.Material.Attached
Pros:
- Allows applications to use the same bindings as before.
Cons:
- Would need a different name for styles like Fusion which have a singleton for their style object.
- It's arguable whether this is worth breaking user code (imports) for.
- Users still can't import their own styles explicitly if they have some API they need to access.
Option 3: Move the attached properties for the predefined styles into QtQuick.Controls.impl or similar
Pros:
- Allows applications to use the same bindings as before.
Cons:
- Applications will have QML types (attached types, singletons, etc.) for every style registered with the QML engine, even if they will never use them.
- Users still can't import their own styles explicitly if they have some API they need to access.
Option 4: Introduce some special QML keyword to only import specific API
Similar to QTBUG-84794.
import QtQuick.Controls import Material from QtQuick.Controls.Material
This would tell the engine to only make the type named "Material" available to QML, not e.g. the control types found in the qmldir file.
Pros:
- Allows applications to use the same bindings as before.
- Could have other uses outside of this, where people only want to use a certain subset of an API.
Cons:
- Would required a potentially large amount of work in qtdeclarative, or might not even be possible?
Option 5: QtQuick.Controls.Material.Style
Each built-in style could have a .Style module that provides only the QML types. Users can still import QtQuick.Controls.Material like they used to, and set the style with "Material", and we'll append ".Style" to the URI in QtQuickControls2Plugin if it's a built-in style.
Pros:
- Code is compatible
Cons:
- Users still can't import their own styles explicitly if they have some API they need to access. We could require that they split their styles up into two modules as well, but that's a lot of hassle for very little benefit to them.
Option 6: State that style-specific API (attached objects, singletons, etc.) should only be used in file-selected files if the application supports more than one style
See https://codereview.qt-project.org/c/qt/qtquickcontrols2/+/311798 for an example of how this would look for the gallery example.
If the application supports only style, this wouldn't be necessary.
Explicit style imports would then mean "use this style".
Pros:
- Works for user styles too.
- No more unconditional usage of style-specific API even when that style isn't in use.
Cons:
- A little tedious.
- Could confuse users: if they import a different style in two QML files, suddenly their application will be using the wrong style. We would need some way of warning users, and it would probably only work for the built-in styles.
Option 7: Introduce some special QML keyword to only import unique API
import QtQuick.Controls import unique from QtQuick.Controls.Material
This would tell the engine to only import types that haven't already been registered.
Pros:
- Allows applications to use the same bindings as before.
- Could have other uses outside of this, to avoid accidentally overwriting types in later imports.
Cons:
- Would required a potentially large amount of work in qtdeclarative, or might not even be possible?
Attachments
Issue Links
- resulted from
-
QTBUG-82922 Register types declaratively
- Closed