Refactoring FVTerm::updateTerminalLine

This commit is contained in:
Markus Gans 2017-11-30 02:38:55 +01:00
parent 6be608ba57
commit abf89f1538
7 changed files with 484 additions and 348 deletions

View File

@ -1,3 +1,6 @@
2017-11-30 Markus Gans <guru.mail@muenster.de>
* Refactoring FVTerm::updateTerminalLine
2017-11-26 Markus Gans <guru.mail@muenster.de> 2017-11-26 Markus Gans <guru.mail@muenster.de>
* Better code readability by splitting FOptiMove::moveCursor * Better code readability by splitting FOptiMove::moveCursor
into sub-functions into sub-functions

View File

@ -343,9 +343,16 @@ class FVTerm : public FTerm
term_area* vwin; // virtual window term_area* vwin; // virtual window
private: private:
// Typedef // Typedef and Enumeration
typedef FTermcap::tcap_map termcap_map; typedef FTermcap::tcap_map termcap_map;
enum exit_state
{
not_used,
used,
line_completely_printed
};
// Constants // Constants
static const uInt TERMINAL_OUTPUT_BUFFER_SIZE = 32768; static const uInt TERMINAL_OUTPUT_BUFFER_SIZE = 32768;
// Buffer size for character output on the terminal // Buffer size for character output on the terminal
@ -363,6 +370,14 @@ class FVTerm : public FTerm
void init(); void init();
void finish(); void finish();
static bool clearTerm (int = ' '); static bool clearTerm (int = ' ');
static bool canClearToEOL (uInt, uInt);
static bool canClearLeadingWS (uInt&, uInt);
static bool canClearTailingWS (uInt&, uInt);
static bool skipUnchangedCharacters (uInt&, uInt, uInt);
static void printRange (uInt, uInt, uInt, bool);
static exit_state eraseCharacters (uInt&, uInt, uInt, bool);
static exit_state repeatCharacter (uInt&, uInt, uInt);
static void cursorWrap();
static void updateTerminalLine (uInt); static void updateTerminalLine (uInt);
static bool updateTerminalCursor(); static bool updateTerminalCursor();
static bool isInsideTerminal (int, int); static bool isInsideTerminal (int, int);

View File

