DriverSDL: Implement colors.
authorRadek Brich <radek.brich@devl.cz>
Sat, 05 Jan 2013 18:44:56 +0100
changeset 50 c5b8b9d2da95
parent 49 1611c462c3e3
child 51 dce7325109c1
DriverSDL: Implement colors.
sdlterm/cython/sdlterm.pyx
sdlterm/demo.cc
sdlterm/src/sdlterm.cc
sdlterm/src/sdlterm.h
tuikit/driver_sdl.py
--- a/sdlterm/cython/sdlterm.pyx	Sat Jan 05 16:47:30 2013 +0100
+++ b/sdlterm/cython/sdlterm.pyx	Sat Jan 05 18:44:56 2013 +0100
@@ -77,6 +77,11 @@
     def commit(self):
         self.thisptr.commit()
 
+    def prepare_attr(self, fg, bg, style):
+        return self.thisptr.prepare_attr(fg, bg, style)
+    def set_attr(self, value):
+        self.thisptr.set_attr(value)
+
     def get_next_event(self):
         self.thisptr.get_next_event(self.event)
         event = self.event
--- a/sdlterm/demo.cc	Sat Jan 05 16:47:30 2013 +0100
+++ b/sdlterm/demo.cc	Sat Jan 05 18:44:56 2013 +0100
@@ -19,7 +19,13 @@
 	term.resize(800, 600);
 	term.select_font("font/DejaVuSansMono.ttf", "font/DejaVuSansMono-Bold.ttf", 12);
 	term.erase();
-	term.putch(5, 5, 'W');
+	term.set_attr( term.prepare_attr(14, 1, 1) );
+
+	char hello[] = "Hello World!";
+	for (char *c = hello; *c; c++)
+	{
+		term.putch(5 + (c - hello), 5, *c);
+	}
 	term.commit();
 }
 
--- a/sdlterm/src/sdlterm.cc	Sat Jan 05 16:47:30 2013 +0100
+++ b/sdlterm/src/sdlterm.cc	Sat Jan 05 18:44:56 2013 +0100
@@ -4,6 +4,14 @@
 #include <algorithm>
 
 
+void ColorMap::index_to_rgb(int index, SDL_Color &color)
+{
+	color.r = _map[index][0];
+	color.g = _map[index][1];
+	color.b = _map[index][2];
+}
+
+
 SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch)
 {
 	auto iter = _glyph_map.find(ch);
@@ -32,7 +40,7 @@
 
 
 GlyphRenderer::GlyphRenderer()
- : _font_regular(NULL), _font_bold(NULL)
+ : _font_regular(NULL), _font_bold(NULL), _cell_width(0), _cell_height(0), _cache(), _colormap()
 {
 	if (TTF_Init() == -1)
 	{
@@ -111,9 +119,11 @@
 }
 
 
-SDL_Surface *GlyphRenderer::render_glyph(Uint16 ch)
+SDL_Surface *GlyphRenderer::render_cell(Uint16 ch, Uint16 attr)
 {
 	SDL_Surface *cell_surface;
+	TTF_Font *font;
+	SDL_Color fgcolor, bgcolor;
 
 	// try cache
 	cell_surface = _cache.lookup_glyph(ch);
@@ -122,8 +132,11 @@
 		return cell_surface;
 	}
 
-	TTF_Font *font = _font_regular;
-	SDL_Color color={0xff,0xff,0xff}, bgcolor={0,0,0};
+	// load attributes
+	_colormap.index_to_rgb(attr & 0x000F, fgcolor);
+	_colormap.index_to_rgb((attr & 0x00F0) >> 4, bgcolor);
+	Style style = (Style) ((attr & 0xFF00) >> 8);
+	font = (style == Style::BOLD) ? _font_bold : _font_regular;
 
 	// create surface for whole cell and fill it with bg color
 	cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
@@ -139,7 +152,7 @@
 	// render glyph, blit it onto cell surface
 	if (ch)
 	{
-		SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor);
+		SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, fgcolor, bgcolor);
 		int minx, maxy;
 		TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL);
 		dst_rect.x = minx;
