aboutsummaryrefslogblamecommitdiff
path: root/helpers.py
blob: b4a0fe00da53e8c2bb4f04f9ae9080f40247b4f4 (plain) (tree)
1
2
                       
                    
























                                                               













                                         
                                         



























                                                                                                
                         

                     


                                                      
















                                                               








                                                             
                         

























































































































                                                                                          









                                                                                    
                                                                                          















































                                                                                           








































                                                                         
# -*- coding: utf-8 -*-
from pygame import *

class Action:
    action_types = [
        'pause',
        'play',
        'run',
        'stop',
        'volume',
        'wait',
    ]

    def __init__(self, action, **kwargs):
        if action in self.action_types:
            self.action = action
        else:
            raise Exception("Unknown action {}".format(action))

        self.arguments = kwargs

    def run(self, callback):
        getattr(self, self.action)(callback, **self.arguments)

    def stop(self, callback, musique = None, fade_out = 0):
        print('stopping')
        return callback()

class Key:
    row_positions = {
        'first':    5,
        'second':  55,
        'third':  105,
        'fourth': 155,
        'fifth':  205,
        'sixth':  255,
    }

    default_outer_color = (120, 120, 120)
    lighter_outer_color = (200, 200, 200)
    default_inner_color = (255, 255, 255)
    mapped_inner_color  = (  0, 255,   0)

    def __init__(self, key_name, key_sym, top, left, width = 48, height = 48, disabled = False):
        self.key_name = key_name
        self.key_sym  = key_sym

        if isinstance(top, str):
            self.top = self.row_positions[top]
        else:
            self.top = top

        self.left   = left
        self.width  = width
        self.height = height

        self.bottom = self.top  + self.height
        self.right  = self.left + self.width

        self.rect     = (self.left, self.top, self.right, self.bottom)
        self.position = (self.left, self.top)

        if disabled:
            self.outer_color = self.lighter_outer_color
            self.linewidth = 1
        else:
            self.outer_color = self.default_outer_color
            self.linewidth = 3

        self.inner_color = self.default_inner_color
        self.actions = []

    def square(self):
        if self.has_action():
            self.inner_color = self.mapped_inner_color

        return RoundedRect((0, 0, self.width, self.height),
            self.outer_color, self.inner_color, self.linewidth)

    def collidepoint(self, position):
        return self.surface.get_rect().collidepoint(
                position[0] - self.position[0],
                position[1] - self.position[1]
                )

    def draw(self, background_surface):
        self.surface = self.square().surface()

        police = font.Font(None, 20)
        text = police.render(self.key_sym, True, (0,0,0))
        self.surface.blit(text, (5,5))
        background_surface.blit(self.surface, self.position)

    def has_action(self):
        return len(self.actions) > 0

    def add_action(self, action_name, **arguments):
        self.actions.append(Action(action_name, **arguments))

    def next_action(self):
        print("running next action")

    def do_actions(self):
        self.current_action = 0
        print("running actions for {}".format(self.key_sym))
        if len(self.actions) > 0:
            self.actions[0].run(self.next_action)

    def find_from_unicode(key_sym):
        for key in Mapping.KEYS:
            if Mapping.KEYS[key].key_sym == key_sym:
                return Mapping.KEYS[key]
        return None

