Update SDL driver: Enlarge char, attr to 32 bits, 64 bits per terminal cell. Colors and attributes are complete, only blink does not work.
--- 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__
--- 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()
--- 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();
}
--- 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;
--- 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 <vector>
-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<Uint16, SDL_Surface*> _glyph_map;
+ std::map<Uint64, SDL_Surface*> _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;
--- 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'])