Add support for the extensions syntax in configurations.

main
Alex Huszagh 2021-07-19 21:51:24 -05:00
parent 458fb583dc
commit 846254032c
12 changed files with 500 additions and 236 deletions

View File

@ -243,10 +243,24 @@ python configure.py --styles=dark,light,<custom> --resource custom.qrc
Then, you can use `custom.qrc`, along with the generated icons and stylesheets in each folder, in place of `breeze.qrc` for any style.
The `--styles` command flag takes a comma-separated list of values, or `all`, which will configure every theme present in the [themes](/theme) directory.
**Generating Colors**
As a reference point, see the pre-generated [themes](/theme). In general, to create a good theme, modify only the highlight colors (blues, greens, purples) to a new color, such that the saturation and lightness stay the same (only the hue changes). For example, the color `rgba(51, 164, 223, 0.5)` becomes `rgba(164, 51, 223, 0.5)`.
**Extensions**
We also allow customizable extensions to extend the default stylesheets with additional style rules, using the colors defined in your theme. This also enables the integration of third-party Qt plugins/widgets into the generated stylesheets.
For example, to configure with extensions for the [Advanced Docking System](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System), run:
```bash
python configure.py --extensions=advanced-docking-system --resource custom.qrc
```
Like with styles, `--extensions` takes a comma-separated list of values, or `all`, which will add every extension present in the [extensions](/extension) directory. For a detailed introduction to creating your own extensions, see the extensions [tutorial](/extensions/README.md).
# Limitations
There are some limitations of using Qt stylesheets in general, which cannot be solved by stylesheets. To get more fine-grained style control, you should subclass `QCommonStyle`:
@ -271,6 +285,7 @@ The limitations of stylesheets include:
- Complete stylesheet for all Qt widgets, including esoteric widgets like `QCalendarWidget`.
- Customizable, beautiful light and dark themes.
- Cross-platform icon packs for standard icons.
- Extensible stylesheets: add your own plugins or rules and automatically configure them using the same configuration syntax.
# Debugging

View File

