#include "terminaldisplay.hpp" using namespace Terminal; /* Print a new "frame" to the terminal, using ANSI/ECMA-48 escape codes. */ std::string Display::new_frame( Framebuffer &f ) { /* fill in background color on any cells that have been reset or created since last time */ f.back_color_erase(); str.clear(); char tmp[ 64 ]; /* has window title changed? */ if ( (!initialized) || (f.get_window_title() != last_frame.get_window_title()) ) { /* set window title */ str.append( "\033]0;[rtm] " ); std::vector window_title = f.get_window_title(); for ( std::vector::iterator i = window_title.begin(); i != window_title.end(); i++ ) { snprintf( tmp, 64, "%lc", *i ); str.append( tmp ); } str.append( "\033\\" ); } /* has reverse video state changed? */ if ( (!initialized) || (f.ds.reverse_video != last_frame.ds.reverse_video) ) { /* set reverse video */ snprintf( tmp, 64, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') ); str.append( tmp ); } /* has size changed? */ if ( (!initialized) || (f.ds.get_width() != last_frame.ds.get_width()) || (f.ds.get_height() != last_frame.ds.get_height()) ) { /* clear screen */ str.append( "\033[0m\033[H\033[2J" ); initialized = false; cursor_x = cursor_y = 0; current_rendition_string = "\033[0m"; } /* iterate for every cell */ for ( y = 0; y < f.ds.get_height(); y++ ) { for ( x = 0; x < f.ds.get_width(); /* let charwidth handle advance */ ) { put_cell( f ); } } /* has cursor location changed? */ if ( (!initialized) || (f.ds.get_cursor_row() != cursor_y) || (f.ds.get_cursor_col() != cursor_x) ) { snprintf( tmp, 64, "\033[%d;%dH", f.ds.get_cursor_row() + 1, f.ds.get_cursor_col() + 1 ); str.append( tmp ); cursor_x = f.ds.get_cursor_col(); cursor_y = f.ds.get_cursor_row(); } /* has cursor visibility changed? */ if ( (!initialized) || (f.ds.cursor_visible != last_frame.ds.cursor_visible) ) { if ( f.ds.cursor_visible ) { str.append( "\033[?25h" ); } else { str.append( "\033[?25l" ); } } last_frame = f; initialized = true; return str; } void Display::put_cell( Framebuffer &f ) { char tmp[ 64 ]; Cell *cell = f.get_cell( y, x ); Cell *last_cell = last_frame.get_cell( y, x ); if ( initialized && ( *cell == *last_cell ) ) { x += cell->width; return; } if ( (x != cursor_x) || (y != cursor_y) ) { snprintf( tmp, 64, "\033[%d;%dH", y + 1, x + 1 ); str.append( tmp ); cursor_x = x; cursor_y = y; } std::string rendition_str = cell->renditions.sgr(); if ( current_rendition_string != rendition_str ) { /* print renditions */ str.append( rendition_str ); current_rendition_string = rendition_str; } if ( cell->contents.empty() ) { /* see how far we can stretch a clear */ int clear_count = 0; for ( int col = x; col < f.ds.get_width(); col++ ) { Cell *other_cell = f.get_cell( y, col ); if ( (cell->renditions == other_cell->renditions) && (other_cell->contents.empty()) ) { clear_count++; } else { break; } } snprintf( tmp, 64, "\033[%dX", clear_count ); str.append( tmp ); x += clear_count; return; } /* cells that begin with combining character get combiner attached to no-break space */ if ( cell->fallback ) { snprintf( tmp, 64, "%lc", 0xA0 ); str.append( tmp ); } for ( std::vector::iterator i = cell->contents.begin(); i != cell->contents.end(); i++ ) { snprintf( tmp, 64, "%lc", *i ); str.append( tmp ); } x += cell->width; cursor_x += cell->width; }