colours.py

Thu, 21 Dec 2017 12:27:16 +0200

author
Santeri Piippo
date
Thu, 21 Dec 2017 12:27:16 +0200
changeset 8
303c51137cb2
parent 4
ldraw.py@8eb83f200486
child 11
b42788f5d0a9
permissions
-rw-r--r--

Added ldconfig.ldr support

#!/usr/bin/env python3
class Colour:
    '''
        Colour interface. Supports LDConfig colours and direct colours.
        For LDConfig colours to work, load_colours must be called first.
    '''
    def __init__(self, index):
        if not isinstance(index, int):
            index = int(index, 0)
        self.index = index
    def __str__(self):
        if self.is_direct_colour:
            # write direct colours with hex codes
            return '0x%07X' % self.index
        else:
            return str(self.index)
    def __repr__(self):
        try:
            return 'colours.' + colours_inverse_dict[self.index]
        except KeyError:
            return str.format('Colour({!r})', self.index)
    @property
    def is_direct_colour(self):
        return self.index >= 0x2000000
    @property
    def is_ldconfig_colour(self):
        return self.index in ldconfig_colour_data
    @property
    def name(self):
        if self.is_ldconfig_colour:
            return ldconfig_colour_data[self.index]['name']
        else:
            return str(self)
    @property
    def face_colour(self):
        if self.is_ldconfig_colour:
            return ldconfig_colour_data[self.index]['value']
        elif self.is_direct_colour:
            return '#%06X' % (self.index & 0xffffff)
        else:
            return '#000000'
    @property
    def is_valid(self):
        return self.is_ldconfig_colour or self.is_direct_colour
    def __eq__(self, other):
        return self.index == other.index
    def __lt__(self, other):
        return self.index < other.index
    def __le__(self, other):
        return self.index <= other.index
    def __gt__(self, other):
        return self.index > other.index
    def __ge__(self, other):
        return self.index >= other.index

def parse_ldconfig_ldr_line(line):
    '''
        Parses a single LDConfig.ldr line.

        Returns:
            · a dict for a successful parsed colour.
            · None for empty lines and comments.

        Raises an error for invalid lines.
    '''
    line = line.strip()
    import re
    def parse_tag(tag):
        match = re.search(tag + r'\s+([^ ]+)', line)
        if match:
            return match.group(1)
        else:
            raise KeyError(str.format('Tag {} not found', tag))
    # parse 0 !COLOUR and get the name
    match = re.search(r'^0\s+!COLOUR\s([^ ]+)', line)
    if not match:
        # failed, check if it's an empty line or comment:
        if not line or line.startswith('0'):
            return None
        else:
            # failed too, thus the line is bad
            raise ValueError('Bad LDConfig.ldr line')
    # replace underscores for readability
    name = match.group(1).replace('_', ' ')
    # parse tags
    code = int(parse_tag('CODE'))
    value = parse_tag('VALUE')
    edge = parse_tag('EDGE')
    return {
        'name': name,
        'code': code,
        'value': value,
        'edge': edge,
    }

def parse_ldconfig_ldr(ldconfig_ldr):
    '''
        Parses LDConfig.ldr and returns pairs
    '''
    for line in ldconfig_ldr:
        colour = parse_ldconfig_ldr_line(line)
        if colour:
            yield (colour['code'], colour)

class colours:
    '''
        LDConfig colour namespace, exists for interactive mode and for
        Colour.__repr__ to return something pretty.
    '''
    pass

# LDConfig lookup tables
colours_inverse_dict = {}
ldconfig_colour_data = {}

def load_colours(ldconfig_ldr):
    '''
        Loads colours. Expects a file pointer to LDConfig.ldr as the parameter.
    '''
    global ldconfig_colour_data
    ldconfig_colour_data = dict(parse_ldconfig_ldr(ldconfig_ldr))
    for index, colour in ldconfig_colour_data.items():
        identifier = colour['name'].replace(' ', '_').lower()
        setattr(colours, identifier, Colour(index))
        colours_inverse_dict[index] = identifier

# Interactive mode support (pass LDConfig.ldr path as a command-line argument)
if __name__ == '__main__':
    from sys import argv
    with open(argv[1]) as ldconfig_ldr:
        load_colours(ldconfig_ldr)

mercurial