class Mapping:
    KEYS = {
        K_ESCAPE: Key(K_ESCAPE, 'ESC', 'first',   0),

        K_F1:     Key(K_F1,     'F1',  'first', 100),
        K_F2:     Key(K_F2,     'F2',  'first', 150),
        K_F3:     Key(K_F3,     'F3',  'first', 200),
        K_F4:     Key(K_F4,     'F4',  'first', 250),

        K_F5:     Key(K_F5,     'F5',  'first', 325),
        K_F6:     Key(K_F6,     'F6',  'first', 375),
        K_F7:     Key(K_F7,     'F7',  'first', 425),
        K_F8:     Key(K_F8,     'F8',  'first', 475),

        K_F9:     Key(K_F9,     'F9',  'first', 550),
        K_F10:    Key(K_F10,    'F10', 'first', 600),
        K_F11:    Key(K_F11,    'F11', 'first', 650),
        K_F12:    Key(K_F12,    'F12', 'first', 700),


        178:          Key(178,          '²', 'second',   0),
        K_AMPERSAND:  Key(K_AMPERSAND,  '&', 'second',  50),
        233:          Key(233,          'é', 'second', 100),
        K_QUOTEDBL:   Key(K_QUOTEDBL,   '"', 'second', 150),
        K_QUOTE:      Key(K_QUOTE,      "'", 'second', 200),
        K_LEFTPAREN:  Key(K_LEFTPAREN,  '(', 'second', 250),
        K_MINUS:      Key(K_MINUS,      '-', 'second', 300),
        232:          Key(232,          'è', 'second', 350),
        K_UNDERSCORE: Key(K_UNDERSCORE, '_', 'second', 400),
        231:          Key(231,          'ç', 'second', 450),
        224:          Key(224,          'à', 'second', 500),
        K_RIGHTPAREN: Key(K_RIGHTPAREN, ')', 'second', 550),
        K_EQUALS:     Key(K_EQUALS,     '=', 'second', 600),

        K_BACKSPACE:  Key(K_BACKSPACE,  '<-', 'second', 650, width = 98),


        K_TAB:        Key(K_TAB,        'tab', 'third',   0, width = 73),
        K_a:          Key(K_a,          'a',   'third',  75),
        K_z:          Key(K_z,          'z',   'third', 125),
        K_e:          Key(K_e,          'e',   'third', 175),
        K_r:          Key(K_r,          'r',   'third', 225),
        K_t:          Key(K_t,          't',   'third', 275),
        K_y:          Key(K_y,          'y',   'third', 325),
        K_u:          Key(K_u,          'u',   'third', 375),
        K_i:          Key(K_i,          'i',   'third', 425),
        K_o:          Key(K_o,          'o',   'third', 475),
        K_p:          Key(K_p,          'p',   'third', 525),
        K_CARET:      Key(K_CARET,      '^',   'third', 575),
        K_DOLLAR:     Key(K_DOLLAR,     '$',   'third', 625),

        K_RETURN: Key(K_RETURN, 'Enter', 'third', 692, width = 56, height = 98),

        K_CAPSLOCK: Key(K_CAPSLOCK,    'CAPS', 'fourth',  0, width = 88, disabled = True),

        K_q:        Key(K_q,        'q', 'fourth',  90),
        K_s:        Key(K_s,        's', 'fourth', 140),
        K_d:        Key(K_d,        'd', 'fourth', 190),
        K_f:        Key(K_f,        'f', 'fourth', 240),
        K_g:        Key(K_g,        'g', 'fourth', 290),
        K_h:        Key(K_h,        'h', 'fourth', 340),
        K_j:        Key(K_j,        'j', 'fourth', 390),
        K_k:        Key(K_k,        'k', 'fourth', 440),
        K_l:        Key(K_l,        'l', 'fourth', 490),
        K_m:        Key(K_m,        'm', 'fourth', 540),
        249:        Key(249,        'ù', 'fourth', 590),
        K_ASTERISK: Key(K_ASTERISK, '*', 'fourth', 640),


        K_LSHIFT: Key(K_LSHIFT, 'LShift', 'fifth', 0, width = 63, disabled = True),

        K_LESS:      Key(K_LESS,      '<', 'fifth',  65),
        K_w:         Key(K_w,         'w', 'fifth', 115),
        K_x:         Key(K_x,         'x', 'fifth', 165),
        K_c:         Key(K_c,         'c', 'fifth', 215),
        K_v:         Key(K_v,         'v', 'fifth', 265),
        K_b:         Key(K_b,         'b', 'fifth', 315),
        K_n:         Key(K_n,         'n', 'fifth', 365),
        K_COMMA:     Key(K_COMMA,     ',', 'fifth', 415),
        K_SEMICOLON: Key(K_SEMICOLON, ';', 'fifth', 465),
        K_COLON:     Key(K_COLON,     ':', 'fifth', 515),
        K_EXCLAIM:   Key(K_EXCLAIM,   '!', 'fifth', 565),

        K_RSHIFT: Key(K_RSHIFT, 'RShift', 'fifth', 615, width = 133, disabled = True),

        K_LCTRL:   Key(K_LCTRL,    'LCtrl',   'sixth', 0, width = 63, disabled = True),
        K_LSUPER:  Key(K_LSUPER,   'LSuper',  'sixth', 115, disabled = True),
        K_LALT:    Key(K_LALT,     'LAlt',    'sixth', 165, disabled = True),
        K_SPACE:   Key(K_SPACE,    'Espace',  'sixth', 215, width = 248),
        K_MODE:    Key(K_MODE,     'AltGr',   'sixth', 465, disabled = True),
        314:       Key(314,        'Compose', 'sixth', 515, disabled = True),
        K_RCTRL:   Key(K_RCTRL,    'RCtrl',   'sixth', 565, width = 63, disabled = True),


        K_INSERT:     Key(K_INSERT,   'ins',  'second', 755),
        K_HOME:       Key(K_HOME,     'home', 'second', 805),
        K_PAGEUP:     Key(K_PAGEUP,   'pg_u', 'second', 855),
        K_DELETE:     Key(K_DELETE,   'del',  'third',  755),
        K_END:        Key(K_END,      'end',  'third',  805),
        K_PAGEDOWN:   Key(K_PAGEDOWN, 'pg_d', 'third',  855),


        K_UP:         Key(K_UP,       'up',    'fifth',  805),
        K_DOWN:       Key(K_DOWN,     'down',  'sixth',  805),
        K_LEFT:       Key(K_LEFT,     'left',  'sixth',  755),
        K_RIGHT:      Key(K_RIGHT,    'right', 'sixth',  855),
    }

