From bff76727fe1270ccb56de86b35c4a813af8c22ae Mon Sep 17 00:00:00 2001
From: Matthias Metelka <62722460+kleinerpirat@users.noreply.github.com>
Date: Wed, 21 Sep 2022 04:02:30 +0200
Subject: [PATCH] Make mdi icons for Qt themeable (#2078)
* Fix create_vars_from_map not creating vars with default definition
* Add white and black to vars
* Replace some hard-coded SVGs with mdi equivalents
* Implement function to dynamically adjust SVG icon color
* Use new svg function to make Qt stylesheet icons respond to theme changes
* Use svg function for sidebar tool icons
* Create copy for each new color instead of modifying source file
* Fix check fails
* Add custom checkbox style for #2079
* Add example of how to generate svgs during build (dae)
* Create arbitrary color variants for each icon with Bazel
* Remove unused label (dae)
---
qt/aqt/BUILD.bazel | 12 +-
qt/aqt/browser/sidebar/toolbar.py | 12 +-
qt/aqt/data/qt/icons/BUILD.bazel | 77 +++++++++-
qt/aqt/data/qt/icons/chevron-down.svg | 3 -
qt/aqt/data/qt/icons/chevron-up.svg | 3 -
qt/aqt/data/qt/icons/color_svg.bzl | 30 ++++
qt/aqt/data/qt/icons/color_svg.py | 47 ++++++
qt/aqt/data/qt/icons/magnifying_glass.svg | 84 -----------
qt/aqt/data/qt/icons/select.svg | 168 ----------------------
qt/aqt/stylesheets.py | 83 +++++++----
qt/aqt/theme.py | 32 ++++-
sass/_functions.scss | 3 +
sass/_vars.scss | 18 ++-
13 files changed, 276 insertions(+), 296 deletions(-)
delete mode 100644 qt/aqt/data/qt/icons/chevron-down.svg
delete mode 100644 qt/aqt/data/qt/icons/chevron-up.svg
create mode 100644 qt/aqt/data/qt/icons/color_svg.bzl
create mode 100644 qt/aqt/data/qt/icons/color_svg.py
delete mode 100644 qt/aqt/data/qt/icons/magnifying_glass.svg
delete mode 100644 qt/aqt/data/qt/icons/select.svg
diff --git a/qt/aqt/BUILD.bazel b/qt/aqt/BUILD.bazel
index 5a60e3393..c09b9fc26 100644
--- a/qt/aqt/BUILD.bazel
+++ b/qt/aqt/BUILD.bazel
@@ -2,7 +2,6 @@ load("@rules_python//python:defs.bzl", "py_library")
load("@py_deps//:requirements.bzl", "requirement")
load("@rules_python//python:packaging.bzl", "py_package", "py_wheel")
load("//:defs.bzl", "anki_version")
-
load("//ts:copy.bzl", "copy_files_into_group")
load("//ts:compile_sass.bzl", "compile_sass")
@@ -31,13 +30,22 @@ genrule(
srcs = [
"_vars.css",
],
- outs = ["colors.py", "props.py"],
+ outs = [
+ "colors.py",
+ "props.py",
+ ],
cmd = "$(location //qt:extract_sass_vars) $(SRCS) $(OUTS)",
tools = [
"//qt:extract_sass_vars",
],
)
+py_library(
+ name = "colors",
+ srcs = [":colors.py"],
+ visibility = ["//qt:__subpackages__"],
+)
+
_py_srcs = glob(
[
"**/*.py",
diff --git a/qt/aqt/browser/sidebar/toolbar.py b/qt/aqt/browser/sidebar/toolbar.py
index 865df2fdd..a111fe3e4 100644
--- a/qt/aqt/browser/sidebar/toolbar.py
+++ b/qt/aqt/browser/sidebar/toolbar.py
@@ -20,8 +20,16 @@ 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,
+ "mdi:magnify",
+ tr.actions_search,
+ ),
+ (
+ SidebarTool.SELECT,
+ "mdi:selection-drag",
+ tr.actions_select,
+ ),
)
def __init__(self, sidebar: aqt.browser.sidebar.SidebarTreeView) -> None:
diff --git a/qt/aqt/data/qt/icons/BUILD.bazel b/qt/aqt/data/qt/icons/BUILD.bazel
index 9692fe8d5..4d8ed0382 100644
--- a/qt/aqt/data/qt/icons/BUILD.bazel
+++ b/qt/aqt/data/qt/icons/BUILD.bazel
@@ -1,4 +1,5 @@
load("//ts:vendor.bzl", "copy_mdi_icons")
+load("color_svg.bzl", "color_svg")
copy_mdi_icons(
name = "mdi-icons",
@@ -33,6 +34,19 @@ copy_mdi_icons(
# tags
"tag-outline.svg",
"tag-off-outline.svg",
+ ],
+)
+
+copy_mdi_icons(
+ name = "mdi-themed",
+ icons = [
+ # sidebar tools
+ "magnify.svg",
+ "selection-drag.svg",
+
+ # QComboBox arrows
+ "chevron-up.svg",
+ "chevron-down.svg",
# QHeaderView arrows
"menu-up.svg",
@@ -41,12 +55,73 @@ copy_mdi_icons(
# drag handle
"drag-vertical.svg",
"drag-horizontal.svg",
+
+ # checkbox
+ "check.svg",
+ "minus-thick.svg",
],
)
+py_binary(
+ name = "color_svg",
+ srcs = [
+ "color_svg.py",
+ "//qt/aqt:colors",
+ ],
+ imports = ["."],
+ visibility = [":__subpackages__"],
+)
+
+color_svg(
+ name = "magnify",
+)
+color_svg(
+ name = "selection-drag",
+)
+color_svg(
+ name = "chevron-up",
+ extra_colors = ["FG_DISABLED"],
+)
+color_svg(
+ name = "chevron-down",
+ extra_colors = ["FG_DISABLED"],
+)
+color_svg(
+ name = "menu-up",
+)
+color_svg(
+ name = "menu-down",
+)
+color_svg(
+ name = "drag-vertical",
+ extra_colors = ["FG_SUBTLE"],
+)
+color_svg(
+ name = "drag-horizontal",
+ extra_colors = ["FG_SUBTLE"],
+)
+color_svg(
+ name = "check",
+)
+color_svg(
+ name = "minus-thick",
+)
+
filegroup(
name = "icons",
- srcs = ["mdi-icons"] + glob([
+ srcs = [
+ "mdi-icons",
+ "magnify",
+ "selection-drag",
+ "chevron-up",
+ "chevron-down",
+ "menu-up",
+ "menu-down",
+ "drag-vertical",
+ "drag-horizontal",
+ "check",
+ "minus-thick",
+ ] + glob([
"*.svg",
"*.png",
]),
diff --git a/qt/aqt/data/qt/icons/chevron-down.svg b/qt/aqt/data/qt/icons/chevron-down.svg
deleted file mode 100644
index 7bd900144..000000000
--- a/qt/aqt/data/qt/icons/chevron-down.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/qt/aqt/data/qt/icons/chevron-up.svg b/qt/aqt/data/qt/icons/chevron-up.svg
deleted file mode 100644
index 19bdb1440..000000000
--- a/qt/aqt/data/qt/icons/chevron-up.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/qt/aqt/data/qt/icons/color_svg.bzl b/qt/aqt/data/qt/icons/color_svg.bzl
new file mode 100644
index 000000000..8dea97eb4
--- /dev/null
+++ b/qt/aqt/data/qt/icons/color_svg.bzl
@@ -0,0 +1,30 @@
+def color_svg(name, extra_colors = [], visibility = ["//qt:__submodules__"]):
+ native.genrule(
+ name = name,
+ srcs = ["mdi-themed"],
+ outs = [
+ name + "-light.svg",
+ ] + [
+ # additional light colors
+ "{}{}{}".format(
+ name,
+ "-{}".format(color),
+ "-light.svg"
+ ) for color in extra_colors
+ ] + [
+ name + "-dark.svg",
+ ] + [
+ # additional dark colors
+ "{}{}{}".format(
+ name,
+ "-{}".format(color),
+ "-dark.svg"
+ ) for color in extra_colors
+ ],
+ cmd = "$(location color_svg) {}.svg {} $(OUTS) $(SRCS)".format(
+ name, ":".join(["FG"] + extra_colors)
+ ),
+ tools = [
+ "color_svg",
+ ],
+ )
diff --git a/qt/aqt/data/qt/icons/color_svg.py b/qt/aqt/data/qt/icons/color_svg.py
new file mode 100644
index 000000000..2fc33a7fc
--- /dev/null
+++ b/qt/aqt/data/qt/icons/color_svg.py
@@ -0,0 +1,47 @@
+# Copyright: Ankitects Pty Ltd and contributors
+# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
+
+import re
+import sys
+from pathlib import Path
+
+from qt.aqt import colors
+
+input_filename = sys.argv[1]
+input_name = input_filename.replace(".svg", "")
+color_names = sys.argv[2].split(":")
+
+# two files created for each additional color
+offset = len(color_names) * 2
+svg_paths = sys.argv[3 : 3 + offset]
+
+# as we've received a group of files, we need to manually join the path
+input_folder = Path(sys.argv[4]).parent
+input_svg = input_folder / input_filename
+
+with open(input_svg, "r") as f:
+ svg_data = f.read()
+
+ for color_name in color_names:
+ color = getattr(colors, color_name)
+ light_svg = dark_svg = ""
+
+ if color_name == "FG":
+ prefix = input_name
+ else:
+ prefix = f"{input_name}-{color_name}"
+
+ for path in svg_paths:
+ if f"{prefix}-light.svg" in path:
+ light_svg = path
+ elif f"{prefix}-dark.svg" in path:
+ dark_svg = path
+
+ for (idx, filename) in enumerate((light_svg, dark_svg)):
+ data = svg_data
+ if "fill" in data:
+ data = re.sub(r"fill=\"#.+?\"", f'fill="{color[idx]}"', data)
+ else:
+ data = re.sub(r"