diff --git a/LICENSES b/LICENSES
index 64b56064..5e043234 100644
--- a/LICENSES
+++ b/LICENSES
@@ -20,19 +20,25 @@ b) Cassowary constraint solving algorithm ( examples )
SPDX-License-Identifier: BSD 3-Clause "New" or "Revised" License
Copyright (c) 2013, Nucleic Development Team
-fonts ( only for running the examples ):
+fonts ( needed for the Material3/Fluent2 skin )
a) Material3 Icons
Code: https://github.com/google/material-design-icons
SPDX-License-Identifier: Apache License 2.0
-b) Fluent2 Icons
+b) Roboto Fonts
+
+ Code: https://github.com/googlefonts/roboto-classic
+ SPDX-License-Identifier: SIL Open Font License 1.1
+ Copyright 2011 The Roboto Project Authors
+
+c) Fluent2 Icons
Code: https://github.com/microsoft/fluentui-system-icons
SPDX-License-Identifier: MIT License
-c) Segoe-UI Fonts
+d) Segoe-UI Fonts
Code: https://github.com/mrbvrz/segoe-ui-linux
License: https://github.com/mrbvrz/segoe-ui-linux/blob/master/license.txt
diff --git a/designsystems/fluent2/QskFluent2Skin.cpp b/designsystems/fluent2/QskFluent2Skin.cpp
index 64bd1cc6..a696d15c 100644
--- a/designsystems/fluent2/QskFluent2Skin.cpp
+++ b/designsystems/fluent2/QskFluent2Skin.cpp
@@ -703,9 +703,10 @@ void Editor::setupListViewMetrics()
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed } )
setBoxBorderMetrics( Q::Cell | state | Q::Selected, { 3_px, 0, 0, 0 } );
+
#if 1
- // taken from M3 - what are the actual values, TODO ...
- setPadding( Q::Cell, { 16_px, 12_px, 16_px, 12_px } );
+ setPadding( Q::Cell, 4_px );
+ setStrutSize( Q::Cell, -1, 40_px );
#endif
}
@@ -1561,9 +1562,6 @@ void Editor::setupSpinBoxMetrics()
setSymbol( Q::UpIndicator, symbol( "chevron_up" ) );
setSymbol( Q::DownIndicator, symbol( "chevron_down" ) );
- setPadding( Q::UpPanel, { 0, 1_px, 0, 0 } );
- setPadding( Q::DownPanel, { 0, 0, 0, 1_px } );
-
#if 0
// QskSpinBox::Pressed is missing yet
setBoxBorderMetrics( Q::Panel | Q::Pressed, { 1_px, 1_px, 1_px, 2_px } );
@@ -1880,7 +1878,6 @@ void Editor::setupTextFieldColors(
{
using Q = QskTextField;
using A = QskAspect;
- using W = QskFluent2Skin;
const auto& pal = theme.palette;
diff --git a/designsystems/fluent2/README b/designsystems/fluent2/README
new file mode 100644
index 00000000..81de77c0
--- /dev/null
+++ b/designsystems/fluent2/README
@@ -0,0 +1,26 @@
+Definitions ( where possible ) taken from:
+ - https://www.figma.com/file/NAWMapFlXnoOb86Q2H5GKr/Windows-UI-(Community)
+
+The Figma model uses the "Segoe Fluent Icons" [1]. Unfortunately its license is
+too restrictive for being included in the QSkinny project. Fortunately similar
+icons are also available from the "Fluent UI System Icons" project [2].
+
+However glyph names/numbers and the corresponding unicode values do not match
+and can't be taken 1:1 from the Figma model.
+
+"Fluent UI System Icons" offers different icon packages ( as font ):
+
+ - FluentSystemIcons-Light.ttf
+ - FluentSystemIcons-Regular.ttf
+ - FluentSystemIcons-Filled.ttf
+ - FluentSystemIcons-Resizable.ttf
+
+For some reason ( might be a bug in the downloaded version ) the checkmark
+glyph offered from the "Regular" font ( pixelsize 12 ) is different
+( works better ) to the one from the "Resizable" font.
+
+That's why we decided to use the "Regular" font for now.
+
+[1] https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
+[2] https://github.com/microsoft/fluentui-system-icons
+
diff --git a/designsystems/fluent2/icons/FluentSystemIcons-Regular.ttf b/designsystems/fluent2/icons/FluentSystemIcons-Regular.ttf
new file mode 100644
index 00000000..fc3c648a
Binary files /dev/null and b/designsystems/fluent2/icons/FluentSystemIcons-Regular.ttf differ
diff --git a/designsystems/fluent2/icons/README b/designsystems/fluent2/icons/README
deleted file mode 100644
index a45cea97..00000000
--- a/designsystems/fluent2/icons/README
+++ /dev/null
@@ -1,10 +0,0 @@
-SVGs have been taken from https://github.com/microsoft/fluentui-system-icons/tree/main/assets.
-
-Icons are available in different sizes. As SVGs can be scaled we only need
-one version of them - chosing the '12'.
-
-As we are replacing the colors of the SVGs using graphic filters we set the
-color in the SVGs manually to black ( instead of #212121 ). So they are in
-line with icons coming from somewhere else.
-
-Names have been shortened ( ic_fluent_xyz_16_regular.svg -> xyz.svg )
diff --git a/designsystems/fluent2/icons/checkmark.svg b/designsystems/fluent2/icons/checkmark.svg
deleted file mode 100644
index f87de9aa..00000000
--- a/designsystems/fluent2/icons/checkmark.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/designsystems/fluent2/icons/chevron_down.svg b/designsystems/fluent2/icons/chevron_down.svg
deleted file mode 100644
index 8ac9ed11..00000000
--- a/designsystems/fluent2/icons/chevron_down.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/designsystems/fluent2/icons/chevron_up.svg b/designsystems/fluent2/icons/chevron_up.svg
deleted file mode 100644
index 28426e1d..00000000
--- a/designsystems/fluent2/icons/chevron_up.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/designsystems/fluent2/icons/icon2qvg.sh b/designsystems/fluent2/icons/icon2qvg.sh
deleted file mode 100755
index c562ca17..00000000
--- a/designsystems/fluent2/icons/icon2qvg.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#! /bin/sh
-
-if [ $# -eq 0 ]; then
- echo "Usage $0 file ..."
- exit 1
-fi
-
-for file in $*
-do
- base=`basename -s .svg $file`
- echo "${base}.svg -> qvg/${base}.qvg"
- svg2qvg ${base}.svg qvg/${base}.qvg
-done
-
-exit $status
diff --git a/designsystems/fluent2/icons/qvg/checkmark.qvg b/designsystems/fluent2/icons/qvg/checkmark.qvg
index 40ab0c75..e1e03bf0 100644
Binary files a/designsystems/fluent2/icons/qvg/checkmark.qvg and b/designsystems/fluent2/icons/qvg/checkmark.qvg differ
diff --git a/designsystems/fluent2/icons/qvg/chevron_down.qvg b/designsystems/fluent2/icons/qvg/chevron_down.qvg
index a8d90d49..d7957b36 100644
Binary files a/designsystems/fluent2/icons/qvg/chevron_down.qvg and b/designsystems/fluent2/icons/qvg/chevron_down.qvg differ
diff --git a/designsystems/fluent2/icons/qvg/chevron_up.qvg b/designsystems/fluent2/icons/qvg/chevron_up.qvg
index 11f3abc4..f5446475 100644
Binary files a/designsystems/fluent2/icons/qvg/chevron_up.qvg and b/designsystems/fluent2/icons/qvg/chevron_up.qvg differ
diff --git a/designsystems/fluent2/icons/symbol2qvg.sh b/designsystems/fluent2/icons/symbol2qvg.sh
new file mode 100755
index 00000000..21be8a82
--- /dev/null
+++ b/designsystems/fluent2/icons/symbol2qvg.sh
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+function symbol2qvg {
+ fontfile=FluentSystemIcons-Regular.ttf
+ glyph2qvg ${fontfile} 12 $1 qvg/$2.qvg
+}
+
+
+symbol2qvg 1724 checkmark
+symbol2qvg 1792 chevron_down
+symbol2qvg 1816 chevron_up
diff --git a/designsystems/fusion/QskFusionSkin.cpp b/designsystems/fusion/QskFusionSkin.cpp
index 4dd17a66..1879782a 100644
--- a/designsystems/fusion/QskFusionSkin.cpp
+++ b/designsystems/fusion/QskFusionSkin.cpp
@@ -1338,7 +1338,7 @@ void Editor::setupListView()
using P = QPalette;
// padding for each cell
- setPadding( Q::Cell, QskMargins( 4, 0 ) );
+ setPadding( Q::Cell, QskMargins( 4, 4 ) );
for ( auto state : { A::NoState, Q::Disabled } )
{
diff --git a/designsystems/material3/QskMaterial3Icons.qrc b/designsystems/material3/QskMaterial3Icons.qrc
index 72725b7a..d30484f9 100644
--- a/designsystems/material3/QskMaterial3Icons.qrc
+++ b/designsystems/material3/QskMaterial3Icons.qrc
@@ -1,21 +1,10 @@
-
-
-
- icons/qvg/check_small.qvg
- icons/qvg/combo-box-arrow-closed.qvg
- icons/qvg/combo-box-arrow-open.qvg
- icons/qvg/segmented-button-check.qvg
- icons/qvg/switchbutton-checked.qvg
- icons/qvg/switchbutton-unchecked.qvg
-
-
-
icons/qvg/add.qvg
icons/qvg/arrow_drop_down.qvg
icons/qvg/arrow_drop_up.qvg
icons/qvg/check.qvg
+ icons/qvg/close.qvg
icons/qvg/remove.qvg
diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp
index 0d3b8f19..1c811a1c 100644
--- a/designsystems/material3/QskMaterial3Skin.cpp
+++ b/designsystems/material3/QskMaterial3Skin.cpp
@@ -227,7 +227,6 @@ void Editor::setupCheckBox()
setStrutSize( Q::Box, 18_px, 18_px );
setBoxBorderMetrics( Q::Box, 2_px );
setBoxShape( Q::Box, 2_px );
- setPadding( Q::Box, 3_px ); // "icon size"
QskShadowMetrics shadowMetrics( 12_px, 0.0 );
shadowMetrics.setShapeMode( QskShadowMetrics::Ellipse );
@@ -240,7 +239,7 @@ void Editor::setupCheckBox()
setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked,
QskMaterial3Skin::GraphicRoleSurface );
- const auto checkMark = symbol( "check_small" );
+ const auto checkMark = symbol( "check" );
for ( auto state : { A::NoState, Q::Disabled } )
{
const auto aspect = Q::Indicator | Q::Checked | state;
@@ -337,7 +336,7 @@ void Editor::setupComboBox()
setColor( Q::Text, m_pal.onSurface );
setFontRole( Q::Text, BodyLarge );
- setStrutSize( Q::StatusIndicator, 12_px, 12_px );
+ setStrutSize( Q::StatusIndicator, 24_px, 24_px );
setGraphicRole( Q::StatusIndicator, QskMaterial3Skin::GraphicRoleOnSurface );
setAlignment( Q::StatusIndicator, Qt::AlignRight | Qt::AlignVCenter );
@@ -346,14 +345,13 @@ void Editor::setupComboBox()
setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface38 );
- setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleOnSurface38 );
-
setColor( Q::Text | Q::Disabled, m_pal.onSurface38 );
- setGraphicRole( Q::StatusIndicator, QskMaterial3Skin::GraphicRoleOnSurface38 );
+ setGraphicRole( Q::StatusIndicator | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 );
+ setGraphicRole( Q::Icon | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 );
- setSymbol( Q::StatusIndicator, symbol( "combo-box-arrow-closed" ) );
- setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "combo-box-arrow-open" ) );
+ setSymbol( Q::StatusIndicator, symbol( "arrow_drop_down" ) );
+ setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "arrow_drop_up" ) );
}
void Editor::setupBox()
@@ -1135,8 +1133,8 @@ void Editor::setupSwitchButton()
setStrutSize( Q::Icon, { 16_px, 16_px } );
setPadding( Q::Icon, 6_px );
- setSymbol( Q::Icon, symbol( "switchbutton-unchecked" ) );
- setSymbol( Q::Icon | Q::Checked, symbol( "switchbutton-checked" ) );
+ setSymbol( Q::Icon, symbol( "close" ) );
+ setSymbol( Q::Icon | Q::Checked, symbol( "check" ) );
setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleSurfaceContainerHighest );
diff --git a/designsystems/material3/icons/LICENSE b/designsystems/material3/icons/LICENSE
deleted file mode 100644
index d6456956..00000000
--- a/designsystems/material3/icons/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/designsystems/material3/icons/MaterialSymbolsOutlined.ttf b/designsystems/material3/icons/MaterialSymbolsOutlined.ttf
new file mode 100644
index 00000000..d446767b
Binary files /dev/null and b/designsystems/material3/icons/MaterialSymbolsOutlined.ttf differ
diff --git a/designsystems/material3/icons/add.svg b/designsystems/material3/icons/add.svg
deleted file mode 100644
index b0570646..00000000
--- a/designsystems/material3/icons/add.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/designsystems/material3/icons/arrow_drop_down.svg b/designsystems/material3/icons/arrow_drop_down.svg
deleted file mode 100644
index 37d90c90..00000000
--- a/designsystems/material3/icons/arrow_drop_down.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/designsystems/material3/icons/arrow_drop_up.svg b/designsystems/material3/icons/arrow_drop_up.svg
deleted file mode 100644
index 24f0831a..00000000
--- a/designsystems/material3/icons/arrow_drop_up.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/designsystems/material3/icons/check.svg b/designsystems/material3/icons/check.svg
deleted file mode 100644
index 3be223be..00000000
--- a/designsystems/material3/icons/check.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/designsystems/material3/icons/check_small.svg b/designsystems/material3/icons/check_small.svg
deleted file mode 100644
index e7a84071..00000000
--- a/designsystems/material3/icons/check_small.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/designsystems/material3/icons/combo-box-arrow-closed.svg b/designsystems/material3/icons/combo-box-arrow-closed.svg
deleted file mode 100644
index c288b426..00000000
--- a/designsystems/material3/icons/combo-box-arrow-closed.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/designsystems/material3/icons/combo-box-arrow-open.svg b/designsystems/material3/icons/combo-box-arrow-open.svg
deleted file mode 100644
index 4138c2cd..00000000
--- a/designsystems/material3/icons/combo-box-arrow-open.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/designsystems/material3/icons/icon2qvg.sh b/designsystems/material3/icons/icon2qvg.sh
deleted file mode 100755
index c562ca17..00000000
--- a/designsystems/material3/icons/icon2qvg.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#! /bin/sh
-
-if [ $# -eq 0 ]; then
- echo "Usage $0 file ..."
- exit 1
-fi
-
-for file in $*
-do
- base=`basename -s .svg $file`
- echo "${base}.svg -> qvg/${base}.qvg"
- svg2qvg ${base}.svg qvg/${base}.qvg
-done
-
-exit $status
diff --git a/designsystems/material3/icons/qvg/add.qvg b/designsystems/material3/icons/qvg/add.qvg
index de7e62c6..51de8ec1 100644
Binary files a/designsystems/material3/icons/qvg/add.qvg and b/designsystems/material3/icons/qvg/add.qvg differ
diff --git a/designsystems/material3/icons/qvg/arrow_drop_down.qvg b/designsystems/material3/icons/qvg/arrow_drop_down.qvg
index 496378d6..69e0301c 100644
Binary files a/designsystems/material3/icons/qvg/arrow_drop_down.qvg and b/designsystems/material3/icons/qvg/arrow_drop_down.qvg differ
diff --git a/designsystems/material3/icons/qvg/arrow_drop_up.qvg b/designsystems/material3/icons/qvg/arrow_drop_up.qvg
index 09b1976e..d48d7e7a 100644
Binary files a/designsystems/material3/icons/qvg/arrow_drop_up.qvg and b/designsystems/material3/icons/qvg/arrow_drop_up.qvg differ
diff --git a/designsystems/material3/icons/qvg/check.qvg b/designsystems/material3/icons/qvg/check.qvg
index 8fb73515..e72e8896 100644
Binary files a/designsystems/material3/icons/qvg/check.qvg and b/designsystems/material3/icons/qvg/check.qvg differ
diff --git a/designsystems/material3/icons/qvg/check_small.qvg b/designsystems/material3/icons/qvg/check_small.qvg
deleted file mode 100644
index 4b92ce5b..00000000
Binary files a/designsystems/material3/icons/qvg/check_small.qvg and /dev/null differ
diff --git a/designsystems/material3/icons/qvg/close.qvg b/designsystems/material3/icons/qvg/close.qvg
new file mode 100644
index 00000000..fa97264e
Binary files /dev/null and b/designsystems/material3/icons/qvg/close.qvg differ
diff --git a/designsystems/material3/icons/qvg/combo-box-arrow-closed.qvg b/designsystems/material3/icons/qvg/combo-box-arrow-closed.qvg
deleted file mode 100644
index 83f33a45..00000000
Binary files a/designsystems/material3/icons/qvg/combo-box-arrow-closed.qvg and /dev/null differ
diff --git a/designsystems/material3/icons/qvg/combo-box-arrow-open.qvg b/designsystems/material3/icons/qvg/combo-box-arrow-open.qvg
deleted file mode 100644
index 1e757789..00000000
Binary files a/designsystems/material3/icons/qvg/combo-box-arrow-open.qvg and /dev/null differ
diff --git a/designsystems/material3/icons/qvg/remove.qvg b/designsystems/material3/icons/qvg/remove.qvg
index 6598d5b0..b038b3fa 100644
Binary files a/designsystems/material3/icons/qvg/remove.qvg and b/designsystems/material3/icons/qvg/remove.qvg differ
diff --git a/designsystems/material3/icons/qvg/segmented-button-check.qvg b/designsystems/material3/icons/qvg/segmented-button-check.qvg
deleted file mode 100644
index 1b0148e3..00000000
Binary files a/designsystems/material3/icons/qvg/segmented-button-check.qvg and /dev/null differ
diff --git a/designsystems/material3/icons/qvg/switchbutton-checked.qvg b/designsystems/material3/icons/qvg/switchbutton-checked.qvg
deleted file mode 100644
index c927ddb3..00000000
Binary files a/designsystems/material3/icons/qvg/switchbutton-checked.qvg and /dev/null differ
diff --git a/designsystems/material3/icons/qvg/switchbutton-unchecked.qvg b/designsystems/material3/icons/qvg/switchbutton-unchecked.qvg
deleted file mode 100644
index b33f61e4..00000000
Binary files a/designsystems/material3/icons/qvg/switchbutton-unchecked.qvg and /dev/null differ
diff --git a/designsystems/material3/icons/remove.svg b/designsystems/material3/icons/remove.svg
deleted file mode 100644
index 9fa856a5..00000000
--- a/designsystems/material3/icons/remove.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/designsystems/material3/icons/segmented-button-check.svg b/designsystems/material3/icons/segmented-button-check.svg
deleted file mode 100644
index b0b66ac9..00000000
--- a/designsystems/material3/icons/segmented-button-check.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/designsystems/material3/icons/switchbutton-checked.svg b/designsystems/material3/icons/switchbutton-checked.svg
deleted file mode 100644
index 7f4d9275..00000000
--- a/designsystems/material3/icons/switchbutton-checked.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/designsystems/material3/icons/switchbutton-unchecked.svg b/designsystems/material3/icons/switchbutton-unchecked.svg
deleted file mode 100644
index a9e2ee7e..00000000
--- a/designsystems/material3/icons/switchbutton-unchecked.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/designsystems/material3/icons/symbol2qvg.sh b/designsystems/material3/icons/symbol2qvg.sh
new file mode 100755
index 00000000..46597425
--- /dev/null
+++ b/designsystems/material3/icons/symbol2qvg.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+function symbol2qvg {
+ fontfile=MaterialSymbolsOutlined.ttf
+ glyph2qvg ${fontfile} 24 $1 qvg/$2.qvg
+}
+
+symbol2qvg 3067 check
+symbol2qvg 3084 close
+
+symbol2qvg 5022 arrow_drop_down
+symbol2qvg 5023 arrow_drop_up
+
+symbol2qvg 3082 add
+symbol2qvg 3080 remove
diff --git a/examples/iotdashboard/MainItem.cpp b/examples/iotdashboard/MainItem.cpp
index d8b7c46f..25db2176 100644
--- a/examples/iotdashboard/MainItem.cpp
+++ b/examples/iotdashboard/MainItem.cpp
@@ -14,7 +14,6 @@
#include
#include
-#include
#include
#include
#include
diff --git a/examples/qvgviewer/MainWindow.cpp b/examples/qvgviewer/MainWindow.cpp
index 001c6c87..5d63002e 100644
--- a/examples/qvgviewer/MainWindow.cpp
+++ b/examples/qvgviewer/MainWindow.cpp
@@ -31,8 +31,8 @@ class GraphicLabel : public QskGraphicLabel
Inverted
};
- GraphicLabel( const QskGraphic& graphic, QQuickItem* parent = nullptr )
- : QskGraphicLabel( graphic, parent )
+ GraphicLabel( QQuickItem* parent = nullptr )
+ : QskGraphicLabel( parent )
{
setMargins( 10 );
setPanel( true );
@@ -74,7 +74,7 @@ class GraphicLabel : public QskGraphicLabel
MainWindow::MainWindow()
{
- auto label = new GraphicLabel( QskGraphicIO::read( QString( ":/qvg/Tux.qvg" ) ) );
+ auto label = new GraphicLabel();
auto invertButton = new QskPushButton( "Inverted" );
invertButton->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
@@ -98,6 +98,12 @@ MainWindow::MainWindow()
setGraphicRoles( qskSkinManager->skin() );
}
+void MainWindow::setGraphic( const QString& path )
+{
+ if ( auto label = findChild< QskGraphicLabel* >() )
+ label->setGraphic( QskGraphicIO::read( path ) );
+}
+
void MainWindow::setGraphicRoles( QskSkin* skin )
{
// substituting black
diff --git a/examples/qvgviewer/MainWindow.h b/examples/qvgviewer/MainWindow.h
index 2d8eb8b5..f486af93 100644
--- a/examples/qvgviewer/MainWindow.h
+++ b/examples/qvgviewer/MainWindow.h
@@ -15,6 +15,7 @@ class MainWindow : public QskWindow
public:
MainWindow();
+ void setGraphic( const QString& );
private Q_SLOTS:
void setGraphicRoles( QskSkin* );
diff --git a/examples/qvgviewer/main.cpp b/examples/qvgviewer/main.cpp
index 9dc3ede2..fc1421bb 100644
--- a/examples/qvgviewer/main.cpp
+++ b/examples/qvgviewer/main.cpp
@@ -27,6 +27,7 @@ int main( int argc, char* argv[] )
focusIndicator->setObjectName( "FocusIndicator" );
MainWindow window;
+ window.setGraphic( ( argc > 1 ) ? argv[1] : ":/qvg/Tux.qvg" );
window.resize( 600, 400 );
window.addItem( focusIndicator );
window.show();
diff --git a/playground/CMakeLists.txt b/playground/CMakeLists.txt
index 30ddc7d1..592c4938 100644
--- a/playground/CMakeLists.txt
+++ b/playground/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(dials)
add_subdirectory(dialogbuttons)
add_subdirectory(fonts)
add_subdirectory(gradients)
+add_subdirectory(iconbrowser)
add_subdirectory(invoker)
add_subdirectory(shadows)
add_subdirectory(shapes)
diff --git a/playground/iconbrowser/CMakeLists.txt b/playground/iconbrowser/CMakeLists.txt
new file mode 100644
index 00000000..945f9ef4
--- /dev/null
+++ b/playground/iconbrowser/CMakeLists.txt
@@ -0,0 +1,15 @@
+############################################################################
+# QSkinny - Copyright (C) The authors
+# SPDX-License-Identifier: BSD-3-Clause
+############################################################################
+
+set(SOURCES
+ GlyphListView.h GlyphListView.cpp
+ main.cpp
+)
+
+qt_add_resources(SOURCES
+ fonts.qrc
+)
+
+qsk_add_example(iconbrowser ${SOURCES})
diff --git a/playground/iconbrowser/GlyphListView.cpp b/playground/iconbrowser/GlyphListView.cpp
new file mode 100644
index 00000000..b93e1e01
--- /dev/null
+++ b/playground/iconbrowser/GlyphListView.cpp
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#include "GlyphListView.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+constexpr int glyphSize = 20;
+
+GlyphListView::GlyphListView( QQuickItem* parentItem )
+ : Inherited( parentItem )
+{
+}
+
+GlyphListView::GlyphListView( const QString& fontName, QQuickItem* parentItem )
+ : GlyphListView( parentItem )
+{
+ setFont( QRawFont( fontName, 16 ) );
+ setFontRoleHint( Text, QskFontRole::Title );
+}
+
+void GlyphListView::setFontPath( const QString& fontPath )
+{
+ setFont( QRawFont( fontPath, 16 ) );
+}
+
+void GlyphListView::setFont( const QRawFont& font )
+{
+ m_glyphTable.setIconFont( font );
+
+ const auto names = m_glyphTable.nameTable();
+
+ m_nameTable.clear();
+ m_nameTable.reserve( names.size() );
+
+ m_maxNameWidth = 0;
+
+ {
+ const QFontMetricsF fm( effectiveFont( Text ) );
+
+ for ( auto it = names.constBegin(); it != names.constEnd(); ++it )
+ {
+ m_nameTable.insert( it.value(), it.key() );
+
+ const qreal w = qskHorizontalAdvance( fm, it.key() );
+ if ( w > m_maxNameWidth )
+ m_maxNameWidth = w;
+ }
+ }
+
+ updateScrollableSize();
+ update();
+}
+
+QRawFont GlyphListView::font() const
+{
+ return m_glyphTable.iconFont();
+}
+
+int GlyphListView::rowCount() const
+{
+ return m_glyphTable.glyphCount() - 1;
+}
+
+int GlyphListView::columnCount() const
+{
+ return 3;
+}
+
+qreal GlyphListView::columnWidth( int col ) const
+{
+ switch( col )
+ {
+ case 0:
+ {
+ const QFontMetricsF fm( effectiveFont( Text ) );
+ return qskHorizontalAdvance( fm, "999999" );
+ }
+
+ case 1:
+ {
+ const auto hint = strutSizeHint( Cell );
+ const auto padding = paddingHint( Cell );
+
+ const qreal w = glyphSize + padding.left() + padding.right();
+ return qMax( w, hint.width() );
+ }
+
+ case 2:
+ return m_maxNameWidth;
+ }
+
+ return 0;
+}
+
+qreal GlyphListView::rowHeight() const
+{
+ const auto hint = strutSizeHint( Cell );
+ const auto padding = paddingHint( Cell );
+
+ const qreal h = glyphSize + padding.top() + padding.bottom();
+ return qMax( h, hint.height() );
+}
+
+QVariant GlyphListView::valueAt( int row, int col ) const
+{
+ const auto glyphIndex = row + 1;
+ switch( col )
+ {
+ case 0:
+ return QVariant::fromValue( QString::number( glyphIndex ) );
+
+ case 1:
+ return QVariant::fromValue( m_glyphTable.glyphGraphic( glyphIndex ) );
+
+ case 2:
+ return QVariant::fromValue( m_nameTable.value( glyphIndex ) );
+ }
+
+ return QVariant();
+}
+
+#include "moc_GlyphListView.cpp"
diff --git a/playground/iconbrowser/GlyphListView.h b/playground/iconbrowser/GlyphListView.h
new file mode 100644
index 00000000..8e9239b6
--- /dev/null
+++ b/playground/iconbrowser/GlyphListView.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#pragma once
+
+#include
+#include
+#include
+
+class GlyphListView : public QskListView
+{
+ Q_OBJECT
+ using Inherited = QskListView;
+
+ public:
+ GlyphListView( QQuickItem* = nullptr);
+ GlyphListView( const QString&, QQuickItem* = nullptr);
+
+ void setFontPath( const QString& );
+ void setFont( const QRawFont& );
+ QRawFont font() const;
+
+ int rowCount() const override;
+ int columnCount() const override;
+
+ virtual qreal columnWidth( int col ) const override;
+ virtual qreal rowHeight() const override;
+
+ QVariant valueAt( int row, int col ) const override;
+
+ private:
+ QskGlyphTable m_glyphTable;
+
+ QHash< uint, QString > m_nameTable;
+ int m_maxNameWidth = 0;
+};
diff --git a/playground/iconbrowser/fonts.qrc b/playground/iconbrowser/fonts.qrc
new file mode 100644
index 00000000..1bcb1237
--- /dev/null
+++ b/playground/iconbrowser/fonts.qrc
@@ -0,0 +1,11 @@
+
+
+
+ ../../designsystems/fluent2/icons/FluentSystemIcons-Regular.ttf
+ fonts/Font Awesome 6 Free-Regular-400.otf
+ fonts/IcoMoon-Free.ttf
+ ../../designsystems/material3/icons/MaterialSymbolsOutlined.ttf
+ fonts/Octicons.ttf
+
+
+
diff --git a/playground/iconbrowser/fonts/Font Awesome 6 Free-Regular-400.otf b/playground/iconbrowser/fonts/Font Awesome 6 Free-Regular-400.otf
new file mode 100644
index 00000000..17a83506
Binary files /dev/null and b/playground/iconbrowser/fonts/Font Awesome 6 Free-Regular-400.otf differ
diff --git a/playground/iconbrowser/fonts/IcoMoon-Free.ttf b/playground/iconbrowser/fonts/IcoMoon-Free.ttf
new file mode 100644
index 00000000..56919449
Binary files /dev/null and b/playground/iconbrowser/fonts/IcoMoon-Free.ttf differ
diff --git a/playground/iconbrowser/fonts/LICENSES b/playground/iconbrowser/fonts/LICENSES
new file mode 100644
index 00000000..12faa7bf
--- /dev/null
+++ b/playground/iconbrowser/fonts/LICENSES
@@ -0,0 +1,16 @@
+a) Font Awesome
+
+ Code: https://fontawesome.com/
+ SPDX-License-Identifier: OFL-1.1-RFN
+ Copyright (c) 2024 Fonticons, Inc.
+
+b) IcoMoon
+
+ Code: https://github.com/Keyamoon/IcoMoon-Free
+ SPDX-License-Identifier: CC-BY-4.0
+
+c) Octicons
+
+ Code: https://github.com/primer/octicons
+ SPDX-License-Identifier: MIT License
+
diff --git a/playground/iconbrowser/fonts/Octicons.ttf b/playground/iconbrowser/fonts/Octicons.ttf
new file mode 100755
index 00000000..9e091053
Binary files /dev/null and b/playground/iconbrowser/fonts/Octicons.ttf differ
diff --git a/playground/iconbrowser/main.cpp b/playground/iconbrowser/main.cpp
new file mode 100644
index 00000000..2a9ad9ad
--- /dev/null
+++ b/playground/iconbrowser/main.cpp
@@ -0,0 +1,100 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#include "GlyphListView.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace
+{
+ class Header : public QskLinearBox
+ {
+ Q_OBJECT
+
+ public:
+ Header( QQuickItem* parent = nullptr )
+ : QskLinearBox( Qt::Horizontal, parent )
+ {
+ setPaddingHint( QskBox::Panel, 5 );
+
+ initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Fixed );
+ setPanel( true );
+
+ m_comboBox = new QskComboBox( this );
+
+ const auto entries = QDir( ":iconfonts" ).entryInfoList();
+ for ( const auto& entry : entries )
+ m_comboBox->addOption( QUrl(), entry.absoluteFilePath() );
+
+ m_comboBox->setCurrentIndex( 0 );
+
+ connect( m_comboBox, &QskComboBox::currentIndexChanged,
+ this, &Header::comboBoxChanged );
+ }
+
+ QString fontPath() const { return m_comboBox->currentText(); }
+
+ Q_SIGNALS:
+ void fontChanged( const QString& );
+
+ private:
+ void comboBoxChanged() { Q_EMIT fontChanged( fontPath() ); }
+
+ QskComboBox* m_comboBox;
+ };
+
+ class MainView : public QskMainView
+ {
+ public:
+ MainView( QQuickItem* parent = nullptr )
+ : QskMainView( parent )
+ {
+ auto listView = new GlyphListView( this );
+ auto header = new Header( this );
+
+ setHeader( header );
+ setBody( listView );
+
+ listView->setFontPath( header->fontPath() );
+
+ connect( header, &Header::fontChanged,
+ listView, &GlyphListView::setFontPath );
+ }
+ };
+}
+
+int main( int argc, char* argv[] )
+{
+#ifdef ITEM_STATISTICS
+ QskObjectCounter counter( true );
+#endif
+
+ QGuiApplication app( argc, argv );
+
+ SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
+
+ auto mainView = new QskMainView();
+ mainView->setBody( new GlyphListView( ":/fonts/Octicons.ttf" ) );
+
+ QskWindow window;
+ window.addItem( new MainView() );
+ window.addItem( new QskFocusIndicator() );
+ window.resize( 600, 400 );
+ window.show();
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7fde8b5e..c86f6783 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -77,6 +77,8 @@ list(APPEND PRIVATE_HEADERS
list(APPEND HEADERS
graphic/QskColorFilter.h
+ graphic/QskGlyphGraphicProvider.h
+ graphic/QskGlyphTable.h
graphic/QskGraphic.h
graphic/QskGraphicImageProvider.h
graphic/QskGraphicIO.h
@@ -91,6 +93,8 @@ list(APPEND HEADERS
list(APPEND SOURCES
graphic/QskColorFilter.cpp
+ graphic/QskGlyphGraphicProvider.cpp
+ graphic/QskGlyphTable.cpp
graphic/QskGraphic.cpp
graphic/QskGraphicImageProvider.cpp
graphic/QskGraphicIO.cpp
diff --git a/src/controls/QskItem.cpp b/src/controls/QskItem.cpp
index c0b83dde..5a5a0940 100644
--- a/src/controls/QskItem.cpp
+++ b/src/controls/QskItem.cpp
@@ -1007,6 +1007,10 @@ void QskItem::itemChange( QQuickItem::ItemChange change,
case QQuickItem::ItemRotationHasChanged:
case QQuickItem::ItemAntialiasingHasChanged:
case QQuickItem::ItemDevicePixelRatioHasChanged:
+#if QT_VERSION >= QT_VERSION_CHECK( 6, 9, 0 )
+ case QQuickItem::ItemScaleHasChanged:
+ case QQuickItem::ItemTransformHasChanged:
+#endif
{
break;
}
diff --git a/src/controls/QskQuick.cpp b/src/controls/QskQuick.cpp
index e252ff5e..d988820c 100644
--- a/src/controls/QskQuick.cpp
+++ b/src/controls/QskQuick.cpp
@@ -29,6 +29,25 @@ QRhi* qskRenderingHardwareInterface( const QQuickWindow* window )
return nullptr;
}
+bool qskIsOpenGLWindow( const QQuickWindow* window )
+{
+ if ( window == nullptr )
+ return false;
+
+ const auto renderer = window->rendererInterface();
+ switch( renderer->graphicsApi() )
+ {
+ case QSGRendererInterface::OpenGL:
+#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
+ case QSGRendererInterface::OpenGLRhi:
+#endif
+ return true;
+
+ default:
+ return false;
+ }
+}
+
QRectF qskItemRect( const QQuickItem* item )
{
auto d = QQuickItemPrivate::get( item );
diff --git a/src/controls/QskQuick.h b/src/controls/QskQuick.h
index 165bec4b..7befde16 100644
--- a/src/controls/QskQuick.h
+++ b/src/controls/QskQuick.h
@@ -27,6 +27,7 @@ template< typename T > class QList;
*/
QSK_EXPORT QRhi* qskRenderingHardwareInterface( const QQuickWindow* );
+QSK_EXPORT bool qskIsOpenGLWindow( const QQuickWindow* );
QSK_EXPORT bool qskIsItemInDestructor( const QQuickItem* );
QSK_EXPORT bool qskIsItemComplete( const QQuickItem* );
diff --git a/src/graphic/QskGlyphGraphicProvider.cpp b/src/graphic/QskGlyphGraphicProvider.cpp
new file mode 100644
index 00000000..9986476c
--- /dev/null
+++ b/src/graphic/QskGlyphGraphicProvider.cpp
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#include "QskGlyphGraphicProvider.h"
+#include "QskGraphic.h"
+#include "QskGlyphTable.h"
+
+#include
+#include
+#include
+
+class QskGlyphGraphicProvider::PrivateData
+{
+ public:
+ QskGlyphTable glyphTable;
+};
+
+QskGlyphGraphicProvider::QskGlyphGraphicProvider( QObject* parent )
+ : QskGraphicProvider( parent )
+ , m_data( new PrivateData )
+{
+}
+
+QskGlyphGraphicProvider::~QskGlyphGraphicProvider()
+{
+}
+
+void QskGlyphGraphicProvider::setIconFont( const QRawFont& font )
+{
+ m_data->glyphTable.setIconFont( font );
+}
+
+QRawFont QskGlyphGraphicProvider::iconFont() const
+{
+ return m_data->glyphTable.iconFont();
+}
+
+QskGraphic QskGlyphGraphicProvider::glyphGraphic( uint index ) const
+{
+ return m_data->glyphTable.glyphGraphic( index );
+}
+
+const QskGraphic* QskGlyphGraphicProvider::loadGraphic( const QString& key ) const
+{
+ if ( const auto index = glyphIndex( key ) )
+ {
+ const auto graphic = glyphGraphic( index );
+ if ( !graphic.isNull() )
+ return new QskGraphic( graphic );
+ }
+
+ return nullptr;
+}
+
+uint QskGlyphGraphicProvider::glyphIndex( const QString& key ) const
+{
+ const auto& table = m_data->glyphTable;
+
+ if ( ( table.glyphCount() > 0 ) && !key.isEmpty() )
+ {
+ if ( key.startsWith( '#' ) )
+ {
+ bool ok;
+ const auto glyphIndex = key.toUInt( &ok );
+ if ( ok )
+ return glyphIndex;
+ }
+ else if ( key.startsWith( "U+" ) )
+ {
+ bool ok;
+ const char32_t code = key.mid( 2 ).toUInt( &ok, 16 );
+ if ( ok )
+ return table.codeToIndex( code );
+ }
+ else
+ {
+ return table.nameToIndex( key );
+ }
+ }
+
+ return 0;
+}
diff --git a/src/graphic/QskGlyphGraphicProvider.h b/src/graphic/QskGlyphGraphicProvider.h
new file mode 100644
index 00000000..15523093
--- /dev/null
+++ b/src/graphic/QskGlyphGraphicProvider.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#ifndef QSK_GLYPH_GRAPHIC_PROVIDER_H
+#define QSK_GLYPH_GRAPHIC_PROVIDER_H
+
+#include "QskGraphicProvider.h"
+
+class QRawFont;
+
+class QSK_EXPORT QskGlyphGraphicProvider : public QskGraphicProvider
+{
+ using Inherited = QskGraphicProvider;
+
+ public:
+ QskGlyphGraphicProvider( QObject* parent = nullptr );
+ ~QskGlyphGraphicProvider() override;
+
+ void setIconFont( const QRawFont& );
+ QRawFont iconFont() const;
+
+ QskGraphic glyphGraphic( uint glyphIndex ) const;
+
+ protected:
+ const QskGraphic* loadGraphic( const QString& ) const override final;
+ virtual uint glyphIndex( const QString& ) const;
+
+ private:
+ class PrivateData;
+ std::unique_ptr< PrivateData > m_data;
+};
+
+#endif
diff --git a/src/graphic/QskGlyphTable.cpp b/src/graphic/QskGlyphTable.cpp
new file mode 100644
index 00000000..13cd7607
--- /dev/null
+++ b/src/graphic/QskGlyphTable.cpp
@@ -0,0 +1,502 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#include "QskGlyphTable.h"
+#include "QskGraphic.h"
+#include "QskInternalMacros.h"
+
+#include
+#include
+#include
+#include
+
+QSK_QT_PRIVATE_BEGIN
+#include
+QSK_QT_PRIVATE_END
+
+typedef QHash< QString, uint > GlyphNameTable;
+
+/*
+ The "parsers" below do no validation checks as the font has
+ already been validated by QRawFont
+
+ Hope QRawFont will extend its API some day ( the underlying
+ font libraries do support glyph names ) and we can remove the nasty
+ code below. see https://bugreports.qt.io/browse/QTBUG-132629
+ */
+namespace PostTableParser
+{
+ // https://learn.microsoft.com/en-us/typography/opentype/spec/post
+
+ static inline QString toString( const uint8_t* s )
+ {
+ // Pascal string. Valid characters are: [A–Z] [a–z] [0–9] '.' '_'
+ return QString::fromUtf8(
+ reinterpret_cast< const char* > ( s + 1 ), *s );
+ }
+
+ static GlyphNameTable glyphNames( const QByteArray& blob )
+ {
+ GlyphNameTable names;
+
+ const auto* glyphData = reinterpret_cast< const uint16_t* >( blob.constData() + 32 );
+ if ( const auto nglyphs = qFromBigEndian( *glyphData++ ) )
+ {
+ QVarLengthArray< const uint8_t* > strings;
+ strings.reserve( nglyphs );
+
+ const auto from = reinterpret_cast< const uint8_t* >( glyphData + nglyphs );
+ const auto to = reinterpret_cast< const uint8_t* >( blob.data() + blob.size() );
+
+ if ( to > from )
+ {
+ for ( auto s = from; s < to; s += *s + 1 )
+ strings += s;
+
+ for ( int i = 0; i < nglyphs; i++ )
+ {
+ const int idx = qFromBigEndian( glyphData[i] ) - 258;
+
+ if ( idx >= 0 && idx < strings.size() )
+ names.insert( toString( strings[idx] ), i );
+ }
+ }
+ }
+
+ return names;
+ }
+}
+
+namespace CFFTableParser
+{
+ // https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf
+
+ static uint32_t offsetAt( const uint8_t* d, int size )
+ {
+ switch (size)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return d[0];
+ case 2:
+ return ( d[0] << 8 ) | d[1];
+ case 3:
+ return ( d[0] << 16 ) | ( d[1] << 8 ) | d[2];
+ default:
+ return ( d[0] << 24 ) | ( d[1] << 16 ) | ( d[2] << 8 ) | d[3];
+ }
+ }
+
+ static int indexDataSize( const uint8_t* d )
+ {
+ const int nitems = ( d[0] << 8 ) | d[1];
+ if ( nitems == 0 )
+ return 2;
+
+ const int size = d[2];
+
+ const uint8_t* lx = d + 3 + nitems * size;
+ return lx + size - 1 + offsetAt( lx, size ) - d;
+ }
+
+ static const uint8_t* indexData( const uint8_t* d )
+ {
+ const int nitems = ( d[0] << 8 ) | d[1];
+ d += 2;
+
+ if ( nitems == 0 )
+ return d;
+
+ const int size = d[0];
+
+ const uint8_t* _contents = d + ( nitems + 1 ) * size;
+ return _contents + offsetAt(d + 1, size);
+ }
+
+ static const uint8_t* skipHeader( const uint8_t* d )
+ {
+ return d + d[2];
+ }
+
+ static const uint8_t* skipIndex( const uint8_t* d )
+ {
+ return d + indexDataSize( d );
+ }
+
+ static QVector< int > stringIds( const uint8_t* data, int nglyphs )
+ {
+ const int format = data[0];
+
+ QVector< int > _sids;
+ _sids += 0;
+
+ const uint8_t* p = data + 1;
+ switch( format )
+ {
+ case 0:
+ {
+ for (; _sids.size() < nglyphs; p += 2)
+ {
+ int sid = ( p[0] << 8 ) | p[1];
+ _sids += sid;
+ }
+ break;
+ }
+ case 1:
+ {
+ for (; _sids.size() < nglyphs; p += 3)
+ {
+ const int sid = ( p[0] << 8 ) | p[1];
+ const int n = p[2];
+
+ for ( int i = 0; i <= n; i++ )
+ _sids += sid + i;
+ }
+ break;
+ }
+ case 2:
+ {
+ for (; _sids.size() < nglyphs; p += 4)
+ {
+ const int sid = ( p[0] << 8 ) | p[1];
+ const int n = ( p[2] << 8 ) | p[3];
+
+ for ( int i = 0; i <= n; i++ )
+ _sids += sid + i;
+ }
+ break;
+ }
+ }
+
+ return _sids;
+ }
+
+ static int dictValue( const uint8_t* d, int op )
+ {
+ /*
+ see https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf
+ We are intersted in the offset ( operator 15 ).
+ */
+
+ const uint8_t* data = indexData( d );
+
+ int value = 0;
+
+ Q_FOREVER
+ {
+ // operand
+ const auto valueType = data[0];
+
+ if ( valueType == 28 )
+ {
+ value = ( data[1] << 8 ) | data[2];
+ data += 3;
+ }
+ else if ( valueType == 29 )
+ {
+ value = ( data[1] << 24 ) | ( data[2] << 16 )
+ | ( data[3] << 8 ) | data[4];
+
+ data += 5;
+ }
+ else if ( valueType == 30 )
+ {
+ /*
+ Assuming, that an offset is never a double
+ we skip the operand without reading it
+ */
+ while( ++data )
+ {
+ const int b = *data;
+ if ( ( b & 0x0f ) == 0x0f || ( b & 0xf0 ) == 0xf0 )
+ break; // 0xf nibble indicating the end
+ }
+
+ data++;
+ }
+ else if ( valueType >= 31 && valueType <= 246 )
+ {
+ value = data[0] - 139;
+ data++;
+ }
+ else if ( valueType >= 247 && valueType <= 250 )
+ {
+ value = ( ( data[0] - 247 ) << 8 ) + data[1] + 108;
+ data += 2;
+ }
+ else if ( valueType >= 251 && valueType <= 254 )
+ {
+ value = -( ( data[0] - 251 ) << 8 ) - data[1] - 108;
+ data += 2;
+ }
+
+ // operator
+
+ if ( op == data[0] )
+ return value;
+
+ data += ( data[0] == 12 ) ? 2 : 1;
+ }
+
+ return 0; // default value
+ }
+
+ class StringTable
+ {
+ public:
+ StringTable( const uint8_t* data )
+ {
+ const int nitems = ( data[0] << 8 ) | data[1];
+ if ( nitems == 0 )
+ {
+ _contents = data + 2;
+ _offset = nullptr;
+ _offsize = 0;
+ }
+ else
+ {
+ _offsize = data[2];
+ _offset = data + 3;
+
+ _contents = _offset + nitems * _offsize + _offsize - 1;
+ }
+ }
+
+ inline QString operator[]( int which ) const
+ {
+ const auto x = _offset + which * _offsize;
+
+ const auto d1 = _contents + offsetAt(x, _offsize);
+ const auto d2 = _contents + offsetAt(x + _offsize, _offsize);
+
+ return QString::fromUtf8(
+ reinterpret_cast< const char* >( d1 ), d2 - d1 );
+ }
+
+ private:
+ const uint8_t* _contents = nullptr;
+ const uint8_t* _offset = nullptr;
+ int _offsize = -1;
+ };
+
+ static GlyphNameTable glyphNames( const QByteArray& blob, int glyphCount )
+ {
+ auto data = reinterpret_cast< const uint8_t* >( blob.constData() );
+
+ auto nameIndex = skipHeader( data );
+ auto dictIndex = skipIndex( nameIndex );
+ auto stringIndex = skipIndex( dictIndex );
+
+ auto charset = data + dictValue( dictIndex, 15 ); // 15: charset offset
+
+ const QVector< int > sids = stringIds( charset, glyphCount );
+
+ const StringTable table( stringIndex );
+
+ GlyphNameTable names;
+
+ for ( int i = 0; i < glyphCount; i++ )
+ {
+ /*
+ The first 391 SIDs are reserved for standard strings
+ ( Appendix A ) that are not from the charset table.
+ */
+
+ const auto idx = sids[i] - 391;
+
+ if ( idx >= 0 )
+ names.insert( table[idx], i );
+ }
+
+ return names;
+ }
+}
+
+static uint qskGlyphCount( const QRawFont& font )
+{
+ /*
+ we could also read the count from the "maxp" table:
+ https://learn.microsoft.com/en-us/typography/opentype/spec/maxp
+ */
+
+ const auto fontEngine = QRawFontPrivate::get( font )->fontEngine;
+ return fontEngine ? fontEngine->glyphCount() : 0;
+}
+
+static qreal qskPixelSize( const QRawFont& font )
+{
+ const auto fontEngine = QRawFontPrivate::get( font )->fontEngine;
+ return fontEngine ? fontEngine->fontDef.pixelSize : 0.0;
+}
+
+static GlyphNameTable qskGlyphNameTable( const QRawFont& font )
+{
+ const auto count = qskGlyphCount( font );
+ if ( count > 0 )
+ {
+ /*
+ The Compact Font Format ( CFF ) table has been introduced with
+ the OpenType specification. For not complying fonts the names
+ might be found in the Post table
+ */
+ auto blob = font.fontTable( "CFF ");
+ if ( !blob.isEmpty() )
+ return CFFTableParser::glyphNames( blob, count );
+
+ blob = font.fontTable( "post" );
+ if ( !blob.isEmpty() )
+ return PostTableParser::glyphNames( blob );
+ }
+
+ return GlyphNameTable();
+}
+
+static inline quint32 qskGlyphIndex( const QRawFont& font, char32_t ucs4 )
+{
+ if ( qskGlyphCount( font ) == 0 )
+ return 0;
+
+ const auto idxs = font.glyphIndexesForString(
+ QString::fromUcs4( &ucs4, 1 ) );
+
+ // fingers crossed: icon fonts will map code points to single glyphs only
+ Q_ASSERT( idxs.size() == 1 );
+
+ return idxs.size() == 1 ? idxs[0] : 0;
+}
+
+class QskGlyphTable::PrivateData
+{
+ public:
+ inline const GlyphNameTable& glyphNameTable() const
+ {
+ if ( !validNames )
+ {
+ auto that = const_cast< PrivateData* >( this );
+ that->nameTable = qskGlyphNameTable( font );
+ that->validNames = true;
+ }
+
+ return nameTable;
+ }
+
+ QRawFont font;
+ GlyphNameTable nameTable;
+ bool validNames = false;
+};
+
+QskGlyphTable::QskGlyphTable()
+ : m_data( new PrivateData )
+{
+}
+
+QskGlyphTable::QskGlyphTable( const QRawFont& font )
+ : QskGlyphTable()
+{
+ m_data->font = font;
+}
+
+QskGlyphTable::QskGlyphTable( const QskGlyphTable& other )
+ : QskGlyphTable()
+{
+ *m_data = *other.m_data;
+}
+
+QskGlyphTable::~QskGlyphTable()
+{
+}
+
+QskGlyphTable& QskGlyphTable::operator=( const QskGlyphTable& other )
+{
+ if ( m_data != other.m_data )
+ *m_data = *other.m_data;
+
+ return *this;
+}
+
+void QskGlyphTable::setIconFont( const QRawFont& font )
+{
+ if ( font != m_data->font )
+ {
+ m_data->font = font;
+ m_data->nameTable.clear();
+ m_data->validNames = false;
+ }
+}
+
+QRawFont QskGlyphTable::iconFont() const
+{
+ return m_data->font;
+}
+
+QPainterPath QskGlyphTable::glyphPath( uint glyphIndex ) const
+{
+ QPainterPath path;
+
+ /*
+ Unfortunately QRawFont::pathForGlyph runs into failing checks
+ when being called from a different thread - f.e the scene graph thread.
+ So we need to bypass QRawFont and retrieve from its fontEngine.
+ */
+ if ( auto fontEngine = QRawFontPrivate::get( m_data->font )->fontEngine )
+ {
+ QFixedPoint position;
+ quint32 idx = glyphIndex;
+
+ fontEngine->addGlyphsToPath( &idx, &position, 1, &path, {} );
+ }
+
+ return path;
+}
+
+QskGraphic QskGlyphTable::glyphGraphic( uint glyphIndex ) const
+{
+ QskGraphic graphic;
+
+ if ( glyphIndex > 0 && qskGlyphCount( m_data->font ) > 0 )
+ {
+ const auto path = glyphPath( glyphIndex );
+
+ if ( !path.isEmpty() )
+ {
+ // vertical glyph coordinates are in the range [-sz, 0.0]
+ const auto sz = qskPixelSize( m_data->font );
+ graphic.setViewBox( QRectF( 0.0, -sz, sz, sz ) );
+
+ QPainter painter( &graphic );
+ painter.setRenderHint( QPainter::Antialiasing, true );
+ painter.fillPath( path, Qt::black );
+ }
+ }
+
+ return graphic;
+}
+
+uint QskGlyphTable::glyphCount() const
+{
+ return qskGlyphCount( m_data->font );
+}
+
+uint QskGlyphTable::codeToIndex( char32_t ucs4 ) const
+{
+ return qskGlyphIndex( m_data->font, ucs4 );
+}
+
+uint QskGlyphTable::nameToIndex( const QString& name ) const
+{
+ /*
+ Names/Codes that do not correspond to any glyph in should
+ be mapped to glyph index 0.
+
+ see https://learn.microsoft.com/en-us/typography/opentype/spec/cmap
+ */
+ return m_data->glyphNameTable().value( name.toLatin1(), 0 );
+}
+
+QHash< QString, uint > QskGlyphTable::nameTable() const
+{
+ return m_data->glyphNameTable();
+}
diff --git a/src/graphic/QskGlyphTable.h b/src/graphic/QskGlyphTable.h
new file mode 100644
index 00000000..c218eab0
--- /dev/null
+++ b/src/graphic/QskGlyphTable.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * QSkinny - Copyright (C) The authors
+ * SPDX-License-Identifier: BSD-3-Clause
+ *****************************************************************************/
+
+#ifndef QSK_GLYPH_TABLE_H
+#define QSK_GLYPH_TABLE_H
+
+#include "QskGlobal.h"
+#include
+
+class QskGraphic;
+class QRawFont;
+class QString;
+class QPainterPath;
+class QByteArray;
+class QChar;
+
+template< typename Key, typename T > class QHash;
+
+class QSK_EXPORT QskGlyphTable
+{
+ public:
+ QskGlyphTable();
+ QskGlyphTable( const QRawFont& );
+ QskGlyphTable( const QskGlyphTable& );
+
+ ~QskGlyphTable();
+
+ QskGlyphTable& operator=( const QskGlyphTable& );
+
+ bool isValid() const;
+
+ void setIconFont( const QRawFont& );
+ QRawFont iconFont() const;
+
+ uint glyphCount() const;
+
+ QPainterPath glyphPath( uint glyphIndex ) const;
+ QskGraphic glyphGraphic( uint glyphIndex ) const;
+
+ /*
+ Most icon fonts use code points from the Unicode Private Use Areas (PUA)
+ ( see https://en.wikipedia.org/wiki/Private_Use_Areas ):
+
+ - [0x00e000, 0x00f8ff]
+ - [0x0f0000, 0x0ffffd]
+ - [0x100000, 0x10fffd]
+
+ Note that QChar is 16-bit entity only that does not cover the higher PUA blocks.
+ */
+ uint codeToIndex( char32_t ) const;
+
+ /*
+ True/OpenType fonts often include a table with glyph names, that can be used
+ instead of the glyph index
+ */
+ uint nameToIndex( const QString& ) const;
+
+ QHash< QString, uint > nameTable() const;
+
+ private:
+ class PrivateData;
+ std::unique_ptr< PrivateData > m_data;
+};
+
+inline bool QskGlyphTable::isValid() const
+{
+ return glyphCount() > 0;
+}
+
+#endif
diff --git a/src/graphic/QskGraphic.cpp b/src/graphic/QskGraphic.cpp
index 3093cf84..74921db7 100644
--- a/src/graphic/QskGraphic.cpp
+++ b/src/graphic/QskGraphic.cpp
@@ -907,7 +907,7 @@ void QskGraphic::drawPath( const QPainterPath& path )
if ( painter == nullptr )
return;
- m_data->addCommand( QskPainterCommand( path ) );
+ addCommand( QskPainterCommand( path ) );
m_data->commandTypes |= QskGraphic::VectorData;
if ( !path.isEmpty() )
@@ -938,7 +938,7 @@ void QskGraphic::drawPixmap( const QRectF& rect,
if ( painter == nullptr )
return;
- m_data->addCommand( QskPainterCommand( rect, pixmap, subRect ) );
+ addCommand( QskPainterCommand( rect, pixmap, subRect ) );
m_data->commandTypes |= QskGraphic::RasterData;
const QRectF r = painter->transform().mapRect( rect );
@@ -953,7 +953,7 @@ void QskGraphic::drawImage( const QRectF& rect, const QImage& image,
if ( painter == nullptr )
return;
- m_data->addCommand( QskPainterCommand( rect, image, subRect, flags ) );
+ addCommand( QskPainterCommand( rect, image, subRect, flags ) );
m_data->commandTypes |= QskGraphic::RasterData;
const QRectF r = painter->transform().mapRect( rect );
@@ -964,7 +964,7 @@ void QskGraphic::drawImage( const QRectF& rect, const QImage& image,
void QskGraphic::updateState( const QPaintEngineState& state )
{
- m_data->addCommand( QskPainterCommand( state ) );
+ addCommand( QskPainterCommand( state ) );
if ( state.state() & QPaintEngine::DirtyTransform )
{
@@ -981,6 +981,11 @@ void QskGraphic::updateState( const QPaintEngineState& state )
}
}
+void QskGraphic::addCommand( const QskPainterCommand& command )
+{
+ m_data->addCommand( command );
+}
+
void QskGraphic::updateBoundingRect( const QRectF& rect )
{
QRectF br = rect;
diff --git a/src/graphic/QskGraphic.h b/src/graphic/QskGraphic.h
index b3834857..882ee59a 100644
--- a/src/graphic/QskGraphic.h
+++ b/src/graphic/QskGraphic.h
@@ -146,7 +146,9 @@ class QSK_EXPORT QskGraphic : public QPaintDevice
virtual void drawImage( const QRectF&,
const QImage&, const QRectF&, Qt::ImageConversionFlags );
- virtual void updateState( const QPaintEngineState& state );
+ virtual void updateState( const QPaintEngineState& );
+
+ virtual void addCommand( const QskPainterCommand& );
private:
void updateBoundingRect( const QRectF& );
diff --git a/src/graphic/QskGraphicTextureFactory.cpp b/src/graphic/QskGraphicTextureFactory.cpp
index 24cff214..efaae47e 100644
--- a/src/graphic/QskGraphicTextureFactory.cpp
+++ b/src/graphic/QskGraphicTextureFactory.cpp
@@ -5,9 +5,38 @@
#include "QskGraphicTextureFactory.h"
#include "QskTextureRenderer.h"
+#include "QskQuick.h"
+#include "QskInternalMacros.h"
#include
+QSK_QT_PRIVATE_BEGIN
+#include
+QSK_QT_PRIVATE_END
+
+static QSGTexture* qskCreatePaintedTexture( QQuickWindow* window,
+ const QSize& size, QskTextureRenderer::PaintHelper* helper )
+{
+ using namespace QskTextureRenderer;
+
+ if ( qskIsOpenGLWindow( window ) )
+ {
+ const auto textureId = createTextureGL( window, size, helper );
+
+ auto texture = new QSGPlainTexture;
+ texture->setHasAlphaChannel( true );
+ texture->setOwnsTexture( true );
+
+ setTextureId( window, textureId, size, texture );
+
+ return texture;
+ }
+ else
+ {
+ return createTextureRaster( window, size, helper );
+ }
+}
+
QskGraphicTextureFactory::QskGraphicTextureFactory()
{
}
@@ -77,7 +106,7 @@ QSGTexture* QskGraphicTextureFactory::createTexture( QQuickWindow* window ) cons
};
PaintHelper helper( m_graphic, m_colorFilter );
- return QskTextureRenderer::createPaintedTexture( window, m_size, &helper );
+ return qskCreatePaintedTexture( window, m_size, &helper );
}
QSize QskGraphicTextureFactory::textureSize() const
diff --git a/src/nodes/QskPaintedNode.cpp b/src/nodes/QskPaintedNode.cpp
index cfdcf6be..56fbfb95 100644
--- a/src/nodes/QskPaintedNode.cpp
+++ b/src/nodes/QskPaintedNode.cpp
@@ -7,6 +7,7 @@
#include "QskSGNode.h"
#include "QskTextureRenderer.h"
#include "QskInternalMacros.h"
+#include "QskQuick.h"
#include
#include
@@ -160,7 +161,7 @@ void QskPaintedNode::updateTexture( QQuickWindow* window,
{
auto imageNode = findImageNode( this );
- if ( ( m_renderHint == OpenGL ) && QskTextureRenderer::isOpenGLWindow( window ) )
+ if ( ( m_renderHint == OpenGL ) && qskIsOpenGLWindow( window ) )
{
const auto textureId = createTextureGL( window, size, nodeData );
@@ -232,5 +233,5 @@ quint32 QskPaintedNode::createTextureGL(
};
PaintHelper helper( this, nodeData );
- return createPaintedTextureGL( window, size, &helper );
+ return QskTextureRenderer::createTextureGL( window, size, &helper );
}
diff --git a/src/nodes/QskTextureRenderer.cpp b/src/nodes/QskTextureRenderer.cpp
index 77ba70cd..2628c5ef 100644
--- a/src/nodes/QskTextureRenderer.cpp
+++ b/src/nodes/QskTextureRenderer.cpp
@@ -30,8 +30,12 @@ static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo )
/*
See https://bugreports.qt.io/browse/QTBUG-103929
- As we create a FBO for each update of a node we can't live
- without having this ( ugly ) workaround.
+ QOpenGLFramebufferObject::takeTexture produces a memory leak
+ that can't be accepted as we create an FBO each time we update
+ a texture.
+
+ The suggested workarond is to call QOpenGLSharedResourceGuard::invalidateResource()
+ manually. Unfortunately this is a protected method and we need this nasty hack.
*/
class MyFBO
{
@@ -64,25 +68,6 @@ static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo )
return textureId;
}
-bool QskTextureRenderer::isOpenGLWindow( const QQuickWindow* window )
-{
- if ( window == nullptr )
- return false;
-
- const auto renderer = window->rendererInterface();
- switch( renderer->graphicsApi() )
- {
- case QSGRendererInterface::OpenGL:
-#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
- case QSGRendererInterface::OpenGLRhi:
-#endif
- return true;
-
- default:
- return false;
- }
-}
-
void QskTextureRenderer::setTextureId( QQuickWindow* window,
quint32 textureId, const QSize& size, QSGTexture* texture )
{
@@ -116,8 +101,8 @@ void QskTextureRenderer::setTextureId( QQuickWindow* window,
#endif
}
-quint32 QskTextureRenderer::createPaintedTextureGL(
- QQuickWindow* window, const QSize& size, QskTextureRenderer::PaintHelper* helper )
+quint32 QskTextureRenderer::createTextureGL(
+ QQuickWindow* window, const QSize& size, PaintHelper* helper )
{
/*
Binding GL_ARRAY_BUFFER/GL_ELEMENT_ARRAY_BUFFER to 0 seems to be enough.
@@ -194,8 +179,8 @@ quint32 QskTextureRenderer::createPaintedTextureGL(
return qskTakeTexture( fbo );
}
-static QSGTexture* qskCreateTextureRaster( QQuickWindow* window,
- const QSize& size, QskTextureRenderer::PaintHelper* helper )
+QSGTexture* QskTextureRenderer::createTextureRaster( QQuickWindow* window,
+ const QSize& size, PaintHelper* helper )
{
const auto ratio = window ? window->effectiveDevicePixelRatio() : 1.0;
@@ -216,24 +201,3 @@ static QSGTexture* qskCreateTextureRaster( QQuickWindow* window,
return window->createTextureFromImage( image, QQuickWindow::TextureHasAlphaChannel );
}
-
-QSGTexture* QskTextureRenderer::createPaintedTexture(
- QQuickWindow* window, const QSize& size, PaintHelper* helper )
-{
- if ( isOpenGLWindow( window ) )
- {
- const auto textureId = createPaintedTextureGL( window, size, helper );
-
- auto texture = new QSGPlainTexture;
- texture->setHasAlphaChannel( true );
- texture->setOwnsTexture( true );
-
- setTextureId( window, textureId, size, texture );
-
- return texture;
- }
- else
- {
- return qskCreateTextureRaster( window, size, helper );
- }
-}
diff --git a/src/nodes/QskTextureRenderer.h b/src/nodes/QskTextureRenderer.h
index 3b907ab2..470c5cc1 100644
--- a/src/nodes/QskTextureRenderer.h
+++ b/src/nodes/QskTextureRenderer.h
@@ -27,16 +27,11 @@ namespace QskTextureRenderer
Q_DISABLE_COPY( PaintHelper )
};
- bool isOpenGLWindow( const QQuickWindow* );
-
void setTextureId( QQuickWindow*,
quint32 textureId, const QSize&, QSGTexture* );
- quint32 createPaintedTextureGL(
- QQuickWindow*, const QSize&, QskTextureRenderer::PaintHelper* );
-
- QSK_EXPORT QSGTexture* createPaintedTexture(
- QQuickWindow* window, const QSize& size, PaintHelper* helper );
+ quint32 createTextureGL( QQuickWindow*, const QSize&, PaintHelper* );
+ QSGTexture* createTextureRaster( QQuickWindow*, const QSize&, PaintHelper* );
}
#endif
diff --git a/tools/glyph2qvg/main.cpp b/tools/glyph2qvg/main.cpp
index d86a7bb6..9d1a2cbe 100644
--- a/tools/glyph2qvg/main.cpp
+++ b/tools/glyph2qvg/main.cpp
@@ -21,51 +21,87 @@
#include
#include
+enum Options
+{
+ ViewBox = 1 << 0,
+ Antialiasing = 1 << 1
+};
+
static void usage( const char* appName )
{
- qWarning() << "usage: " << appName << " ";
+ qWarning() << "usage: " << appName << " ";
+}
+
+static QPainterPath glyphPath( const QRawFont& font,
+ const qreal pixelSize, const uint glyphIndex )
+{
+ auto path = font.pathForGlyph( glyphIndex );
+ path = path.simplified();
+ path = path.translated( 0.0, pixelSize );
+
+ return path;
+}
+
+static QskGraphic icon( const QPainterPath& path,
+ const qreal pixelSize, const int options )
+{
+ QskGraphic graphic;
+
+ if ( options & ViewBox )
+ graphic.setViewBox( QRectF( 0.0, 0.0, pixelSize, pixelSize ) );
+
+ QPainter painter( &graphic );
+
+ if ( options & Antialiasing )
+ painter.setRenderHint( QPainter::Antialiasing, true );
+
+ painter.fillPath( path, Qt::black );
+
+ return graphic;
}
int main( int argc, char* argv[] )
{
- if ( argc != 4 )
+ QGuiApplication app( argc, argv );
+
+ if ( argc != 5 )
{
usage( argv[0] );
return -1;
}
- QGuiApplication app( argc, argv );
+ bool ok;
- QRawFont font( QString( argv[1] ), 16 );
+ const auto pixelSize = QString( argv[2] ).toDouble( &ok );
+ if ( !ok || ( pixelSize <= 0 ) )
+ {
+ qWarning() << "invalid pixel size:" << argv[2];
+ return -3;
+ }
+
+ const auto glyphIndex = QString( argv[3] ).toUInt( &ok );
+ if ( !ok )
+ {
+ qWarning() << "invalid glyph index:" << argv[3];
+ return -3;
+ }
+
+ QRawFont font( QString( argv[1] ), pixelSize );
if ( !font.isValid() )
{
qWarning() << "invalid font name:" << argv[1];
return -2;
}
- bool ok;
-
- const auto glyphIndex = QString( argv[2] ).toUInt( &ok );
- if ( !ok )
- {
- qWarning() << "invalid glyph index:" << argv[2];
- return -3;
- }
-
- const auto path = font.pathForGlyph( glyphIndex );
+ const auto path = glyphPath( font, pixelSize, glyphIndex );
if ( path.isEmpty() )
{
- qWarning() << "no glyph for index:" << argv[2];
+ qWarning() << "no glyph for index:" << argv[3];
return -3;
}
- QskGraphic graphic;
-
- QPainter painter( &graphic );
- painter.setRenderHint( QPainter::Antialiasing, true );
- painter.fillPath( path, Qt::black );
-
- QskGraphicIO::write( graphic, argv[3] );
+ const auto graphic = icon( path, pixelSize, ViewBox | Antialiasing );
+ QskGraphicIO::write( graphic, argv[4] );
return 0;
}
diff --git a/tools/svg2qvg/main.cpp b/tools/svg2qvg/main.cpp
index 2695a80f..c0c0691f 100644
--- a/tools/svg2qvg/main.cpp
+++ b/tools/svg2qvg/main.cpp
@@ -41,6 +41,28 @@ static QRectF viewBox( QSvgRenderer& renderer )
return hasViewBox ? viewBox : QRectF( 0.0, 0.0, -1.0, -1.0 );
}
+class Graphic : public QskGraphic
+{
+ protected:
+ void addCommand( const QskPainterCommand& cmd ) override
+ {
+#if 0
+ if ( cmd.type() == QskPainterCommand::State )
+ {
+ /*
+ QSvgRenderer enables QPainter::Antialiasing initially
+ However this is something we might want to decide,
+ when replaying the commands.
+ */
+ auto sd = const_cast< QskPainterCommand::StateData* >( cmd.stateData() );
+ sd->renderHints &= ~QPainter::Antialiasing;
+ }
+#endif
+
+ QskGraphic::addCommand( cmd );
+ }
+};
+
int main( int argc, char* argv[] )
{
if ( argc != 3 )
@@ -71,7 +93,7 @@ int main( int argc, char* argv[] )
if ( !renderer.load( QString( argv[1] ) ) )
return -2;
- QskGraphic graphic;
+ Graphic graphic;
graphic.setViewBox( ::viewBox( renderer ) );
QPainter painter( &graphic );