@ -8,18 +8,26 @@
import argparse
import glob
import json
import re
import os
import re
import sys
home = os.path.dirname(os.path.realpath(__file__))
# Create our arguments.
def parse_args(argv=None):
'''Parse the command-line options.'''
parser = argparse.ArgumentParser(description='Styles to configure for a Qt application.')
parser.add_argument(
'--styles',
help='''comma-separate list of styles to configure. pass `all` to build all themes''',
default='light,dark',
)
parser.add_argument(
'--extensions',
help='''comma-separate list of styles to configure. pass `all` to build all themes''',
default='',
)
parser.add_argument(
'--resource',
help='''output resource file name''',
@ -30,151 +38,82 @@ parser.add_argument(
help='''use PyQt6 rather than PyQt5.''',
action='store_true'
)
args = parser.parse_args(argv)
parse_styles(args)
parse_extensions(args)
set_style_home(args)
# List of all icons to configure.
icons = {
# Arrows
'down_arrow': {
'default': ['foreground:hex', 'foreground:opacity'],
'hover': ['highlight:hex', 'highlight:opacity'],
'disabled': ['midtone:light:hex', 'midtone:light:opacity'],
},
'left_arrow': {
'default': ['foreground'],
'disabled': ['midtone:light'],
},
'right_arrow': {
'default': ['foreground'],
'disabled': ['midtone:light'],
},
'up_arrow': {
'default': ['foreground:hex', 'foreground:opacity'],
'hover': ['highlight:hex', 'highlight:opacity'],
'disabled': ['midtone:light:hex', 'midtone:light:opacity'],
},
# Abstract buttons.
'checkbox_checked': {
'default': ['checkbox:light'],
'disabled': ['checkbox:disabled'],
},
'checkbox_indeterminate': {
'default': ['checkbox:light'],
'disabled': ['checkbox:disabled'],
},
'checkbox_unchecked': {
'default': ['checkbox:light'],
'disabled': ['checkbox:disabled'],
},
'radio_checked': {
'default': ['checkbox:light'],
'disabled': ['checkbox:disabled'],
},
'radio_unchecked': {
'default': ['checkbox:light'],
'disabled': ['checkbox:disabled'],
},
# Dock/Tab widgets
'close': {
'default': ['midtone:dark:hex', 'midtone:dark:opacity'],
'hover': ['close:hover:hex', 'close:hover:opacity'],
'pressed': ['close:pressed:hex', 'close:pressed:opacity'],
},
'undock': {
'default': ['dock:float'],
},
'undock_hover': {
'default': ['dock:float', 'foreground'],
},
# Tree views.
'branch_open': {
'default': ['tree:hex', 'tree:opacity'],
'hover': ['highlight:hex', 'highlight:opacity'],
},
'branch_closed': {
'default': ['tree:hex', 'tree:opacity'],
'hover': ['highlight:hex', 'highlight:opacity'],
},
'branch_end': {
'default': ['tree'],
},
'branch_end_arrow': {
'default': ['tree'],
},
'branch_more': {
'default': ['tree'],
},
'branch_more_arrow': {
'default': ['tree'],
},
'vline': {
'default': ['tree'],
},
'calendar_next': {
'default': ['foreground'],
},
'calendar_previous': {
'default': ['foreground'],
},
'transparent': {
'default': [],
},
'hmovetoolbar': {
'default': ['midtone:light'],
},
'vmovetoolbar': {
'default': ['midtone:light'],
},
'hseptoolbar': {
'default': ['midtone:light'],
},
'vseptoolbar': {
'default': ['midtone:light'],
},
'sizegrip': {
'default': ['midtone:light'],
},
# Dialog icons
'dialog-cancel': {
'default': ['foreground'],
},
'dialog-close': {
'default': ['foreground'],
},
'dialog-ok': {
'default': ['foreground'],
},
'dialog-open': {
'default': ['foreground'],
},
'dialog-save': {
'default': ['foreground'],
},
'dialog-reset': {
'default': ['foreground'],
},
'dialog-help': {
'default': ['foreground'],
},
'dialog-no': {
'default': ['foreground'],
},
'dialog-discard': {
'default': ['foreground'],
},
# Message icons
'message-critical': {
'default': ['critical', 'foreground'],
},
'message-information': {
'default': ['information', 'foreground'],
},
'message-question': {
'default': ['question', 'foreground'],
},
'message-warning': {
'default': ['warning', 'foreground'],
},
return args
def load_json(path):
'''Read a JSON file with limited comments support.'''
# Note: we need comments for maintainability, so we
# can annotate what works and the rationale, but
# we don't want to prevent code from working without
# a complex parser, so we do something very simple:
# only remove lines starting with '//'.
with open(path) as file:
lines = file.read().splitlines()
lines = [i for i in lines if not i.strip().startswith('//')]
return json.loads('\n'.join(lines))
def read_template_dir(directory):
'''Read the template data from a directory'''
data = {
'stylesheet': open(f'{directory}/stylesheet.qss.in').read(),
'icons': [],
}
icon_data = load_json(f'{directory}/icons.json')
for file in glob.glob(f'{directory}/*.svg.in'):
svg = open(file).read()
name = os.path.splitext(os.path.splitext(os.path.basename(file))[0])[0]
if name in icon_data:
replacements = icon_data[name]
else:
# Need to find all the values inside the image.
keys = re.findall(r'\^[0-9a-zA-Z_-]+\^', svg)
replacements = [i[1:-1] for i in keys]
data['icons'].append({
'name': name,
'svg': svg,
'replacements': replacements,
})
return data
def split_csv(string):
'''Split a list of values provided as comma-separated values.'''
values = string.split(',')
return [i for i in values if i]
def parse_styles(args):
'''Parse a list of valid styles.'''
values = split_csv(args.styles)
if 'all' in values:
files = glob.glob(f'{home}/theme/*json')
values = [os.path.splitext(os.path.basename(i))[0] for i in files]
args.styles = values
def parse_extensions(args):
'''Parse a list of valid extensions.'''
values = split_csv(args.extensions)
if 'all' in values:
files = glob.glob(f'{home}/extension/*/*stylesheet.qss.in')
values = [os.path.basename(os.path.dirname(i)) for i in files]
args.extensions = values
def set_style_home(args):
'''Get the home directory to write the configured styles to.'''
if args.pyqt6:
args.style_home = f'{home}/pyqt6'
else:
args.style_home = f'{home}'
def parse_hexcolor(color):
'''Parse a hexadecimal color.'''
@ -219,70 +158,119 @@ def parse_color(color):
return parse_rgba(color)
raise NotImplementedError
def replace(contents, colors, color_map):
'''Replace all template values.'''
def icon_basename(icon, extension):
'''Get the basename for an icon.'''
if extension == 'default':
return icon
return f'{icon}_{extension}'
def replace_by_name(contents, theme, colors=None):
'''Replace values by color name.'''
# The placeholders have a syntax like `^foreground^`.
# To simplify the replacement process, you can specify
# a limited subset of colors, rather than use all of them.
if colors is None:
colors = theme.keys()
for key in colors:
color = theme[key]
contents = contents.replace(f'^{key}^', color)
return contents
def replace_by_index(contents, theme, colors):
'''Replace values by color name.'''
# The placeholders have a syntax like `^0^`, where
# the is a list of valid colors and the index of
# the color is the replacement key.
# This is useful since we can want multiple colors
# for the same icon (such as hovered arrows).
for index, key in enumerate(colors):
sub = f'^{index}^'
# Need special handling if we have a hex or non:hex character.
# Need special handle values with opacities. Standard
# SVG currently does not support `rgba` syntax, with an
# opacity, but it does provide `fill-opacity` and `stroke-opacity`.
# Therefore, if the replacement specifies `opacity` or `hex`,
# parse the color, get the correct value, and use only that
# for the replacement.
if key.endswith(':hex'):
color = color_map[key[:-len(':hex')]]
color = theme[key[:-len(':hex')]]
rgb = [f"{i:02x}" for i in parse_color(color)[:3]]
value = f'#{"".join(rgb)}'
elif key.endswith(':opacity'):
color = color_map[key[:-len(':opacity')]]
color = theme[key[:-len(':opacity')]]
value = str(parse_color(color)[3])
else:
value = color_map[key]
value = theme[key]
contents = contents.replace(sub, value)
return contents
def configure_icons(style, color_map):
def configure_icons(config, style):
'''Configure icons for a given style.'''
for icon, extensions in icons.items():
template = f'{home}/template/{icon}.svg.in'
template_contents = open(template).read()
for extension, colors in extensions.items():
contents = replace(template_contents, colors, color_map)
if extension == 'default':
filename = f'{style_home}/{style}/{icon}.svg'
theme = config['themes'][style]
style_home = config['style_home']
for template in config['templates']:
for icon in template['icons']:
replacements = icon['replacements']
name = icon['name']
if isinstance(replacements, dict):
# Then we have the following format:
# The key is the substate of the icon, such
# as default, hover, pressed, etc, and the value
# is an ordered list of replacements.
for ext, colors in replacements.items():
contents = replace_by_index(icon['svg'], theme, colors)
filename = f'{style_home}/{style}/{icon_basename(name, ext)}.svg'
with open(filename, 'w') as file:
file.write(contents)
else:
filename = f'{style_home}/{style}/{icon}_{extension}.svg'
# Then we just have a list of replacements for the
# icon, using standard colors. For example,
# replacement values might be `^foreground^`.
assert isinstance(replacements, list)
contents = replace_by_name(icon['svg'], theme, replacements)
filename = f'{style_home}/{style}/{name}.svg'
with open(filename, 'w') as file:
file.write(contents)
def configure_stylesheet(style, color_map):
def configure_stylesheet(config, style):
'''Configure the stylesheet for a given style.'''
contents = open(f'{home}/template/stylesheet.qss.in').read()
for key, color in color_map.items():
contents = contents.replace(f'^{key}^', color)
if args.pyqt6:
contents = '\n'.join([i['stylesheet'] for i in config['templates']])
contents = replace_by_name(contents, config['themes'][style])
# Need to replace the URL paths for loading icons/
# assets. In C++ Qt and PyQt5, this uses the resource
# system, AKA, `url(:/dark/path/to/resource)`. In PyQt6, the
# resource system has been replaced to use native
# Python packaging, so we define a user-friendly name
# based on the theme name, so `url(dark:path/to/resource)`.
if config['pyqt6']:
contents = contents.replace('^style^', f'{style}:')
else:
contents = contents.replace('^style^', f':/{style}/')
with open(f'{style_home}/{style}/stylesheet.qss', 'w') as file:
with open(f'{config["style_home"]}/{style}/stylesheet.qss', 'w') as file:
file.write(contents)
def configure_style(style, color_map):
def configure_style(config, style):
'''Configure the icons and stylesheet for a given style.'''
os.makedirs(f'{style_home}/{style}', exist_ok=True)
configure_icons(style, color_map)
configure_stylesheet(style, color_map)
os.makedirs(f'{config["style_home"]}/{style}', exist_ok=True)
configure_icons(config, style)
configure_stylesheet(config, style)
def write_xml(styles, path):
def write_xml(config):
'''Simple QRC writer.'''
# Can't be used with PyQt6.
assert not args.pyqt6
# rcc doesn't exist for PyQt6
assert not config['pyqt6']
resources = []
for style in styles:
files = os.listdir(f'{style_home}/{style}')
for style in config['themes'].keys():
files = os.listdir(f'{config["style_home"]}/{style}')
resources += [f'{style}/{i}' for i in files]
with open(path, 'w') as file:
with open(config['path'], 'w') as file:
print('<RCC>', file=file)
print(' <qresource>', file=file)
for resource in sorted(resources):
@ -290,34 +278,34 @@ def write_xml(styles, path):
print(' </qresource>', file=file)
print('</RCC>', file=file)
def configure(styles, path):
def configure(args):
'''Configure all styles and write the files to a QRC file.'''
for style in styles:
# Note: we need comments for maintainability, so we
# can annotate what works and the rationale, but
# we don't want to prevent code from working without
# a complex parser, so we do something very simple:
# only remove lines starting with '//'.
with open(f'{home}/theme/{style}.json') as file:
lines = file.read().splitlines()
lines = [i for i in lines if not i.strip().startswith('//')]
color_map = json.loads('\n'.join(lines))
configure_style(style, color_map)
# Need to convert our styles accordingly.
config = {
'themes': {},
'templates': [],
'pyqt6': args.pyqt6,
'style_home': args.style_home,
'path': args.resource
}
config['templates'].append(read_template_dir(f'{home}/template'))
for style in args.styles:
config['themes'][style] = load_json(f'{home}/theme/{style}.json')
for extension in args.extensions:
config['templates'].append(read_template_dir(f'{home}/extension/{extension}'))
for style in config['themes'].keys():
configure_style(config, style)
if not args.pyqt6:
# No point generating a resource file for PyQt6,
# since we can't use rcc6 anyway.
write_xml(styles, path)
write_xml(config)
def main(argv=None):
'''Configuration entry point'''
configure(parse_args(argv))
if __name__ == '__main__':
args = parser.parse_args()
styles = args.styles.split(',')
if args.pyqt6:
style_home = f'{home}/pyqt6'
else:
style_home = f'{home}'
if args.styles == 'all':
files = glob.glob(f'{home}/theme/*json')
styles = [os.path.splitext(os.path.basename(i))[0] for i in files]
configure(styles, args.resource)
sys.exit(main())

View File

@ -12,7 +12,7 @@
* The MIT License (MIT)
*
* Copyright (c) <2013-2014> <Colin Duquesnoy>
* Copyright (c) <2015-2016> <Alex Huszagh>
* Copyright (c) <2015-2021> <Alex Huszagh>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -1951,3 +1951,36 @@ QMessageBox QPushButton
min-height: 1.1em;
min-width: 5em;
}
/*
* Extension stylesheet for the Advanced Docking System.
*
* :author: Alex Huszagh
* :license: MIT, see LICENSE.md
*
* ---------------------------------------------------------------------
* The MIT License (MIT)
*
* Copyright (c) <2021> <Alex Huszagh>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ---------------------------------------------------------------------
*/

11
extension/README.md Normal file
View File

@ -0,0 +1,11 @@
extensions
==========
Extensions enable the creation of stylesheets using the same, customizable themes of the original stylesheet. This both allows refining the generated stylesheet and supporting third-party Qt plugins/widgets.
**TODO(ahuszagh)**
- Describe stylesheet.qss.in
- Describe icons.json
Document this...

View File

@ -0,0 +1,4 @@
// NOTE: This is a custom JSON file, where lines leading
// with `//` are removed. No other comments are valid.
{
}

View File

@ -0,0 +1,32 @@
/*
* Extension stylesheet for the Advanced Docking System.
*
* :author: Alex Huszagh
* :license: MIT, see LICENSE.md
*
* ---------------------------------------------------------------------
* The MIT License (MIT)
*
* Copyright (c) <2021> <Alex Huszagh>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ---------------------------------------------------------------------
*/

View File

@ -12,7 +12,7 @@
* The MIT License (MIT)
*
* Copyright (c) <2013-2014> <Colin Duquesnoy>
* Copyright (c) <2015-2016> <Alex Huszagh>
* Copyright (c) <2015-2021> <Alex Huszagh>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -1951,3 +1951,36 @@ QMessageBox QPushButton
min-height: 1.1em;
min-width: 5em;
}
/*
* Extension stylesheet for the Advanced Docking System.
*
* :author: Alex Huszagh
* :license: MIT, see LICENSE.md
*
* ---------------------------------------------------------------------
* The MIT License (MIT)
*
* Copyright (c) <2021> <Alex Huszagh>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ---------------------------------------------------------------------
*/

