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