# HG changeset patch # User Radek Brich # Date 1357423241 -3600 # Node ID 50a1857557da211581a686b295dfc95c8c09c930 # Parent dce7325109c1e4fc2055b88845d1790261cd0e97 Update SDL driver: Enlarge char, attr to 32 bits, 64 bits per terminal cell. Colors and attributes are complete, only blink does not work. diff -r dce7325109c1 -r 50a1857557da .hgignore --- a/.hgignore Sat Jan 05 18:56:45 2013 +0100 +++ b/.hgignore Sat Jan 05 23:00:41 2013 +0100 @@ -7,8 +7,8 @@ ^sdlterm/font ^sdlterm/cython/sdlterm.cpp$ ^sdlterm/demo$ -^\.project -^\.pydevproject +^(.*/)?\.c?project$ +^(.*/)?\.pydevproject$ ^\.settings .*\.appstats __pycache__ diff -r dce7325109c1 -r 50a1857557da demo_colors.py --- a/demo_colors.py Sat Jan 05 18:56:45 2013 +0100 +++ b/demo_colors.py Sat Jan 05 23:00:41 2013 +0100 @@ -12,13 +12,20 @@ Application.__init__(self) self.top.add_handler('keypress', self.on_top_keypress) - for attr in ['blink', 'bold', 'dim', 'standout', 'underline']: + for attr in ['blink', 'bold', 'standout', 'underline']: label = Label(attr) label.color = 'test-' + attr self.top.add(label) self.top.layout = VerticalLayout() + def applytheme(self): + Application.applytheme(self) + self.driver.setcolor('test-blink', 'cyan on blue, blink') + self.driver.setcolor('test-bold', 'cyan on blue, bold') + self.driver.setcolor('test-standout', 'cyan on blue, standout') + self.driver.setcolor('test-underline', 'cyan on blue, underline') + def on_top_keypress(self, ev): if ev.keyname == 'escape': self.terminate() diff -r dce7325109c1 -r 50a1857557da sdlterm/demo.cc --- a/sdlterm/demo.cc Sat Jan 05 18:56:45 2013 +0100 +++ b/sdlterm/demo.cc Sat Jan 05 23:00:41 2013 +0100 @@ -19,12 +19,18 @@ term.resize(800, 600); term.select_font("font/DejaVuSansMono.ttf", "font/DejaVuSansMono-Bold.ttf", 12); term.erase(); - term.set_attr( term.prepare_attr(14, 1, 1) ); char hello[] = "Hello World!"; - for (char *c = hello; *c; c++) + for (int bg = 0; bg < 16; bg++) { - term.putch(5 + (c - hello), 5, *c); + for (int fg = 0; fg < 16; fg++) + { + for (char *c = hello; *c; c++) + { + term.set_attr( term.prepare_attr(fg, bg, 1) ); + term.putch(5 + 6 * bg + (c - hello), 5 + fg, *c); + } + } } term.commit(); } diff -r dce7325109c1 -r 50a1857557da sdlterm/src/sdlterm.cc --- a/sdlterm/src/sdlterm.cc Sat Jan 05 18:56:45 2013 +0100 +++ b/sdlterm/src/sdlterm.cc Sat Jan 05 23:00:41 2013 +0100 @@ -12,9 +12,9 @@ } -SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch) +SDL_Surface *GlyphCache::lookup_glyph(Uint64 id) { - auto iter = _glyph_map.find(ch); + auto iter = _glyph_map.find(id); if (iter == _glyph_map.end()) { return NULL; @@ -23,9 +23,9 @@ } -void GlyphCache::put_glyph(Uint16 ch, SDL_Surface *srf) +void GlyphCache::put_glyph(Uint64 id, SDL_Surface *srf) { - _glyph_map[ch] = srf; + _glyph_map[id] = srf; } @@ -119,24 +119,29 @@ } -SDL_Surface *GlyphRenderer::render_cell(Uint16 ch, Uint16 attr) +SDL_Surface *GlyphRenderer::render_cell(Uint32 ch, Uint32 attr) { SDL_Surface *cell_surface; TTF_Font *font; SDL_Color fgcolor, bgcolor; // try cache - cell_surface = _cache.lookup_glyph(ch); + Uint64 id = (Uint64)ch | (Uint64)attr << 32; + cell_surface = _cache.lookup_glyph(id); if (cell_surface) { return cell_surface; } // 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; + _colormap.index_to_rgb((attr & 0x000000FF), fgcolor); + _colormap.index_to_rgb((attr & 0x0000FF00) >> 8, bgcolor); + int style = (attr & 0xFF000000) >> 24; + font = (style & Style::BOLD) ? _font_bold : _font_regular; + if (style & Style::STANDOUT) + { + std::swap(fgcolor, bgcolor); + } // create surface for whole cell and fill it with bg color cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, @@ -152,13 +157,30 @@ // render glyph, blit it onto cell surface if (ch) { - 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; - dst_rect.y = TTF_FontAscent(font) - maxy; - SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect); - SDL_FreeSurface(glyph_surface); + // when glyph is not provided by BOLD font but is provided by REGULAR font, use that (better than nothing) + if ((style & Style::BOLD) && !TTF_GlyphIsProvided(font, ch) && TTF_GlyphIsProvided(_font_regular, ch)) + { + // use bold style of regular font instead of bold font + TTF_SetFontStyle(_font_regular, TTF_STYLE_BOLD); + _render_glyph(cell_surface, _font_regular, ch, fgcolor, bgcolor); + TTF_SetFontStyle(_font_regular, TTF_STYLE_NORMAL); + } + else + { + // normal case + _render_glyph(cell_surface, font, ch, fgcolor, bgcolor); + } + if (style & Style::UNDERLINE) + { + // draw underline + SDL_LockSurface(cell_surface); + int y = 1 + TTF_FontAscent(font); + Uint32 fgcolor_mapped = SDL_MapRGB(cell_surface->format, fgcolor.r, fgcolor.g, fgcolor.b); + Uint32 *p = (Uint32 *)(cell_surface->pixels + y * cell_surface->pitch); + for (int x = 0; x < _cell_width; x++) + *p++ = fgcolor_mapped; + SDL_UnlockSurface(cell_surface); + } } // convert to display format @@ -167,12 +189,26 @@ SDL_FreeSurface(tmp_surface); // put to cache - _cache.put_glyph(ch, cell_surface); + _cache.put_glyph(id, cell_surface); return cell_surface; } +void GlyphRenderer::_render_glyph(SDL_Surface *cell_surface, TTF_Font *font, Uint32 ch, + SDL_Color fgcolor, SDL_Color bgcolor) +{ + int minx, maxy; + SDL_Rect dst_rect; + SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, fgcolor, bgcolor); + TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL); + dst_rect.x = minx; + dst_rect.y = TTF_FontAscent(font) - maxy; + SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect); + SDL_FreeSurface(glyph_surface); +} + + void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize) { _render.open_font(fname_regular, fname_bold, ptsize); @@ -204,7 +240,7 @@ } -void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr) +void TerminalScreen::putch(int x, int y, Uint32 ch, Uint32 attr) { TerminalCell &cell = _cells_front[y * _width + x]; cell.ch = ch; diff -r dce7325109c1 -r 50a1857557da sdlterm/src/sdlterm.h --- a/sdlterm/src/sdlterm.h Sat Jan 05 18:56:45 2013 +0100 +++ b/sdlterm/src/sdlterm.h Sat Jan 05 23:00:41 2013 +0100 @@ -5,12 +5,12 @@ #include -enum class Style: Uint16 +namespace Style { - BOLD = 1 << 0, // bold font - UNDERLINE = 1 << 1, // underline text - STANDOUT = 1 << 2, // inverse bg/fg - BLINK = 1 << 3, // blinking + const int BOLD = 1 << 0; // bold font + const int UNDERLINE = 1 << 1; // underline text + const int STANDOUT = 1 << 2; // inverse bg/fg + const int BLINK = 1 << 3; // blinking }; @@ -44,12 +44,13 @@ class GlyphCache { public: - SDL_Surface *lookup_glyph(Uint16 ch); - void put_glyph(Uint16 ch, SDL_Surface *srf); + // lookup glyph in cache, id is combined char and attr + SDL_Surface *lookup_glyph(Uint64 id); + void put_glyph(Uint64 id, SDL_Surface *srf); void flush(); private: - std::map _glyph_map; + std::map _glyph_map; }; @@ -63,7 +64,7 @@ void close_font(); // do not free surface returned! - SDL_Surface *render_cell(Uint16 ch, Uint16 attr); + SDL_Surface *render_cell(Uint32 ch, Uint32 attr); int get_cell_width() { return _cell_width; }; int get_cell_height() { return _cell_height; }; @@ -75,13 +76,30 @@ int _cell_height; GlyphCache _cache; ColorMap _colormap; + + void _render_glyph(SDL_Surface *cell_surface, TTF_Font *font, Uint32 ch, + SDL_Color fgcolor, SDL_Color bgcolor); }; +/* One cell of terminal window + * + * Each cell contains one character, its color and attributes. + * Character is encoded in 32bit unicode. + * Other 32 bits are attributes: + * 0-7 (8b) - foreground color index + * 8-15 (8b) - background color index + * 16-23 (8b) - RESERVED for alpha channel + * 24 (1b) - bold font + * 25 (1b) - underline + * 26 (1b) - standout (swap fg/bg color) + * 27 (1b) - blink + * 28-31 (4b) - RESERVED + */ struct TerminalCell { - Uint16 ch; - Uint16 attr; + Uint32 ch; + Uint32 attr; bool operator !=(const TerminalCell &rhs) const { return ch != rhs.ch || attr != rhs.attr; }; }; @@ -99,7 +117,7 @@ void resize(int pxwidth, int pxheight); void erase(); - void putch(int x, int y, Uint16 ch, Uint16 attr); + void putch(int x, int y, Uint32 ch, Uint32 attr); void commit(); int get_width() { return _width; }; @@ -134,7 +152,7 @@ struct { char keyname[10]; - Uint16 unicode; + Uint32 unicode; } key; struct { @@ -156,11 +174,11 @@ void resize(int pxwidth, int pxheight) { _screen.resize(pxwidth, pxheight); }; void erase() { _screen.erase(); }; - void putch(int x, int y, Uint16 ch) { _screen.putch(x, y, ch, _attr); }; + void putch(int x, int y, Uint32 ch) { _screen.putch(x, y, ch, _attr); }; void commit() { _screen.commit(); }; - Uint16 prepare_attr(Uint8 fg, Uint8 bg, Uint8 style) { return fg | bg << 4 | style << 8; }; - void set_attr(Uint16 value) { _attr = value; }; + Uint32 prepare_attr(Uint8 fg, Uint8 bg, Uint8 style) { return (Uint32)fg | (Uint32)bg << 8 | (Uint32)style << 24; }; + void set_attr(Uint32 value) { _attr = value; }; void set_cursor(int x, int y) { _cursor_x = x; _cursor_y = y; }; void show_cursor(bool visible) { _cursor_visible = visible; }; @@ -172,7 +190,7 @@ private: TerminalScreen _screen; - Uint16 _attr; + Uint32 _attr; int _cursor_x; int _cursor_y; bool _cursor_visible; diff -r dce7325109c1 -r 50a1857557da tuikit/application.py --- a/tuikit/application.py Sat Jan 05 18:56:45 2013 +0100 +++ b/tuikit/application.py Sat Jan 05 23:00:41 2013 +0100 @@ -124,6 +124,9 @@ def applytheme(self): + #TODO: allow custom colors: + # e.g. "blue (#2020FF) on black (#101010), underline" + # color in brackets is used when driver supports custom colors driver = self.driver driver.setcolor('normal', 'white on black') driver.setcolor('strong', 'white on black, bold') @@ -137,12 +140,6 @@ driver.setcolor('menu-active', 'white on cyan, bold') driver.setcolor('combo:normal', 'black on green') - driver.setcolor('test-blink', 'cyan on blue, blink') - driver.setcolor('test-bold', 'cyan on blue, bold') - driver.setcolor('test-dim', 'cyan on blue, dim') - driver.setcolor('test-standout', 'cyan on blue, standout') - driver.setcolor('test-underline', 'cyan on blue, underline') - def get_driver_instance(self, name): module = __import__('tuikit.driver_' + name, fromlist=['driverclass'])