View File

@ -1,4 +0,0 @@
recipes
=======
Sample recipes and template files for adding third-party Qt widgets and stylesheets into BreezeStyleSheets.

View File

@ -1,11 +0,0 @@
<svg height="90" width="90">
<g transform="matrix(4.05,0,0,4.05,4.55,12.55)">
<g fill="^0^" fill-rule="evenodd" transform="translate(-255,-381)">
<g transform="translate(255,381)">
<path d="M 14,0 H 2 C 0.9,0 0,0.9 0,2 v 14 c 0,1.1 0.9,2 2,2 h 14 c 1.1,0 2,-0.9 2,-2 V 4 Z M 9,16 c -1.7,0 -3,-1.3 -3,-3 0,-1.7 1.3,-3 3,-3 1.7,0 3,1.3 3,3 0,1.7 -1.3,3 -3,3 z M 12,6 H 2 V 2 h 10 z"/>
</g>
</g>
</g>
<path stroke="^0^" stroke-width="4" fill="none" d="m 18.798165,13.22123 c 0,-3.588874 2.889238,-6.478111 6.478111,-6.478111 h 6.51694 6.516941 6.51694 6.51694 6.51694 6.51694 m 0,0 h 6.516941 m 12.995051,13.36252 v 6.884409 6.884409 6.88441 6.884409 6.884409 6.884409 6.884409 c 0,3.588873 -2.889237,6.47811 -6.478111,6.47811"/>
<path stroke="^0^" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter" d="M 69.439106,6.1172946 84.439417,21.496069"/>
</svg>

