Source code for domdf_wxpython_tools.panel_listctrl.css_parser

#!/usr/bin/env python
#
#  css_parser.py
#
#  Copyright (c) 2020 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
# generated by wxGlade 0.9.2 on Thu Jan 16 16:34:51 2020
#

# stdlib
from typing import Dict

# 3rd party
import tinycss  # type: ignore
import webcolors
import wx  # type: ignore
from domdf_python_tools.typing import PathLike

# this package
from domdf_wxpython_tools.panel_listctrl.constants import sys_colour_lookup, text_defaults

__all__ = ["parse_css_file", "parse_css"]

# Setup tinycss
parser = tinycss.make_parser("page3")


[docs]def parse_css_file(filename: PathLike) -> Dict: """ Parse the stylesheet in the given file. :param filename: The filename of the stylesheet to parse. :return: Parsed CSS stylesheet. """ stylesheet = parser.parse_stylesheet_file(css_file=str(filename)) return _parse_css(stylesheet)
[docs]def parse_css(css_data: str) -> Dict: """ Parse the stylesheet from the given string :param css_data: A string representing a CSS stylesheel :return: Parsed CSS stylesheet """ stylesheet = parser.parse_stylesheet(css_unicode=css_data) return _parse_css(stylesheet)
def _parse_css(stylesheet: tinycss.css21.Stylesheet) -> Dict: """ Internal function for actual parsing of css. :param stylesheet: A tinycss parsed stylesheet. :return: Parsed CSS stylesheet. """ if stylesheet.errors: raise ValueError(stylesheet.errors[0]) styles = {} # type: ignore # Remove declarations for other platforms and make for rule in stylesheet.rules: styles[rule.selector.as_css()] = {} for declaration in rule.declarations: name = declaration.name value = declaration.value.as_css() if "color" in name: value.lstrip("wx.") if value.startswith("SYS_COLOUR"): # wx.SystemColour if value in sys_colour_lookup: value = wx.SystemSettings.GetColour(sys_colour_lookup[value]) else: raise ValueError( f"""wx.SystemColour 'value' not recognised. See https://wxpython.org/Phoenix/docs/html/wx.SystemColour.enumeration.html for the list of valid values""" ) elif value.startswith('#'): # Hex value, pass to wx.Colour directly pass elif value.startswith("rgb("): # RGB value, convert to hex rgb_triplet = tuple(int(x) for x in value.lstrip("rgb(").rstrip(')').split(',')) value = webcolors.rgb_to_hex(rgb_triplet) # type: ignore else: # Named colour, convert to hex value = webcolors.name_to_hex(value) if name == "font-family": if value == "decorative": value = wx.FONTFAMILY_DECORATIVE elif value == "roman": value = wx.FONTFAMILY_ROMAN elif value == "script": value = wx.FONTFAMILY_SCRIPT elif value == "swiss": value = wx.FONTFAMILY_SWISS elif value == "modern": value = wx.FONTFAMILY_MODERN else: value = wx.FONTFAMILY_DEFAULT elif name == "font-style": if value == "slant": value = wx.FONTSTYLE_SLANT elif value == "italic": value = wx.FONTSTYLE_ITALIC else: value = wx.FONTSTYLE_NORMAL elif name == "font-weight": if value == "light": value = wx.FONTWEIGHT_LIGHT elif value == "bolt": value = wx.FONTWEIGHT_BOLD else: value = wx.FONTWEIGHT_NORMAL styles[rule.selector.as_css()][name] = value # if li p is not styled, use the default values if "li p" not in styles: styles["li p"] = text_defaults.copy() # If li p is missing any parameters, add them from the default values styles["li p"] = {**text_defaults, **styles["li p"]} # if li p::selection is not styled, use the values from p if "li p::selection" not in styles: styles["li p::selection"] = styles["li p"].copy() # If li p is missing any parameters, add them from p styles["li p::selection"] = {**styles["li p"], **styles["li p::selection"]} # For each li p class, add undefined values from p for style in styles: if style.split('.')[0] == "li p": if style == "li p": continue if "::selection" in style: continue styles[style] = {**styles["li p"], **styles[style]} # For each p::selection class, add undefined values from p::selection for style in styles: if style.split('.')[0] == "li p": if style == "li p::selection": continue if "::selection" not in style: continue styles[style] = {**styles["li p::selection"], **styles[style]} return styles