diff --git a/qt/aqt/BUILD.bazel b/qt/aqt/BUILD.bazel index bf9c8a20d..e4bac550a 100644 --- a/qt/aqt/BUILD.bazel +++ b/qt/aqt/BUILD.bazel @@ -32,7 +32,6 @@ _py_srcs = glob( _py_srcs_and_forms = _py_srcs + [ "//qt/aqt/forms:forms", - "//qt/aqt/forms:icons", ] aqt_core_data = [ diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index c74149823..566250522 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -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]) diff --git a/qt/aqt/browser/previewer.py b/qt/aqt/browser/previewer.py index d3a4c882d..35314208a 100644 --- a/qt/aqt/browser/previewer.py +++ b/qt/aqt/browser/previewer.py @@ -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) diff --git a/qt/aqt/browser/sidebar/toolbar.py b/qt/aqt/browser/sidebar/toolbar.py index 0f9c53fc3..61a0b0b5e 100644 --- a/qt/aqt/browser/sidebar/toolbar.py +++ b/qt/aqt/browser/sidebar/toolbar.py @@ -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: diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index 28da752b8..d3b1e9245 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -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, diff --git a/qt/aqt/data/BUILD.bazel b/qt/aqt/data/BUILD.bazel index efd53c8ca..f8745bed2 100644 --- a/qt/aqt/data/BUILD.bazel +++ b/qt/aqt/data/BUILD.bazel @@ -2,6 +2,7 @@ filegroup( name = "data", srcs = [ "//qt/aqt/data/lib", + "//qt/aqt/data/qt", "//qt/aqt/data/web", ], visibility = ["//qt:__subpackages__"], diff --git a/qt/aqt/data/qt/BUILD.bazel b/qt/aqt/data/qt/BUILD.bazel new file mode 100644 index 000000000..a98b579a8 --- /dev/null +++ b/qt/aqt/data/qt/BUILD.bazel @@ -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__"], +) diff --git a/qt/aqt/forms/build_qrc.py b/qt/aqt/data/qt/build_qrc.py similarity index 52% rename from qt/aqt/forms/build_qrc.py rename to qt/aqt/data/qt/build_qrc.py index 6d385b402..18afceae5 100644 --- a/qt/aqt/forms/build_qrc.py +++ b/qt/aqt/data/qt/build_qrc.py @@ -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}{path}" + 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}{path}' lines.append(line) with open(qrc_file, "w") as file: diff --git a/qt/aqt/forms/icons/BUILD.bazel b/qt/aqt/data/qt/icons/BUILD.bazel similarity index 80% rename from qt/aqt/forms/icons/BUILD.bazel rename to qt/aqt/data/qt/icons/BUILD.bazel index db492a4dc..f991a4220 100644 --- a/qt/aqt/forms/icons/BUILD.bazel +++ b/qt/aqt/data/qt/icons/BUILD.bazel @@ -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"], ) diff --git a/qt/aqt/forms/icons/anki.png b/qt/aqt/data/qt/icons/anki.png similarity index 100% rename from qt/aqt/forms/icons/anki.png rename to qt/aqt/data/qt/icons/anki.png diff --git a/qt/aqt/forms/icons/card-state.svg b/qt/aqt/data/qt/icons/card-state.svg similarity index 100% rename from qt/aqt/forms/icons/card-state.svg rename to qt/aqt/data/qt/icons/card-state.svg diff --git a/qt/aqt/forms/icons/clock.svg b/qt/aqt/data/qt/icons/clock.svg similarity index 100% rename from qt/aqt/forms/icons/clock.svg rename to qt/aqt/data/qt/icons/clock.svg diff --git a/qt/aqt/forms/icons/collection.svg b/qt/aqt/data/qt/icons/collection.svg similarity index 100% rename from qt/aqt/forms/icons/collection.svg rename to qt/aqt/data/qt/icons/collection.svg diff --git a/qt/aqt/forms/icons/deck.svg b/qt/aqt/data/qt/icons/deck.svg similarity index 100% rename from qt/aqt/forms/icons/deck.svg rename to qt/aqt/data/qt/icons/deck.svg diff --git a/qt/aqt/forms/icons/flag.svg b/qt/aqt/data/qt/icons/flag.svg similarity index 100% rename from qt/aqt/forms/icons/flag.svg rename to qt/aqt/data/qt/icons/flag.svg diff --git a/qt/aqt/forms/icons/heart.svg b/qt/aqt/data/qt/icons/heart.svg similarity index 100% rename from qt/aqt/forms/icons/heart.svg rename to qt/aqt/data/qt/icons/heart.svg diff --git a/qt/aqt/forms/icons/magnifying_glass.svg b/qt/aqt/data/qt/icons/magnifying_glass.svg similarity index 100% rename from qt/aqt/forms/icons/magnifying_glass.svg rename to qt/aqt/data/qt/icons/magnifying_glass.svg diff --git a/qt/aqt/forms/icons/media-record.png b/qt/aqt/data/qt/icons/media-record.png similarity index 100% rename from qt/aqt/forms/icons/media-record.png rename to qt/aqt/data/qt/icons/media-record.png diff --git a/qt/aqt/forms/icons/notetype.svg b/qt/aqt/data/qt/icons/notetype.svg similarity index 100% rename from qt/aqt/forms/icons/notetype.svg rename to qt/aqt/data/qt/icons/notetype.svg diff --git a/qt/aqt/forms/icons/select.svg b/qt/aqt/data/qt/icons/select.svg similarity index 100% rename from qt/aqt/forms/icons/select.svg rename to qt/aqt/data/qt/icons/select.svg diff --git a/qt/aqt/forms/icons/tag.svg b/qt/aqt/data/qt/icons/tag.svg similarity index 100% rename from qt/aqt/forms/icons/tag.svg rename to qt/aqt/data/qt/icons/tag.svg diff --git a/qt/aqt/flags.py b/qt/aqt/flags.py index e1e209aeb..64ee04524 100644 --- a/qt/aqt/flags.py +++ b/qt/aqt/flags.py @@ -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( diff --git a/qt/aqt/forms/BUILD.bazel b/qt/aqt/forms/BUILD.bazel index 0bdf3afbc..931df6037 100644 --- a/qt/aqt/forms/BUILD.bazel +++ b/qt/aqt/forms/BUILD.bazel @@ -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__"], -) diff --git a/qt/aqt/forms/build_rcc.py b/qt/aqt/forms/build_rcc.py deleted file mode 100644 index b2dd530a8..000000000 --- a/qt/aqt/forms/build_rcc.py +++ /dev/null @@ -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) diff --git a/qt/aqt/forms/build_ui.py b/qt/aqt/forms/build_ui.py index a36857ff0..d45d4f8ac 100644 --- a/qt/aqt/forms/build_ui.py +++ b/qt/aqt/forms/build_ui.py @@ -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: diff --git a/qt/aqt/forms/icons.qrc b/qt/aqt/forms/icons.qrc index e2b267b80..d17297082 120000 --- a/qt/aqt/forms/icons.qrc +++ b/qt/aqt/forms/icons.qrc @@ -1 +1 @@ -../../../bazel-bin/qt/aqt/forms/icons.qrc \ No newline at end of file +../../../bazel-bin/qt/aqt/data/qrc/icons.qrc \ No newline at end of file diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 8154778ca..38042621e 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -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, ) diff --git a/qt/aqt/sound.py b/qt/aqt/sound.py index f00568fc7..d0d088889 100644 --- a/qt/aqt/sound.py +++ b/qt/aqt/sound.py @@ -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)