class MusicFile:
    def __init__(self, filename):
        self.filename = filename

class RoundedRect:
    def __init__(self, rect, outer_color, inner_color, linewidth = 2, radius = 0.4):
        self.rect        = Rect(rect)
        self.outer_color = Color(*outer_color)
        self.inner_color = Color(*inner_color)
        self.linewidth   = linewidth
        self.radius      = radius

    def surface(self):
        rectangle       = self.filledRoundedRect(self.rect, self.outer_color, self.radius)

        inner_rect      = Rect((
                self.rect.left   + 2 * self.linewidth,
                self.rect.top    + 2 * self.linewidth,
                self.rect.right  - 2 * self.linewidth,
                self.rect.bottom - 2 * self.linewidth
                ))

        inner_rectangle = self.filledRoundedRect(inner_rect, self.inner_color, self.radius)

        rectangle.blit(inner_rectangle, (self.linewidth, self.linewidth))

        return rectangle

    def filledRoundedRect(self, rect, color, radius=0.4):
        """
        filledRoundedRect(rect,color,radius=0.4)

        rect    : rectangle
        color   : rgb or rgba
        radius  : 0 <= radius <= 1
        """

        alpha        = color.a
        color.a      = 0
        pos          = rect.topleft
        rect.topleft = 0,0
        rectangle    = Surface(rect.size,SRCALPHA)

        circle       = Surface([min(rect.size)*3]*2,SRCALPHA)
        draw.ellipse(circle,(0,0,0),circle.get_rect(),0)
        circle       = transform.smoothscale(circle,[int(min(rect.size)*radius)]*2)

        radius              = rectangle.blit(circle,(0,0))
        radius.bottomright  = rect.bottomright
        rectangle.blit(circle,radius)
        radius.topright     = rect.topright
        rectangle.blit(circle,radius)
        radius.bottomleft   = rect.bottomleft
        rectangle.blit(circle,radius)

        rectangle.fill((0,0,0),rect.inflate(-radius.w,0))
        rectangle.fill((0,0,0),rect.inflate(0,-radius.h))

        rectangle.fill(color,special_flags=BLEND_RGBA_MAX)
        rectangle.fill((255,255,255,alpha),special_flags=BLEND_RGBA_MIN)

        return rectangle


def parse_config():
    import yaml
    stream = open("config.yml", "r")
    config = yaml.load(stream)
    stream.close()

    aliases = config['aliases']
    seen_files = {}

    for mapped_key in config['keys']:
        key = Key.find_from_unicode(mapped_key)
        if key is None:
            continue

        for action in config['keys'][mapped_key]:
            action_name = list(action)[0]
            action_args = {}
            if action[action_name] is None:
                action[action_name] = []

            for argument in action[action_name]:
                if argument == 'include':
                    included = action[action_name]['include']
                    if isinstance(included, str):
                        action_args.update(aliases[included])
                    else:
                        for included_ in included:
                            action_args.update(aliases[included_])
                elif argument == 'file':
                    filename = action[action_name]['file']
                    if filename not in seen_files:
                        seen_files[filename] = MusicFile.new(filename)

                    action_args['file'] = seen_files[filename]

                else:
                    action_args[argument] = action[action_name][argument]

            key.add_action(action_name, **action_args)