Modularize display code and add representation of wrapped line flag

This commit is contained in:
Keith Winstein
2011-02-09 15:30:50 -05:00
parent 1ee54cd70a
commit 71dfd5a763
7 changed files with 141 additions and 104 deletions
+1
View File
@@ -40,6 +40,7 @@ void Emulator::print( Parser::Print *act )
case 1: /* normal character */ case 1: /* normal character */
case 2: /* wide character */ case 2: /* wide character */
if ( fb.ds.auto_wrap_mode && fb.ds.next_print_will_wrap ) { if ( fb.ds.auto_wrap_mode && fb.ds.next_print_will_wrap ) {
fb.get_row( -1 )->wrap = true;
fb.ds.move_col( 0 ); fb.ds.move_col( 0 );
fb.move_rows_autoscroll( 1 ); fb.move_rows_autoscroll( 1 );
} }
+1 -17
View File
@@ -10,25 +10,9 @@
#include "terminalframebuffer.hpp" #include "terminalframebuffer.hpp"
#include "terminaldispatcher.hpp" #include "terminaldispatcher.hpp"
#include "terminaluserinput.hpp" #include "terminaluserinput.hpp"
#include "terminaldisplay.hpp"
namespace Terminal { namespace Terminal {
class Display {
private:
bool initialized;
Framebuffer last_frame;
std::string current_rendition_string;
int cursor_x, cursor_y;
public:
Display( int width, int height )
: initialized( false ), last_frame( width, height ),
current_rendition_string(), cursor_x( -1 ), cursor_y( -1 )
{}
std::string new_frame( Framebuffer &f );
void invalidate( void ) { initialized = false; }
};
class Emulator { class Emulator {
friend void Parser::Print::act_on_terminal( Emulator * ); friend void Parser::Print::act_on_terminal( Emulator * );
friend void Parser::Execute::act_on_terminal( Emulator * ); friend void Parser::Execute::act_on_terminal( Emulator * );
+84 -81
View File
@@ -1,4 +1,4 @@
#include "terminal.hpp" #include "terminaldisplay.hpp"
using namespace Terminal; using namespace Terminal;
@@ -6,33 +6,34 @@ using namespace Terminal;
std::string Display::new_frame( Framebuffer &f ) 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(); f.back_color_erase();
std::string screen; str.clear();
char tmp[ 64 ];
/* has window title changed? */ /* has window title changed? */
if ( (!initialized) if ( (!initialized)
|| (f.get_window_title() != last_frame.get_window_title()) ) { || (f.get_window_title() != last_frame.get_window_title()) ) {
/* set window title */ /* set window title */
screen.append( "\033]0;[rtm] " ); str.append( "\033]0;[rtm] " );
std::vector<wchar_t> window_title = f.get_window_title(); std::vector<wchar_t> window_title = f.get_window_title();
for ( std::vector<wchar_t>::iterator i = window_title.begin(); for ( std::vector<wchar_t>::iterator i = window_title.begin();
i != window_title.end(); i != window_title.end();
i++ ) { i++ ) {
char utf8[ 8 ]; snprintf( tmp, 64, "%lc", *i );
snprintf( utf8, 8, "%lc", *i ); str.append( tmp );
screen.append( utf8 );
} }
screen.append( "\033\\" ); str.append( "\033\\" );
} }
/* has reverse video state changed? */ /* has reverse video state changed? */
if ( (!initialized) if ( (!initialized)
|| (f.ds.reverse_video != last_frame.ds.reverse_video) ) { || (f.ds.reverse_video != last_frame.ds.reverse_video) ) {
/* set reverse video */ /* set reverse video */
char rev[ 8 ]; snprintf( tmp, 64, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') );
snprintf( rev, 8, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') ); str.append( tmp );
screen.append( rev );
} }
/* has size changed? */ /* has size changed? */
@@ -40,77 +41,16 @@ std::string Display::new_frame( Framebuffer &f )
|| (f.ds.get_width() != last_frame.ds.get_width()) || (f.ds.get_width() != last_frame.ds.get_width())
|| (f.ds.get_height() != last_frame.ds.get_height()) ) { || (f.ds.get_height() != last_frame.ds.get_height()) ) {
/* clear screen */ /* clear screen */
screen.append( "\033[0m\033[H\033[2J" ); str.append( "\033[0m\033[H\033[2J" );
initialized = false; initialized = false;
cursor_x = cursor_y = 0; cursor_x = cursor_y = 0;
current_rendition_string = "\033[0m"; current_rendition_string = "\033[0m";
} }
/* iterate for every cell */ /* iterate for every cell */
for ( int y = 0; y < f.ds.get_height(); y++ ) { for ( y = 0; y < f.ds.get_height(); y++ ) {
for ( int x = 0; x < f.ds.get_width(); /* let charwidth handle advance */ ) { for ( x = 0; x < f.ds.get_width(); /* let charwidth handle advance */ ) {
Cell *cell = f.get_cell( y, x ); put_cell( f );
if ( initialized
&& ( *cell == *(last_frame.get_cell( y, x )) ) ) {
x += cell->width;
continue;
}
if ( (x != cursor_x) || (y != cursor_y) ) {
char curmove[ 32 ];
snprintf( curmove, 32, "\033[%d;%dH", y + 1, x + 1 );
screen.append( curmove );
}
cursor_x = x;
cursor_y = y;
std::string rendition_str = cell->renditions.sgr();
if ( current_rendition_string != rendition_str ) {
/* print renditions */
screen.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;
}
}
char clearer[ 32 ];
snprintf( clearer, 32, "\033[%dX", clear_count );
screen.append( clearer );
x += clear_count;
continue;
}
/* cells that begin with combining character get combiner attached to no-break space */
if ( cell->fallback ) {
char utf8[ 8 ];
snprintf( utf8, 8, "%lc", 0xA0 );
screen.append( utf8 );
}
for ( std::vector<wchar_t>::iterator i = cell->contents.begin();
i != cell->contents.end();
i++ ) {
char utf8[ 8 ];
snprintf( utf8, 8, "%lc", *i );
screen.append( utf8 );
}
x += cell->width;
cursor_x += cell->width;
} }
} }
@@ -118,10 +58,9 @@ std::string Display::new_frame( Framebuffer &f )
if ( (!initialized) if ( (!initialized)
|| (f.ds.get_cursor_row() != cursor_y) || (f.ds.get_cursor_row() != cursor_y)
|| (f.ds.get_cursor_col() != cursor_x) ) { || (f.ds.get_cursor_col() != cursor_x) ) {
char curmove[ 32 ]; snprintf( tmp, 64, "\033[%d;%dH", f.ds.get_cursor_row() + 1,
snprintf( curmove, 32, "\033[%d;%dH", f.ds.get_cursor_row() + 1,
f.ds.get_cursor_col() + 1 ); f.ds.get_cursor_col() + 1 );
screen.append( curmove ); str.append( tmp );
cursor_x = f.ds.get_cursor_col(); cursor_x = f.ds.get_cursor_col();
cursor_y = f.ds.get_cursor_row(); cursor_y = f.ds.get_cursor_row();
} }
@@ -130,14 +69,78 @@ std::string Display::new_frame( Framebuffer &f )
if ( (!initialized) if ( (!initialized)
|| (f.ds.cursor_visible != last_frame.ds.cursor_visible) ) { || (f.ds.cursor_visible != last_frame.ds.cursor_visible) ) {
if ( f.ds.cursor_visible ) { if ( f.ds.cursor_visible ) {
screen.append( "\033[?25h" ); str.append( "\033[?25h" );
} else { } else {
screen.append( "\033[?25l" ); str.append( "\033[?25l" );
} }
} }
last_frame = f; last_frame = f;
initialized = true; initialized = true;
return screen; 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<wchar_t>::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;
} }
+30
View File
@@ -0,0 +1,30 @@
#ifndef TERMINALDISPLAY_HPP
#define TERMINALDISPLAY_HPP
#include "terminalframebuffer.hpp"
namespace Terminal {
class Display {
private:
bool initialized;
Framebuffer last_frame;
std::string current_rendition_string;
int cursor_x, cursor_y;
int x, y;
std::string str;
void put_cell( Framebuffer &f );
public:
Display( int width, int height )
: initialized( false ), last_frame( width, height ),
current_rendition_string(), cursor_x( -1 ), cursor_y( -1 ),
x( 0 ), y( 0 ), str( "" )
{}
std::string new_frame( Framebuffer &f );
void invalidate( void ) { initialized = false; }
};
}
#endif
+9
View File
@@ -411,3 +411,12 @@ std::string Renditions::sgr( void )
return ret; return ret;
} }
void Row::reset( void )
{
for ( std::vector<Cell>::iterator i = cells.begin();
i != cells.end();
i++ ) {
i->reset();
}
}
+11 -1
View File
@@ -60,13 +60,16 @@ namespace Terminal {
class Row { class Row {
public: public:
std::vector<Cell> cells; std::vector<Cell> cells;
bool wrap;
Row( size_t s_width ) Row( size_t s_width )
: cells( s_width ) : cells( s_width ), wrap( false )
{} {}
void insert_cell( int col ); void insert_cell( int col );
void delete_cell( int col ); void delete_cell( int col );
void reset( void );
}; };
class SavedCursor { class SavedCursor {
@@ -161,6 +164,13 @@ namespace Terminal {
void move_rows_autoscroll( int rows ); void move_rows_autoscroll( int rows );
Row *get_row( int row )
{
if ( row == -1 ) row = ds.get_cursor_row();
return &rows[ row ];
}
inline Cell *get_cell( void ) inline Cell *get_cell( void )
{ {
return &rows[ ds.get_cursor_row() ].cells[ ds.get_cursor_col() ]; return &rows[ ds.get_cursor_row() ].cells[ ds.get_cursor_col() ];
+5 -5
View File
@@ -27,7 +27,7 @@ void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
clearline( fb, -1, 0, fb->ds.get_cursor_col() ); clearline( fb, -1, 0, fb->ds.get_cursor_col() );
break; break;
case 2: /* all of line */ case 2: /* all of line */
clearline( fb, -1, 0, fb->ds.get_width() - 1 ); fb->get_row( -1 )->reset();
break; break;
} }
} }
@@ -40,18 +40,18 @@ void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) {
case 0: /* active position to end of screen, inclusive */ case 0: /* active position to end of screen, inclusive */
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 ); clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
for ( int y = fb->ds.get_cursor_row() + 1; y < fb->ds.get_height(); y++ ) { for ( int y = fb->ds.get_cursor_row() + 1; y < fb->ds.get_height(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 ); fb->get_row( y )->reset();
} }
break; break;
case 1: /* start of screen to active position, inclusive */ case 1: /* start of screen to active position, inclusive */
for ( int y = 0; y < fb->ds.get_cursor_row(); y++ ) { for ( int y = 0; y < fb->ds.get_cursor_row(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 ); fb->get_row( y )->reset();
} }
clearline( fb, -1, 0, fb->ds.get_cursor_col() ); clearline( fb, -1, 0, fb->ds.get_cursor_col() );
break; break;
case 2: /* entire screen */ case 2: /* entire screen */
for ( int y = 0; y < fb->ds.get_height(); y++ ) { for ( int y = 0; y < fb->ds.get_height(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 ); fb->get_row( y )->reset();
} }
break; break;
} }
@@ -215,7 +215,7 @@ static bool *get_DEC_mode( int param, Framebuffer *fb ) {
fb->ds.move_row( 0 ); fb->ds.move_row( 0 );
fb->ds.move_col( 0 ); fb->ds.move_col( 0 );
for ( int y = 0; y < fb->ds.get_height(); y++ ) { for ( int y = 0; y < fb->ds.get_height(); y++ ) {
clearline( fb, y, 0, fb->ds.get_width() - 1 ); fb->get_row( y )->reset();
} }
return NULL; return NULL;
case 5: /* reverse video */ case 5: /* reverse video */