use Qt search path instead of resource system

Means URLs like :/icons/foo.jpg should become icons:foo.jpg

This is part of the prep work for a PyQt6 update. PyQt6 has dropped
pyrcc, so we can longer generate the icons_qrc.py file we did previously.

Qt Designer expects us to use the resource system, so we continue to
generate the icons.qrc file to make editing the UI files easier. But at
runtime, we no longer use that file.
This commit is contained in:
Damien Elmes 2021-10-05 14:44:07 +10:00
parent ebe7125e81
commit e357dbf6b3
28 changed files with 73 additions and 72 deletions

View file

@ -32,7 +32,6 @@ _py_srcs = glob(
_py_srcs_and_forms = _py_srcs + [
"//qt/aqt/forms:forms",
"//qt/aqt/forms:icons",
]
aqt_core_data = [

View file

@ -587,6 +587,11 @@ def _run(argv: Optional[list[str]] = None, exec: bool = True) -> Optional[AnkiAp
)
return None
# make image resources available
from aqt.utils import aqt_data_folder
QDir.addSearchPath("icons", os.path.join(aqt_data_folder(), "qt", "icons"))
if pmLoadResult.firstTime:
pm.setDefaultLang(lang[0])

View file

@ -53,7 +53,7 @@ class Previewer(QDialog):
self._close_callback = on_close
self.mw = mw
icon = QIcon()
icon.addPixmap(QPixmap(":/icons/anki.png"), QIcon.Normal, QIcon.Off)
icon.addPixmap(QPixmap("icons:anki.png"), QIcon.Normal, QIcon.Off)
disable_help_button(self)
self.setWindowIcon(icon)

View file

@ -18,8 +18,8 @@ class SidebarTool(Enum):
class SidebarToolbar(QToolBar):
_tools: tuple[tuple[SidebarTool, str, Callable[[], str]], ...] = (
(SidebarTool.SEARCH, ":/icons/magnifying_glass.svg", tr.actions_search),
(SidebarTool.SELECT, ":/icons/select.svg", tr.actions_select),
(SidebarTool.SEARCH, "icons:magnifying_glass.svg", tr.actions_search),
(SidebarTool.SELECT, "icons:select.svg", tr.actions_select),
)
def __init__(self, sidebar: aqt.browser.sidebar.SidebarTreeView) -> None:

View file

@ -527,7 +527,7 @@ class SidebarTreeView(QTreeView):
###########################
def _saved_searches_tree(self, root: SidebarItem) -> None:
icon = ":/icons/heart-outline.svg"
icon = "icons:heart-outline.svg"
saved = self._get_saved_searches()
root = self._section_root(
@ -551,7 +551,7 @@ class SidebarTreeView(QTreeView):
###########################
def _today_tree(self, root: SidebarItem) -> None:
icon = ":/icons/clock-outline.svg"
icon = "icons:clock-outline.svg"
root = self._section_root(
root=root,
name=tr.browsing_today(),
@ -621,8 +621,8 @@ class SidebarTreeView(QTreeView):
###########################
def _card_state_tree(self, root: SidebarItem) -> None:
icon = ":/icons/circle.svg"
icon_outline = ":/icons/circle-outline.svg"
icon = "icons:circle.svg"
icon_outline = "icons:circle-outline.svg"
root = self._section_root(
root=root,
@ -670,8 +670,8 @@ class SidebarTreeView(QTreeView):
###########################
def _flags_tree(self, root: SidebarItem) -> None:
icon = ":/icons/flag.svg"
icon_outline = ":/icons/flag-outline.svg"
icon = "icons:flag.svg"
icon_outline = "icons:flag-outline.svg"
root = self._section_root(
root=root,
@ -704,8 +704,8 @@ class SidebarTreeView(QTreeView):
###########################
def _tag_tree(self, root: SidebarItem) -> None:
icon = ":/icons/tag-outline.svg"
icon_off = ":/icons/tag-off-outline.svg"
icon = "icons:tag-outline.svg"
icon_off = "icons:tag-off-outline.svg"
def render(
root: SidebarItem, nodes: Iterable[TagTreeNode], head: str = ""
@ -752,9 +752,9 @@ class SidebarTreeView(QTreeView):
###########################
def _deck_tree(self, root: SidebarItem) -> None:
icon = ":/icons/book-outline.svg"
icon_current = ":/icons/book-clock-outline.svg"
icon_filtered = ":/icons/book-cog-outline.svg"
icon = "icons:book-outline.svg"
icon_current = "icons:book-clock-outline.svg"
icon_filtered = "icons:book-cog-outline.svg"
def render(
root: SidebarItem, nodes: Iterable[DeckTreeNode], head: str = ""
@ -807,9 +807,9 @@ class SidebarTreeView(QTreeView):
###########################
def _notetype_tree(self, root: SidebarItem) -> None:
notetype_icon = ":/icons/newspaper.svg"
template_icon = ":/icons/iframe-braces-outline.svg"
field_icon = ":/icons/form-textbox.svg"
notetype_icon = "icons:newspaper.svg"
template_icon = "icons:iframe-braces-outline.svg"
field_icon = "icons:form-textbox.svg"
root = self._section_root(
root=root,

View file

@ -2,6 +2,7 @@ filegroup(
name = "data",
srcs = [
"//qt/aqt/data/lib",
"//qt/aqt/data/qt",
"//qt/aqt/data/web",
],
visibility = ["//qt:__subpackages__"],

View file

@ -0,0 +1,27 @@
load("@rules_python//python:defs.bzl", "py_binary")
py_binary(
name = "build_qrc",
srcs = ["build_qrc.py"],
legacy_create_init = False,
)
genrule(
name = "icons_qrc",
srcs = ["//qt/aqt/data/qt/icons"],
outs = ["icons.qrc"],
cmd = "$(location build_qrc) $(location icons.qrc) $(SRCS)",
tools = ["build_qrc"],
visibility = ["//qt/aqt:__pkg__"],
)
filegroup(
name = "qt",
srcs = [
"//qt/aqt/data/qt/icons",
# not needed at runtime, but including it here ensures
# it's up to date when a dev opens Qt Designer after a ./run
":icons_qrc",
],
visibility = ["//qt:__subpackages__"],
)

View file

@ -1,5 +1,8 @@
import sys
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import os
import sys
qrc_file = os.path.abspath(sys.argv[1])
icons = sys.argv[2:]
@ -15,10 +18,13 @@ FILES
indent = " " * 8
lines = []
for icon in icons:
alias = ""
base = os.path.basename(icon)
path = os.path.relpath(icon, start=os.path.dirname(qrc_file))
alias = "" if os.path.dirname(path) == "icons" else f' alias="icons/{os.path.basename(path)}"'
line = f"{indent}<file{alias}>{path}</file>"
if not path.startswith("icons/"):
path = f"../data/qt/icons/{base}"
else:
path = f"../../../bazel-bin/qt/aqt/data/qt/icons/{base}"
line = f'{indent}<file alias="icons/{base}">{path}</file>'
lines.append(line)
with open(qrc_file, "w") as file:

View file

@ -1,4 +1,5 @@
load("//ts:vendor.bzl", "copy_mdi_icons", "copy_bootstrap_icons")
load("//ts:vendor.bzl", "copy_mdi_icons")
load("@rules_python//python:defs.bzl", "py_binary")
copy_mdi_icons(
name = "mdi-icons",
@ -37,6 +38,9 @@ copy_mdi_icons(
filegroup(
name = "icons",
srcs = ["mdi-icons"] + glob(["*.svg", "*.png"]),
srcs = ["mdi-icons"] + glob([
"*.svg",
"*.png",
]),
visibility = ["//visibility:public"],
)

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

Before

Width:  |  Height:  |  Size: 832 B

After

Width:  |  Height:  |  Size: 832 B

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 727 B

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -56,7 +56,7 @@ class FlagManager:
def _load_flags(self) -> None:
labels = cast(dict[str, str], self.mw.col.get_config("flagLabels", {}))
icon = ColoredIcon(path=":/icons/flag.svg", color=colors.DISABLED)
icon = ColoredIcon(path="icons:flag.svg", color=colors.DISABLED)
self._flags = [
Flag(

View file

@ -15,35 +15,3 @@ py_binary(
legacy_create_init = False,
deps = ["@pyqt5//:pkg"],
)
py_binary(
name = "build_qrc",
srcs = ["build_qrc.py"],
legacy_create_init = False,
deps = ["@pyqt5//:pkg"],
)
py_binary(
name = "build_rcc",
srcs = ["build_rcc.py"],
legacy_create_init = False,
deps = ["@pyqt5//:pkg"],
)
genrule(
name = "icons_qrc",
srcs = ["//qt/aqt/forms/icons"],
outs = ["icons.qrc"],
cmd = "$(location build_qrc) $(location icons.qrc) $(SRCS)",
tools = ["build_qrc"],
visibility = ["//qt/aqt:__pkg__"],
)
genrule(
name = "icons",
srcs = ["icons_qrc", "//qt/aqt/forms/icons"],
outs = ["icons_rc.py"],
cmd = "$(location build_rcc) $(location icons_qrc) $(location icons_rc.py)",
tools = ["build_rcc"],
visibility = ["//qt/aqt:__pkg__"],
)

View file

@ -1,12 +0,0 @@
import sys
import os
from PyQt5.pyrcc_main import processResourceFile
icons_qrc = sys.argv[1]
py_file = os.path.abspath(sys.argv[2])
# make paths relative for pyrcc
os.chdir(os.path.dirname(icons_qrc))
icons_qrc = os.path.basename(icons_qrc)
processResourceFile([icons_qrc], py_file, False)

View file

@ -29,6 +29,9 @@ for line in outdata.splitlines():
if substr in line:
line = line + " # type: ignore"
break
if line == "from . import icons_rc":
continue
line = line.replace(":/icons/", "icons:")
outlines.append(line)
with open(py_file, "w") as file:

View file

@ -1 +1 @@
../../../bazel-bin/qt/aqt/forms/icons.qrc
../../../bazel-bin/qt/aqt/data/qrc/icons.qrc

View file

@ -190,7 +190,7 @@ class ProfileManager:
app = QtWidgets.QApplication([])
icon = QtGui.QIcon()
icon.addPixmap(
QtGui.QPixmap(":/icons/anki.png"),
QtGui.QPixmap("icons:anki.png"),
QtGui.QIcon.Normal,
QtGui.QIcon.Off,
)

View file

@ -734,7 +734,7 @@ class RecordDialog(QDialog):
def _setup_dialog(self) -> None:
self.setWindowTitle("Anki")
icon = QLabel()
icon.setPixmap(QPixmap(":/icons/media-record.png"))
icon.setPixmap(QPixmap("icons:media-record.png"))
self.label = QLabel("...")
hbox = QHBoxLayout()
hbox.addWidget(icon)