-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prepare icon and UI imports for qt6 QGis builds #250
base: main
Are you sure you want to change the base?
Changes from 1 commit
5af221d
bcf193c
e9ef078
04afa42
1342b9a
8a16947
dd66b60
de76e40
1a7bb96
61d64b4
36795dc
1a69192
7f1b3eb
fc9d644
3e33e9c
b3c51a6
7ece625
13ef7b5
62ae5e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
# -*- coding: utf-8 -*- | ||
"""GUI Utilities | ||
|
||
.. note:: This program is free software; you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation; either version 2 of the License, or | ||
(at your option) any later version. | ||
""" | ||
|
||
__author__ = '(C) 2018 by Nyall Dawson' | ||
__date__ = '20/04/2018' | ||
__copyright__ = 'Copyright 2018, North Road' | ||
# This will get replaced with a git SHA1 when you do a git archive | ||
__revision__ = '$Format:%H$' | ||
|
||
import math | ||
import os | ||
import re | ||
from typing import ( | ||
Optional, | ||
Union | ||
) | ||
|
||
from qgis.PyQt.QtCore import Qt | ||
from qgis.PyQt.QtGui import ( | ||
QIcon, | ||
QFont, | ||
QFontMetrics, | ||
QImage, | ||
QPixmap, | ||
QFontDatabase, | ||
QColor, | ||
QPainter | ||
) | ||
from qgis.PyQt.QtSvg import QSvgRenderer | ||
from qgis.PyQt.QtWidgets import ( | ||
QMenu | ||
) | ||
from qgis.core import ( | ||
Qgis | ||
) | ||
from qgis.utils import iface | ||
|
||
from ORStools import RESOURCE_PREFIX | ||
from ORStools.utils import logger | ||
|
||
FONT_FAMILIES = "" | ||
|
||
FELT_STYLESHEET = """ | ||
QDialog { | ||
background-color: #ececec; | ||
color: black; | ||
} | ||
QLabel { | ||
color: black !important; | ||
} | ||
|
||
QPushButton { | ||
background: solid #3d521e !important; | ||
color: white !important; | ||
} | ||
|
||
QLineEdit { | ||
background: solid white; | ||
color: black; | ||
} | ||
|
||
QProgressBar { | ||
background: solid white; | ||
} | ||
|
||
""" | ||
|
||
|
||
class GuiUtils: | ||
""" | ||
Utilities for GUI plugin components | ||
""" | ||
|
||
APPLICATION_FONT_MAP = {} | ||
|
||
@staticmethod | ||
def set_link_color(html: str, | ||
wrap_color=True, | ||
color: Optional[Union[QColor, str]] = None) -> str: | ||
""" | ||
Adds style tags to links in a HTML string for the standard link color | ||
""" | ||
if color: | ||
if isinstance(color, str): | ||
color_string = color | ||
else: | ||
color_string = color.name() | ||
else: | ||
color_string = 'rgba(0,0,0,.3)' | ||
res = re.sub(r'(<a href.*?)>', | ||
r'\1 style="color: {};">'.format(color_string), | ||
html) | ||
if wrap_color: | ||
res = '<span style="color: {};">{}</span>'.format(color_string, | ||
res) | ||
return res | ||
|
||
@staticmethod | ||
def get_icon(icon: str) -> QIcon: | ||
""" | ||
Returns a plugin icon | ||
:param icon: icon name (svg file name) | ||
:return: QIcon | ||
""" | ||
path = GuiUtils.get_icon_svg(icon) | ||
if not path: | ||
return QIcon() | ||
|
||
return QIcon(path) | ||
|
||
@staticmethod | ||
def get_icon_svg(icon: str) -> str: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While this reads like it should do something with |
||
""" | ||
Returns a plugin icon's SVG file path | ||
:param icon: icon name (svg file name) | ||
:return: icon svg path | ||
""" | ||
path = os.path.join( | ||
os.path.dirname(__file__), | ||
'..', | ||
'gui/img', | ||
icon) | ||
logger.log(path) | ||
if not os.path.exists(path): | ||
return '' | ||
|
||
return path | ||
|
||
@staticmethod | ||
def get_icon_pixmap(icon: str) -> QPixmap: | ||
""" | ||
Returns a plugin icon's PNG file path | ||
:param icon: icon name (png file name) | ||
:return: icon png path | ||
""" | ||
path = os.path.join( | ||
os.path.dirname(__file__), | ||
'..', | ||
'icons', | ||
icon) | ||
if not os.path.exists(path): | ||
return QPixmap() | ||
|
||
im = QImage(path) | ||
return QPixmap.fromImage(im) | ||
|
||
@staticmethod | ||
def get_svg_as_image(icon: str, width: int, height: int, | ||
background_color: Optional[QColor] = None, | ||
device_pixel_ratio: float = 1) -> QImage: | ||
""" | ||
Returns an SVG returned as an image | ||
""" | ||
path = GuiUtils.get_icon_svg(icon) | ||
if not os.path.exists(path): | ||
return QImage() | ||
|
||
renderer = QSvgRenderer(path) | ||
image = QImage(int(width * device_pixel_ratio), | ||
int(height * device_pixel_ratio), | ||
QImage.Format_ARGB32) | ||
image.setDevicePixelRatio(device_pixel_ratio) | ||
if not background_color: | ||
image.fill(Qt.transparent) | ||
else: | ||
image.fill(background_color) | ||
|
||
painter = QPainter(image) | ||
painter.scale(1 / device_pixel_ratio, | ||
1 / device_pixel_ratio) | ||
renderer.render(painter) | ||
painter.end() | ||
|
||
return image | ||
|
||
@staticmethod | ||
def get_ui_file_path(file: str) -> str: | ||
""" | ||
Returns a UI file's path | ||
:param file: file name (uifile name) | ||
:return: ui file path | ||
""" | ||
path = os.path.join( | ||
os.path.dirname(__file__), | ||
'..', | ||
'gui', | ||
file) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is highly dependent on the code layout of the plugin - in our case, it works, but it feels way more generic than it is? |
||
if not os.path.exists(path): | ||
return path | ||
|
||
return path | ||
Comment on lines
+174
to
+177
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This branching is essentially useless? |
||
|
||
@staticmethod | ||
def scale_icon_size(standard_size: int) -> int: | ||
""" | ||
Scales an icon size accounting for device DPI | ||
""" | ||
fm = QFontMetrics((QFont())) | ||
scale = 1.1 * standard_size / 24.0 | ||
return int(math.floor(max(Qgis.UI_SCALE_FACTOR * fm.height() * scale, | ||
float(standard_size)))) | ||
|
||
@staticmethod | ||
def get_default_font() -> QFont: | ||
""" | ||
Returns the best font match for the Koordinates default font | ||
families which is available on the system | ||
""" | ||
for family in FONT_FAMILIES.split(','): | ||
family_cleaned = re.match(r'^\s*\'?(.*?)\'?\s*$', family).group(1) | ||
font = QFont(family_cleaned) | ||
if font.exactMatch(): | ||
return font | ||
|
||
return QFont() | ||
|
||
@staticmethod | ||
def get_font_path(font: str) -> str: | ||
""" | ||
Returns the path to an included font file | ||
:param font: font name | ||
:return: font file path | ||
""" | ||
path = os.path.join( | ||
os.path.dirname(__file__), | ||
'..', | ||
'fonts', | ||
font) | ||
if not os.path.exists(path): | ||
return '' | ||
|
||
return path | ||
|
||
@staticmethod | ||
def get_embedded_font(font: str) -> QFont: | ||
""" | ||
Returns a font created from an embedded font file | ||
""" | ||
if font in GuiUtils.APPLICATION_FONT_MAP: | ||
return GuiUtils.APPLICATION_FONT_MAP[font] | ||
|
||
path = GuiUtils.get_font_path(font) | ||
if not path: | ||
return QFont() | ||
|
||
res = QFontDatabase.addApplicationFont(path) | ||
families = QFontDatabase.applicationFontFamilies(res) | ||
installed_font = QFont(families[0]) | ||
GuiUtils.APPLICATION_FONT_MAP[font] = installed_font | ||
return installed_font | ||
|
||
@staticmethod | ||
def get_project_import_export_menu() -> Optional[QMenu]: | ||
""" | ||
Returns the application Project - Import/Export sub menu | ||
""" | ||
try: | ||
# requires QGIS 3.30+ | ||
return iface.projectImportExportMenu() | ||
except AttributeError: | ||
pass | ||
|
||
project_menu = iface.projectMenu() | ||
matches = [m for m in project_menu.children() | ||
if m.objectName() == 'menuImport_Export'] | ||
if matches: | ||
return matches[0] | ||
|
||
return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the license of this compatible with ours?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are importing a rather large chunk of code here, of which only 3 small functions are used.
I suggest to reduce the import to the functions in question.