sdlterm/src/sdlterm.cc
changeset 60 fccca2a60492
parent 58 50308ed5e4f9
child 61 15088f62c4ac
equal deleted inserted replaced
59:729fcdfe6b57 60:fccca2a60492
   113         _font_bold = NULL;
   113         _font_bold = NULL;
   114     }
   114     }
   115 }
   115 }
   116 
   116 
   117 
   117 
   118 SDL_Surface *GlyphRenderer::render_cell(Uint32 ch, Uint32 attr)
   118 SDL_Surface *GlyphRenderer::render_cell(Uint32 ch, Uint32 attr, bool blink_state)
   119 {
   119 {
   120     SDL_Surface *cell_surface;
   120     SDL_Surface *cell_surface;
   121     TTF_Font *font;
   121     TTF_Font *font;
   122     SDL_Color fgcolor, bgcolor;
   122     SDL_Color fgcolor, bgcolor;
       
   123 
       
   124     // blink affects cache lookup, must be processed first
       
   125     if ((attr & Style::BLINK) && !blink_state)
       
   126     {
       
   127         ch = ' ';
       
   128     }
   123 
   129 
   124     // try cache
   130     // try cache
   125     Uint64 id = (Uint64)ch | (Uint64)attr << 32;
   131     Uint64 id = (Uint64)ch | (Uint64)attr << 32;
   126     cell_surface = _cache.lookup_glyph(id);
   132     cell_surface = _cache.lookup_glyph(id);
   127     if (cell_surface)
   133     if (cell_surface)
   130     }
   136     }
   131 
   137 
   132     // load attributes
   138     // load attributes
   133     _colormap.index_to_rgb((attr & 0x000000FF), fgcolor);
   139     _colormap.index_to_rgb((attr & 0x000000FF), fgcolor);
   134     _colormap.index_to_rgb((attr & 0x0000FF00) >> 8, bgcolor);
   140     _colormap.index_to_rgb((attr & 0x0000FF00) >> 8, bgcolor);
   135     int style = (attr & 0xFF000000) >> 24;
   141     font = (attr & Style::BOLD) ? _font_bold : _font_regular;
   136     font = (style & Style::BOLD) ? _font_bold : _font_regular;
   142     if (attr & Style::STANDOUT)
   137     if (style & Style::STANDOUT)
       
   138     {
   143     {
   139         std::swap(fgcolor, bgcolor);
   144         std::swap(fgcolor, bgcolor);
   140     }
   145     }
   141 
   146 
   142     // create surface for whole cell and fill it with bg color
   147     // create surface for whole cell and fill it with bg color
   152 
   157 
   153     // render glyph, blit it onto cell surface
   158     // render glyph, blit it onto cell surface
   154     if (ch)
   159     if (ch)
   155     {
   160     {
   156         // when glyph is not provided by BOLD font but is provided by REGULAR font, use that (better than nothing)
   161         // when glyph is not provided by BOLD font but is provided by REGULAR font, use that (better than nothing)
   157         if ((style & Style::BOLD) && !TTF_GlyphIsProvided(font, ch) && TTF_GlyphIsProvided(_font_regular, ch))
   162         if ((attr & Style::BOLD) && !TTF_GlyphIsProvided(font, ch) && TTF_GlyphIsProvided(_font_regular, ch))
   158         {
   163         {
   159             // use bold style of regular font instead of bold font
   164             // use bold style of regular font instead of bold font
   160             TTF_SetFontStyle(_font_regular, TTF_STYLE_BOLD);
   165             TTF_SetFontStyle(_font_regular, TTF_STYLE_BOLD);
   161             _render_glyph(cell_surface, _font_regular, ch, fgcolor, bgcolor);
   166             _render_glyph(cell_surface, _font_regular, ch, fgcolor, bgcolor);
   162             TTF_SetFontStyle(_font_regular, TTF_STYLE_NORMAL);
   167             TTF_SetFontStyle(_font_regular, TTF_STYLE_NORMAL);
   164         else
   169         else
   165         {
   170         {
   166             // normal case
   171             // normal case
   167             _render_glyph(cell_surface, font, ch, fgcolor, bgcolor);
   172             _render_glyph(cell_surface, font, ch, fgcolor, bgcolor);
   168         }
   173         }
   169         if (style & Style::UNDERLINE)
   174         if (attr & Style::UNDERLINE)
   170         {
   175         {
   171             // draw underline
   176             // draw underline
   172             SDL_LockSurface(cell_surface);
   177             SDL_LockSurface(cell_surface);
   173             int y = 1 + TTF_FontAscent(font);
   178             int y = 1 + TTF_FontAscent(font);
   174             Uint32 fgcolor_mapped = SDL_MapRGB(cell_surface->format, fgcolor.r, fgcolor.g, fgcolor.b);
   179             Uint32 fgcolor_mapped = SDL_MapRGB(cell_surface->format, fgcolor.r, fgcolor.g, fgcolor.b);
   242 
   247 
   243 
   248 
   244 void TerminalScreen::toggle_cursor(int x, int y)
   249 void TerminalScreen::toggle_cursor(int x, int y)
   245 {
   250 {
   246     TerminalCell &cell = _cells_front[y * _width + x];
   251     TerminalCell &cell = _cells_front[y * _width + x];
   247     cell.attr ^= (Style::STANDOUT << 24);
   252     cell.attr ^= Style::STANDOUT;
   248 }
   253 }
   249 
   254 
   250 
   255 
   251 void TerminalScreen::commit()
   256 void TerminalScreen::commit()
   252 {
   257 {
   260         {
   265         {
   261             if (*front_iter != *back_iter)
   266             if (*front_iter != *back_iter)
   262             {
   267             {
   263                 dst_rect.x = x * _cell_width;
   268                 dst_rect.x = x * _cell_width;
   264                 dst_rect.y = y * _cell_height;
   269                 dst_rect.y = y * _cell_height;
   265                 cell_surface = _render.render_cell(front_iter->ch, front_iter->attr);
   270                 cell_surface = _render.render_cell(front_iter->ch, front_iter->attr, _blink_state);
   266                 SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
   271                 SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
   267                 *back_iter = *front_iter;
   272                 *back_iter = *front_iter;
   268             }
   273             }
   269             front_iter++;
   274             front_iter++;
   270             back_iter++;
   275             back_iter++;
   299     _cells_back.resize(num_cells);
   304     _cells_back.resize(num_cells);
   300     redraw();
   305     redraw();
   301 }
   306 }
   302 
   307 
   303 
   308 
       
   309 void TerminalScreen::_draw_blink()
       
   310 {
       
   311     // Use back buffer which contains commited changes.
       
   312     // This is called from timer while application may draw into front_buffer.
       
   313     auto back_iter = _cells_back.begin();
       
   314     SDL_Surface *cell_surface;
       
   315     SDL_Rect dst_rect;
       
   316     for (int y = 0; y < _height; y++)
       
   317     {
       
   318         for (int x = 0; x < _width; x++)
       
   319         {
       
   320             // draw only blinking characters
       
   321             if (back_iter->attr & Style::BLINK)
       
   322             {
       
   323                 dst_rect.x = x * _cell_width;
       
   324                 dst_rect.y = y * _cell_height;
       
   325                 cell_surface = _render.render_cell(back_iter->ch, back_iter->attr, _blink_state);
       
   326                 SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
       
   327             }
       
   328             back_iter++;
       
   329         }
       
   330     }
       
   331 
       
   332     SDL_UpdateRect(_screen_surface, 0, 0, 0, 0);
       
   333 }
       
   334 
       
   335 
   304 Terminal::Terminal()
   336 Terminal::Terminal()
   305  : _screen(), _attr(7), _cursor_x(0), _cursor_y(0), _cursor_visible(false),
   337  : _screen(), _attr(7), _cursor_x(0), _cursor_y(0), _cursor_visible(false),
   306    _mousemove_last_x(-1), _mousemove_last_y(-1)
   338    _mousemove_last_x(-1), _mousemove_last_y(-1)
   307 {
   339 {
   308     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1)
   340     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1)
   310         throw SDLTermError(std::string("SDL_Init: ") + SDL_GetError());
   342         throw SDLTermError(std::string("SDL_Init: ") + SDL_GetError());
   311     }
   343     }
   312     SDL_EnableUNICODE(1);
   344     SDL_EnableUNICODE(1);
   313     SDL_EnableKeyRepeat(250, SDL_DEFAULT_REPEAT_INTERVAL);
   345     SDL_EnableKeyRepeat(250, SDL_DEFAULT_REPEAT_INTERVAL);
   314     SDL_WM_SetCaption("terminal", NULL);
   346     SDL_WM_SetCaption("terminal", NULL);
       
   347     SDL_AddTimer(500, _blink_toggle_callback, NULL);
   315 }
   348 }
   316 
   349 
   317 
   350 
   318 Terminal::~Terminal()
   351 Terminal::~Terminal()
   319 {
   352 {
   360             SDL_RemoveTimer(timer_id);
   393             SDL_RemoveTimer(timer_id);
   361             timer_id = NULL;
   394             timer_id = NULL;
   362         }
   395         }
   363         switch (sdl_event.type)
   396         switch (sdl_event.type)
   364         {
   397         {
       
   398             case SDL_USEREVENT:
       
   399                 // toggle blink
       
   400                 if (sdl_event.user.code == 2)
       
   401                 {
       
   402                     _screen.toggle_blink();
       
   403                 }
       
   404                 break; // continue loop
   365             case SDL_QUIT:
   405             case SDL_QUIT:
   366                 event.type = Event::QUIT;
   406                 event.type = Event::QUIT;
   367                 return true;
   407                 return true;
   368 
   408 
   369             case SDL_VIDEORESIZE:
   409             case SDL_VIDEORESIZE:
   480     event.user.code = 1;
   520     event.user.code = 1;
   481     SDL_PushEvent(&event);
   521     SDL_PushEvent(&event);
   482     return 0;
   522     return 0;
   483 }
   523 }
   484 
   524 
       
   525 
       
   526 Uint32 Terminal::_blink_toggle_callback(Uint32 interval, void *param)
       
   527 {
       
   528     SDL_Event event;
       
   529     event.type = SDL_USEREVENT;
       
   530     event.user.code = 2;
       
   531     SDL_PushEvent(&event);
       
   532     return interval;
       
   533 }
       
   534