@@ -203,7 +216,7 @@
 {
 	auto front_iter = _cells_front.begin();
 	auto back_iter = _cells_back.begin();
-	SDL_Surface *glyph_surface;
+	SDL_Surface *cell_surface;
 	SDL_Rect dst_rect;
 	for (int y = 0; y < _height; y++)
 	{
@@ -213,8 +226,8 @@
 			{
 				dst_rect.x = x * _cell_width;
 				dst_rect.y = y * _cell_height;
-				glyph_surface = _render.render_glyph(front_iter->ch);
-				SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect);
+				cell_surface = _render.render_cell(front_iter->ch, front_iter->attr);
+				SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
 				*back_iter = *front_iter;
 			}
 			front_iter++;
@@ -230,17 +243,22 @@
 {
 	_cell_width = _render.get_cell_width();
 	_cell_height = _render.get_cell_height();
+	if (!_cell_width || !_cell_height)
+		return;
+
 	_width = _pixel_width / _cell_width;
 	_height = _pixel_height / _cell_height;
+	if (!_width || !_height)
+		return;
 
 	int num_cells = _width * _height;
-	_cells_front.resize(num_cells);
-	_cells_back.resize(num_cells);
+	_cells_front.resize(num_cells, TerminalCell());
+	_cells_back.resize(num_cells, TerminalCell());
 }
 
 
 Terminal::Terminal()
- : _screen(), _mousemove_last_x(-1)
+ : _screen(), _attr(7), _mousemove_last_x(-1)
 {
     if (SDL_Init(SDL_INIT_VIDEO) == -1)
     {
@@ -327,7 +345,6 @@
 		case SDLK_TAB:			return "tab";
 		case SDLK_RETURN:		return "enter";
 		case SDLK_KP_ENTER:		return "enter";
-		case SDLK_PAUSE:	    return "pause";
 		case SDLK_ESCAPE:		return "escape";
 		case SDLK_DELETE:		return "delete";
 		case SDLK_INSERT:		return "insert";
@@ -351,6 +368,9 @@
 		case SDLK_F10:			return "f10";
 		case SDLK_F11:			return "f11";
 		case SDLK_F12:			return "f12";
+		case SDLK_PRINT:		return "print";
+		case SDLK_SCROLLOCK:	return "scrllock";
+		case SDLK_PAUSE:	    return "pause";
 		default: return NULL;
 	}
 }
--- a/sdlterm/src/sdlterm.h	Sat Jan 05 16:47:30 2013 +0100
+++ b/sdlterm/src/sdlterm.h	Sat Jan 05 18:44:56 2013 +0100
@@ -5,6 +5,42 @@
 #include <vector>
 
 
+enum class Style: Uint16
+{
+	BOLD      = 1 << 0,  // bold font
+	UNDERLINE = 1 << 1,  // underline text
+	STANDOUT  = 1 << 2,  // inverse bg/fg
+	BLINK     = 1 << 3,  // blinking
+};
+
+
+class ColorMap
+{
+private:
+	Uint8 _map[16][3] = {
+		{0,0,0},		// 0 - black
+        {23,23,178},	// 1 - blue
+        {23,178,23},    // 2 - green
+        {23,178,178},   // 3 - cyan
+        {178,23,23},	// 4 - red
+        {178,23,178},	// 5 - magenta
+        {178,103,23},	// 6 - brown
+        {178,178,178},	// 7 - light gray
+        {104,104,104},	// 8 - gray
+        {84,84,255},	// 9 - light blue
+        {84,255,84},	// 10 - light green
+        {84,255,255},	// 11 - light cyan
+        {255,84,84},	// 12 - light red
+        {255,84,255},	// 13 - light magenta
+        {255,255,84},   // 14 - yellow
+        {255,255,255},  // 15 - white
+	};
+
+public:
+    void index_to_rgb(int index, SDL_Color &color);
+};
+
+
 class GlyphCache
 {
 public:
@@ -27,7 +63,7 @@
 	void close_font();
 
 	// do not free surface returned!
-	SDL_Surface *render_glyph(Uint16 ch);
+	SDL_Surface *render_cell(Uint16 ch, Uint16 attr);
 
 	int get_cell_width() { return _cell_width; };
 	int get_cell_height() { return _cell_height; };
@@ -38,6 +74,7 @@
 	int _cell_width;
 	int _cell_height;
 	GlyphCache _cache;
+	ColorMap _colormap;
 };
 
 
@@ -52,7 +89,9 @@
 class TerminalScreen
 {
 public:
-	TerminalScreen(): _screen_surface(NULL), _render() {};
+	TerminalScreen():
+		_screen_surface(NULL), _cells_front(0), _cells_back(0), _render(),
+		_pixel_width(0), _pixel_height(0) {};
 	~TerminalScreen() {};
 
 	void select_font(const char *fname_regular, const char *fname_bold, int ptsize);
@@ -119,7 +158,7 @@
 	void putch(int x, int y, Uint16 ch) { _screen.putch(x, y, ch, _attr); };
 	void commit() { _screen.commit(); };
 
-	Uint16 prepare_attr(Uint8 fg, Uint8 bg, Uint8 style) { return fg | bg << 8 | style << 16; };
+	Uint16 prepare_attr(Uint8 fg, Uint8 bg, Uint8 style) { return fg | bg << 4 | style << 8; };
 	void set_attr(Uint16 value) { _attr = value; };
 
 	void set_cursor(int x, int y) { _cursor_x = x; _cursor_y = y; };
--- a/tuikit/driver_sdl.py	Sat Jan 05 16:47:30 2013 +0100
+++ b/tuikit/driver_sdl.py	Sat Jan 05 18:44:56 2013 +0100
@@ -19,11 +19,40 @@
 
     '''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.'''
@@ -67,15 +96,43 @@
         desc - color description - foreground, background, attributes (e.g. 'black on white, bold')
 
         '''
-        self.log.info('DummyDriver.setcolor(name=%r, desc=%r)', name, desc)
+        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.'''
-        self.log.info('DummyDriver.pushcolor(name=%r)', name)
+        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.log.info('DummyDriver.popcolor()')
+        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 ##