# HG changeset patch # User Radek Brich # Date 1318373926 -7200 # Node ID 139d1241b4c56408bdc0bd0c035aebb1dcfae7a6 # Parent 37745c5abc4920c674be5ac874e9d9b9348eed9b DriverPygame: add colors, make window resizable. diff -r 37745c5abc49 -r 139d1241b4c5 tuikit/driver.py --- a/tuikit/driver.py Tue Oct 11 10:09:58 2011 +0200 +++ b/tuikit/driver.py Wed Oct 12 00:58:46 2011 +0200 @@ -16,9 +16,11 @@ '''Clipping region stack.''' self.unigraph = UnicodeGraphics() '''Unicode graphics characters.''' + self.colorprefix = [] + '''Stack of color prefixes.''' - # drawing + ## drawing ## def puts(self, x, y, s): '''Output string of characters.''' @@ -55,4 +57,12 @@ self.vline(x, y+1, h-2, self.unigraph.VLINE) self.vline(x+w-1, y+1, h-2, self.unigraph.VLINE) - \ No newline at end of file + + ## colors ## + + def pushcolorprefix(self, name): + self.colorprefix.append(name) + + def popcolorprefix(self): + self.colorprefix.pop() + diff -r 37745c5abc49 -r 139d1241b4c5 tuikit/driver_curses.py --- a/tuikit/driver_curses.py Tue Oct 11 10:09:58 2011 +0200 +++ b/tuikit/driver_curses.py Wed Oct 12 00:58:46 2011 +0200 @@ -47,7 +47,7 @@ (0x1b,0x5b,0x5b,0x45, 'f5' ), # linux ) - color_names = { + color_map = { 'black' : curses.COLOR_BLACK, 'blue' : curses.COLOR_BLUE, 'cyan' : curses.COLOR_CYAN, @@ -58,6 +58,14 @@ 'yellow' : curses.COLOR_YELLOW, } + attr_map = { + 'blink' : curses.A_BLINK, + 'bold' : curses.A_BOLD, + 'dim' : curses.A_DIM, + 'standout' : curses.A_STANDOUT, + 'underline' : curses.A_UNDERLINE, + } + def __init__(self): '''Set driver attributes to default values.''' Driver.__init__(self) @@ -67,7 +75,6 @@ self.colors = {} # maps names to curses attributes self.colorpairs = {} # maps tuple (fg,bg) to curses color_pair self.colorstack = [] # pushcolor/popcolor puts or gets attributes from this - self.colorprefix = [] # stack of color prefixes self.inputqueue = [] self.mbtnstack = [] @@ -92,7 +99,7 @@ def _parsecolor(self, name): name = name.lower().strip() - return self.color_names[name] + return self.color_map[name] def _getcolorpair(self, fg, bg): pair = (fg, bg) @@ -107,14 +114,7 @@ res = 0 for a in attrs: a = a.lower().strip() - trans = { - 'blink' : curses.A_BLINK, - 'bold' : curses.A_BOLD, - 'dim' : curses.A_DIM, - 'standout' : curses.A_STANDOUT, - 'underline' : curses.A_UNDERLINE, - } - res = res | trans[a] + res = res | self.attr_map[a] return res def setcolor(self, name, desc): @@ -128,7 +128,7 @@ self.colors[name] = curses.color_pair(col) | attr def pushcolor(self, name): - # add prefix if available + # add prefix if such color is available if len(self.colorprefix): prefixname = self.colorprefix[-1] + name if prefixname in self.colors: @@ -144,13 +144,7 @@ else: attr = 0 self.screen.attrset(attr) - - def pushcolorprefix(self, name): - self.colorprefix.append(name) - - def popcolorprefix(self): - self.colorprefix.pop() - + ## drawing ## diff -r 37745c5abc49 -r 139d1241b4c5 tuikit/driver_pygame.py --- a/tuikit/driver_pygame.py Tue Oct 11 10:09:58 2011 +0200 +++ b/tuikit/driver_pygame.py Wed Oct 12 00:58:46 2011 +0200 @@ -17,7 +17,9 @@ ''' def __init__(self): - self.font = pygame.font.SysFont('dejavusansmono,liberationmono,freemono', 14) + fontselect = 'dejavusansmono,liberationmono,freemono' + self.font = pygame.font.SysFont(fontselect, 14) + self.font_bold = pygame.font.SysFont(fontselect, 14, True) # get advance of some random char (all should be same in monospace font) advance = self.font.metrics('Q')[0][4] height = self.font.get_height() @@ -30,7 +32,7 @@ else: self.render = self.render_noglyph - def render_glyph(self, screen, x, y, c, fgcolor, bgcolor): + def render_glyph(self, screen, x, y, c, fgcolor, bgcolor, attr): '''Render using render_glyph and metrics. This is the correct way, but the output seems same as of render_noglyph @@ -39,9 +41,14 @@ This implements render() method. See render_noglyph for other implementation. ''' + if attr == 'bold': + font = self.font_bold + else: + font = self.font + # render character, get metrics - surface = self.font.render_glyph(c, True, fgcolor, bgcolor) - metrics = self.font.metrics(c)[0] + surface = font.render_glyph(c, True, fgcolor, bgcolor) + metrics = font.metrics(c)[0] minx, maxx, miny, maxy, advance = metrics height, ascent = self.charsize.h, self.ascent @@ -68,15 +75,20 @@ area = pygame.Rect(startx, starty, maxx - minx, maxy - miny) screen.blit(surface, tuple(dest), area) - def render_noglyph(self, screen, x, y, c, fgcolor, bgcolor): + def render_noglyph(self, screen, x, y, c, fgcolor, bgcolor, attr): '''Render character using normal text rendering. This implements render() method. See render_glyph for other implementation. - ''' + ''' + if attr == 'bold': + font = self.font_bold + else: + font = self.font + # render character, get metrics - surface = self.font.render(c, True, fgcolor, bgcolor) - metrics = self.font.metrics(c)[0] + surface = font.render(c, True, fgcolor, bgcolor) + metrics = font.metrics(c)[0] minx = metrics[0] startx = 0 if minx < 0: @@ -95,7 +107,7 @@ '''PyGame driver class.''' - key_map = { + keymap = { pygame.K_ESCAPE : 'escape', pygame.K_TAB : 'tab', pygame.K_RETURN : 'enter', @@ -127,15 +139,23 @@ pygame.K_PAUSE : 'pause', } - color_map = { - 'black' : (0,0,0), - 'blue' : (0,0,0), - 'cyan' : (0,0,0), - 'green' : (0,0,0), - 'magenta' : (0,0,0), - 'red' : (0,0,0), - 'white' : (0,0,0), - 'yellow' : (0,0,0), + colormap = { + 'black' : (0,0,0), + 'blue' : (23,23,178), + 'green' : (23,178,23), + 'cyan' : (23,178,178), + 'red' : (178,23,23), + 'magenta' : (178,23,178), + 'yellow' : (178,103,23), + 'white' : (178,178,178), + 'intenseblack' : (104,104,104), + 'intenseblue' : (84,84,255), + 'intensegreen' : (84,255,84), + 'intensecyan' : (84,255,255), + 'intensered' : (255,84,84), + 'intensemagenta': (255,84,255), + 'intenseyellow' : (255,255,84), + 'intensewhite' : (255,255,255), } def __init__(self): @@ -146,15 +166,19 @@ self.size.w, self.size.h = 120, 40 # screen size in characters self.charcache = None self.charsize = Size(16, 8) # character size in pixels - - self.colorprefix = [] # stack of color prefixes + self.last_keypress = None + self.last_key = None + self.colors = {} # maps names to curses attributes + self.colorstack = [] # pushcolor/popcolor puts or gets attributes from this + self.default_color = (self.colormap['white'], self.colormap['black'], 0) + self.current_color = self.default_color def start(self, mainfunc): pygame.init() self.charcache = CharCache() self.charsize = self.charcache.charsize mode = self.size.w * self.charsize.w, self.size.h * self.charsize.h - self.screen = pygame.display.set_mode(mode) + self.screen = pygame.display.set_mode(mode, pygame.RESIZABLE) mainfunc() @@ -177,10 +201,11 @@ # keyboard elif ev.type == pygame.KEYDOWN: keypress = self.keypress_from_pygame_event(ev) - events.append(keypress) - self.last_keypress = keypress - self.last_key = ev.key - pygame.time.set_timer(pygame.USEREVENT, 200) + if keypress: + events.append(keypress) + self.last_keypress = keypress + self.last_key = ev.key + pygame.time.set_timer(pygame.USEREVENT, 200) elif ev.type == pygame.USEREVENT: # repeat last key press events.append(self.last_keypress) pygame.time.set_timer(pygame.USEREVENT, 50) @@ -188,12 +213,14 @@ if ev.key == self.last_key: pygame.time.set_timer(pygame.USEREVENT, 0) - # window resize + # window elif ev.type == pygame.VIDEORESIZE: - #self.size.h, self.size.w = self.screen.getmaxyx() - events.append(('resize',)) - - # window close + neww, newh = ev.w // self.charsize.w, ev.h // self.charsize.h + if neww != self.size.w or newh != self.size.h: + self.size.w, self.size.h = neww, newh + mode = self.size.w * self.charsize.w, self.size.h * self.charsize.h + self.screen = pygame.display.set_mode(mode, pygame.RESIZABLE) + events.append(('resize',)) elif ev.type == pygame.QUIT: events.append(('quit',)) @@ -202,24 +229,26 @@ return events def keypress_from_pygame_event(self, ev): - if ev.key in self.key_map: - keypress = ('keypress', self.key_map[ev.key], None) + if ev.key in self.keymap: + keypress = ('keypress', self.keymap[ev.key], None) elif ev.unicode: keypress = ('keypress', None, ev.unicode) + else: + self.log.debug('Unknown key: key=%r unicode=%r' % (ev.key, ev.unicode)) + keypress = None return keypress ## drawing ## def erase(self): '''Clear screen.''' - self.screen.fill(self.color_map['black']) + self.screen.fill(self.colormap['black']) def putch(self, x, y, c): if not self.clipstack.test(x, y): return - fgcolor = (255,255,255) - bgcolor = (70,70,70) - self.charcache.render(self.screen, x, y, c, fgcolor, bgcolor) + fgcolor, bgcolor, attr = self.current_color + self.charcache.render(self.screen, x, y, c, fgcolor, bgcolor, attr) def commit(self): '''Commit changes to the screen.''' @@ -228,6 +257,20 @@ ## colors ## + def _parsecolor(self, name, attr=None): + name = name.lower().strip() + if attr == 'bold': + name = 'intense' + name + return self.colormap[name] + + def _parseattrs(self, attrs): + res = '' + for a in attrs: + a = a.lower().strip() + if a == 'bold': + res = a + return res + def setcolor(self, name, desc): '''Define color name. @@ -235,18 +278,33 @@ desc - color description - foreground, background, attributes (e.g. 'black on white, bold') ''' + parts = desc.split(',') + fg, bg = parts[0].split(' on ') + attrs = parts[1:] + attr = self._parseattrs(attrs) + fg = self._parsecolor(fg, attr) + bg = self._parsecolor(bg) + self.colors[name] = (fg, bg, attr) def pushcolor(self, name): '''Add color on top of stack and use this color for following output.''' + # add prefix if such color is available + if len(self.colorprefix): + prefixname = self.colorprefix[-1] + name + if prefixname in self.colors: + name = prefixname + col = self.colors[name] + self.current_color = col + self.colorstack.append(col) def popcolor(self): '''Remove color from top of stack and use new top color for following output.''' - - def pushcolorprefix(self, name): - self.colorprefix.append(name) - - def popcolorprefix(self): - self.colorprefix.pop() + self.colorstack.pop() + if len(self.colorstack): + col = self.colorstack[-1] + else: + col = self.default_color + self.current_color = col ## cursor ##