Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-QtAwesome for openSUSE:Factory checked in at 2022-10-29 20:16:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-QtAwesome (Old) and /work/SRC/openSUSE:Factory/.python-QtAwesome.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-QtAwesome" Sat Oct 29 20:16:48 2022 rev:11 rq:1032072 version:1.2.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-QtAwesome/python-QtAwesome.changes 2022-08-30 14:49:31.356126946 +0200 +++ /work/SRC/openSUSE:Factory/.python-QtAwesome.new.2275/python-QtAwesome.changes 2022-10-29 20:18:04.610520779 +0200 @@ -1,0 +2,18 @@ +Thu Oct 27 21:07:18 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to 1.2.1 + Issues Closed + * Issue 214 - Regression with 1.2 on Windows (PR 215 by @dalthviz) + * Issue 212 - Release QtAwesome 1.2.1 + * Issue 210 - QtAwesome 1.2.0 incompatible with PySide2 (PR 211 by @dalthviz) + In this release 3 issues were closed. + + Pull Requests Merged + * PR 215 - PR: Handle per user font installation failing due to missing/not available registry keys, by @dalthviz (214) + * PR 211 - PR: Handle PySide2 not having QtGui.QGlyphRun and add tests jobs with PySide2, by @dalthviz (210) + In this release 2 pull requests were closed. + +- Update to 1.2.0 + Full changelog https://github.com/spyder-ide/qtawesome/blob/master/CHANGELOG.md#version-120-2022-10-19 + +------------------------------------------------------------------- Old: ---- QtAwesome-1.1.1.tar.gz New: ---- QtAwesome-1.2.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-QtAwesome.spec ++++++ --- /var/tmp/diff_new_pack.2QGazm/_old 2022-10-29 20:18:05.054523144 +0200 +++ /var/tmp/diff_new_pack.2QGazm/_new 2022-10-29 20:18:05.062523187 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-QtAwesome -Version: 1.1.1 +Version: 1.2.1 Release: 0 Summary: FontAwesome icons in PyQt and PySide applications License: MIT ++++++ QtAwesome-1.1.1.tar.gz -> QtAwesome-1.2.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/CHANGELOG.md new/QtAwesome-1.2.1/CHANGELOG.md --- old/QtAwesome-1.1.1/CHANGELOG.md 2021-11-29 16:22:48.000000000 +0100 +++ new/QtAwesome-1.2.1/CHANGELOG.md 2022-10-24 16:34:07.000000000 +0200 @@ -1,5 +1,61 @@ # History of changes +## Version 1.2.1 (2022-10-24) + +### Issues Closed + +* [Issue 214](https://github.com/spyder-ide/qtawesome/issues/214) - Regression with 1.2 on Windows ([PR 215](https://github.com/spyder-ide/qtawesome/pull/215) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 212](https://github.com/spyder-ide/qtawesome/issues/212) - Release QtAwesome 1.2.1 +* [Issue 210](https://github.com/spyder-ide/qtawesome/issues/210) - QtAwesome 1.2.0 incompatible with PySide2 ([PR 211](https://github.com/spyder-ide/qtawesome/pull/211) by [@dalthviz](https://github.com/dalthviz)) + +In this release 3 issues were closed. + +### Pull Requests Merged + +* [PR 215](https://github.com/spyder-ide/qtawesome/pull/215) - PR: Handle per user font installation failing due to missing/not available registry keys, by [@dalthviz](https://github.com/dalthviz) ([214](https://github.com/spyder-ide/qtawesome/issues/214)) +* [PR 211](https://github.com/spyder-ide/qtawesome/pull/211) - PR: Handle PySide2 not having `QtGui.QGlyphRun` and add tests jobs with PySide2, by [@dalthviz](https://github.com/dalthviz) ([210](https://github.com/spyder-ide/qtawesome/issues/210)) + +In this release 2 pull requests were closed. + + +---- + + +## Version 1.2.0 (2022-10-19) + +### Issues Closed + +* [Issue 208](https://github.com/spyder-ide/qtawesome/issues/208) - Release QtAwesome 1.2.0 ([PR 209](https://github.com/spyder-ide/qtawesome/pull/209) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 196](https://github.com/spyder-ide/qtawesome/issues/196) - Unexpected corruption check when qta.load_font() with same ttf_filename as bundled ([PR 197](https://github.com/spyder-ide/qtawesome/pull/197) by [@kumattau](https://github.com/kumattau)) +* [Issue 195](https://github.com/spyder-ide/qtawesome/issues/195) - Incorrect search directory docstring of qta.load_font() with directory=None ([PR 198](https://github.com/spyder-ide/qtawesome/pull/198) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 193](https://github.com/spyder-ide/qtawesome/issues/193) - Drop Python 3.6 support ([PR 204](https://github.com/spyder-ide/qtawesome/pull/204) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 191](https://github.com/spyder-ide/qtawesome/issues/191) - Update Codicons to the latest release (0.0.26) ([PR 206](https://github.com/spyder-ide/qtawesome/pull/206) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 189](https://github.com/spyder-ide/qtawesome/issues/189) - Incorrect FontAwesome5 Version in docs and update FontAwesome5 to the latest release (5.15.4) ([PR 206](https://github.com/spyder-ide/qtawesome/pull/206) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 167](https://github.com/spyder-ide/qtawesome/issues/167) - Icons are blocked because of untrusted fonts on Windows 10 ([PR 205](https://github.com/spyder-ide/qtawesome/pull/205) by [@dalthviz](https://github.com/dalthviz)) +* [Issue 39](https://github.com/spyder-ide/qtawesome/issues/39) - Tremulous spinning icons ([PR 202](https://github.com/spyder-ide/qtawesome/pull/202) by [@kumattau](https://github.com/kumattau)) + +In this release 8 issues were closed. + +### Pull Requests Merged + +* [PR 209](https://github.com/spyder-ide/qtawesome/pull/209) - PR: Update docs with info about `example.py` args, new `draw` option and screenshot, by [@dalthviz](https://github.com/dalthviz) ([208](https://github.com/spyder-ide/qtawesome/issues/208)) +* [PR 206](https://github.com/spyder-ide/qtawesome/pull/206) - PR: Update FA5 icons to 5.15.4 and Codicons icons to 0.0.32, by [@dalthviz](https://github.com/dalthviz) ([191](https://github.com/spyder-ide/qtawesome/issues/191), [189](https://github.com/spyder-ide/qtawesome/issues/189)) +* [PR 205](https://github.com/spyder-ide/qtawesome/pull/205) - PR: Install bundled fonts for user on Windows and fix Linux CI, by [@dalthviz](https://github.com/dalthviz) ([167](https://github.com/spyder-ide/qtawesome/issues/167)) +* [PR 204](https://github.com/spyder-ide/qtawesome/pull/204) - PR: Drop Python 3.6 support, by [@dalthviz](https://github.com/dalthviz) ([193](https://github.com/spyder-ide/qtawesome/issues/193)) +* [PR 203](https://github.com/spyder-ide/qtawesome/pull/203) - PR: Disable font hinting to mitigate tremulous spinning to some extent, by [@kumattau](https://github.com/kumattau) +* [PR 202](https://github.com/spyder-ide/qtawesome/pull/202) - PR: Use QRawFont and draw PainterPath of Glyph for animation to prevent tremulous spinning icons, by [@kumattau](https://github.com/kumattau) ([39](https://github.com/spyder-ide/qtawesome/issues/39)) +* [PR 199](https://github.com/spyder-ide/qtawesome/pull/199) - PR: Replace now deprecated distutils with setuptools, by [@kumattau](https://github.com/kumattau) +* [PR 198](https://github.com/spyder-ide/qtawesome/pull/198) - PR: Update `load_font` documentation, by [@dalthviz](https://github.com/dalthviz) ([195](https://github.com/spyder-ide/qtawesome/issues/195)) +* [PR 197](https://github.com/spyder-ide/qtawesome/pull/197) - PR: Fix unexpected corruption check except for bundled fonts, by [@kumattau](https://github.com/kumattau) ([196](https://github.com/spyder-ide/qtawesome/issues/196)) +* [PR 190](https://github.com/spyder-ide/qtawesome/pull/190) - PR: Preserves timestamp, bboxes, and table order for faithful to original and reproducible font updating, by [@kumattau](https://github.com/kumattau) +* [PR 187](https://github.com/spyder-ide/qtawesome/pull/187) - PR: Update RELEASE.md, by [@dalthviz](https://github.com/dalthviz) + +In this release 11 pull requests were closed. + + +---- + + ## Version 1.1.1 (2021-11-29) ### Issues Closed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/PKG-INFO new/QtAwesome-1.2.1/PKG-INFO --- old/QtAwesome-1.1.1/PKG-INFO 2021-11-29 16:29:00.249306400 +0100 +++ new/QtAwesome-1.2.1/PKG-INFO 2022-10-24 16:35:29.913881300 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: QtAwesome -Version: 1.1.1 +Version: 1.2.1 Summary: FontAwesome icons in PyQt and PySide applications Home-page: https://github.com/spyder-ide/qtawesome Author: Sylvain Corlay and the Spyder Development Team @@ -15,12 +15,11 @@ Classifier: Topic :: Software Development :: User Interfaces Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 -Requires-Python: >=3.6 +Requires-Python: >=3.7 Description-Content-Type: text/markdown License-File: LICENSE.txt @@ -34,9 +33,9 @@ [](https://gitter.im/spyder-ide/public)<br> [](https://github.com/spyder-ide/qtawesome) [](https://github.com/spyder-ide/qtawesome/actions) -[](https://qtawesomedocs.readthedocs.io/en/latest/?badge=latest) +[](https://qtawesome.readthedocs.io/en/latest/?badge=latest) -*Copyright ?? 2015???2021 Spyder Project Contributors* +*Copyright ?? 2015???2022 Spyder Project Contributors* ## Description @@ -74,11 +73,11 @@ - [**FontAwesome**](https://fontawesome.com): - - FA 5.9.0 features 1,534 free icons in different styles: + - FA 5.15.4 features 1,608 free icons in different styles: - - `fa5` prefix has [152 icons in the "**regular**" style.](https://fontawesome.com/icons?d=gallery&s=regular&m=free) - - `fa5s` prefix has [1000 icons in the "**solid**" style.](https://fontawesome.com/icons?d=gallery&s=solid&m=free) - - `fa5b` prefix has [449 icons of various **brands**.](https://fontawesome.com/icons?d=gallery&s=brands&m=free) + - `fa5` prefix has [151 icons in the "**regular**" style.](https://fontawesome.com/v5/search?o=r&m=free&s=regular) + - `fa5s` prefix has [1001 icons in the "**solid**" style.](https://fontawesome.com/v5/search?o=r&m=free&s=solid) + - `fa5b` prefix has [456 icons of various **brands**.](https://fontawesome.com/v5/search?o=r&m=free&f=brands) - `fa` is the legacy [FA 4.7 version with its 675 icons](https://fontawesome.com/v4.7.0/icons/) but **all** of them (*and more!*) are part of FA 5.x so you should probably use the newer version above. @@ -94,7 +93,7 @@ - `ri` prefix holds [**Remix Icon** 2.5.0 with its 2271 icons.](https://github.com/Remix-Design/RemixIcon) -- `msc` prefix holds Microsoft's [**Codicons** 0.0.25 with its 385 icons.](https://github.com/microsoft/vscode-codicons) +- `msc` prefix holds Microsoft's [**Codicons** 0.0.32 with its 421 icons.](https://github.com/microsoft/vscode-codicons) ### Examples @@ -168,6 +167,16 @@ stack_button.setIconSize(QtCore.QSize(32, 32)) ``` +- Define the way to draw icons (`text`- default for icons without animation, `path` - default for icons with animations, `glyphrun` and `image`) + +```python +# Icon drawn with the `image` option +drawn_image_icon = qta.icon('ri.truck-fill', + options=[{'draw': 'image'}]) +drawn_image_button = QtWidgets.QPushButton(drawn_image_icon, + 'Icon drawn as an image') +``` + - Animations ```python @@ -196,6 +205,12 @@  +To check these options you can launch the `example.py` script and pass to it the options as arguments. For example, to test how the icons could look using the `glyphrun` draw option, you can run something like: + +``` +python example.py draw=glyphrun +``` + ## Other features - QtAwesome comes bundled with _Font Awesome_, _Elusive Icons_, _Material Design_ @@ -240,5 +255,3 @@ and the donations we have received from our users around the world through [Open Collective](https://opencollective.com/spyder/): [](https://opencollective.com/spyder#support) - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/QtAwesome.egg-info/PKG-INFO new/QtAwesome-1.2.1/QtAwesome.egg-info/PKG-INFO --- old/QtAwesome-1.1.1/QtAwesome.egg-info/PKG-INFO 2021-11-29 16:28:58.000000000 +0100 +++ new/QtAwesome-1.2.1/QtAwesome.egg-info/PKG-INFO 2022-10-24 16:35:27.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: QtAwesome -Version: 1.1.1 +Version: 1.2.1 Summary: FontAwesome icons in PyQt and PySide applications Home-page: https://github.com/spyder-ide/qtawesome Author: Sylvain Corlay and the Spyder Development Team @@ -15,12 +15,11 @@ Classifier: Topic :: Software Development :: User Interfaces Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 -Requires-Python: >=3.6 +Requires-Python: >=3.7 Description-Content-Type: text/markdown License-File: LICENSE.txt @@ -34,9 +33,9 @@ [](https://gitter.im/spyder-ide/public)<br> [](https://github.com/spyder-ide/qtawesome) [](https://github.com/spyder-ide/qtawesome/actions) -[](https://qtawesomedocs.readthedocs.io/en/latest/?badge=latest) +[](https://qtawesome.readthedocs.io/en/latest/?badge=latest) -*Copyright ?? 2015???2021 Spyder Project Contributors* +*Copyright ?? 2015???2022 Spyder Project Contributors* ## Description @@ -74,11 +73,11 @@ - [**FontAwesome**](https://fontawesome.com): - - FA 5.9.0 features 1,534 free icons in different styles: + - FA 5.15.4 features 1,608 free icons in different styles: - - `fa5` prefix has [152 icons in the "**regular**" style.](https://fontawesome.com/icons?d=gallery&s=regular&m=free) - - `fa5s` prefix has [1000 icons in the "**solid**" style.](https://fontawesome.com/icons?d=gallery&s=solid&m=free) - - `fa5b` prefix has [449 icons of various **brands**.](https://fontawesome.com/icons?d=gallery&s=brands&m=free) + - `fa5` prefix has [151 icons in the "**regular**" style.](https://fontawesome.com/v5/search?o=r&m=free&s=regular) + - `fa5s` prefix has [1001 icons in the "**solid**" style.](https://fontawesome.com/v5/search?o=r&m=free&s=solid) + - `fa5b` prefix has [456 icons of various **brands**.](https://fontawesome.com/v5/search?o=r&m=free&f=brands) - `fa` is the legacy [FA 4.7 version with its 675 icons](https://fontawesome.com/v4.7.0/icons/) but **all** of them (*and more!*) are part of FA 5.x so you should probably use the newer version above. @@ -94,7 +93,7 @@ - `ri` prefix holds [**Remix Icon** 2.5.0 with its 2271 icons.](https://github.com/Remix-Design/RemixIcon) -- `msc` prefix holds Microsoft's [**Codicons** 0.0.25 with its 385 icons.](https://github.com/microsoft/vscode-codicons) +- `msc` prefix holds Microsoft's [**Codicons** 0.0.32 with its 421 icons.](https://github.com/microsoft/vscode-codicons) ### Examples @@ -168,6 +167,16 @@ stack_button.setIconSize(QtCore.QSize(32, 32)) ``` +- Define the way to draw icons (`text`- default for icons without animation, `path` - default for icons with animations, `glyphrun` and `image`) + +```python +# Icon drawn with the `image` option +drawn_image_icon = qta.icon('ri.truck-fill', + options=[{'draw': 'image'}]) +drawn_image_button = QtWidgets.QPushButton(drawn_image_icon, + 'Icon drawn as an image') +``` + - Animations ```python @@ -196,6 +205,12 @@  +To check these options you can launch the `example.py` script and pass to it the options as arguments. For example, to test how the icons could look using the `glyphrun` draw option, you can run something like: + +``` +python example.py draw=glyphrun +``` + ## Other features - QtAwesome comes bundled with _Font Awesome_, _Elusive Icons_, _Material Design_ @@ -240,5 +255,3 @@ and the donations we have received from our users around the world through [Open Collective](https://opencollective.com/spyder/): [](https://opencollective.com/spyder#support) - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/QtAwesome.egg-info/entry_points.txt new/QtAwesome-1.2.1/QtAwesome.egg-info/entry_points.txt --- old/QtAwesome-1.1.1/QtAwesome.egg-info/entry_points.txt 2021-11-29 16:28:58.000000000 +0100 +++ new/QtAwesome-1.2.1/QtAwesome.egg-info/entry_points.txt 2022-10-24 16:35:27.000000000 +0200 @@ -1,3 +1,2 @@ [console_scripts] qta-browser = qtawesome.icon_browser:run - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/README.md new/QtAwesome-1.2.1/README.md --- old/QtAwesome-1.1.1/README.md 2021-11-29 16:18:25.000000000 +0100 +++ new/QtAwesome-1.2.1/README.md 2022-10-19 17:06:17.000000000 +0200 @@ -8,9 +8,9 @@ [](https://gitter.im/spyder-ide/public)<br> [](https://github.com/spyder-ide/qtawesome) [](https://github.com/spyder-ide/qtawesome/actions) -[](https://qtawesomedocs.readthedocs.io/en/latest/?badge=latest) +[](https://qtawesome.readthedocs.io/en/latest/?badge=latest) -*Copyright ?? 2015???2021 Spyder Project Contributors* +*Copyright ?? 2015???2022 Spyder Project Contributors* ## Description @@ -48,11 +48,11 @@ - [**FontAwesome**](https://fontawesome.com): - - FA 5.9.0 features 1,534 free icons in different styles: + - FA 5.15.4 features 1,608 free icons in different styles: - - `fa5` prefix has [152 icons in the "**regular**" style.](https://fontawesome.com/icons?d=gallery&s=regular&m=free) - - `fa5s` prefix has [1000 icons in the "**solid**" style.](https://fontawesome.com/icons?d=gallery&s=solid&m=free) - - `fa5b` prefix has [449 icons of various **brands**.](https://fontawesome.com/icons?d=gallery&s=brands&m=free) + - `fa5` prefix has [151 icons in the "**regular**" style.](https://fontawesome.com/v5/search?o=r&m=free&s=regular) + - `fa5s` prefix has [1001 icons in the "**solid**" style.](https://fontawesome.com/v5/search?o=r&m=free&s=solid) + - `fa5b` prefix has [456 icons of various **brands**.](https://fontawesome.com/v5/search?o=r&m=free&f=brands) - `fa` is the legacy [FA 4.7 version with its 675 icons](https://fontawesome.com/v4.7.0/icons/) but **all** of them (*and more!*) are part of FA 5.x so you should probably use the newer version above. @@ -68,7 +68,7 @@ - `ri` prefix holds [**Remix Icon** 2.5.0 with its 2271 icons.](https://github.com/Remix-Design/RemixIcon) -- `msc` prefix holds Microsoft's [**Codicons** 0.0.25 with its 385 icons.](https://github.com/microsoft/vscode-codicons) +- `msc` prefix holds Microsoft's [**Codicons** 0.0.32 with its 421 icons.](https://github.com/microsoft/vscode-codicons) ### Examples @@ -142,6 +142,16 @@ stack_button.setIconSize(QtCore.QSize(32, 32)) ``` +- Define the way to draw icons (`text`- default for icons without animation, `path` - default for icons with animations, `glyphrun` and `image`) + +```python +# Icon drawn with the `image` option +drawn_image_icon = qta.icon('ri.truck-fill', + options=[{'draw': 'image'}]) +drawn_image_button = QtWidgets.QPushButton(drawn_image_icon, + 'Icon drawn as an image') +``` + - Animations ```python @@ -170,6 +180,12 @@  +To check these options you can launch the `example.py` script and pass to it the options as arguments. For example, to test how the icons could look using the `glyphrun` draw option, you can run something like: + +``` +python example.py draw=glyphrun +``` + ## Other features - QtAwesome comes bundled with _Font Awesome_, _Elusive Icons_, _Material Design_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/docs/source/usage.rst new/QtAwesome-1.2.1/docs/source/usage.rst --- old/QtAwesome-1.1.1/docs/source/usage.rst 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/docs/source/usage.rst 2022-10-19 17:06:17.000000000 +0200 @@ -10,11 +10,11 @@ - `FontAwesome`_: - - FA 5.9.0 features 1,534 free icons in different styles: + - FA 5.15.4 features 1,608 free icons in different styles: - - ``fa5`` prefix has `152 icons in the "regular" style.`_ - - ``fa5s`` prefix has `1000 icons in the "solid" style.`_ - - ``fa5b`` prefix has `449 icons of various brands.`_ + - ``fa5`` prefix has `151 icons in the "regular" style.`_ + - ``fa5s`` prefix has `1001 icons in the "solid" style.`_ + - ``fa5b`` prefix has `456 icons of various brands.`_ - ``fa`` is the legacy `FA 4.7 version with its 675 icons`_ but **all** of them (*and more!*) are part of FA 5.x so you should @@ -32,12 +32,12 @@ - ``ri`` prefix holds `Remix Icon 2.5.0 with its 2271 icons.`_ -- ``msc`` prefix holds Microsoft's `Codicons 0.0.25 with its 385 icons.`_ +- ``msc`` prefix holds Microsoft's `Codicons 0.0.32 with its 421 icons.`_ .. _FontAwesome: https://fontawesome.com -.. _152 icons in the "regular" style.: https://fontawesome.com/icons?d=gallery&s=regular&m=free -.. _1000 icons in the "solid" style.: https://fontawesome.com/icons?d=gallery&s=solid&m=free -.. _449 icons of various brands.: https://fontawesome.com/icons?d=gallery&s=brands&m=free +.. _151 icons in the "regular" style.: https://fontawesome.com/v5/search?o=r&m=free&s=regular +.. _1001 icons in the "solid" style.: https://fontawesome.com/v5/search?o=r&m=free&s=solid +.. _456 icons of various brands.: https://fontawesome.com/v5/search?o=r&m=free&f=brands .. _FA 4.7 version with its 675 icons: https://fontawesome.com/v4.7.0/icons/ .. _Elusive Icons 2.0 with its 304 icons: http://elusiveicons.com/icons/ .. _Material Design Icons: https://cdn.materialdesignicons.com/ @@ -45,7 +45,7 @@ .. _Material Design Icons 5.9.55 with its 5955 icons.: https://cdn.materialdesignicons.com/5.9.55/ .. _Phosphor 1.3.0 with its 4470 icons (894 icons * 5 weights\: Thin, Light, Regular, Bold and Fill).: https://github.com/phosphor-icons/phosphor-icons .. _Remix Icon 2.5.0 with its 2271 icons.: https://github.com/Remix-Design/RemixIcon -.. _Codicons 0.0.25 with its 385 icons.: https://github.com/microsoft/vscode-codicons +.. _Codicons 0.0.32 with its 421 icons.: https://github.com/microsoft/vscode-codicons Examples ~~~~~~~~ @@ -115,7 +115,7 @@ color_active='orange') music_button = QtWidgets.QPushButton(styling_icon, 'Styling') -- Set alpha in colors +- Set alpha in colors: .. code:: python @@ -138,6 +138,16 @@ toggle_button = QtWidgets.QPushButton(toggle_icon, 'Toggle') toggle_button.setCheckable(True) +- Define the way to draw icons (`text`- default for icons without animation, `path` - default for icons with animations, `glyphrun` and `image`): + +.. code:: python + + # Icon drawn with the `image` option + drawn_image_icon = qta.icon('ri.truck-fill', + options=[{'draw': 'image'}]) + drawn_image_button = QtWidgets.QPushButton(drawn_image_icon, + 'Icon drawn as an image') + - Stack multiple icons: .. code:: python diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/example.py new/QtAwesome-1.2.1/example.py --- old/QtAwesome-1.1.1/example.py 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/example.py 2022-10-19 17:06:17.000000000 +0200 @@ -98,6 +98,12 @@ iconwidgetholder.setLayout(lo) iconwidget2 = qta.IconWidget('mdi.web', color='blue') + # Icon drawn with the `image` option + drawn_image_icon = qta.icon('ri.truck-fill', + options=[{'draw': 'image'}]) + drawn_image_button = QtWidgets.QPushButton(drawn_image_icon, + 'Icon drawn as an image') + # Stack icons camera_ban = qta.icon('fa5s.camera', 'fa5s.ban', options=[{'scale_factor': 0.5, @@ -160,7 +166,8 @@ rot_button, hflip_button, vflip_button, - toggle_button + toggle_button, + drawn_image_button ] animated_widgets = [ spin_button, @@ -180,26 +187,44 @@ for idx, w in enumerate(styled_widgets): grid.addWidget(w, idx, 1) - + for idx, w in enumerate(animated_widgets): grid.addWidget(w, idx + len(styled_widgets), 1) - + for idx, w in enumerate(other_widgets): grid.addWidget(w, idx + len(styled_widgets) + len(animated_widgets), 1) + title = 'Awesome' + args = ' '.join(sys.argv[1:]).strip() + if args: + title += ' (' + args + ')' + self.setLayout(grid) - self.setWindowTitle('Awesome') + self.setWindowTitle(title) self.setMinimumWidth(520) self.show() def main(): + + global_defaults = {} + for arg in sys.argv[1:]: + try: + key, val = arg.split('=', maxsplit=1) + global_defaults[key] = val + except: + pass + if global_defaults: + qta.set_global_defaults(**global_defaults) + app = QtWidgets.QApplication(sys.argv) # Enable High DPI display with PyQt5 if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'): app.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) + # Timer needed to close the example application + # when testing QtCore.QTimer.singleShot(10000, app.exit) _ = AwesomeExample() sys.exit(app.exec_()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/__init__.py new/QtAwesome-1.2.1/qtawesome/__init__.py --- old/QtAwesome-1.1.1/qtawesome/__init__.py 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/qtawesome/__init__.py 2022-10-19 17:06:17.000000000 +0200 @@ -16,18 +16,70 @@ set_defaults """ +import hashlib +import os + # Third party imports from qtpy import QtCore, QtWidgets, QtGui # Local imports from ._version import __version__, version_info from .animation import Pulse, Spin -from .iconic_font import IconicFont, set_global_defaults +from .iconic_font import IconicFont, set_global_defaults, FontError +from .iconic_font import SYSTEM_FONTS as _SYSTEM_FONTS from .styles import dark, light # Constants _resource = { 'iconic': None } +_BUNDLED_FONTS = ( + ('fa', + 'fontawesome4.7-webfont.ttf', + 'fontawesome4.7-webfont-charmap.json'), + ('fa5', + 'fontawesome5-regular-webfont.ttf', + 'fontawesome5-regular-webfont-charmap.json'), + ('fa5s', + 'fontawesome5-solid-webfont.ttf', + 'fontawesome5-solid-webfont-charmap.json'), + ('fa5b', + 'fontawesome5-brands-webfont.ttf', + 'fontawesome5-brands-webfont-charmap.json'), + ('ei', + 'elusiveicons-webfont.ttf', + 'elusiveicons-webfont-charmap.json'), + ('mdi', + 'materialdesignicons5-webfont.ttf', + 'materialdesignicons5-webfont-charmap.json'), + ('mdi6', + 'materialdesignicons6-webfont.ttf', + 'materialdesignicons6-webfont-charmap.json'), + ('ph', + 'phosphor.ttf', + 'phosphor-charmap.json'), + ('ri', + 'remixicon.ttf', + 'remixicon-charmap.json'), + ('msc', + 'codicon.ttf', + 'codicon-charmap.json'), +) + + +# MD5 Hashes for font files bundled with qtawesome: +_MD5_HASHES = { + 'fontawesome4.7-webfont.ttf': 'b06871f281fee6b241d60582ae9369b9', + 'fontawesome5-regular-webfont.ttf': 'dc47e4089f5bcb25f241bdeb2de0fb58', + 'fontawesome5-solid-webfont.ttf': '5de19800fc9ae73438c2e5c61d041b48', + 'fontawesome5-brands-webfont.ttf': '513aa607d398efaccc559916c3431403', + 'elusiveicons-webfont.ttf': '207966b04c032d5b873fd595a211582e', + 'materialdesignicons5-webfont.ttf': 'b7d40e7ef80c1d4af6d94902af66e524', + 'materialdesignicons6-webfont.ttf': '9a2f455e7cbce011368aee95d292613b', + 'phosphor.ttf': '5b8dc57388b2d86243566b996cc3a789', + 'remixicon.ttf': '888e61f04316f10bddfff7bee10c6dd0', + 'codicon.ttf': 'd8565ee605ac4d2fa71fe018863337ca', +} + def has_valid_font_ids(inst): """Validate instance's font ids are loaded to QFontDatabase. @@ -60,28 +112,22 @@ _resource['iconic'] = None if _resource['iconic'] is None: - _resource['iconic'] = IconicFont( - ('fa', - 'fontawesome4.7-webfont.ttf', - 'fontawesome4.7-webfont-charmap.json'), - ('fa5', - 'fontawesome5-regular-webfont.ttf', - 'fontawesome5-regular-webfont-charmap.json'), - ('fa5s', - 'fontawesome5-solid-webfont.ttf', - 'fontawesome5-solid-webfont-charmap.json'), - ('fa5b', - 'fontawesome5-brands-webfont.ttf', - 'fontawesome5-brands-webfont-charmap.json'), - ('ei', 'elusiveicons-webfont.ttf', 'elusiveicons-webfont-charmap.json'), - ('mdi', 'materialdesignicons5-webfont.ttf', - 'materialdesignicons5-webfont-charmap.json'), - ('mdi6', 'materialdesignicons6-webfont.ttf', - 'materialdesignicons6-webfont-charmap.json'), - ('ph', 'phosphor.ttf', 'phosphor-charmap.json'), - ('ri', 'remixicon.ttf', 'remixicon-charmap.json'), - ('msc', 'codicon.ttf', 'codicon-charmap.json'), - ) + # Verify that vendorized fonts are not corrupt + if not _SYSTEM_FONTS: + for fargs in _BUNDLED_FONTS: + ttf_filename = fargs[1] + ttf_hash = _MD5_HASHES.get(ttf_filename, None) + if ttf_hash is None: + continue + ttf_filepath = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "fonts", ttf_filename) + with open(ttf_filepath, "rb") as f: + ttf_calculated_hash_code = hashlib.md5(f.read()).hexdigest() + if ttf_calculated_hash_code != ttf_hash: + raise FontError(f"Font is corrupt at: '{ttf_filepath}'") + + _resource['iconic'] = IconicFont(*_BUNDLED_FONTS) return _resource['iconic'] @@ -192,7 +238,8 @@ """ Loads a font file and the associated charmap. - If ``directory`` is None, the files will be looked for in ``./fonts/``. + If ``directory`` is passed, the files will be looked for in the qtawesome + ``fonts`` directory. Parameters ---------- @@ -203,14 +250,31 @@ charmap_filename: str Character map filename directory: str or None, optional - Directory for font and charmap files + Directory path for font and charmap files Example ------- - The spyder ide uses qtawesome and uses a custom font for spyder-specific - icons:: + If you want to load a font ``myicon.tff`` with a ``myicon-charmap.json`` + charmap added to the qtawesome ``fonts`` directory (usually located at + ``</path/to/lib/python>/site-packages/qtawesome/fonts/``) you can use:: + + qta.load_font( + 'myicon', + 'myicon.ttf', + 'myicon-charmap.json' + ) - qta.load_font('spyder', 'spyder.ttf', 'spyder-charmap.json') + However, if you want to load a font ``myicon.tff`` with a + ``myicon-charmap.json`` charmap located in a specific path outside the + qtawesome ``font`` directory like for example ``/path/to/myproject/fonts`` + you can use:: + + qta.load_font( + 'myicon', + 'myicon.ttf', + 'myicon-charmap.json', + directory='/path/to/myproject/fonts' + ) """ return _instance().load_font(prefix, ttf_filename, charmap_filename, directory) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/_version.py new/QtAwesome-1.2.1/qtawesome/_version.py --- old/QtAwesome-1.1.1/qtawesome/_version.py 2021-11-29 16:27:17.000000000 +0100 +++ new/QtAwesome-1.2.1/qtawesome/_version.py 2022-10-24 16:34:21.000000000 +0200 @@ -1,2 +1,2 @@ -version_info = (1, 1, 1) +version_info = (1, 2, 1) __version__ = '.'.join(map(str, version_info)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/fonts/codicon-charmap.json new/QtAwesome-1.2.1/qtawesome/fonts/codicon-charmap.json --- old/QtAwesome-1.1.1/qtawesome/fonts/codicon-charmap.json 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/qtawesome/fonts/codicon-charmap.json 2022-10-19 17:06:17.000000000 +0200 @@ -4,6 +4,10 @@ "add": "0xea60", "archive": "0xea98", "arrow-both": "0xea99", + "arrow-circle-down": "0xebfc", + "arrow-circle-left": "0xebfd", + "arrow-circle-right": "0xebfe", + "arrow-circle-up": "0xebff", "arrow-down": "0xea9a", "arrow-left": "0xea9b", "arrow-right": "0xea9c", @@ -19,6 +23,9 @@ "beaker-stop": "0xebe1", "bell": "0xeaa2", "bell-dot": "0xeb9a", + "bell-slash": "0xec08", + "bell-slash-dot": "0xec09", + "blank": "0xec03", "bold": "0xeaa3", "book": "0xeaa4", "bookmark": "0xeaa5", @@ -43,11 +50,13 @@ "chrome-maximize": "0xeab9", "chrome-minimize": "0xeaba", "chrome-restore": "0xeabb", + "circle": "0xeabc", "circle-filled": "0xea71", + "circle-large": "0xebb5", "circle-large-filled": "0xebb4", - "circle-large-outline": "0xebb5", - "circle-outline": "0xeabc", "circle-slash": "0xeabd", + "circle-small": "0xec07", + "circle-small-filled": "0xeb8a", "circuit-board": "0xeabe", "clear-all": "0xeabf", "clippy": "0xeac0", @@ -62,6 +71,7 @@ "combine": "0xebb6", "comment": "0xea6b", "comment-discussion": "0xeac7", + "comment-unresolved": "0xec0a", "compass": "0xebd5", "compass-active": "0xebd7", "compass-dot": "0xebd6", @@ -96,7 +106,6 @@ "debug-reverse-continue": "0xeb8e", "debug-stackframe": "0xeb8b", "debug-stackframe-active": "0xeb89", - "debug-stackframe-dot": "0xeb8a", "debug-start": "0xead3", "debug-step-back": "0xeb8f", "debug-step-into": "0xead4", @@ -119,6 +128,7 @@ "ellipsis": "0xea7c", "empty-window": "0xeae4", "error": "0xea87", + "error-small": "0xebfb", "exclude": "0xeae5", "expand-all": "0xeb95", "export": "0xebac", @@ -156,6 +166,8 @@ "git-pull-request-closed": "0xebda", "git-pull-request-create": "0xebbc", "git-pull-request-draft": "0xebdb", + "git-pull-request-go-to-changes": "0xec0b", + "git-pull-request-new-changes": "0xec0c", "github": "0xea84", "github-action": "0xeaff", "github-alt": "0xeb00", @@ -170,11 +182,13 @@ "gripper": "0xeb04", "group-by-ref-type": "0xeb97", "heart": "0xeb05", + "heart-filled": "0xec04", "history": "0xea82", "home": "0xeb06", "horizontal-rule": "0xeb07", "hubot": "0xeb08", "inbox": "0xeb09", + "indent": "0xebf9", "info": "0xea74", "inspect": "0xebd1", "issue-draft": "0xebd9", @@ -189,6 +203,22 @@ "layers": "0xebd2", "layers-active": "0xebd4", "layers-dot": "0xebd3", + "layout": "0xebeb", + "layout-activitybar-left": "0xebec", + "layout-activitybar-right": "0xebed", + "layout-centered": "0xebf7", + "layout-menubar": "0xebf6", + "layout-panel": "0xebf2", + "layout-panel-center": "0xebef", + "layout-panel-justify": "0xebf0", + "layout-panel-left": "0xebee", + "layout-panel-off": "0xec01", + "layout-panel-right": "0xebf1", + "layout-sidebar-left": "0xebf3", + "layout-sidebar-left-off": "0xec02", + "layout-sidebar-right": "0xebf4", + "layout-sidebar-right-off": "0xec00", + "layout-statusbar": "0xebf5", "library": "0xeb9c", "lightbulb": "0xea61", "lightbulb-autofix": "0xeb13", @@ -208,6 +238,8 @@ "magnet": "0xebae", "mail": "0xeb1c", "mail-read": "0xeb1b", + "map": "0xec05", + "map-filled": "0xec06", "markdown": "0xeb1d", "megaphone": "0xeb1e", "mention": "0xeb1f", @@ -221,6 +253,7 @@ "mute": "0xeb24", "new-file": "0xea7f", "new-folder": "0xea80", + "newline": "0xebea", "no-newline": "0xeb25", "note": "0xeb26", "notebook": "0xebaf", @@ -253,6 +286,7 @@ "reactions": "0xeb35", "record": "0xeba7", "record-keys": "0xea65", + "record-small": "0xebfa", "redo": "0xebb0", "references": "0xeb36", "refresh": "0xeb37", @@ -286,6 +320,7 @@ "screen-full": "0xeb4c", "screen-normal": "0xeb4d", "search": "0xea6d", + "search-fuzzy": "0xec0d", "search-stop": "0xeb4e", "server": "0xeb50", "server-environment": "0xeba3", @@ -334,6 +369,7 @@ "sync-ignored": "0xeb9f", "table": "0xebb7", "tag": "0xea66", + "target": "0xebf8", "tasklist": "0xeb67", "telescope": "0xeb68", "terminal": "0xea85", @@ -365,6 +401,7 @@ "unverified": "0xeb76", "variable-group": "0xebb8", "verified": "0xeb77", + "verified-filled": "0xebe9", "versions": "0xeb78", "vm": "0xea7a", "vm-active": "0xeb79", Binary files old/QtAwesome-1.1.1/qtawesome/fonts/codicon.ttf and new/QtAwesome-1.2.1/qtawesome/fonts/codicon.ttf differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-brands-webfont-charmap.json new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-brands-webfont-charmap.json --- old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-brands-webfont-charmap.json 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-brands-webfont-charmap.json 2022-10-19 17:06:17.000000000 +0200 @@ -4,7 +4,6 @@ "accusoft": "f369", "acquisitions-incorporated": "f6af", "adn": "f170", - "adobe": "f778", "adversal": "f36a", "affiliatetheme": "f36b", "airbnb": "f834", @@ -65,6 +64,7 @@ "centos": "f789", "chrome": "f268", "chromecast": "f838", + "cloudflare": "e07d", "cloudscale": "f383", "cloudsmith": "f384", "cloudversify": "f385", @@ -191,12 +191,14 @@ "grav": "f2d6", "gripfire": "f3ac", "grunt": "f3ad", + "guilded": "e07e", "gulp": "f3ae", "hacker-news": "f1d4", "hacker-news-square": "f3af", "hackerrank": "f5f7", "hips": "f452", "hire-a-helper": "f3b0", + "hive": "e07f", "hooli": "f427", "hornbill": "f592", "hotjar": "f3b1", @@ -205,8 +207,10 @@ "hubspot": "f3b2", "ideal": "e013", "imdb": "f2d8", + "innosoft": "e080", "instagram": "f16d", "instagram-square": "e055", + "instalod": "e081", "intercom": "f7af", "internet-explorer": "f26b", "invision": "f7b0", @@ -270,6 +274,7 @@ "npm": "f3d4", "ns8": "f3d5", "nutritionix": "f3d6", + "octopus-deploy": "e082", "odnoklassniki": "f263", "odnoklassniki-square": "f264", "old-republic": "f510", @@ -285,6 +290,7 @@ "patreon": "f3d9", "paypal": "f1ed", "penny-arcade": "f704", + "perbyte": "e083", "periscope": "f3da", "phabricator": "f3db", "phoenix-framework": "f3dc", @@ -385,7 +391,6 @@ "tiktok": "e07b", "trade-federation": "f513", "trello": "f181", - "tripadvisor": "f262", "tumblr": "f173", "tumblr-square": "f174", "twitch": "f1e8", @@ -396,6 +401,7 @@ "ubuntu": "f7df", "uikit": "f403", "umbraco": "f8e8", + "uncharted": "e084", "uniregistry": "f404", "unity": "e049", "unsplash": "e07c", @@ -416,6 +422,7 @@ "vk": "f189", "vnv": "f40b", "vuejs": "f41f", + "watchman-monitoring": "e087", "waze": "f83f", "weebly": "f5cc", "weibo": "f18a", @@ -427,6 +434,7 @@ "windows": "f17a", "wix": "f5cf", "wizards-of-the-coast": "f730", + "wodu": "e088", "wolf-pack-battalion": "f514", "wordpress": "f19a", "wordpress-simple": "f411", Binary files old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-brands-webfont.ttf and new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-brands-webfont.ttf differ Binary files old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-regular-webfont.ttf and new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-regular-webfont.ttf differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-solid-webfont-charmap.json new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-solid-webfont-charmap.json --- old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-solid-webfont-charmap.json 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-solid-webfont-charmap.json 2022-10-19 17:06:17.000000000 +0200 @@ -961,6 +961,8 @@ "venus": "f221", "venus-double": "f226", "venus-mars": "f228", + "vest": "e085", + "vest-patches": "e086", "vial": "f492", "vials": "f493", "video": "f03d", Binary files old/QtAwesome-1.1.1/qtawesome/fonts/fontawesome5-solid-webfont.ttf and new/QtAwesome-1.2.1/qtawesome/fonts/fontawesome5-solid-webfont.ttf differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/iconic_font.py new/QtAwesome-1.2.1/qtawesome/iconic_font.py --- old/QtAwesome-1.1.1/qtawesome/iconic_font.py 2021-11-29 16:18:25.000000000 +0100 +++ new/QtAwesome-1.2.1/qtawesome/iconic_font.py 2022-10-24 16:31:15.000000000 +0200 @@ -14,35 +14,67 @@ """ # Standard library imports -from __future__ import print_function -import hashlib +import ctypes +import filecmp import json import os +import shutil import warnings # Third party imports -from qtpy.QtCore import QByteArray, QObject, QPoint, QRect, Qt +from qtpy.QtCore import (QByteArray, QObject, QPoint, QRect, Qt, + QSizeF, QRectF, QPointF, QThread) from qtpy.QtGui import (QColor, QFont, QFontDatabase, QIcon, QIconEngine, - QPainter, QPixmap, QTransform, QPalette) + QPainter, QPixmap, QTransform, QPalette, QRawFont, + QImage) from qtpy.QtWidgets import QApplication +try: + # Needed since `QGlyphRun` is not available for PySide2 + # See spyder-ide/qtawesome#210 + from qtpy.QtGui import QGlyphRun +except ImportError: + QGlyphRun = None + # Linux packagers, please set this to True if you want to make qtawesome # use system fonts SYSTEM_FONTS = False -# MD5 Hashes for font files bundled with qtawesome: -MD5_HASHES = { - 'fontawesome4.7-webfont.ttf': 'b06871f281fee6b241d60582ae9369b9', - 'fontawesome5-regular-webfont.ttf': '808833867034fb67a4a86dd2155e195d', - 'fontawesome5-solid-webfont.ttf': '139654bb0acaba6b00ae30d5faf3d02f', - 'fontawesome5-brands-webfont.ttf': '085b1dd8427dbeff10bd55410915a3f6', - 'elusiveicons-webfont.ttf': '207966b04c032d5b873fd595a211582e', - 'materialdesignicons5-webfont.ttf': 'b7d40e7ef80c1d4af6d94902af66e524', - 'materialdesignicons6-webfont.ttf': '9a2f455e7cbce011368aee95d292613b', - 'phosphor.ttf': '5b8dc57388b2d86243566b996cc3a789', - 'remixicon.ttf': '888e61f04316f10bddfff7bee10c6dd0', - 'codicon.ttf': 'ca2f9e22cee3a59156b3eded74d87784', -} +# Needed imports and constants to install bundled fonts on Windows +# Based on https://stackoverflow.com/a/41841088/15954282 +if os.name == 'nt': + from ctypes import wintypes + import winreg + + user32 = ctypes.WinDLL('user32', use_last_error=True) + gdi32 = ctypes.WinDLL('gdi32', use_last_error=True) + + FONTS_REG_PATH = r'Software\Microsoft\Windows NT\CurrentVersion\Fonts' + GFRI_DESCRIPTION = 1 + GFRI_ISTRUETYPE = 3 + + if not hasattr(wintypes, 'LPDWORD'): + wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD) + + user32.SendMessageTimeoutW.restype = wintypes.LPVOID + user32.SendMessageTimeoutW.argtypes = ( + wintypes.HWND, # hWnd + wintypes.UINT, # Msg + wintypes.LPVOID, # wParam + wintypes.LPVOID, # lParam + wintypes.UINT, # fuFlags + wintypes.UINT, # uTimeout + wintypes.LPVOID) # lpdwResult + + gdi32.AddFontResourceW.argtypes = ( + wintypes.LPCWSTR,) # lpszFilename + + # http://www.undocprint.org/winspool/getfontresourceinfo + gdi32.GetFontResourceInfoW.argtypes = ( + wintypes.LPCWSTR, # lpszFilename + wintypes.LPDWORD, # cbBuffer + wintypes.LPVOID, # lpBuffer + wintypes.DWORD) # dwQueryType def text_color(): @@ -80,7 +112,8 @@ 'color_active', 'color_selected', 'color_disabled', 'color_on_selected', 'color_on_active', 'color_on_disabled', 'color_off_selected', 'color_off_active', 'color_off_disabled', - 'animation', 'offset', 'scale_factor', 'rotated', 'hflip', 'vflip' + 'animation', 'offset', 'scale_factor', 'rotated', 'hflip', 'vflip', + 'draw' ] for kw in kwargs: @@ -103,8 +136,6 @@ def _paint_icon(self, iconic, painter, rect, mode, state, options): """Paint a single icon.""" painter.save() - color = options['color'] - char = options['char'] color_options = { QIcon.On: { @@ -155,40 +186,98 @@ if animation is not None: animation.setup(self, painter, rect) - painter.setFont(iconic.font(prefix, draw_size)) if 'offset' in options: rect = QRect(rect) rect.translate(round(options['offset'][0] * rect.width()), round(options['offset'][1] * rect.height())) - if 'vflip' in options and options['vflip'] == True: - x_center = rect.width() * 0.5 - y_center = rect.height() * 0.5 - painter.translate(x_center, y_center) - transfrom = QTransform() - transfrom.scale(1,-1) - painter.setTransform(transfrom, True) - painter.translate(-x_center, -y_center) - - if 'hflip' in options and options['hflip'] == True: - x_center = rect.width() * 0.5 - y_center = rect.height() * 0.5 - painter.translate(x_center, y_center) - transfrom = QTransform() - transfrom.scale(-1, 1) - painter.setTransform(transfrom, True) - painter.translate(-x_center, -y_center) - + x_center = rect.width() * 0.5 + y_center = rect.height() * 0.5 + transform = QTransform() + transform.translate(+x_center, +y_center) + if 'vflip' in options and options['vflip'] is True: + transform.scale(1,-1) + if 'hflip' in options and options['hflip'] is True: + transform.scale(-1, 1) if 'rotated' in options: - x_center = rect.width() * 0.5 - y_center = rect.height() * 0.5 - painter.translate(x_center, y_center) - painter.rotate(options['rotated']) - painter.translate(-x_center, -y_center) + transform.rotate(options['rotated']) + transform.translate(-x_center, -y_center) + painter.setTransform(transform, True) painter.setOpacity(options.get('opacity', 1.0)) - painter.drawText(rect, int(Qt.AlignCenter | Qt.AlignVCenter), char) + draw = options.get('draw') + if draw not in ('text', 'path', 'glyphrun', 'image'): + # Use QPainterPath when setting an animation + # to fix tremulous spinning icons. + # See spyder-ide/qtawesome#39 + draw = 'path' if animation is not None else 'text' + + def try_draw_rawfont(): + if draw == 'glyphrun' and animation is not None: + # Disable font hinting to mitigate tremulous spinning to some extent + # See spyder-ide/qtawesome#39 + rawfont = iconic.rawfont(prefix, draw_size, QFont.PreferNoHinting) + else: + rawfont = iconic.rawfont(prefix, draw_size) + + # Check glyf table and fallback to draw text if missing + # because font glyph is necessary to draw path/glyphrun/image. + if not rawfont.fontTable('glyf'): + return False + + glyph = rawfont.glyphIndexesForString(char)[0] + advance = rawfont.advancesForGlyphIndexes((glyph,))[0] + ascent = rawfont.ascent() + size = QSizeF(abs(advance.x()), ascent + rawfont.descent()) + painter.translate(QRectF(rect).center()) + painter.translate(-size.width() / 2, -size.height() / 2) + + if draw == 'path': + path = rawfont.pathForGlyph(glyph) + path.translate(0, ascent) + path.setFillRule(Qt.WindingFill) + painter.setRenderHint(QPainter.Antialiasing, True) + painter.fillPath(path, painter.pen().color()) + + elif draw == 'glyphrun': + if QGlyphRun: + glyphrun = QGlyphRun() + glyphrun.setRawFont(rawfont) + glyphrun.setGlyphIndexes((glyph,)) + glyphrun.setPositions((QPointF(0, ascent),)) + painter.drawGlyphRun(QPointF(0, 0), glyphrun) + else: + warnings.warn("QGlyphRun is unavailable for the current Qt binding! " + "QtAwesome will use the default draw values") + return False + elif draw == 'image': + image = rawfont.alphaMapForGlyph(glyph, QRawFont.PixelAntialiasing) \ + .convertToFormat(QImage.Format_ARGB32_Premultiplied) + painter2 = QPainter(image) + painter2.setCompositionMode(QPainter.CompositionMode_SourceIn) + painter2.fillRect(image.rect(), painter.pen().color()) + painter2.end() + brect = rawfont.boundingRect(glyph) + brect.translate(0, ascent) + painter.setRenderHint(QPainter.SmoothPixmapTransform, True) + painter.drawImage(brect.topLeft(), image) + + else: + # fallback to draw text if unknown value + return False + + return True + + if draw == 'text' or not try_draw_rawfont(): + font = iconic.font(prefix, draw_size) + # Disable font hinting to mitigate tremulous spinning to some extent + # See spyder-ide/qtawesome#39 + if animation is not None: + font.setHintingPreference(QFont.PreferNoHinting) + painter.setFont(font) + painter.drawText(rect, int(Qt.AlignCenter | Qt.AlignVCenter), char) + painter.restore() @@ -232,22 +321,26 @@ - The ttf font filename, - The json charmap filename, - Optionally, the directory containing these files. When not - provided, the files will be looked for in ``./fonts/``. + provided, the files will be looked for in the QtAwesome ``fonts`` + directory. """ super().__init__() self.painter = CharIconPainter() self.painters = {} self.fontname = {} + self.fontdata = {} self.fontids = {} self.charmap = {} self.icon_cache = {} + self.rawfont_cache = {} for fargs in args: self.load_font(*fargs) def load_font(self, prefix, ttf_filename, charmap_filename, directory=None): """Loads a font file and the associated charmap. - If ``directory`` is None, the files will be looked for in ``./fonts/``. + If ``directory`` is None, the files will be looked for in + the qtawesome ``fonts`` directory. Parameters ---------- @@ -258,7 +351,7 @@ charmap_filename: str Charmap filename directory: str or None, optional - Directory for font and charmap files + Directory path for font and charmap files """ def hook(obj): @@ -277,13 +370,13 @@ return result if directory is None: - directory = os.path.join( - os.path.dirname(os.path.realpath(__file__)), 'fonts') + directory = self._get_fonts_directory() # Load font if QApplication.instance() is not None: with open(os.path.join(directory, ttf_filename), 'rb') as font_data: - id_ = QFontDatabase.addApplicationFontFromData(QByteArray(font_data.read())) + data = font_data.read() + id_ = QFontDatabase.addApplicationFontFromData(data) font_data.close() loadedFontFamilies = QFontDatabase.applicationFontFamilies(id_) @@ -291,6 +384,7 @@ if loadedFontFamilies: self.fontids[prefix] = id_ self.fontname[prefix] = loadedFontFamilies[0] + self.fontdata[prefix] = data else: raise FontError(u"Font at '{0}' appears to be empty. " "If you are on Windows 10, please read " @@ -303,20 +397,6 @@ with open(os.path.join(directory, charmap_filename), 'r') as codes: self.charmap[prefix] = json.load(codes, object_hook=hook) - # Verify that vendorized fonts are not corrupt - if not SYSTEM_FONTS: - ttf_hash = MD5_HASHES.get(ttf_filename, None) - if ttf_hash is not None: - hasher = hashlib.md5() - with open(os.path.join(directory, ttf_filename), - 'rb') as f: - content = f.read() - hasher.update(content) - ttf_calculated_hash_code = hasher.hexdigest() - if ttf_calculated_hash_code != ttf_hash: - raise FontError(u"Font is corrupt at: '{0}'".format( - os.path.join(directory, ttf_filename))) - def icon(self, *names, **kwargs): """Return a QIcon object corresponding to the provided icon name.""" cache_key = '{}{}'.format(names,kwargs) @@ -443,6 +523,24 @@ font.setStyleName('Solid') return font + def rawfont(self, prefix, size, hintingPreference=QFont.PreferDefaultHinting): + """Return a QRawFont corresponding to the given prefix and size.""" + cache = self.rawfont_cache + # https://doc.qt.io/qt-5/qrawfont.html + # QRawFont is considered local to the thread in which it is constructed + # (either using a constructor, or by calling loadFromData() or loadFromFile()). + # The QRawFont cannot be moved to a different thread, + # but will have to be recreated in the thread in question. + tid = str(QThread.currentThread()) + if tid not in cache: + cache[tid] = {} + def clear_cache(): cache.pop(tid) + QThread().currentThread().finished.connect(clear_cache) + key = prefix, size, hintingPreference + if key not in cache[tid]: + cache[tid][key] = QRawFont(self.fontdata[prefix], size, hintingPreference) + return cache[tid][key] + def set_custom_icon(self, name, painter): """Associate a user-provided CharIconPainter to an icon name. @@ -472,3 +570,88 @@ """Return the icon corresponding to the given painter.""" engine = CharIconEngine(self, painter, options) return QIcon(engine) + + def _get_fonts_directory(self): + """ + Get bundled fonts directory. + + On Windows an attempt to install the fonts per user is done + to prevent errors with fonts loading. + + See spyder-ide/qtawesome#167 and spyder-ide/spyder#18642 for + context. + """ + fonts_directory = os.path.join( + os.path.dirname(os.path.realpath(__file__)), 'fonts') + if os.name == 'nt': + fonts_directory = self._install_fonts(fonts_directory) + return fonts_directory + + def _install_fonts(self, fonts_directory): + """ + Copy the fonts to the user Fonts folder. + + Based on https://stackoverflow.com/a/41841088/15954282 + """ + # Try to get LOCALAPPDATA path + local_appdata_dir = os.environ.get('LOCALAPPDATA', None) + if not local_appdata_dir: + return fonts_directory + + # Construct path to fonts from LOCALAPPDATA + user_fonts_dir = os.path.join( + local_appdata_dir, 'Microsoft', 'Windows', 'Fonts') + os.makedirs(user_fonts_dir, exist_ok=True) + + # Setup bundled fonts on the LOCALAPPDATA fonts directory + for root, __, files in os.walk(fonts_directory): + for name in files: + src_path = os.path.join(root, name) + dst_path = os.path.join( + user_fonts_dir, + os.path.basename(src_path)) + + # Check if font already exists and copy font + if os.path.isfile(dst_path) and filecmp.cmp(src_path, dst_path): + continue + shutil.copy(src_path, user_fonts_dir) + + # Further process the font file (`.ttf`) + if os.path.splitext(name)[-1] == '.ttf': + # Load the font in the current session + if not gdi32.AddFontResourceW(dst_path): + os.remove(dst_path) + raise WindowsError( + f'AddFontResource failed to load "{src_path}"') + + # Store the fontname/filename in the registry + filename = os.path.basename(dst_path) + fontname = os.path.splitext(filename)[0] + + # Try to get the font's real name + cb = wintypes.DWORD() + if gdi32.GetFontResourceInfoW( + filename, ctypes.byref(cb), None, GFRI_DESCRIPTION): + buf = (ctypes.c_wchar * cb.value)() + if gdi32.GetFontResourceInfoW( + filename, ctypes.byref(cb), buf, GFRI_DESCRIPTION): + fontname = buf.value + is_truetype = wintypes.BOOL() + cb.value = ctypes.sizeof(is_truetype) + gdi32.GetFontResourceInfoW( + filename, ctypes.byref(cb), ctypes.byref(is_truetype), + GFRI_ISTRUETYPE) + if is_truetype: + fontname += ' (TrueType)' + try: + with winreg.OpenKey(winreg.HKEY_CURRENT_USER, FONTS_REG_PATH, 0, + winreg.KEY_SET_VALUE) as key: + winreg.SetValueEx(key, fontname, 0, winreg.REG_SZ, filename) + except OSError: + # Needed to support older Windows version where + # font installation per user is not possible/related registry + # entry is not available + # See spyder-ide/qtawesome#214 + return fonts_directory + + return user_fonts_dir diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/qtawesome/tests/test_qtawesome.py new/QtAwesome-1.2.1/qtawesome/tests/test_qtawesome.py --- old/QtAwesome-1.1.1/qtawesome/tests/test_qtawesome.py 2020-09-25 20:07:35.000000000 +0200 +++ new/QtAwesome-1.2.1/qtawesome/tests/test_qtawesome.py 2022-10-19 17:06:17.000000000 +0200 @@ -2,9 +2,10 @@ Tests for QtAwesome. """ # Standard library imports +import collections +import os import subprocess import sys -import collections # Test Library imports import pytest @@ -42,5 +43,36 @@ assert not duplicates +@pytest.mark.skipif(os.name != "nt", reason="Only meant for Windows") +def test_bundled_font_installation(): + """ + Test that the bundled fonts are being installed on Windows. + + See spyder-ide/qtawesome#167 and spyder-ide/spyder#18642 + """ + qta._instance() + fonts_expected = [ + ("codicon", "codicon.ttf"), + ("elusiveicons-webfont", "elusiveicons-webfont.ttf"), + ("fontawesome4.7-webfont", "fontawesome4.7-webfont.ttf"), + ("fontawesome5-brands-webfont", "fontawesome5-brands-webfont.ttf"), + ("fontawesome5-regular-webfont", "fontawesome5-regular-webfont.ttf"), + ("fontawesome5-solid-webfont", "fontawesome5-solid-webfont.ttf"), + ("materialdesignicons5-webfont", "materialdesignicons5-webfont.ttf"), + ("materialdesignicons6-webfont ", "materialdesignicons6-webfont.ttf"), + ("phosphor", "phosphor.ttf"), + ("remixicon", "remixicon.ttf") + ] + fonts_command = [ + "powershell.exe", + r'Get-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"' + ] + fonts_result = subprocess.run(fonts_command, capture_output=True, check=True, text=True).stdout + + for font_name, font_filename in fonts_expected: + assert font_name in fonts_result + assert font_filename in fonts_result + + if __name__ == "__main__": pytest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/setup.py new/QtAwesome-1.2.1/setup.py --- old/QtAwesome-1.1.1/setup.py 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/setup.py 2022-10-19 17:06:17.000000000 +0200 @@ -2,12 +2,8 @@ import os import io -try: - from setuptools import setup - from setuptools.command.install import install -except ImportError: - from distutils.core import setup - from distutils.core.command.install import install +from setuptools import setup +from setuptools.command.install import install # Code to add custom build commands comes from here: import setupbase @@ -38,7 +34,7 @@ packages=['qtawesome'], install_requires=['qtpy'], include_package_data=True, - python_requires='>=3.6', + python_requires='>=3.7', platforms=['OS-independent'], classifiers=[ 'Development Status :: 5 - Production/Stable', @@ -46,7 +42,6 @@ 'Topic :: Software Development :: User Interfaces', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/QtAwesome-1.1.1/setupbase.py new/QtAwesome-1.2.1/setupbase.py --- old/QtAwesome-1.1.1/setupbase.py 2021-11-02 17:26:02.000000000 +0100 +++ new/QtAwesome-1.2.1/setupbase.py 2022-10-19 17:06:17.000000000 +0200 @@ -17,11 +17,12 @@ from urllib.request import urlopen -import distutils.cmd -import distutils.log +import setuptools + +LOG_INFO = 2 HERE = os.path.abspath(os.path.dirname(__file__)) -ICONIC_FONT_PY_PATH = os.path.join(HERE, 'qtawesome', 'iconic_font.py') +INIT_PY_PATH = os.path.join(HERE, 'qtawesome', '__init__.py') def rename_font(font_path, font_name): @@ -29,7 +30,7 @@ Font renaming code originally from: https://github.com/chrissimpkins/fontname.py/blob/master/fontname.py """ - tt = ttLib.TTFont(font_path) + tt = ttLib.TTFont(font_path, recalcBBoxes=False, recalcTimestamp=False) namerecord_list = tt["name"].names variant = "" @@ -68,13 +69,13 @@ # write changes to the font file try: - tt.save(font_path) + tt.save(font_path, reorderTables=False) except: raise RuntimeError( f"ERROR: unable to write new name to OpenType tables for: {font_path}") -class UpdateFA5Command(distutils.cmd.Command): +class UpdateFA5Command(setuptools.Command): """A custom command to make updating FontAwesome 5.x easy!""" description = 'Try to update the FontAwesome 5.x data in the project.' user_options = [ @@ -102,8 +103,8 @@ 'Local zipfile does not exist: %s' % self.zip_path) def __print(self, msg): - """Shortcut for printing with the distutils logger.""" - self.announce(msg, level=distutils.log.INFO) + """Shortcut for printing with the setuptools logger.""" + self.announce(msg, level=LOG_INFO) def __get_charmap_path(self, style): """Get the project FA charmap path for a given style.""" @@ -209,11 +210,11 @@ # Store hashes for later: hashes[style] = hashlib.md5(data).hexdigest() - # Now it's time to patch "iconic_font.py": - iconic_path = ICONIC_FONT_PY_PATH - self.__print('Patching new MD5 hashes in: %s' % iconic_path) - with open(iconic_path, 'r') as iconic_file: - contents = iconic_file.read() + # Now it's time to patch "__init__.py": + init_path = INIT_PY_PATH + self.__print('Patching new MD5 hashes in: %s' % init_path) + with open(init_path, 'r') as init_file: + contents = init_file.read() # We read it in full, then use regex substitution: for style, md5 in hashes.items(): self.__print('New "%s" hash is: %s' % (style, md5)) @@ -221,9 +222,9 @@ subst = r"\g<1>'" + md5 + "'" contents = re.sub(regex, subst, contents, 1) # and finally overwrite with the modified file: - self.__print('Dumping updated file: %s' % iconic_path) - with open(iconic_path, 'w') as iconic_file: - iconic_file.write(contents) + self.__print('Dumping updated file: %s' % init_path) + with open(init_path, 'w') as init_file: + init_file.write(contents) self.__print( '\nFinished!\n' @@ -232,7 +233,7 @@ 'qtawesome/docs/source/usage.rst to reflect the changes.') -class UpdateCodiconCommand(distutils.cmd.Command): +class UpdateCodiconCommand(setuptools.Command): """A custom command to make updating Microsoft's Codicons easy!""" description = 'Try to update the Codicon font data in the project.' user_options = [] @@ -245,14 +246,14 @@ DOWNLOAD_URL_JSON = 'https://raw.githubusercontent.com/microsoft/vscode-codicons/master/package.json' def initialize_options(self): - """Required by distutils.""" + """Required by setuptools.""" def finalize_options(self): - """Required by distutils.""" + """Required by setuptools.""" def __print(self, msg): - """Shortcut for printing with the distutils logger.""" - self.announce(msg, level=distutils.log.INFO) + """Shortcut for printing with the setuptools logger.""" + self.announce(msg, level=LOG_INFO) def run(self): """Run command.""" @@ -295,16 +296,16 @@ md5 = hashlib.md5(data).hexdigest() self.__print('New hash is: %s' % md5) - # Now it's time to patch "iconic_font.py": - self.__print('Patching new MD5 hashes in: %s' % ICONIC_FONT_PY_PATH) - with open(ICONIC_FONT_PY_PATH, 'r') as iconic_file: - contents = iconic_file.read() + # Now it's time to patch "__init__.py": + self.__print('Patching new MD5 hashes in: %s' % INIT_PY_PATH) + with open(INIT_PY_PATH, 'r') as init_file: + contents = init_file.read() regex = r"('codicon.ttf':\s+)'(\w+)'" subst = r"\g<1>'" + md5 + "'" contents = re.sub(regex, subst, contents, 1) - self.__print('Dumping updated file: %s' % ICONIC_FONT_PY_PATH) - with open(ICONIC_FONT_PY_PATH, 'w') as iconic_file: - iconic_file.write(contents) + self.__print('Dumping updated file: %s' % INIT_PY_PATH) + with open(INIT_PY_PATH, 'w') as init_file: + init_file.write(contents) self.__print( '\nFinished!\n'