DriverSDL: Implement blink attribute.
authorRadek Brich <radek.brich@devl.cz>
Wed, 09 Jan 2013 22:32:15 +0100
changeset 60 fccca2a60492
parent 59 729fcdfe6b57
child 61 15088f62c4ac
DriverSDL: Implement blink attribute.
demo_colors.py
sdlterm/src/sdlterm.cc
sdlterm/src/sdlterm.h
--- a/demo_colors.py	Tue Jan 08 23:59:55 2013 +0100
+++ b/demo_colors.py	Wed Jan 09 22:32:15 2013 +0100
@@ -4,7 +4,7 @@
 import locale
 locale.setlocale(locale.LC_ALL, '')
 
-from tuikit import Application, Label, VerticalLayout
+from tuikit import Application, Window, Label, VerticalLayout
 
 
 class MyApplication(Application):
@@ -12,6 +12,10 @@
         Application.__init__(self)
         self.top.add_handler('keypress', self.on_top_keypress)
 
+        win = Window()
+        self.top.add(win)
+        win.layout = VerticalLayout()
+
         for attr in ['blink', 'bold', 'standout', 'underline']:
             label = Label(attr)
             label.color = 'test-' + attr
--- a/sdlterm/src/sdlterm.cc	Tue Jan 08 23:59:55 2013 +0100
+++ b/sdlterm/src/sdlterm.cc	Wed Jan 09 22:32:15 2013 +0100
@@ -115,12 +115,18 @@
 }
 
 
-SDL_Surface *GlyphRenderer::render_cell(Uint32 ch, Uint32 attr)
+SDL_Surface *GlyphRenderer::render_cell(Uint32 ch, Uint32 attr, bool blink_state)
 {
     SDL_Surface *cell_surface;
     TTF_Font *font;
     SDL_Color fgcolor, bgcolor;
 
+    // blink affects cache lookup, must be processed first
+    if ((attr & Style::BLINK) && !blink_state)
+    {
+        ch = ' ';
+    }
+
     // try cache
     Uint64 id = (Uint64)ch | (Uint64)attr << 32;
     cell_surface = _cache.lookup_glyph(id);
@@ -132,9 +138,8 @@
     // load attributes
     _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)
+    font = (attr & Style::BOLD) ? _font_bold : _font_regular;
+    if (attr & Style::STANDOUT)
     {
         std::swap(fgcolor, bgcolor);
     }
@@ -154,7 +159,7 @@
     if (ch)
     {
         // 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))
+        if ((attr & 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);
@@ -166,7 +171,7 @@
             // normal case
             _render_glyph(cell_surface, font, ch, fgcolor, bgcolor);
         }
-        if (style & Style::UNDERLINE)
+        if (attr & Style::UNDERLINE)
         {
             // draw underline
             SDL_LockSurface(cell_surface);
@@ -244,7 +249,7 @@
 void TerminalScreen::toggle_cursor(int x, int y)
 {
     TerminalCell &cell = _cells_front[y * _width + x];
-    cell.attr ^= (Style::STANDOUT << 24);
+    cell.attr ^= Style::STANDOUT;
 }
 
 
@@ -262,7 +267,7 @@
             {
                 dst_rect.x = x * _cell_width;
                 dst_rect.y = y * _cell_height;
-                cell_surface = _render.render_cell(front_iter->ch, front_iter->attr);
+                cell_surface = _render.render_cell(front_iter->ch, front_iter->attr, _blink_state);
                 SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
                 *back_iter = *front_iter;
             }
@@ -301,6 +306,33 @@
 }
 
 
+void TerminalScreen::_draw_blink()
+{
+    // Use back buffer which contains commited changes.
+    // This is called from timer while application may draw into front_buffer.
+    auto back_iter = _cells_back.begin();
+    SDL_Surface *cell_surface;
+    SDL_Rect dst_rect;
+    for (int y = 0; y < _height; y++)
+    {
+        for (int x = 0; x < _width; x++)
+        {
+            // draw only blinking characters
+            if (back_iter->attr & Style::BLINK)
+            {
+                dst_rect.x = x * _cell_width;
+                dst_rect.y = y * _cell_height;
+                cell_surface = _render.render_cell(back_iter->ch, back_iter->attr, _blink_state);
+                SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
+            }
+            back_iter++;
+        }
+    }
+
+    SDL_UpdateRect(_screen_surface, 0, 0, 0, 0);
+}
+
+
 Terminal::Terminal()
  : _screen(), _attr(7), _cursor_x(0), _cursor_y(0), _cursor_visible(false),
    _mousemove_last_x(-1), _mousemove_last_y(-1)
@@ -312,6 +344,7 @@
     SDL_EnableUNICODE(1);
     SDL_EnableKeyRepeat(250, SDL_DEFAULT_REPEAT_INTERVAL);
     SDL_WM_SetCaption("terminal", NULL);
+    SDL_AddTimer(500, _blink_toggle_callback, NULL);
 }
 
 
