diff --git a/qdarkstyle/palette.py b/qdarkstyle/palette.py index 782fccf..c0b7300 100644 --- a/qdarkstyle/palette.py +++ b/qdarkstyle/palette.py @@ -29,6 +29,8 @@ class Palette(object): COLOR_ACCENT_4 = '' COLOR_ACCENT_5 = '' + COLOR_DISABLED = '' + OPACITY_TOOLTIP = 0 # Size @@ -100,3 +102,8 @@ class Palette(object): def color_palette(cls): """Return the ordered colored palette dictionary.""" return cls.to_dict(colors_only=True) + + @staticmethod + def from_dict(class_values, class_name="FromDictPalette"): + """Return palette class definition from dictionary.""" + return type(class_name, (Palette, ), class_values) diff --git a/qdarkstyle/utils/__init__.py b/qdarkstyle/utils/__init__.py index 885bc96..bb98fa9 100644 --- a/qdarkstyle/utils/__init__.py +++ b/qdarkstyle/utils/__init__.py @@ -5,10 +5,19 @@ Utilities for processing SASS and images from default and custom palette. # Standard library imports import logging +import os +import shutil import sys # Local imports -from qdarkstyle import PACKAGE_PATH, SVG_PATH, IMAGES_PATH +from qdarkstyle import ( + PACKAGE_PATH, + SVG_PATH, + IMAGES_PATH, + MAIN_SCSS_FILE, + QSS_PATH, + STYLES_SCSS_FILE, +) from qdarkstyle.utils.images import ( compile_qrc_file, create_images, @@ -39,12 +48,6 @@ def process_palette( - QSS file in [palette_id]/[palette_id]style.qss. - Compiled QRC file in [palette_id]/[palette_id]style_rc.py - TODO: - - Must generalize to create custom palettes and folder paths. - - Must create/copy all files under [palette_id], such as main.scss, - __init__.py, palette.py. - - Add option or avoid adding the palette under docs for custom palettes. - Args: palette (Palette): Palette. compile_for (list, optional): Prefix used in resources. @@ -52,6 +55,16 @@ def process_palette( 'pyqt', 'pyqt5', 'pyqt6', 'pyside', 'pyside2', 'pyside6', 'qt', 'qt5', qt6, 'all'. + base_svg_path (str, optional): Base path for the `.svg` source files. + Defaults to `SVG_PATH`. + base_path (str): Base path for the palette directory, required for + custom palettes. Defaults to `PACKAGE_PATH`. + images_path (str): Path to save generated image files (`palette.svg` and `palette.png`). + Defaults to `IMAGES_PATH`. + resource_prefix (str, optional): Prefix used in resources. + Defaults to 'qss_icons'. + style_prefix (str, optional): Prefix used to this style. + Defaults to 'qdarkstyle'. """ if palette is None: @@ -68,6 +81,50 @@ def process_palette( id_ = palette.ID print(f"-- PROCESSING THEME: {id_}") + # Create base palette directory and files from id + palette_path = os.path.join(base_path, id_) + if not os.path.exists(palette_path): + os.mkdir(palette_path) + + init_path = os.path.join(palette_path, "__init__.py") + if not os.path.isfile(init_path): + with open(init_path, mode="x"): + pass + + palette_file_path = os.path.join(palette_path, "palette.py") + if not os.path.isfile(palette_file_path): + with open(palette_file_path, mode="w") as palette_file: + palette_file.write("from qdarkstyle.palette import Palette\n\n\n") + palette_file.write(f"class {palette.__name__}(Palette):\n") + palette_file.write(f' """{palette.__name__} palette variables."""\n\n') + for attr, value in palette.to_dict().items(): + if attr in ["ID", "OPACITY_TOOLTIP"]: + palette_file.write(f" {attr} = {value}\n") + else: + palette_file.write(f' {attr} = "{value}"\n') + + qss_path = os.path.join(base_path, "qss") + if not os.path.exists(qss_path): + os.mkdir(qss_path) + + main_scss_path = os.path.join(palette_path, MAIN_SCSS_FILE) + if not os.path.exists(main_scss_path): + # Create basic `main.scss` file for custom path + with open(main_scss_path, "w") as main_scss: + main_scss.write(f""" +/* {id_} Style - QDarkStyleSheet ------------------------------------------ */ + +@import '_variables'; +@import '../qss/_styles'; + +""") + + styles_scss_path = os.path.join(qss_path, STYLES_SCSS_FILE) + if not os.path.exists(styles_scss_path): + # Copy `qss/_styles.scss` file to custom path + base_styles_scss_path = os.path.join(QSS_PATH, STYLES_SCSS_FILE) + shutil.copy(base_styles_scss_path, styles_scss_path) + # TODO: delete/remove all files and folders to ensure that old files # are not used @@ -96,4 +153,5 @@ def process_palette( compile_qrc_file( compile_for=compile_for, palette=palette, + base_path=base_path, ) diff --git a/qdarkstyle/utils/__main__.py b/qdarkstyle/utils/__main__.py index fe51870..199b3e0 100644 --- a/qdarkstyle/utils/__main__.py +++ b/qdarkstyle/utils/__main__.py @@ -33,6 +33,7 @@ from watchdog.observers import Observer # Local imports from qdarkstyle import PACKAGE_PATH, SVG_PATH, IMAGES_PATH +from qdarkstyle.palette import Palette from qdarkstyle.dark.palette import DarkPalette from qdarkstyle.light.palette import LightPalette from qdarkstyle.utils import process_palette @@ -57,30 +58,74 @@ class QSSFileHandler(FileSystemEventHandler): print('\n') +# See https://sumit-ghosh.com/posts/parsing-dictionary-key-value-pairs-kwargs-argparse-python/ +class CustomPaletteParser(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, dict()) + for value in values: + key, value = value.split('=') + getattr(namespace, self.dest)[key] = value + + def main(): """Process QRC files.""" parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('--base_path', - default=PACKAGE_PATH, - type=str, - help="Base QRC file directory.",) - parser.add_argument('--create', - default='qtpy', - choices=['pyqt5', 'pyqt6', 'pyside2', 'pyside6', 'qtpy', 'pyqtgraph', 'qt', 'qt5', 'all'], - type=str, - help="Choose which one would be generated.") - parser.add_argument('--watch', '-w', - action='store_true', - help="Watch for file changes.") - parser.add_argument('--base_svg_path', - default=SVG_PATH, - type=str, - help="Base path were source .svg files are located.",) - parser.add_argument('--images_path', - default=IMAGES_PATH, - type=str, - help="Path were documentation images are located.",) + parser.add_argument( + "--base_path", + default=PACKAGE_PATH, + type=str, + help="Base QRC file directory.", + ) + parser.add_argument( + "--create", + default="qtpy", + choices=[ + "pyqt5", + "pyqt6", + "pyside2", + "pyside6", + "qtpy", + "pyqtgraph", + "qt", + "qt5", + "all", + ], + type=str, + help="Choose which one would be generated.", + ) + parser.add_argument( + "--watch", "-w", action="store_true", help="Watch for file changes." + ) + parser.add_argument( + "--base_svg_path", + default=SVG_PATH, + type=str, + help="Base path were source .svg files are located.", + ) + parser.add_argument( + "--images_path", + default=IMAGES_PATH, + type=str, + help="Path were documentation images are located.", + ) + parser.add_argument( + "--resource_prefix", + default="qdarkstyle", + type=str, + help="Prefix used to this style.", + ) + parser.add_argument( + "--style_prefix", + default="qss_icons", + type=str, + help="Prefix used in resources.", + ) + parser.add_argument( + "--custom_palette", + nargs="*", + action=CustomPaletteParser, + ) args = parser.parse_args() @@ -95,6 +140,18 @@ def main(): except KeyboardInterrupt: observer.stop() observer.join() + elif args.custom_palette: + process_palette( + palette=Palette.from_dict( + args.custom_palette, + class_name=f'{args.custom_palette["ID"].capitalize()}Palette', + ), + compile_for=args.create, + base_svg_path=args.base_svg_path, + images_path=args.images_path, + base_path=args.base_path, + ) + else: for palette in [DarkPalette, LightPalette]: process_palette( diff --git a/qdarkstyle/utils/images.py b/qdarkstyle/utils/images.py index da52e3a..ee0dba0 100644 --- a/qdarkstyle/utils/images.py +++ b/qdarkstyle/utils/images.py @@ -92,7 +92,7 @@ def convert_svg_to_png(svg_path, png_path, height, width): def create_palette_image( - base_svg_path=SVG_PATH, path=PACKAGE_PATH, palette=None + base_svg_path=SVG_PATH, path=IMAGES_PATH, palette=None ): """ Create palette image svg and png image on specified path. @@ -101,7 +101,7 @@ def create_palette_image( base_svg_path (str, optional): Base path for the `.svg` source files. Defaults to `SVG_PATH`. path (str): Path to save generated image files (`.svg` and `.png`). - Defaults to `PACKAGE_PATH`. + Defaults to `IMAGES_PATH`. palette (Palette, optional): Palette. """ # Needed to use QPixmap