Icons In Qt Quick Controls: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=Problem: No easy way to specify an icon for e.g. Button and have the correct dimension and <span class="caps">DPI</span> chosen automatically=
h1. Problem: No easy way to specify an icon for e.g. Button and have the correct dimension and DPI chosen automatically


Currently, the following Button’s icon will use the same <span class="caps">PNG</span> on every platform (besides OS X/iOS), regardless of the device <span class="caps">DPI</span>, etc.:
Currently, the following Button's icon will use the same PNG on every platform (besides OS X/iOS), regardless of the device DPI, etc.:
 
<code><br />Button {<br /> iconSource: &quot;pencil.png&amp;quot;<br />}<br /></code>


What should happen is:
What should happen is:


# An icon bitmap for the logical dimensions of the Button is chosen. We might default to 32×32, but if the button is larger, we could use a larger icon if it exists. If the button is in between these sizes, we should choose the larger icon and down-scale it.
# An icon bitmap for the logical dimensions of the Button is chosen. We might default to 32x32, but if the button is larger, we could use a larger icon if it exists. If the button is in between these sizes, we should choose the larger icon and down-scale it.
# In addition to the above, the <span class="caps">DPI</span> of the device is respected. For example, we would choose “icons/32×32/pencil-@2x.png” on high <span class="caps">DPI</span> devices, “icons/32×32/pencil-@3x.png” on higher <span class="caps">DPI</span> devices, etc.
# In addition to the above, the DPI of the device is respected. For example, we would choose &quot;icons/32x32/pencil-<code>2x.png&amp;quot; on high DPI devices, &quot;icons/32x32/pencil-<code>3x.png&amp;quot; on higher DPI devices, etc.
# The icon chosen should reflect the state of the button, whether that state is disabled, active, selected, etc.
# The icon chosen should reflect the state of the button, whether that state is disabled, active, selected, etc.


This has been a problem for a while, and I’d like to address it in Qt 5.5. Hopefully people will correct me if I’m wrong anywhere in this page. Note that this only applies to items in Qt Quick Controls that use icons; e.g. Button, ToolButton, MenuItem.
This has been a problem for a while, and I'd like to address it in Qt 5.5. Hopefully people will correct me if I'm wrong anywhere in this page. Note that this only applies to items in Qt Quick Controls that use icons; e.g. Button, ToolButton, MenuItem.


On Android and most other platforms, the “@2x” thing is not implemented, so it’s hard for us to switch out images depending on the resolution of the device; you’d have to do it manually:
On Android and most other platforms, the &quot;</code>2x&amp;quot; thing is not implemented, so it's hard for us to switch out images depending on the resolution of the device; you'd have to do it manually:


File selectors have been discussed, but are [http://lists.qt.io/pipermail/development/2013-March/010564.html not the best approach] ''[lists.qt.io]''. We can make it easier for developers.
<code>iconSource: Screen.pixelDensity &gt; someAmount ? &quot;icon<code>2x.png&amp;quot; : &quot;icon.png&amp;quot;<code>


==Inherently scalable icons==
File selectors have been discussed, but are &quot;not the best approach&amp;quot;:http://lists.qt.io/pipermail/development/2013-March/010564.html. We can make it easier for developers.
 
== Inherently scalable icons ==


There are other approaches that are inherently scalable, but come with their own drawbacks.
There are other approaches that are inherently scalable, but come with their own drawbacks.


===1. Use Canvas.===
=== 1. Use Canvas. ===


====Advantages:====
==== Advantages: ====


* Colour can be changed at runtime
* Colour can be changed at runtime
* Can use HTML5 Canvas techniques off the Internet
* Can use HTML5 Canvas techniques off the Internet
* Full control over when we repaint as long as you don’t resize
* Full control over when we repaint as long as you don't resize
* Improvements to performance being made all the time (the latest as of writing being https://codereview.qt.io/#/c/95937/)
* Improvements to performance being made all the time (the latest as of writing being https://codereview.qt.io/#/c/95937/)


====Disadvantages:====
==== Disadvantages: ====
 
* Can't be used with Image, so won't currently work with MenuItem (which only accepts a path to an image for the icon)
* Repaints on resizing, but in practice this is not an issue, as most applications won't be resizing
* Means taking something tangible like an SVG file and turning it into a series of coordinates. On the other hand, this is could very easily be automated; it's just one line of XML that needs to be extracted, and in terms of files on a file system, it's the same as using SVGs:
 
</code> images/<br /> icon-1.svg<br /> icon-2.svg


* Can’t be used with Image, so won’t currently work with MenuItem (which only accepts a path to an image for the icon)
qml/<br /> icon-1.qml<br /> icon-2.qml<code>
* Repaints on resizing, but in practice this is not an issue, as most applications won’t be resizing
* Means taking something tangible like an <span class="caps">SVG</span> file and turning it into a series of coordinates. On the other hand, this is could very easily be automated; it’s just one line of <span class="caps">XML</span> that needs to be extracted, and in terms of files on a file system, it’s the same as using <span class="caps">SVG</span>s:


===2. Use <span class="caps">SVG</span>s.===
=== 2. Use SVGs. ===


====Advantages:====
==== Advantages: ====


* We can take them straight from the designer and whack them in.
* We can take them straight from the designer and whack them in.
* We get the same performance as Image after the initial rendering as long as we don’t change the [http://doc.qt.io/qt-5/qml-qtquick-image.html#sourceSize-prop sourceSize] ''[qt.io]''
* We get the same performance as Image after the initial rendering as long as we don't change the &quot;sourceSize&amp;quot;:http://doc.qt.io/qt-5/qml-qtquick-image.html#sourceSize-prop
* We have control over the above (scaling vs re-rasterising) via the sourceSize property
* We have control over the above (scaling vs re-rasterising) via the sourceSize property
* Works with Image, so will work with things like MenuItem
* Works with Image, so will work with things like MenuItem


====Disadvantages:====
==== Disadvantages: ====


* libQtSvg dependency for both controls modules
* libQtSvg dependency for both controls modules
* Re-rasterising is expensive (but how expensive, e.g. compared to Canvas?), but you shouldn’t do it often anyway (ideally you paint once)
* Re-rasterising is expensive (but how expensive, e.g. compared to Canvas?), but you shouldn't do it often anyway (ideally you paint once)


===3. Create an icon font (<span class="caps">TTF</span> file, for example) and embed that into the <span class="caps">QRC</span> file, converting icons that we get from the designer into text glyphs (is that the correct term?).===
=== 3. Create an icon font (TTF file, for example) and embed that into the QRC file, converting icons that we get from the designer into text glyphs (is that the correct term?). ===


====Advantages:====
==== Advantages: ====


* No libQtSvg dependency
* No libQtSvg dependency
* Harnesses the power of text layouting/rendering engines
* Harnesses the power of text layouting/rendering engines


====Disadvantages:====
==== Disadvantages: ====


* Doesn’t work with Image, hence won’t work with MenuItem
* Doesn't work with Image, hence won't work with MenuItem
* More work required to convert (but how much?)
* More work required to convert (but how much?)
* Uses text layouting/rendering just to display an icon (Gunnar said “it feels wrong to do text layout to draw an icon”)
* Uses text layouting/rendering just to display an icon (Gunnar said &quot;it feels wrong to do text layout to draw an icon&amp;quot;)
* Can’t colorise (Shawn said “the solution for color fonts is not resolved yet”)
* Can't colorise (Shawn said &quot;the solution for color fonts is not resolved yet&amp;quot;)


=Solution: use different icons at different Item sizes and device <span class="caps">DPI</span>s=
= Solution: use different icons at different Item sizes and device DPIs =


==Solution Criteria:==
== Solution Criteria:<br /># It has to provide a URL (to work with Button and MenuItem, etc.).<br /> A visual item like IconImage would work, but not with Button, MenuItem, etc., which have iconSource properties.<br /># It needs to support enabled, disabled, active, selected, etc. states; the Item in use should specify its state<br /># It needs to support different file formats, not just PNG ==


# It has to provide a <span class="caps">URL</span> (to work with Button and MenuItem, etc.). A visual item like IconImage would work, but not with Button, MenuItem, etc., which have iconSource properties.
The following solutions are the result of brainstorming; &quot;off the top of our head&amp;quot; stuff, with some quick follow-up research (Googling &amp; grepping) for the more attractive ideas.
# It needs to support enabled, disabled, active, selected, etc. states; the Item in use should specify its state
# It needs to support different file formats, not just <span class="caps">PNG</span>


The following solutions are the result of brainstorming; “off the top of our head” stuff, with some quick follow-up research (Googling &amp; grepping) for the more attractive ideas.
== Solution #1: ==
 
==Solution #1:==


QQmlAbstractUrlInterceptor (http://doc.qt.io/qt-5/qqmlabstracturlinterceptor.html)
QQmlAbstractUrlInterceptor (http://doc.qt.io/qt-5/qqmlabstracturlinterceptor.html)
Line 78: Line 82:
Pass full path to non existent file, e.g.:
Pass full path to non existent file, e.g.:


/home/user/myapp is checked for folders named 32×32, etc.<br /> (similar to the freedesktop standard: http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html):
</code><br />Button {<br /> iconSource: &quot;/home/user/myapp/image.png&amp;quot;.<br /> anchors.fill: parent // 40 x 40<br />}<br /><code>
 
/home/user/myapp is checked for folders named 32x32, etc.<br />(similar to the freedesktop standard: http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html):
 
</code><br />/home/user/myapp/<br /> 32x32/<br /> image.png<br /> image<code>2x.png<br /> 64x64/<br /> image.png<br /> image</code>2x.png<br /><code>


our QIconUrlInterceptor must know the size of the Item so that it can choose the appropriate directory.<br /> in this case, there are two approaches we could take:
our QIconUrlInterceptor must know the size of the Item so that it can choose the appropriate directory.<br />in this case, there are two approaches we could take:


1. Choose the smaller image and centre it<br /> 2. Choose the larger image and down-scale it
1. Choose the smaller image and centre it<br />2. Choose the larger image and down-scale it


for the sake of this example, the 32×32 size is chosen, so we enter that directory.<br /> a file matching the <span class="caps">DPI</span> is then searched for. for example, if the device is at the lowest<br /><span class="caps">DPI</span> (whatever that is), the plain image.png file is chosen.<br /> if the dpi is twice the lowest, image@2x.png is chosen, and so on.
for the sake of this example, the 32x32 size is chosen, so we enter that directory.<br />a file matching the DPI is then searched for. for example, if the device is at the lowest<br />DPI (whatever that is), the plain image.png file is chosen.<br />if the dpi is twice the lowest, image</code>2x.png is chosen, and so on.


====Advantages:====
==== Advantages: ====


* Happens automatically, no effort needed from user besides organising directories (this could be toolable)
* Happens automatically, no effort needed from user besides organising directories (this could be toolable)


====Disadvantages:====
==== Disadvantages: ====


* Filesystem reads
* Filesystem reads
* Can’t QQmlEngine only have one interceptor at a time? E.g. what if someone is using QFileSelector?
* Can't QQmlEngine only have one interceptor at a time? E.g. what if someone is using QFileSelector?
* Path to non-existent file is a bit magic; could be a better way of describing the “base” <span class="caps">URL</span>
* Path to non-existent file is a bit magic; could be a better way of describing the &quot;base&amp;quot; URL


====Conclusion:====
==== Conclusion: ====


Not feasible.
Not feasible.


==Solution #2: IconSet.qml==
== Solution #2: IconSet.qml ==
 
Have a QML file that describes which icons at which physical sizes are available.<br />&quot;<code>2x&amp;quot; logic from above is still used, assuming the files will be in the same directory<br />as the appropriate physically sized image.
 
</code><br />// IconSet.qml<br />IconSet {<br /> basePath: &quot;path/to/icons/&amp;quot;
 
IconFile {<br /> path: &quot;file-open-32x32.png&amp;quot;<br /> width: 32<br /> height: 32<br /> }<br /> IconFile {<br /> path: &quot;file-open-64x64.png&amp;quot;<br /> width: 64<br /> height: 64<br /> }<br /> IconFile {<br /> path: &quot;file-open-128x128.png&amp;quot;<br /> width: 128<br /> height: 128<br /> }<br />}


Have a <span class="caps">QML</span> file that describes which icons at which physical sizes are available.<br /> “@2x” logic from above is still used, assuming the files will be in the same directory<br /> as the appropriate physically sized image.
Button {<br /> iconSource: IconSet.url(&quot;file-open&amp;quot;, width, height)


====Advantages:====
// If we can somehow let the url function know the Item that is calling it,<br /> // and specify the file name some other way, we could turn this into a property:<br /> iconSource: IconSet.url<br /> iconName: &quot;file-open&amp;quot;<br />}<br /><code>
 
==== Advantages: ====


* Easily toolable
* Easily toolable
* Doable by hand if people dislike using tooling for whatever reason
* Doable by hand if people dislike using tooling for whatever reason
* Can be used with QFileSelector
* Can be used with QFileSelector
* No checking if folders exist; the only IO involved is the “@2x” check
* No checking if folders exist; the only IO involved is the &quot;</code>2x&amp;quot; check


====Disadvantages:====
==== Disadvantages: ====


* A bit of work to set up
* A bit of work to set up
* A bit verbose, but you shouldn’t be looking at this file outside of the tooling <span class="caps">GUI</span>
* A bit verbose, but you shouldn't be looking at this file outside of the tooling GUI
* It’s a function, not a property; properties look nicer, but the function will still get called when the width/height changes
* It's a function, not a property; properties look nicer, but the function will still get called when the width/height changes


====Conclusion:====
==== Conclusion: ====


Too verbose and too much work for the user.
Too verbose and too much work for the user.


==Solution #3: Hijack iconName (in Button, MenuItem, etc.)==
== Solution #3: Hijack iconName (in Button, MenuItem, etc.) ==


Same directory structure as Solution #1.
Same directory structure as Solution #1.


====Advantages:====
==== Advantages: ====


* It’s declarative
* It's declarative
* Since the Items own the properties, it’s not necessary to specify the physical size of the icon
* Since the Items own the properties, it's not necessary to specify the physical size of the icon


====Disadvantages:====
==== Disadvantages: ====


* Behaviour change on Linux (apparently the only place where iconName is actually used by how many people, who knows)
* Behaviour change on Linux (apparently the only place where iconName is actually used - by how many people, who knows)
* Still need to specify base path/directory containing the icons, which brings back the problem of Qt lacking a <span class="caps">QML</span> entry point (.json file or whatever) it needs to be specified once and before any <span class="caps">QML</span> is loaded
* Still need to specify base path/directory containing the icons, which brings back the problem of Qt lacking a QML entry point (.json file or whatever) - it needs to be specified once and before any QML is loaded


====Conclusion:====
==== Conclusion: ====


Suitable.
Suitable.


=Notes About Chosen Solution=
= Notes About Chosen Solution =


We think that #3 is the best.
We think that #3 is the best.


The bitmap approach is good for icons, because it ensures that they are pixel perfect, which you can’t guarantee with inherently scalable approaches (fuzzy pixels with small <span class="caps">SVG</span>s, distance field stops working for glyphs larger than 100×100 with icon font approach). Of course you can resize a button and cause the icon to be scaled down, but typically you place a Button on a UI without forcing a size for it; its size is determined by the style for the platform you’re on and we’ll choose the size that ensures no scaling occurs.
The bitmap approach is good for icons, because it ensures that they are pixel perfect, which you can't guarantee with inherently scalable approaches (fuzzy pixels with small SVGs, distance field stops working for glyphs larger than 100x100 with icon font approach). Of course you can resize a button and cause the icon to be scaled down, but typically you place a Button on a UI without forcing a size for it; its size is determined by the style for the platform you're on and we'll choose the size that ensures no scaling occurs.


Down-scale when we have to, never scale up.
Down-scale when we have to, never scale up.


“icons/48×48/pencil.png” – default (normal, off), also fallback if none of the others are available<br /> “icons/48×48/pencil-on-disabled.png”<br /> “icons/48×48/pencil-disabled-on.png” (order doesn’t matter)<br /> “icons/48×48/pencil-pressed-off.png”
<code><br />Button {<br /> iconName: &quot;pencil&amp;quot;<br />}<br /></code>
 
&quot;icons/48x48/pencil.png&amp;quot; - default (normal, off), also fallback if none of the others are available<br />&quot;icons/48x48/pencil-on-disabled.png&amp;quot;<br />&quot;icons/48x48/pencil-disabled-on.png&amp;quot; (order doesn't matter)<br />&quot;icons/48x48/pencil-pressed-off.png&amp;quot;


We may need a platform-specific variation:<br /> “android/icons/48×48/pencil.png”
We may need a platform-specific variation:<br />&quot;android/icons/48x48/pencil.png&amp;quot;


Default path is “qrc:/icons/<br /> At first, we use an undocumented env variable QT_QUICK_CONTROLS_ICON_PATH to override this
Default path is &quot;qrc:/icons/&amp;quot;<br />At first, we use an undocumented env variable QT_QUICK_CONTROLS_ICON_PATH to override this


qtquickcontrols/src/controls/plugin.cpp
qtquickcontrols/src/controls/plugin.cpp


Button, ToolButton, MenuItem<br /> normal, disabled, hovered, pressed, focused, selected (for view items), selected+disabled, pressed+selected<br /> Focus and Hovered = Active in QIcon
Button, ToolButton, MenuItem<br />normal, disabled, hovered, pressed, focused, selected (for view items), selected+disabled, pressed+selected<br />Focus and Hovered = Active in QIcon


QQuickImageProvider asks QIcons to return a pixmap for the given state (provided by the control)<br /> Desktop styles will access the QIcons directly
QQuickImageProvider asks QIcons to return a pixmap for the given state (provided by the control)

Revision as of 11:06, 24 February 2015

h1. Problem: No easy way to specify an icon for e.g. Button and have the correct dimension and DPI chosen automatically

Currently, the following Button's icon will use the same PNG on every platform (besides OS X/iOS), regardless of the device DPI, etc.:

<br />Button {<br /> iconSource: &quot;pencil.png&amp;quot;<br />}<br />

What should happen is:

  1. An icon bitmap for the logical dimensions of the Button is chosen. We might default to 32x32, but if the button is larger, we could use a larger icon if it exists. If the button is in between these sizes, we should choose the larger icon and down-scale it.
  2. In addition to the above, the DPI of the device is respected. For example, we would choose "icons/32x32/pencil-
    2x.png&amp;quot; on high DPI devices, &quot;icons/32x32/pencil-<code>3x.png&amp;quot; on higher DPI devices, etc.
    # The icon chosen should reflect the state of the button, whether that state is disabled, active, selected, etc.
    
    This has been a problem for a while, and I'd like to address it in Qt 5.5. Hopefully people will correct me if I'm wrong anywhere in this page. Note that this only applies to items in Qt Quick Controls that use icons; e.g. Button, ToolButton, MenuItem.
    
    On Android and most other platforms, the &quot;
    
    2x&quot; thing is not implemented, so it's hard for us to switch out images depending on the resolution of the device; you'd have to do it manually:
iconSource: Screen.pixelDensity &gt; someAmount ? &quot;icon<code>2x.png&amp;quot; : &quot;icon.png&amp;quot;<code>

File selectors have been discussed, but are &quot;not the best approach&amp;quot;:http://lists.qt.io/pipermail/development/2013-March/010564.html. We can make it easier for developers.

== Inherently scalable icons ==

There are other approaches that are inherently scalable, but come with their own drawbacks.

=== 1. Use Canvas. ===

==== Advantages: ====

* Colour can be changed at runtime
* Can use HTML5 Canvas techniques off the Internet
* Full control over when we repaint as long as you don't resize
* Improvements to performance being made all the time (the latest as of writing being https://codereview.qt.io/#/c/95937/)

==== Disadvantages: ====

* Can't be used with Image, so won't currently work with MenuItem (which only accepts a path to an image for the icon)
* Repaints on resizing, but in practice this is not an issue, as most applications won't be resizing
* Means taking something tangible like an SVG file and turning it into a series of coordinates. On the other hand, this is could very easily be automated; it's just one line of XML that needs to be extracted, and in terms of files on a file system, it's the same as using SVGs:

images/
icon-1.svg
icon-2.svg qml/
icon-1.qml
icon-2.qml

=== 2. Use SVGs. ===

==== Advantages: ====

* We can take them straight from the designer and whack them in.
* We get the same performance as Image after the initial rendering as long as we don't change the &quot;sourceSize&amp;quot;:http://doc.qt.io/qt-5/qml-qtquick-image.html#sourceSize-prop
* We have control over the above (scaling vs re-rasterising) via the sourceSize property
* Works with Image, so will work with things like MenuItem

==== Disadvantages: ====

* libQtSvg dependency for both controls modules
* Re-rasterising is expensive (but how expensive, e.g. compared to Canvas?), but you shouldn't do it often anyway (ideally you paint once)

=== 3. Create an icon font (TTF file, for example) and embed that into the QRC file, converting icons that we get from the designer into text glyphs (is that the correct term?). ===

==== Advantages: ====

* No libQtSvg dependency
* Harnesses the power of text layouting/rendering engines

==== Disadvantages: ====

* Doesn't work with Image, hence won't work with MenuItem
* More work required to convert (but how much?)
* Uses text layouting/rendering just to display an icon (Gunnar said &quot;it feels wrong to do text layout to draw an icon&amp;quot;)
* Can't colorise (Shawn said &quot;the solution for color fonts is not resolved yet&amp;quot;)

= Solution: use different icons at different Item sizes and device DPIs =

== Solution Criteria:<br /># It has to provide a URL (to work with Button and MenuItem, etc.).<br /> A visual item like IconImage would work, but not with Button, MenuItem, etc., which have iconSource properties.<br /># It needs to support enabled, disabled, active, selected, etc. states; the Item in use should specify its state<br /># It needs to support different file formats, not just PNG ==

The following solutions are the result of brainstorming; &quot;off the top of our head&amp;quot; stuff, with some quick follow-up research (Googling &amp; grepping) for the more attractive ideas.

== Solution #1: ==

QQmlAbstractUrlInterceptor (http://doc.qt.io/qt-5/qqmlabstracturlinterceptor.html)

Pass full path to non existent file, e.g.:


Button {
iconSource: "/home/user/myapp/image.png&quot;.
anchors.fill: parent // 40 x 40
}

/home/user/myapp is checked for folders named 32x32, etc.<br />(similar to the freedesktop standard: http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html):


/home/user/myapp/
32x32/
image.png
image

2x.png<br /> 64x64/<br /> image.png<br /> image

2x.png

our QIconUrlInterceptor must know the size of the Item so that it can choose the appropriate directory.<br />in this case, there are two approaches we could take:

1. Choose the smaller image and centre it<br />2. Choose the larger image and down-scale it

for the sake of this example, the 32x32 size is chosen, so we enter that directory.<br />a file matching the DPI is then searched for. for example, if the device is at the lowest<br />DPI (whatever that is), the plain image.png file is chosen.<br />if the dpi is twice the lowest, image

2x.png is chosen, and so on.

Advantages:

  • Happens automatically, no effort needed from user besides organising directories (this could be toolable)

Disadvantages:

  • Filesystem reads
  • Can't QQmlEngine only have one interceptor at a time? E.g. what if someone is using QFileSelector?
  • Path to non-existent file is a bit magic; could be a better way of describing the "base&quot; URL

Conclusion:

Not feasible.

Solution #2: IconSet.qml

Have a QML file that describes which icons at which physical sizes are available.
"

2x&amp;quot; logic from above is still used, assuming the files will be in the same directory<br />as the appropriate physically sized image.


// IconSet.qml
IconSet {
basePath: "path/to/icons/&quot;

IconFile {
path: "file-open-32x32.png&quot;
width: 32
height: 32
}
IconFile {
path: "file-open-64x64.png&quot;
width: 64
height: 64
}
IconFile {
path: "file-open-128x128.png&quot;
width: 128
height: 128
}
}

Button {
iconSource: IconSet.url("file-open&quot;, width, height)

// If we can somehow let the url function know the Item that is calling it,
// and specify the file name some other way, we could turn this into a property:
iconSource: IconSet.url
iconName: "file-open&quot;
}

==== Advantages: ====

* Easily toolable
* Doable by hand if people dislike using tooling for whatever reason
* Can be used with QFileSelector
* No checking if folders exist; the only IO involved is the &quot;

2x&quot; check

Disadvantages:

  • A bit of work to set up
  • A bit verbose, but you shouldn't be looking at this file outside of the tooling GUI
  • It's a function, not a property; properties look nicer, but the function will still get called when the width/height changes

Conclusion:

Too verbose and too much work for the user.

Solution #3: Hijack iconName (in Button, MenuItem, etc.)

Same directory structure as Solution #1.

Advantages:

  • It's declarative
  • Since the Items own the properties, it's not necessary to specify the physical size of the icon

Disadvantages:

  • Behaviour change on Linux (apparently the only place where iconName is actually used - by how many people, who knows)
  • Still need to specify base path/directory containing the icons, which brings back the problem of Qt lacking a QML entry point (.json file or whatever) - it needs to be specified once and before any QML is loaded

Conclusion:

Suitable.

Notes About Chosen Solution

We think that #3 is the best.

The bitmap approach is good for icons, because it ensures that they are pixel perfect, which you can't guarantee with inherently scalable approaches (fuzzy pixels with small SVGs, distance field stops working for glyphs larger than 100x100 with icon font approach). Of course you can resize a button and cause the icon to be scaled down, but typically you place a Button on a UI without forcing a size for it; its size is determined by the style for the platform you're on and we'll choose the size that ensures no scaling occurs.

Down-scale when we have to, never scale up.

<br />Button {<br /> iconName: &quot;pencil&amp;quot;<br />}<br />

"icons/48x48/pencil.png&quot; - default (normal, off), also fallback if none of the others are available
"icons/48x48/pencil-on-disabled.png&quot;
"icons/48x48/pencil-disabled-on.png&quot; (order doesn't matter)
"icons/48x48/pencil-pressed-off.png&quot;

We may need a platform-specific variation:
"android/icons/48x48/pencil.png&quot;

Default path is "qrc:/icons/&quot;
At first, we use an undocumented env variable QT_QUICK_CONTROLS_ICON_PATH to override this

qtquickcontrols/src/controls/plugin.cpp

Button, ToolButton, MenuItem
normal, disabled, hovered, pressed, focused, selected (for view items), selected+disabled, pressed+selected
Focus and Hovered = Active in QIcon

QQuickImageProvider asks QIcons to return a pixmap for the given state (provided by the control)