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); |
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: |