@ -2244,28 +2244,16 @@ bool FVTerm::clearTerm (int fillchar)
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FVTerm::updateTerminalLine (uInt y) bool FVTerm::canClearToEOL (uInt xmin, uInt y)
{ {
// Updates pending changes from line y to the terminal // Is the line from xmin to the end of the line blank?
term_area* vt = vterm; // => clear to end of line
uInt& xmin = vt->changes[y].xmin;
uInt& xmax = vt->changes[y].xmax;
int term_width = vt->width - 1;
int term_height = vt->height - 1;
if ( xmin <= xmax ) term_area*& vt = vterm;
{ bool& ut = FTermcap::background_color_erase;
bool is_eol_clean = false;
bool draw_leading_ws = false;
bool draw_tailing_ws = false;
char*& ce = TCAP(fc::t_clr_eol); char*& ce = TCAP(fc::t_clr_eol);
char*& cb = TCAP(fc::t_clr_bol);
bool ut = FTermcap::background_color_erase;
char_data* first_char = &vt->text[y * uInt(vt->width)];
char_data* last_char = &vt->text[(y + 1) * uInt(vt->width) - 1];
char_data* min_char = &vt->text[y * uInt(vt->width) + xmin]; char_data* min_char = &vt->text[y * uInt(vt->width) + xmin];
// Is the line from xmin to the end of the line blank?
if ( ce && min_char->code == ' ' ) if ( ce && min_char->code == ' ' )
{ {
uInt beginning_whitespace = 1; uInt beginning_whitespace = 1;
@ -2284,12 +2272,23 @@ void FVTerm::updateTerminalLine (uInt y)
if ( beginning_whitespace == uInt(vt->width) - xmin if ( beginning_whitespace == uInt(vt->width) - xmin
&& (ut || normal) && (ut || normal)
&& clr_eol_length < int(beginning_whitespace) ) && clr_eol_length < int(beginning_whitespace) )
is_eol_clean = true; return true;
} }
if ( ! is_eol_clean ) return false;
{ }
// leading whitespace
//----------------------------------------------------------------------
bool FVTerm::canClearLeadingWS (uInt& xmin, uInt y)
{
// Line has leading whitespace
// => clear from xmin to beginning of line
term_area*& vt = vterm;
bool& ut = FTermcap::background_color_erase;
char*& cb = TCAP(fc::t_clr_bol);
char_data* first_char = &vt->text[y * uInt(vt->width)];
if ( cb && first_char->code == ' ' ) if ( cb && first_char->code == ' ' )
{ {
uInt leading_whitespace = 1; uInt leading_whitespace = 1;
@ -2309,12 +2308,25 @@ void FVTerm::updateTerminalLine (uInt y)
&& (ut || normal) && (ut || normal)
&& clr_bol_length < int(leading_whitespace) ) && clr_bol_length < int(leading_whitespace) )
{ {
draw_leading_ws = true;
xmin = leading_whitespace - 1; xmin = leading_whitespace - 1;
return true;
} }
} }
// tailing whitespace return false;
}
//----------------------------------------------------------------------
bool FVTerm::canClearTailingWS (uInt& xmax, uInt y)
{
// Line has tailing whitespace
// => clear from xmax to end of line
term_area*& vt = vterm;
bool& ut = FTermcap::background_color_erase;
char*& ce = TCAP(fc::t_clr_eol);
char_data* last_char = &vt->text[(y + 1) * uInt(vt->width) - 1];
if ( ce && last_char->code == ' ' ) if ( ce && last_char->code == ' ' )
{ {
uInt tailing_whitespace = 1; uInt tailing_whitespace = 1;
@ -2334,38 +2346,23 @@ void FVTerm::updateTerminalLine (uInt y)
&& (ut || normal) && (ut || normal)
&& clr_bol_length < int(tailing_whitespace) ) && clr_bol_length < int(tailing_whitespace) )
{ {
draw_tailing_ws = true;
xmax = uInt(vt->width) - tailing_whitespace; xmax = uInt(vt->width) - tailing_whitespace;
} return true;
} }
} }
setTermXY (int(xmin), int(y)); return false;
}
if ( is_eol_clean ) //----------------------------------------------------------------------
{ bool FVTerm::skipUnchangedCharacters(uInt& x, uInt xmax, uInt y)
appendAttributes (min_char); {
appendOutputBuffer (ce); // Skip characters without changes if it is faster than redrawing
markAsPrinted (xmin, uInt(vt->width - 1), y);
}
else
{
if ( draw_leading_ws )
{
appendAttributes (first_char);
appendOutputBuffer (cb);
markAsPrinted (0, xmin, y);
}
for (uInt x = xmin; x <= xmax; x++) term_area*& vt = vterm;
{ char_data* print_char = &vt->text[y * uInt(vt->width) + x];
char_data* print_char;
char*& ec = TCAP(fc::t_erase_chars);
char*& rp = TCAP(fc::t_repeat_char);
print_char = &vt->text[y * uInt(vt->width) + x];
print_char->attr.bit.printed = true; print_char->attr.bit.printed = true;
// skip character with no changes
if ( print_char->attr.bit.no_changes ) if ( print_char->attr.bit.no_changes )
{ {
uInt count = 1; uInt count = 1;
@ -2384,13 +2381,65 @@ void FVTerm::updateTerminalLine (uInt y)
{ {
setTermXY (int(x + count), int(y)); setTermXY (int(x + count), int(y));
x = x + count - 1; x = x + count - 1;
continue; return true;
} }
} }
// Erase a number of characters to draw simple whitespaces return false;
}
//----------------------------------------------------------------------
void FVTerm::printRange ( uInt xmin, uInt xmax, uInt y
, bool draw_tailing_ws )
{
for (uInt x = xmin; x <= xmax; x++)
{
char_data* print_char;
term_area*& vt = vterm;
char*& ec = TCAP(fc::t_erase_chars);
char*& rp = TCAP(fc::t_repeat_char);
print_char = &vt->text[y * uInt(vt->width) + x];
print_char->attr.bit.printed = true;
// skip character with no changes
if ( skipUnchangedCharacters(x, xmax, y) )
continue;
// Erase character
if ( ec && print_char->code == ' ' ) if ( ec && print_char->code == ' ' )
{ {
exit_state erase_state = \
eraseCharacters(x, xmax, y, draw_tailing_ws);
if ( erase_state == line_completely_printed )
break;
}
else if ( rp ) // Repeat one character n-fold
{
repeatCharacter(x, xmax, y);
}
else
{
// General character output
appendCharacter (print_char);
markAsPrinted (x, y);
}
}
}
//----------------------------------------------------------------------
FVTerm::exit_state FVTerm::eraseCharacters ( uInt& x, uInt xmax, uInt y
, bool draw_tailing_ws )
{
// Erase a number of characters to draw simple whitespaces
term_area*& vt = vterm;
bool& ut = FTermcap::background_color_erase;
char*& ec = TCAP(fc::t_erase_chars);
char_data* print_char = &vt->text[y * uInt(vt->width) + x];
if ( ! ec || print_char->code != ' ' )
return not_used;
uInt whitespace = 1; uInt whitespace = 1;
bool normal = isNormal(print_char); bool normal = isNormal(print_char);
@ -2422,7 +2471,7 @@ void FVTerm::updateTerminalLine (uInt y)
if ( x + whitespace - 1 < xmax || draw_tailing_ws ) if ( x + whitespace - 1 < xmax || draw_tailing_ws )
setTermXY (int(x + whitespace), int(y)); setTermXY (int(x + whitespace), int(y));
else else
break; return line_completely_printed;
x = x + whitespace - 1; x = x + whitespace - 1;
} }
@ -2436,9 +2485,22 @@ void FVTerm::updateTerminalLine (uInt y)
markAsPrinted (start_pos, x, y); markAsPrinted (start_pos, x, y);
} }
}
else if ( rp ) // Repeat one character n-fold return used;
{ }
//----------------------------------------------------------------------
FVTerm::exit_state FVTerm::repeatCharacter (uInt& x, uInt xmax, uInt y)
{
// Repeat one character n-fold
term_area*& vt = vterm;
char*& rp = TCAP(fc::t_repeat_char);
char_data* print_char = &vt->text[y * uInt(vt->width) + x];
if ( ! rp )
return not_used;
uInt repetitions = 1; uInt repetitions = 1;
for (uInt i = x + 1; i <= xmax; i++) for (uInt i = x + 1; i <= xmax; i++)
@ -2480,28 +2542,18 @@ void FVTerm::updateTerminalLine (uInt y)
markAsPrinted (start_pos, x, y); markAsPrinted (start_pos, x, y);
} }
}
else // General character output
{
appendCharacter (print_char);
markAsPrinted (x, y);
}
}
if ( draw_tailing_ws ) return used;
{ }
appendAttributes (last_char);
appendOutputBuffer (ce);
markAsPrinted (xmax + 1, uInt(vt->width - 1), y);
}
}
// Reset line changes //----------------------------------------------------------------------
xmin = uInt(vt->width); void FVTerm::cursorWrap()
xmax = 0; {
} // Wrap the cursor
term_area*& vt = vterm;
int term_width = vt->width - 1;
int term_height = vt->height - 1;
// cursor wrap
if ( term_pos->getX() > term_width ) if ( term_pos->getX() > term_width )
{ {
if ( term_pos->getY() == term_height ) if ( term_pos->getY() == term_height )
@ -2523,6 +2575,72 @@ void FVTerm::updateTerminalLine (uInt y)
} }
} }
//----------------------------------------------------------------------
void FVTerm::updateTerminalLine (uInt y)
{
// Updates pending changes from line y to the terminal
term_area*& vt = vterm;
uInt& xmin = vt->changes[y].xmin;
uInt& xmax = vt->changes[y].xmax;
if ( xmin <= xmax )
{
bool draw_leading_ws = false;
bool draw_tailing_ws = false;
char*& ce = TCAP(fc::t_clr_eol);
char*& cb = TCAP(fc::t_clr_bol);
char_data* first_char = &vt->text[y * uInt(vt->width)];
char_data* last_char = &vt->text[(y + 1) * uInt(vt->width) - 1];
char_data* min_char = &vt->text[y * uInt(vt->width) + xmin];
// Clear rest of line
bool is_eol_clean = canClearToEOL (xmin, y);
if ( ! is_eol_clean )
{
// leading whitespace
draw_leading_ws = canClearLeadingWS (xmin, y);
// tailing whitespace
draw_tailing_ws = canClearTailingWS (xmax, y);
}
setTermXY (int(xmin), int(y));
if ( is_eol_clean )
{
appendAttributes (min_char);
appendOutputBuffer (ce);
markAsPrinted (xmin, uInt(vt->width - 1), y);
}
else
{
if ( draw_leading_ws )
{
appendAttributes (first_char);
appendOutputBuffer (cb);
markAsPrinted (0, xmin, y);
}
printRange (xmin, xmax, y, draw_tailing_ws);
if ( draw_tailing_ws )
{
appendAttributes (last_char);
appendOutputBuffer (ce);
markAsPrinted (xmax + 1, uInt(vt->width - 1), y);
}
}
// Reset line changes
xmin = uInt(vt->width);
xmax = 0;
}
cursorWrap();
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
bool FVTerm::updateTerminalCursor() bool FVTerm::updateTerminalCursor()
{ {