PKt{Kqtico/__init__.py"""Tools for using cross-platform Qt icon themes. """ from .common import PATH_ICON_THEME from .theme_index import write_theme_indices from .qrc_compile import write_resources from .osx_iconset import write_iconset from .install_theme import install_icon_theme __version__ = '0.1' PKt{K>$zzqtico/common.pyfrom pathlib import Path from typing import Union, Optional, Tuple, Iterable, Generator, List PATH_ICON_THEME = Path('icons') def k(n: Union[str, int]) -> int: return int(n) if n != 'scalable' else 10000 def all_sizes(dir_theme: Path) -> List[str]: return sorted((p.name.split('x')[0] for p in dir_theme.iterdir() if p.is_dir()), key=k) def size_dirs( dir_theme: Path, sizes: Optional[Iterable[Union[str, int]]]=None, ) -> Generator[Tuple[Union[str, int], Path], None, None]: if sizes is None: sizes = all_sizes(dir_theme) for s in sizes: n = '{0}x{0}'.format(s) if s != 'scalable' else s yield s, dir_theme / n PKTq{KG)pPPqtico/install_theme.pyimport os from warnings import warn from PyQt5.QtGui import QIcon from .common import PATH_ICON_THEME def theme_warning(*msgs): warn('NBManager: {} – using builtin theme'.format(' '.join(msgs))) def install_icon_theme(builtin_theme_name, theme_path=PATH_ICON_THEME, *, ignore_varnames=('USE_BUILTIN_ICON_THEME',)): ignore = {vn: os.environ.get(vn, '') for vn in ignore_varnames} forced = [vn for vn, val in ignore.items() if val] no_theme = not QIcon.themeName() if forced: theme_warning(', '.join(forced), set) paths = QIcon.themeSearchPaths() builtin = paths.pop(paths.index(':/{}'.format(theme_path))) QIcon.setThemeSearchPaths([builtin] + paths) # this is always available, but we force its use elif no_theme: theme_warning('no available theme found') if forced or no_theme: QIcon.setThemeName(builtin_theme_name) PKci{K+^55qtico/osx_iconset.pyfrom pathlib import Path from logging import getLogger from .common import size_dirs logger = getLogger(__name__) iconset_sizes = {16, 32, 128, 256, 512} def write_iconset(app_name: str, dir_themes: Path, dir_iconset: Path): """Create a OSX-compatible iconset. :param app_name: Your application’s name. We use the files ``/hicolor/x/.png``. :param dir_themes: A directory containing the freedesktop icon theme ``hicolor`` with all OSX-sized icons. :param dir_iconset: Directory where the iconset will be written to. """ logger.info('Creating iconset files %s', dir_iconset / 'icon_?x?[@2x].png') dir_iconset.mkdir(parents=True, exist_ok=True) for size, size_dir in size_dirs(dir_themes / 'hicolor', iconset_sizes): links = [dir_iconset / 'icon_{s}x{s}.png'.format(s=size)] if size // 2 in iconset_sizes: links += [dir_iconset / 'icon_{h}x{h}@2x.png'.format(h=size // 2)] target = size_dir / 'apps' / (app_name + '.png') for link in links: if link.is_symlink(): link.unlink() link.symlink_to('..' / target) PKFs{Km:7 7 qtico/qrc_compile.pyfrom pathlib import Path from logging import getLogger from warnings import warn from PyQt5.pyrcc_main import processResourceFile from .common import size_dirs, PATH_ICON_THEME logger = getLogger(__name__) template_qrc = '''\ {} '''.format template_qrc_file = '\t\t{}'.format def warn_suffix(path: Path, suffix: str): if not path.suffix == suffix: warn('path {!r} does not end with the suffix {!r}'.format(path, suffix)) def ensure_is_file(path: Path, creator: str): if not path.is_file(): raise FileNotFoundError('Could not find {}. Consider creating it via {}'.format(path, creator)) def write_resources( path_qrc: Path, path_rcpy: Path, dir_themes: Path=None, ): """Create a ``.qrc`` and a ``_rc.py`` file for your project containing all themes’ icons. Make sure your icon themes have an index.theme (We have a function for creating them!). :param path_qrc: A path to a ``.qrc`` file to write. Usually directly in the project directory. :param path_rcpy: A path to a compiled python file containing the resources. Usually ``*_rc.py``. :param dir_themes: A directory containing freedesktop icon themes with the necessary icons for your application. The default is ``{}`` next to ``path_qrc``. Needs to be next to or below ``path_qrc``. """.format(PATH_ICON_THEME) warn_suffix(path_qrc, '.qrc') warn_suffix(path_rcpy, '.py') dir_project = path_qrc.parent if dir_themes is None: dir_themes = dir_project / PATH_ICON_THEME if not dir_themes.is_absolute(): dir_themes = dir_project / dir_themes if dir_project not in dir_themes.parents: raise ValueError('path_qrc needs to be in a parent directory of dir_themes') files = [] for dir_theme in dir_themes.iterdir(): path_index = dir_theme / 'index.theme' from .theme_index import write_theme_indices ensure_is_file(path_index, write_theme_indices.__name__) files.append(template_qrc_file(path_index.relative_to(dir_project))) for _, size_dir in size_dirs(dir_theme): for sec in size_dir.iterdir(): for icon in sec.iterdir(): files.append(template_qrc_file(icon.relative_to(dir_project))) logger.info('Creating QRC file: %s', path_qrc) path_qrc.parent.mkdir(parents=True, exist_ok=True) with path_qrc.open('wt', encoding='utf-8') as qrc: qrc.write(template_qrc('\n'.join(files))) logger.info('Creating RC.py file %s from %s', path_rcpy, path_qrc) path_rcpy.parent.mkdir(parents=True, exist_ok=True) if not processResourceFile([str(path_qrc)], str(path_rcpy), False): raise OSError('Error during processing of resource file') PKas{K!1qtico/theme_index.pyfrom pathlib import Path from logging import getLogger from .common import size_dirs, PATH_ICON_THEME # just for refactoring names from .qrc_compile import write_resources from .install_theme import install_icon_theme logger = getLogger(__name__) contexts = dict( apps='Applications', mimetypes='MimeTypes', actions='Actions' ) template_index = '''\ [Icon Theme] Name={name} Inherits=default Directories={dirs} {sections} '''.format template_section = '''\ [{s}x{s}/{sec}] Size={s} Type=Fixed Context={ctx}\ '''.format template_scalable = '''\ [{s}/{sec}] Size=512 Type=Scalable MinSize=1 MaxSize=1024 Context={ctx}\ '''.format def write_theme_indices(dir_themes: Path): """Create index.theme files for all icon themes in the directory. If you use the directory name ``{}``, you can use ``{}`` and ``{}`` without specifying this. :param dir_themes: A directory containing freedesktop-compatible icon themes (without index.theme). """.format(PATH_ICON_THEME, write_resources.__name__, install_icon_theme.__name__) dirs = [] sections = [] for dir_theme in dir_themes.iterdir(): for size, size_dir in size_dirs(dir_theme): for sec in size_dir.iterdir(): dirs.append(str(sec.relative_to(dir_theme))) template = template_scalable if size == 'scalable' else template_section sections.append(template( s=size, sec=sec.name, ctx=contexts[sec.name], )) index_theme = dir_theme / 'index.theme' logger.info('Creating theme index file: %s', index_theme) with index_theme.open('wt', encoding='utf-8') as index: index.write(template_index( name=dir_theme.name.title(), dirs=','.join(dirs), sections='\n\n'.join(sections), )) PK!H0RRqtico-0.1.dist-info/WHEEL1 W% 0n1JBZS`ޝ/Qf:3&.~l" kW*дY00?PK!H x^ qtico-0.1.dist-info/METADATAVn6)ƀE7qY4-Ҡi~͢F"e#`' %۲-$8~D/3e Z8d#Xxhs81P9gZ\\ғ[ϱ@'Mq)gdu}9 fϫHM154N/Ur9~zelFP֋ƴN+?7v7sSъb,Gе '"'\TʢojRVO8:˥sj}%,P{WF#b@ځX3(R*ʐq~۴NҚ%f|>Q9T\rc$ޙ_I;CԎwzk!GBFloRҭ?[qvOϕR62t5Bj`]6"§ 5=?ϏVĎ1-͊LH|=zSv`JLq?ZUJf4TzW;ھv^9_ P ?70e]G̤56%M箅Bm-㧸5~T- 7mNM*|%51+.tD@Ж$YYqcbKY $tO"*牠i!,HΜ} [4ɦ։F}lSQ֭NN>x "8ppESAK@S{Ih\ m(0b&`$#ۦy{D{DݩA;!qb$-OZFMpluh,*{o;urI/}oLI&EoDg vѰ&;I7=?kWJr֦9NNb)CK/ޓT"﹦τsO5Yu3o{="!"}H$ٻNxOP /Ox 6+ac*3IBI9Ι> B6Yn΂h(oPK!HBռqtico-0.1.dist-info/RECORDmr@} aHPtC^25U.ݩn2ið$e˝⇶l}KZf9'NB_H2}es&A[% yaLJ ?һ+*lם1n(LI>/F/Zr>Ʀ[]_T`tSk)|$Pb9vf]\o4jDale$鉵$|k0U( ^x&7*#9 Y{|JNf79z;wtwlͬCPİ1Yz$Y7BeW,MUhMYyYHbV찼}n M+da&U  sĬ`#Kގk;E&d'UgQ?PKt{Kqtico/__init__.pyPKt{K>$zzJqtico/common.pyPKTq{KG)pPPqtico/install_theme.pyPKci{K+^55uqtico/osx_iconset.pyPKFs{Km:7 7  qtico/qrc_compile.pyPKas{K!1Eqtico/theme_index.pyPK!H0RRqtico-0.1.dist-info/WHEELPK!H x^ qtico-0.1.dist-info/METADATAPK!HBռf"qtico-0.1.dist-info/RECORDPK _Z$