Before

Width:  |  Height:  |  Size: 900 B

163
template/icons.json Normal file
View File

@ -0,0 +1,163 @@
// NOTE: This is a custom JSON file, where lines leading
// with `//` are removed. No other comments are valid.
{
// There's 3 different ways to provide valid replacement colors for
// icons:
// 1. Provide a dict of the icon suffix to the color replacements.
// This will do index-based replacement, so, for example,
// `"down_arrow": { "default": ["foreground"] }` will
// replace the `down_arrow` template and create an icon
// named `down_arrow.svg` with `^0^` replaced by the
// theme's foreground color.
// 2. Provide a list to the color replacements.
// This will do name-based replacement, so, for example,
// `"down_arrow": ["foreground"]` will replace the
// `down_arrow` template and create an icon named
// `down_arrow.svg` with `^foreground^` replaced by
// the theme's foreground color.
// 3. Don't provide an entry for the icon.
// The replacements will be auto-deduced from the file,
// and will use name-based replacement like above.
// Arrows
"down_arrow": {
"default": ["foreground:hex", "foreground:opacity"],
"hover": ["highlight:hex", "highlight:opacity"],
"disabled": ["midtone:light:hex", "midtone:light:opacity"]
},
"left_arrow": {
"default": ["foreground"],
"disabled": ["midtone:light"]
},
"right_arrow": {
"default": ["foreground"],
"disabled": ["midtone:light"]
},
"up_arrow": {
"default": ["foreground:hex", "foreground:opacity"],
"hover": ["highlight:hex", "highlight:opacity"],
"disabled": ["midtone:light:hex", "midtone:light:opacity"]
},
// Abstract buttons.
"checkbox_checked": {
"default": ["checkbox:light"],
"disabled": ["checkbox:disabled"]
},
"checkbox_indeterminate": {
"default": ["checkbox:light"],
"disabled": ["checkbox:disabled"]
},
"checkbox_unchecked": {
"default": ["checkbox:light"],
"disabled": ["checkbox:disabled"]
},
"radio_checked": {
"default": ["checkbox:light"],
"disabled": ["checkbox:disabled"]
},
"radio_unchecked": {
"default": ["checkbox:light"],
"disabled": ["checkbox:disabled"]
},
// Dock/Tab widgets
"close": {
"default": ["midtone:dark:hex", "midtone:dark:opacity"],
"hover": ["close:hover:hex", "close:hover:opacity"],
"pressed": ["close:pressed:hex", "close:pressed:opacity"]
},
"undock": {
"default": ["dock:float"]
},
"undock_hover": {
"default": ["dock:float", "foreground"]
},
// Tree views.
"branch_open": {
"default": ["tree:hex", "tree:opacity"],
"hover": ["highlight:hex", "highlight:opacity"]
},
"branch_closed": {
"default": ["tree:hex", "tree:opacity"],
"hover": ["highlight:hex", "highlight:opacity"]
},
"branch_end": {
"default": ["tree"]
},
"branch_end_arrow": {
"default": ["tree"]
},
"branch_more": {
"default": ["tree"]
},
"branch_more_arrow": {
"default": ["tree"]
},
"vline": {
"default": ["tree"]
},
"calendar_next": {
"default": ["foreground"]
},
"calendar_previous": {
"default": ["foreground"]
},
"transparent": {
"default": []
},
"hmovetoolbar": {
"default": ["midtone:light"]
},
"vmovetoolbar": {
"default": ["midtone:light"]
},
"hseptoolbar": {
"default": ["midtone:light"]
},
"vseptoolbar": {
"default": ["midtone:light"]
},
"sizegrip": {
"default": ["midtone:light"]
},
// Dialog icons
"dialog-cancel": {
"default": ["foreground"]
},
"dialog-close": {
"default": ["foreground"]
},
"dialog-ok": {
"default": ["foreground"]
},
"dialog-open": {
"default": ["foreground"]
},
"dialog-save": {
"default": ["foreground"]
},
"dialog-reset": {
"default": ["foreground"]
},
"dialog-help": {
"default": ["foreground"]
},
"dialog-no": {
"default": ["foreground"]
},
"dialog-discard": {
"default": ["foreground"]
},
// Message icons
"message-critical": {
"default": ["critical", "foreground"]
},
"message-information": {
"default": ["information", "foreground"]
},
"message-question": {
"default": ["question", "foreground"]
},
"message-warning": {
"default": ["warning", "foreground"]
}
}

View File

@ -12,7 +12,7 @@
* The MIT License (MIT)
*
* Copyright (c) <2013-2014> <Colin Duquesnoy>
* Copyright (c) <2015-2016> <Alex Huszagh>
* Copyright (c) <2015-2021> <Alex Huszagh>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the