@@ -362,6 +395,13 @@
         }
         switch (sdl_event.type)
         {
+            case SDL_USEREVENT:
+                // toggle blink
+                if (sdl_event.user.code == 2)
+                {
+                    _screen.toggle_blink();
+                }
+                break; // continue loop
             case SDL_QUIT:
                 event.type = Event::QUIT;
                 return true;
@@ -482,3 +522,13 @@
     return 0;
 }
 
+
+Uint32 Terminal::_blink_toggle_callback(Uint32 interval, void *param)
+{
+    SDL_Event event;
+    event.type = SDL_USEREVENT;
+    event.user.code = 2;
+    SDL_PushEvent(&event);
+    return interval;
+}
+
--- a/sdlterm/src/sdlterm.h	Tue Jan 08 23:59:55 2013 +0100
+++ b/sdlterm/src/sdlterm.h	Wed Jan 09 22:32:15 2013 +0100
@@ -10,10 +10,10 @@
 namespace Style
 {
     enum {
-        BOLD      = 1 << 0,  // bold font
-        UNDERLINE = 1 << 1,  // underline text
-        STANDOUT  = 1 << 2,  // inverse bg/fg
-        BLINK     = 1 << 3,  // blinking
+        BOLD      = 1 << 24,  // bold font
+        UNDERLINE = 1 << 25,  // underline text
+        STANDOUT  = 1 << 26,  // inverse bg/fg
+        BLINK     = 1 << 27,  // blinking
     };
 };
 
@@ -76,7 +76,7 @@
     void close_font();
 
     // do not free surface returned!
-    SDL_Surface *render_cell(Uint32 ch, Uint32 attr);
+    SDL_Surface *render_cell(Uint32 ch, Uint32 attr, bool blink_state);
 
     int get_cell_width() const { return _cell_width; };
     int get_cell_height() const { return _cell_height; };
@@ -124,7 +124,7 @@
     TerminalScreen():
         _screen_surface(NULL), _cells_front(0), _cells_back(0), _render(),
         _pixel_width(0), _pixel_height(0), _width(0), _height(0),
-        _cell_width(0), _cell_height(0) {};
+        _cell_width(0), _cell_height(0), _blink_state(1) {};
     ~TerminalScreen() {};
 
     void select_font(const char *fname_regular, const char *fname_bold, int ptsize);
@@ -133,6 +133,7 @@
     void erase();
     void putch(int x, int y, Uint32 ch, Uint32 attr);
     void toggle_cursor(int x, int y);
+    void toggle_blink() { _blink_state = !_blink_state; _draw_blink(); };
     void commit();
 
     // force full redraw on next commit()
@@ -156,7 +157,10 @@
     int _cell_width;  // character cell width in pixels
     int _cell_height;
 
+    int _blink_state; // 0 - blink chars hidden, 1 - visible
+
     void _reset_cells();
+    void _draw_blink();
 };
 
 
@@ -223,6 +227,7 @@
 
     const char *_translate_keyname(SDLKey sym);
     static Uint32 _wait_event_callback(Uint32 interval, void *param);
+    static Uint32 _blink_toggle_callback(Uint32 interval, void *param);
 };