tuikit/driver_sdl.py
author Radek Brich <radek.brich@devl.cz>
Sun, 06 Jan 2013 13:55:02 +0100
changeset 53 c4263588b716
parent 50 c5b8b9d2da95
child 54 86b84535726e
permissions -rw-r--r--
DriverSDL: Implement cursor, handle window resize.

# -*- coding: utf-8 -*-
'''SDL driver.

Requires C++ extension module.
See sdlterm directory.

'''

from tuikit.driver import Driver

import logging

import sys
sys.path.insert(0, 'sdlterm/build/lib.linux-x86_64-3.2')
from sdlterm import SDLTerminal


class DriverSDL(Driver):

    '''SDL driver class'''

    color_map = {
        'black'         : 0,
        'blue'          : 1,
        'green'         : 2,
        'cyan'          : 3,
        'red'           : 4,
        'magenta'       : 5,
        'brown'         : 6,
        'lightgray'     : 7,
        'gray'          : 8,
        'lightblue'     : 9,
        'lightgreen'    : 10,
        'lightcyan'     : 11,
        'lightred'      : 12,
        'lightmagenta'  : 13,
        'yellow'        : 14,
        'white'         : 15,
    }

    style_map = {
        'bold'      : 1 << 0,  # bold font
        'underline' : 1 << 1,  # underline text
        'standout'  : 1 << 2,  # inverse bg/fg
        'blink'     : 1 << 3,  # blinking text
        'dim'       : 0,
    }

    def __init__(self):
        '''Initialize instance attributes'''
        Driver.__init__(self)
        self.log = logging.getLogger('tuikit')
        self.sdlterm = SDLTerminal()
        self.colors = {}     # maps names to attributes
        self.colorstack = [] # pushcolor/popcolor puts or gets attributes from this

    def start(self, mainfunc):
        '''Start driver and run mainfunc.'''
        self.sdlterm.resize(800, 600)
        self.sdlterm.select_font("sdlterm/font/DejaVuSansMono.ttf", "sdlterm/font/DejaVuSansMono-Bold.ttf", 12)
        self.size.w, self.size.h = self.sdlterm.width, self.sdlterm.height
        mainfunc()


    ## input ##

    def getevents(self, timeout=None):
        '''Process input, return list of events.'''
        event = self.sdlterm.get_next_event()
        if event[0] == 'resize':
            self.size.w, self.size.h = self.sdlterm.width, self.sdlterm.height
        return [event]


    ## drawing ##

    def erase(self):
        '''Clear screen.'''
        self.sdlterm.erase()

    def putch(self, x, y, c):
        '''Output one unicode character to specified coordinates.'''
        if not self.clipstack.test(x, y):
            return
        self.sdlterm.putch(x, y, c)

    def commit(self):
        '''Commit changes to the screen.'''
        self.sdlterm.commit()


    ## colors ##

    def setcolor(self, name, desc):
        '''Define color name.

        name - name of color (e.g. 'normal', 'active')
        desc - color description - foreground, background, attributes (e.g. 'black on white, bold')

        '''
        parts = desc.split(',')
        fg, bg = parts[0].split(' on ')
        style = parts[1:]
        fg = self._color_by_name(fg)
        bg = self._color_by_name(bg)
        style = self._style_by_names(style)
        self.colors[name] = self.sdlterm.prepare_attr(fg, bg, style);

    def pushcolor(self, name):
        '''Add color on top of stack and use this color for following output.'''
        if len(self.colorprefix):
            prefixname = self.colorprefix[-1] + name
            if prefixname in self.colors:
                name = prefixname
        attr = self.colors[name]
        self.sdlterm.set_attr(attr)
        self.colorstack.append(attr)

    def popcolor(self):
        '''Remove color from top of stack and use new top color for following output.'''
        self.colorstack.pop()
        if len(self.colorstack):
            attr = self.colorstack[-1]
        else:
            attr = 0
        self.sdlterm.set_attr(attr)

    def _color_by_name(self, name):
        name = name.lower().strip()
        return self.color_map[name]

    def _style_by_names(self, names):
        style = 0
        for name in names:
            name = name.lower().strip()
            style |= self.style_map[name]
        return style


    ## cursor ##

    def showcursor(self, x, y):
        '''Set cursor to be shown at x, y coordinates.'''
        if not self.clipstack.test(x, y):
            return
        self.sdlterm.show_cursor(x, y)

    def hidecursor(self):
        '''Hide cursor.'''
        self.sdlterm.hide_cursor()


driverclass = DriverSDL