Solve issue 837, doc some protected methods.

This commit is contained in:
Greg Ercolano 2023-11-20 09:26:40 -08:00
parent eb9dd202b2
commit 6252131017
2 changed files with 246 additions and 123 deletions

View File

@ -259,11 +259,10 @@
**/
class FL_EXPORT Fl_Terminal : public Fl_Group {
public:
//////////////////////////////////////
////// Fl_Terminal Public Enums //////
//////////////////////////////////////
public:
/**
\enum RedrawStyle
Determines when Fl_Terminal calls redraw() if new text is added.
@ -356,7 +355,7 @@ protected:
int fontdescent_; // font descent (pixels below font baseline)
int charwidth_; // width of a fixed width ASCII character
public:
CharStyle(void);
CharStyle(bool fontsize_defer);
Fl_Color fgcolor(void) const;
Fl_Color bgcolor(void) const;
Fl_Color defaultfgcolor(void) const { return defaultfgcolor_; }
@ -382,6 +381,7 @@ protected:
void fontface(Fl_Font val) { fontface_ = val; update(); }
void fontsize(Fl_Fontsize val) { fontsize_ = val; update(); }
void update(void);
void update_fake(void);
// SGR MODES: Set Graphics Rendition
void sgr_reset(void) { // e.g. ESC[0m
attrib(Fl_Terminal::NORMAL);
@ -571,7 +571,6 @@ private:
const Utf8Char* u8c_hist_row(int hrow) const;
const Utf8Char* u8c_hist_use_row(int hurow) const;
const Utf8Char* u8c_disp_row(int drow) const;
// Non-const versions of the above methods
// Using "Effective C++" ugly-as-hell syntax technique.
//
@ -726,9 +725,10 @@ private:
//////
///////////////////////////////////////////////////////////////
private:
bool fontsize_defer_; // flag defers font calcs until first draw() (issue 837)
Fl_Scrollbar *vscroll_; // vertical scrollbar (value: rows above disp_chars[])
int scrollbar_size_; // local preference for scrollbar size
CharStyle current_style_; // current font, attrib, color..
CharStyle *current_style_; // current font, attrib, color..
// A ring buffer is used for the terminal's history (hist) and display (disp) buffer.
// See README-Fl_Terminal.txt, section "RING BUFFER DESCRIPTION" for diagrams/info.
@ -758,15 +758,17 @@ protected:
const Utf8Char* u8c_hist_row(int hrow) const;
const Utf8Char* u8c_hist_use_row(int hrow) const;
const Utf8Char* u8c_disp_row(int drow) const;
// non-const versions of the above.
// Non-const versions of the above.
// "Effective C++" says: implement non-const method to cast away const
//
Utf8Char* u8c_ring_row(int grow);
Utf8Char* u8c_hist_row(int hrow);
Utf8Char* u8c_hist_use_row(int hurow);
Utf8Char* u8c_disp_row(int drow);
Utf8Char* u8c_cursor(void);
private:
void create_ring(int drows, int dcols, int hrows);
void init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer);
protected:
int vscroll_width(void) const;
private:
@ -992,21 +994,21 @@ public:
void textfgcolor_default(Fl_Color val);
void textbgcolor_default(Fl_Color val);
/// Return text font used to draw all text in the terminal.
Fl_Font textfont(void) const { return current_style_.fontface(); }
Fl_Font textfont(void) const { return current_style_->fontface(); }
/// Return text font size used to draw all text in the terminal.
Fl_Fontsize textsize(void) const { return current_style_.fontsize(); }
Fl_Fontsize textsize(void) const { return current_style_->fontsize(); }
/// Return base widget Fl_Group's box() color()
Fl_Color color(void) const { return Fl_Group::color(); }
/// Return textcolor(). This is a convenience method that returns textfgcolor_default()
Fl_Color textcolor(void) const { return textfgcolor_default(); }
/// Return text's current foreground color.
Fl_Color textfgcolor(void) const { return current_style_.fgcolor(); }
Fl_Color textfgcolor(void) const { return current_style_->fgcolor(); }
/// Return text's current background color.
Fl_Color textbgcolor(void) const { return current_style_.bgcolor(); }
Fl_Color textbgcolor(void) const { return current_style_->bgcolor(); }
/// Return text's default foreground color. \see textfgcolor()
Fl_Color textfgcolor_default(void) const { return current_style_.defaultfgcolor(); }
Fl_Color textfgcolor_default(void) const { return current_style_->defaultfgcolor(); }
/// Return text's default background color. \see textbgcolor()
Fl_Color textbgcolor_default(void) const { return current_style_.defaultbgcolor(); }
Fl_Color textbgcolor_default(void) const { return current_style_->defaultbgcolor(); }
void textfgcolor_xterm(uchar val);
void textbgcolor_xterm(uchar val);
/// Set mouse selection foreground color.
@ -1040,7 +1042,8 @@ public:
void printf(const char *fmt, ...);
void vprintf(const char *fmt, va_list ap);
// Ctor
Fl_Terminal(int X, int Y, int W, int H, const char*L=0);
Fl_Terminal(int X,int Y,int W,int H,const char*L=0);
Fl_Terminal(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist);
// Dtor
~Fl_Terminal(void);
// Debugging features

View File

@ -419,7 +419,10 @@ pfail:
//////////////////////////////////////
// Ctor
Fl_Terminal::CharStyle::CharStyle(void) {
// fontsize_defer - if true, hold off on doing fl_font() oriented calculations until
// just before draw(). This is for fluid's headless mode. (issue 837)
//
Fl_Terminal::CharStyle::CharStyle(bool fontsize_defer) {
attrib_ = 0;
flags_ = 0;
defaultfgcolor_ = 0xd0d0d000; // off white
@ -429,7 +432,8 @@ Fl_Terminal::CharStyle::CharStyle(void) {
flags_ |= (FG_XTERM | BG_XTERM);
fontface_ = FL_COURIER;
fontsize_ = 14;
update(); // updates fontheight_, fontdescent_, charwidth_
if (!fontsize_defer) update(); // normal behavior
else update_fake(); // use fake values instead
}
// Update fontheight/descent cache whenever font changes
@ -441,6 +445,16 @@ void Fl_Terminal::CharStyle::update(void) {
charwidth_ = int(fl_width("X") + 0.5);
}
// Update fontheight/descent cache with fake values (issue 837)
// XXX: Please remove this issue 837 hack the minute fluid no longer has to
// instance fltk classes in headless mode
//
void Fl_Terminal::CharStyle::update_fake(void) {
fontheight_ = 99; // Use fake values until first draw() when we call update() for real values.
fontdescent_ = 99; // Use absurdly large values here to make un-updated sizes clearly evident
charwidth_ = 99;
}
// Return fg color
Fl_Color Fl_Terminal::CharStyle::fgcolor(void) const {
return fgcolor_;
@ -545,7 +559,7 @@ void Fl_Terminal::Utf8Char::text_utf8(const char *text,
int len,
const CharStyle& style) {
text_utf8_(text, len); // updates text_, len_
fl_font(style.fontface(), style.fontsize()); // need font to calc UTF-8 width
//issue 837 // fl_font(style.fontface(), style.fontsize()); // need font to calc UTF-8 width
attrib_ = style.attrib();
flags_ = style.colorbits_only(flags_);
fgcolor_ = style.fgcolor();
@ -841,14 +855,14 @@ void Fl_Terminal::RingBuffer::scroll(int rows, const CharStyle& style) {
}
// Return UTF-8 char for 'row' in the ring
// Scrolling offset is NOT applied; this is raw access to the ring's rows.
// Scrolling offset is NOT applied; this is raw access to the ring's rows.
//
// Example:
// // Walk ALL rows in the ring buffer..
// for (int row=0; row<ring.rows(); row++) {
// Utf8Char *u8c = ring.u8c_ring_row(row);
// ..
// }
// Example:
// // Walk ALL rows in the ring buffer..
// for (int row=0; row<ring.rows(); row++) {
// Utf8Char *u8c = ring.u8c_ring_row(row);
// ..
// }
//
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row) const {
row = normalize(row, ring_rows());
@ -892,8 +906,8 @@ const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_use_row(int hurow
// Example:
// // Walk ALL rows in display..
// for (int drow=0; drow<ring.drows(); drow++) {
// Utf8Char *u8c = u8c_disp_row(drow);
// ..
// Utf8Char *u8c = u8c_disp_row(drow);
// ..
// }
//
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_disp_row(int drow) const {
@ -903,7 +917,17 @@ const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_disp_row(int drow) con
return &ring_chars_[rowi * ring_cols()];
}
// non-const versions of the above
// non-const versions of the above ////////////////////////////////////////////////
// Return UTF-8 char for 'row' in the ring.
// Scrolling offset is NOT applied; this is raw access to the ring's rows.
// Example:
// // Walk ALL rows in the ring buffer..
// for (int row=0; row<ring.rows(); row++) {
// Utf8Char *u8c = ring.u8c_ring_row(row);
// ..
// }
//
Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_ring_row(row)); }
@ -913,6 +937,13 @@ Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_row(int hrow)
Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_use_row(int hurow)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_hist_use_row(hurow)); }
// Return UTF-8 char for beginning of 'row' in the display buffer
// Example:
// // Walk ALL rows in display..
// for (int drow=0; drow<ring.drows(); drow++) {
// Utf8Char *u8c = u8c_disp_row(drow);
// ..
// }
Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_disp_row(int drow)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_disp_row(drow)); }
@ -965,43 +996,87 @@ void Fl_Terminal::RingBuffer::change_disp_cols(int dcols, const CharStyle& style
///// Fl_Terminal Class Methods /////
/////////////////////////////////////
// Return u8c for beginning of a row inside the ring.
// 'grow' is 'globally' indexed (relative to the beginning of the ring buffer),
// and so can access ANY character in the entire ring buffer (hist or disp)
// by its global index, which is to say without any scrolling offset applied.
// Should really ONLY be used for making a complete copy of the ring.
//
/// See docs for non-const version of u8c_ring_row(int)
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_ring_row(int grow) const
{ return ring_.u8c_ring_row(grow); }
// Return u8c for beginning of a row inside the history.
// 'hrow' is indexed relative to the beginning of the history buffer.
//
/// See docs for non-const version of u8c_hist_row(int)
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_row(int hrow) const
{ return ring_.u8c_hist_row(hrow); }
// Return u8c for beginning of a row inside the 'in use' history.
// 'hurow' is indexed relative to the beginning of the 'in use' buffer.
//
/// See docs for non-const version of u8c_hist_use_row(int)
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_use_row(int hurow) const
{ return ring_.u8c_hist_use_row(hurow); }
// Return u8c for beginning of a row inside the display
// 'drow' is indexed relative to the beginning of the display buffer.
//
/// See docs for non-const version of u8c_disp_row(int)
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow) const
{ return ring_.u8c_disp_row(drow); }
// non-const versions of the above
// non-const versions of the above ////////////////////////////////////////////////
/**
Return UTF-8 char for row \p grow in the ring buffer.
\p grow is globally indexed relative to the beginning of the ring buffer,
so this method can access ANY character in the entire ring buffer (hist or disp)
by the global index.
Scrolling offset is NOT applied; this is raw access to the ring's rows.
Should really ONLY be used for making a complete copy of the ring.
Example:
\code
// Walk ALL rows and cols in the ring buffer..
for (int row=0; row<ring.rows(); row++) {
Utf8Char *u8c = ring.u8c_ring_row(row);
for (int col=0; col<ring.cols(); col++,u8c++) {
..make use of u8c->xxx() methods..
}
}
\endcode
*/
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_ring_row(int grow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_ring_row(grow)); }
/**
Return u8c for beginning of a row inside the scrollback history.
'hrow' is indexed relative to the beginning of the scrollback history buffer.
\see u8c_disp_row(int) for example use.
*/
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_row(int hrow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_hist_row(hrow)); }
/**
Return u8c for beginning of row \p hurow inside the 'in use' part
of the scrollback history.
'hurow' is indexed relative to the beginning of the 'in use' part
of the scrollback history buffer. This may be a different from
u8c_hist_row(int) if the history was recently cleared, and there
aren't many (or any) rows in the history buffer that have been
populated with scrollback text yet.
\see u8c_disp_row(int) for example use.
*/
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_use_row(int hurow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_hist_use_row(hurow)); }
/**
Return pointer to the first u8c character in row \p drow of the display.
- 'drow' is indexed relative to the beginning of the display buffer.
- This can be used to walk all columns in the specfied row, e.g.
\code
// Print all chars in first row of display (ASCII and UTF-8)
Utf8Char *u8c = u8c_disp_row(0); // first char of first display row
int scol = 0, ecol = disp_cols(); // start/end for column loop
for (int col=scol; col<ecol; col++,u8c++) { // loop from first char to last
char *text = u8c->text_utf8(); // text string for char
int len = u8c->length(); // text string length for char
::printf("<%.*s>", len, text); // print potentially multibyte char
}
\endcode
*/
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_disp_row(drow)); }
@ -1023,6 +1098,11 @@ void Fl_Terminal::create_ring(int drows, int dcols, int hrows) {
cursor_.home();
}
/// Return the Utf8Char* for character under cursor.
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_cursor(void) {
return u8c_disp_row(cursor_.row()) + cursor_.col();
}
/// Return scrollbar width if visible, or 0 if not visible.
int Fl_Terminal::vscroll_width(void) const {
return(vscroll_->visible() ? vscroll_->w() : 0);
@ -1116,7 +1196,7 @@ void Fl_Terminal::refit_disp_to_screen(void) {
int drows = clamp(dh, 2, dh); // 2 rows minimum
int dcols = clamp(dw, 10, dw); // 10 cols minimum
int drow_diff = drows - ring_.disp_rows(); // change in rows?
ring_.resize(drows, dcols, hist_rows(), current_style_);
ring_.resize(drows, dcols, hist_rows(), *current_style_);
cursor_.scroll(-drow_diff);
clear_mouse_selection();
update_screen(false);
@ -1160,7 +1240,7 @@ void Fl_Terminal::resize_display_rows(int drows) {
int new_dcols = ring_cols(); // keep cols the same
int new_hrows = hist_rows() - drow_diff; // keep disp:hist ratio same
if (new_hrows<0) new_hrows = 0; // don't let hist be <0
ring_.resize(drows, new_dcols, new_hrows, current_style_);
ring_.resize(drows, new_dcols, new_hrows, *current_style_);
// ..update cursor/selections to track text position
cursor_.scroll(-drow_diff);
select_.clear(); // clear any mouse selection
@ -1177,7 +1257,7 @@ void Fl_Terminal::resize_display_columns(int dcols) {
// No changes? early exit
if (dcols == disp_cols()) return;
// Change cols, preserves previous content if possible
ring_.resize(disp_rows(), dcols, hist_rows(), current_style_);
ring_.resize(disp_rows(), dcols, hist_rows(), *current_style_);
update_scrollbar();
}
@ -1200,8 +1280,11 @@ void Fl_Terminal::update_screen(bool font_changed) {
// current_style: update cursor's size for current font/size
if (font_changed) {
// Change font and current_style's font height
fl_font(current_style_.fontface(), current_style_.fontsize());
cursor_.h(current_style_.fontheight());
if (!fontsize_defer_) { // issue 837
//DEBUG fprintf(stderr, "update_screen(font change): row/cols=%d/%d, cs.width=%d, cs.height=%d\n", display_rows(), display_columns(), current_style_->charwidth(), current_style_->fontheight());
fl_font(current_style_->fontface(), current_style_->fontsize());
}
cursor_.h(current_style_->fontheight());
}
// Update the scrn_* values
update_screen_xywh();
@ -1221,7 +1304,7 @@ int Fl_Terminal::history_rows(void) const {
*/
void Fl_Terminal::history_rows(int hrows) {
if (hrows == history_rows()) return; // no change? done
ring_.resize(disp_rows(), disp_cols(), hrows, current_style_);
ring_.resize(disp_rows(), disp_cols(), hrows, *current_style_);
update_screen(false); // false: no font change
display_modified();
}
@ -1258,7 +1341,7 @@ int Fl_Terminal::display_rows(void) const {
*/
void Fl_Terminal::display_rows(int drows) {
if (drows == disp_rows()) return; // no change? early exit
ring_.resize(drows, disp_cols(), hist_rows(), current_style_);
ring_.resize(drows, disp_cols(), hist_rows(), *current_style_);
update_screen(false); // false: no font change ?NEED?
}
@ -1289,18 +1372,18 @@ int Fl_Terminal::display_columns(void) const {
void Fl_Terminal::display_columns(int dcols) {
if (dcols == disp_cols()) return; // no change? early exit
// Change cols, preserves previous content if possible
ring_.resize(disp_rows(), dcols, hist_rows(), current_style_);
ring_.resize(disp_rows(), dcols, hist_rows(), *current_style_);
update_screen(false); // false: no font change ?NEED?
}
/** Return current style for rendering text. */
const Fl_Terminal::CharStyle& Fl_Terminal::current_style(void) const {
return current_style_;
return *current_style_;
}
/** Set current style for rendering text. */
void Fl_Terminal::current_style(const CharStyle& sty) {
current_style_ = sty;
*current_style_ = sty;
}
/**
@ -1354,7 +1437,7 @@ void Fl_Terminal::margin_bottom(int val) {
as they are monospace.
*/
void Fl_Terminal::textfont(Fl_Font val) {
current_style_.fontface(val);
current_style_->fontface(val);
update_screen(true);
display_modified();
}
@ -1368,7 +1451,7 @@ void Fl_Terminal::textfont(Fl_Font val) {
Changing this will affect the display_rows() and display_columns().
*/
void Fl_Terminal::textsize(Fl_Fontsize val) {
current_style_.fontsize(val);
current_style_->fontsize(val);
update_screen(true);
// Changing font size affects #lines in display, so resize it
refit_disp_to_screen();
@ -1404,7 +1487,7 @@ void Fl_Terminal::textsize(Fl_Fontsize val) {
\see textfgcolor_default(Fl_Color)
*/
void Fl_Terminal::textfgcolor_xterm(uchar val) {
current_style_.fgcolor(fltk_fg_color(val));
current_style_->fgcolor(fltk_fg_color(val));
}
/**
@ -1436,7 +1519,7 @@ void Fl_Terminal::textfgcolor_xterm(uchar val) {
\see textbgcolor_default(Fl_Color)
*/
void Fl_Terminal::textbgcolor_xterm(uchar val) {
current_style_.bgcolor(fltk_bg_color(val));
current_style_->bgcolor(fltk_bg_color(val));
}
/**
@ -1485,7 +1568,7 @@ void Fl_Terminal::color(Fl_Color val) {
\see textfgcolor_default(Fl_Color)
*/
void Fl_Terminal::textfgcolor(Fl_Color val) {
current_style_.fgcolor(val);
current_style_->fgcolor(val);
}
/**
@ -1509,7 +1592,7 @@ void Fl_Terminal::textfgcolor(Fl_Color val) {
\see textbgcolor_default(Fl_Color)
*/
void Fl_Terminal::textbgcolor(Fl_Color val) {
current_style_.bgcolor(val);
current_style_->bgcolor(val);
}
/**
@ -1521,7 +1604,7 @@ void Fl_Terminal::textbgcolor(Fl_Color val) {
\see textfgcolor(Fl_Color)
*/
void Fl_Terminal::textfgcolor_default(Fl_Color val) {
current_style_.defaultfgcolor(val);
current_style_->defaultfgcolor(val);
}
/**
@ -1537,7 +1620,7 @@ void Fl_Terminal::textfgcolor_default(Fl_Color val) {
\see textbgcolor(Fl_Color)
*/
void Fl_Terminal::textbgcolor_default(Fl_Color val) {
current_style_.defaultbgcolor(val);
current_style_->defaultbgcolor(val);
}
/**
@ -1547,7 +1630,7 @@ void Fl_Terminal::textbgcolor_default(Fl_Color val) {
\see Fl_Terminal::Attrib
*/
void Fl_Terminal::textattrib(uchar val) {
current_style_.attrib(val);
current_style_->attrib(val);
}
/**
@ -1560,7 +1643,7 @@ int Fl_Terminal::x_to_glob_col(int X, int grow, int &gcol) const {
int cx = x() + margin_.left(); // char x position
const Utf8Char *u8c = utf8_char_at_glob(grow, 0);
for (gcol=0; gcol<ring_cols(); gcol++,u8c++) { // walk the cols looking for X
u8c->fl_font_set(current_style_); // pwidth_int() needs fl_font set
u8c->fl_font_set(*current_style_); // pwidth_int() needs fl_font set
int cx2 = cx + u8c->pwidth_int(); // char x2 (right edge of char)
if (X >= cx && X < cx2) return 1; // found? return with gcol set
cx += u8c->pwidth_int(); // move cx to start x of next char
@ -1584,7 +1667,7 @@ int Fl_Terminal::xy_to_glob_rowcol(int X, int Y, int &grow, int &gcol) const {
// Find toprow of what's currently drawn on screen
int toprow = disp_srow() - vscroll_->value();
// Find row the 'Y' value is in
grow = toprow + ( (Y-scrn_.y()) / current_style_.fontheight());
grow = toprow + ( (Y-scrn_.y()) / current_style_->fontheight());
return x_to_glob_col(X, grow, gcol);
}
@ -1676,7 +1759,7 @@ void Fl_Terminal::clear_eod(void) {
void Fl_Terminal::clear_eol(void) {
Utf8Char *u8c = u8c_disp_row(cursor_.row()) + cursor_.col(); // start at cursor
for (int col=cursor_.col(); col<disp_cols(); col++) // run from cursor to eol
(u8c++)->clear(current_style_);
(u8c++)->clear(*current_style_);
//TODO: Clear mouse selection?
}
@ -1684,7 +1767,7 @@ void Fl_Terminal::clear_eol(void) {
void Fl_Terminal::clear_sol(void) {
Utf8Char *u8c = u8c_disp_row(cursor_.row()); // start at sol
for (int col=0; col<=cursor_.col(); col++) // run from sol to cursor
(u8c++)->clear(current_style_);
(u8c++)->clear(*current_style_);
//TODO: Clear mouse selection?
}
@ -1692,7 +1775,7 @@ void Fl_Terminal::clear_sol(void) {
void Fl_Terminal::clear_line(int drow) {
Utf8Char *u8c = u8c_disp_row(drow); // start at sol
for (int col=0; col<disp_cols(); col++) // run to eol
(u8c++)->clear(current_style_);
(u8c++)->clear(*current_style_);
//TODO: Clear mouse selection?
}
@ -1908,7 +1991,7 @@ bool Fl_Terminal::selection_extend(int X,int Y) {
*/
void Fl_Terminal::scroll(int rows) {
// Scroll the ring
ring_.scroll(rows, current_style_);
ring_.scroll(rows, *current_style_);
if (rows > 0) update_scrollbar(); // scroll up? changes hist, so scrollbar affected
else clear_mouse_selection(); // scroll dn? clear mouse select; it might wrap ring
}
@ -1930,7 +2013,7 @@ void Fl_Terminal::insert_rows(int count) {
while ( dst_drow >= cursor_.row() ) { // walk srcrow to curs line
Utf8Char *dst = u8c_disp_row(dst_drow--);
for (int dcol=0; dcol<disp_cols(); dcol++)
dst++->clear(current_style_);
dst++->clear(*current_style_);
}
clear_mouse_selection();
}
@ -1953,7 +2036,7 @@ void Fl_Terminal::delete_rows(int count) {
while ( dst_drow < disp_rows() ) { // walk srcrow to EOD
Utf8Char *dst = u8c_disp_row(dst_drow++);
for (int dcol=0; dcol<disp_cols(); dcol++)
dst++->clear(current_style_);
dst++->clear(*current_style_);
}
clear_mouse_selection();
}
@ -1981,7 +2064,7 @@ void Fl_Terminal::insert_char_eol(char c, int drow, int dcol, int rep) {
//
rep = clamp(rep, 0, disp_cols()); // sanity
if (rep == 0) return;
const CharStyle &style = current_style_;
const CharStyle &style = *current_style_;
Utf8Char *src = u8c_disp_row(drow)+disp_cols()-1-rep; // start src at 'g'
Utf8Char *dst = u8c_disp_row(drow)+disp_cols()-1; // start dst at 'j'
for (int col=(disp_cols()-1); col>=dcol; col--) { // loop col in reverse: eol -> dcol
@ -2002,7 +2085,7 @@ void Fl_Terminal::insert_char(char c, int rep) {
void Fl_Terminal::delete_chars(int drow, int dcol, int rep) {
rep = clamp(rep, 0, disp_cols()); // sanity
if (rep == 0) return;
const CharStyle &style = current_style_;
const CharStyle &style = *current_style_;
Utf8Char *u8c = u8c_disp_row(drow);
for (int col=dcol; col<disp_cols(); col++) // delete left-to-right
if (col+rep >= disp_cols()) u8c[col].text_ascii(' ', style); // blanks
@ -2026,7 +2109,7 @@ void Fl_Terminal::clear_history(void) {
for (int hrow=0; hrow<hist_rows(); hrow++) {
Utf8Char *u8c = u8c_hist_row(hrow); // walk history rows..
for (int hcol=0; hcol<hist_cols(); hcol++) { // ..and history cols
(u8c++)->clear(current_style_);
(u8c++)->clear(*current_style_);
}
}
// Adjust scrollbar (hist_use changed)
@ -2038,7 +2121,7 @@ void Fl_Terminal::clear_history(void) {
mouse selection, homes cursor, resets tabstops. Same as \c "<ESC>c"
*/
void Fl_Terminal::reset_terminal(void) {
current_style_.sgr_reset(); // reset current style
current_style_->sgr_reset(); // reset current style
clear_screen_home(); // clear screen, home cursor
clear_history();
clear_mouse_selection();
@ -2302,7 +2385,7 @@ void Fl_Terminal::handle_SGR(void) { // ESC[...m?
int tot = esc.total_vals();
// Handle ESC[m or ESC[;m
if (tot == 0)
{ current_style_.sgr_reset(); return; }
{ current_style_->sgr_reset(); return; }
// Handle ESC[#;#;#...m
int rgbcode = 0; // 0=none, 38=fg, 48=bg
int rgbmode = 0; // 0=none, 1="2", 2=<r>, 3=<g>, 4=<b>
@ -2328,9 +2411,9 @@ void Fl_Terminal::handle_SGR(void) { // ESC[...m?
case 3: g=clamp(val,0,255); ++rgbmode; continue; // parse grn value
case 4: b=clamp(val,0,255); // parse blu value
switch (rgbcode) {
case 38: current_style_.fgcolor(r,g,b); // Set fg rgb
case 38: current_style_->fgcolor(r,g,b); // Set fg rgb
break;
case 48: current_style_.bgcolor(r,g,b); // Set bg rgb
case 48: current_style_->bgcolor(r,g,b); // Set bg rgb
break;
}
rgbcode = rgbmode = 0; // done w/rgb mode parsing
@ -2338,42 +2421,42 @@ void Fl_Terminal::handle_SGR(void) { // ESC[...m?
}
if (val < 10) { // Set attribute? (bold,underline..)
switch ( val ) {
case 0: current_style_.sgr_reset(); break; // ESC[0m - reset
case 1: current_style_.sgr_bold(1); break; // ESC[1m - bold
case 2: current_style_.sgr_dim(1); break; // ESC[2m - dim
case 3: current_style_.sgr_italic(1); break; // ESC[3m - italic
case 4: current_style_.sgr_underline(1);break; // ESC[4m - underline
case 5: current_style_.sgr_blink(1); break; // ESC[5m - blink
case 6: handle_unknown_char(); break; // ESC[6m - (unused)
case 7: current_style_.sgr_inverse(1); break; // ESC[7m - inverse
case 8: handle_unknown_char(); break; // ESC[8m - (unused)
case 9: current_style_.sgr_strike(1); break; // ESC[9m - strikeout
case 0: current_style_->sgr_reset(); break; // ESC[0m - reset
case 1: current_style_->sgr_bold(1); break; // ESC[1m - bold
case 2: current_style_->sgr_dim(1); break; // ESC[2m - dim
case 3: current_style_->sgr_italic(1); break; // ESC[3m - italic
case 4: current_style_->sgr_underline(1);break; // ESC[4m - underline
case 5: current_style_->sgr_blink(1); break; // ESC[5m - blink
case 6: handle_unknown_char(); break; // ESC[6m - (unused)
case 7: current_style_->sgr_inverse(1); break; // ESC[7m - inverse
case 8: handle_unknown_char(); break; // ESC[8m - (unused)
case 9: current_style_->sgr_strike(1); break; // ESC[9m - strikeout
}
} else if (val >= 21 && val <= 29) { // attribute extras
switch ( val ) {
case 21: current_style_.sgr_dbl_under(1);break; // ESC[21m - doubly underline
case 22: current_style_.sgr_dim(0); // ESC[22m - disable bold/dim
current_style_.sgr_bold(0); break; //
case 23: current_style_.sgr_italic(0); break; // ESC[23m - disable italic
case 24: current_style_.sgr_underline(0);break; // ESC[24m - disable underline
case 25: current_style_.sgr_blink(0); break; // ESC[25m - disable blink
case 26: handle_unknown_char(); break; // ESC[26m - (unused)
case 27: current_style_.sgr_inverse(0); break; // ESC[27m - disable inverse
case 28: handle_unknown_char(); break; // ESC[28m - disable hidden
case 29: current_style_.sgr_strike(0); break; // ESC[29m - disable strikeout
case 21: current_style_->sgr_dbl_under(1);break; // ESC[21m - doubly underline
case 22: current_style_->sgr_dim(0); // ESC[22m - disable bold/dim
current_style_->sgr_bold(0); break; //
case 23: current_style_->sgr_italic(0); break; // ESC[23m - disable italic
case 24: current_style_->sgr_underline(0);break; // ESC[24m - disable underline
case 25: current_style_->sgr_blink(0); break; // ESC[25m - disable blink
case 26: handle_unknown_char(); break; // ESC[26m - (unused)
case 27: current_style_->sgr_inverse(0); break; // ESC[27m - disable inverse
case 28: handle_unknown_char(); break; // ESC[28m - disable hidden
case 29: current_style_->sgr_strike(0); break; // ESC[29m - disable strikeout
}
} else if (val >= 30 && val <= 37) { // Set fg color?
current_style_.fgcolor_uchar(val - 30);
} else if (val == 39) { // ESC[39m -- "normal" fg color:
Fl_Color fg = current_style_.defaultfgcolor(); // ..get default color
current_style_.fgcolor(fg); // ..set current color
} else if (val >= 40 && val <= 47) { // Set bg color?
current_style_.bgcolor_uchar(val - 40);
} else if (val == 49) { // ESC[49m -- "normal" bg color:
Fl_Color bg = current_style_.defaultbgcolor(); // ..get default bg color
current_style_.bgcolor(bg); // ..set current bg color
} else if (val >= 30 && val <= 37) { // Set fg color?
current_style_->fgcolor_uchar(val - 30);
} else if (val == 39) { // ESC[39m -- "normal" fg color:
Fl_Color fg = current_style_->defaultfgcolor(); // ..get default color
current_style_->fgcolor(fg); // ..set current color
} else if (val >= 40 && val <= 47) { // Set bg color?
current_style_->bgcolor_uchar(val - 40);
} else if (val == 49) { // ESC[49m -- "normal" bg color:
Fl_Color bg = current_style_->defaultbgcolor(); // ..get default bg color
current_style_->bgcolor(bg); // ..set current bg color
} else {
handle_unknown_char(); // does an escseq.reset() // unimplemented SGR codes
handle_unknown_char(); // does an escseq.reset() // unimplemented SGR codes
}
}
}
@ -2624,7 +2707,7 @@ void Fl_Terminal::display_modified(void) {
*/
void Fl_Terminal::clear_char_at_disp(int drow, int dcol) {
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
u8c->clear(current_style_);
u8c->clear(*current_style_);
}
/**
@ -2676,7 +2759,7 @@ void Fl_Terminal::putchar(const char *text, int len, int drow, int dcol) {
// text_utf8() warns we must do invalid checks first
if (!text || len<1 || len>u8c->max_utf8() || len!=fl_utf8len(*text))
{ handle_unknown_char(); return; }
u8c->text_utf8(text, len, current_style_);
u8c->text_utf8(text, len, *current_style_);
}
/**
@ -2700,7 +2783,7 @@ void Fl_Terminal::putchar(const char *text, int len, int drow, int dcol) {
void Fl_Terminal::putchar(char c, int drow, int dcol) {
if (!is_printable(c)) { handle_unknown_char(); return; }
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
u8c->text_ascii(c, current_style_);
u8c->text_ascii(c, *current_style_);
}
/**
@ -3003,16 +3086,47 @@ void Fl_Terminal::redraw_timer_cb(void *udata) {
\param[in] L label string (optional), may be NULL.
*/
Fl_Terminal::Fl_Terminal(int X,int Y,int W,int H,const char*L) : Fl_Group(X,Y,W,H,L) {
bool fontsize_defer = false;
init_(X,Y,W,H,L,-1,-1,100,fontsize_defer);
}
/**
Same as the default FLTK constructor, but lets the user force the rows, columns
and history to specific sizes on creation.
Since the row/cols/hist are specified directly, this prevents the widget from auto-calculating
the initial text buffer size based on the widget's pixel width/height, bypassing calls to
the font system before the widget is displayed.
\note fluid uses this constructor internally to avoid font calculations that opens
the display, useful for when running in a headless context. (issue 837)
*/
Fl_Terminal::Fl_Terminal(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist) : Fl_Group(X,Y,W,H,L) {
bool fontsize_defer = true;
init_(X,Y,W,H,L,rows,cols,hist,fontsize_defer);
}
// Private contructor method
void Fl_Terminal::init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer) {
fontsize_defer_ = fontsize_defer; // defer font calls until draw() (issue 837)
current_style_ = new CharStyle(fontsize_defer);
// scrollbar_size must be set before scrn_
scrollbar_size_ = 0; // 0 uses Fl::scrollbar_size()
scrollbar_size_ = 0; // 0 uses Fl::scrollbar_size()
update_screen_xywh();
// Tabs
tabstops_ = 0;
tabstops_size_ = 0;
// Init ringbuffer. Also creates default tabstops
create_ring(h_to_row(scrn_.h()), // desired row
w_to_col(scrn_.w()), // desired col
100); // history size: use 100 for production release
if ( rows == -1 || cols == -1 ) {
int newrows = h_to_row(scrn_.h()); // rows based on height
int newcols = w_to_col(scrn_.w()); // cols based on width
// Sanity check
newrows = (newrows >= 1) ? newrows : 1;
newcols = (newcols >= 1) ? newcols : 1;
create_ring(newrows, newcols, hist);
} else {
create_ring(rows, cols, 100);
}
// Misc
redraw_style_ = RATE_LIMITED; // NO_REDRAW, RATE_LIMITED, PER_WRITE
redraw_rate_ = 0.10f; // maximum rate in seconds (1/10=10fps)
@ -3108,8 +3222,8 @@ void Fl_Terminal::scrollbar_size(int val) {
no pixels are drawn.
*/
void Fl_Terminal::draw_row_bg(int grow, int X, int Y) const {
int bg_h = current_style_.fontheight();
int bg_y = Y - current_style_.fontheight() + current_style_.fontdescent();
int bg_h = current_style_->fontheight();
int bg_y = Y - current_style_->fontheight() + current_style_->fontdescent();
Fl_Color bg_col;
int pwidth = 9;
const Utf8Char *u8c = u8c_ring_row(grow); // start of spec'd row
@ -3117,7 +3231,7 @@ void Fl_Terminal::draw_row_bg(int grow, int X, int Y) const {
for (int gcol=0; gcol<ring_cols(); gcol++,u8c++) { // walk columns
// Attribute changed since last char?
if (gcol==0 || u8c->attrib() != lastattr) {
u8c->fl_font_set(current_style_); // pwidth_int() needs fl_font set
u8c->fl_font_set(*current_style_); // pwidth_int() needs fl_font set
lastattr = u8c->attrib();
}
pwidth = u8c->pwidth_int();
@ -3149,7 +3263,7 @@ void Fl_Terminal::draw_row(int grow, int Y) const {
int disp_top = (disp_srow() - scrollval); // top row we need to view
int drow = grow - disp_top; // disp row
bool inside_display = is_disp_ring_row(grow); // row inside 'display'?
int strikeout_y = Y - (current_style_.fontheight() / 3);
int strikeout_y = Y - (current_style_->fontheight() / 3);
int underline_y = Y;
const Utf8Char *u8c = u8c_ring_row(grow);
uchar lastattr = -1;
@ -3161,14 +3275,14 @@ void Fl_Terminal::draw_row(int grow, int Y) const {
is_cursor = inside_display ? cursor_.is_rowcol(drow-scrollval, dcol) : 0;
// Attribute changed since last char?
if (u8c->attrib() != lastattr) {
u8c->fl_font_set(current_style_); // pwidth_int() needs fl_font set
u8c->fl_font_set(*current_style_); // pwidth_int() needs fl_font set
lastattr = u8c->attrib();
}
int pwidth = u8c->pwidth_int();
// DRAW CURSOR BLOCK - TODO: support other cursor types?
if (is_cursor) {
int cx = X;
int cy = Y - cursor_.h() + current_style_.fontdescent();
int cy = Y - cursor_.h() + current_style_->fontdescent();
int cw = pwidth;
int ch = cursor_.h();
fl_color(cursorbgcolor());
@ -3211,7 +3325,7 @@ void Fl_Terminal::draw_row(int grow, int Y) const {
void Fl_Terminal::draw_buff(int Y) const {
int srow = disp_srow() - vscroll_->value();
int erow = srow + disp_rows();
const int rowheight = current_style_.fontheight();
const int rowheight = current_style_->fontheight();
for (int grow=srow; (grow<erow) && (Y<scrn_.b()); grow++) {
Y += rowheight; // advance Y to bottom left corner of row
draw_row(grow, Y); // draw global row at Y
@ -3224,6 +3338,12 @@ void Fl_Terminal::draw_buff(int Y) const {
followed by the terminal's screen contents.
*/
void Fl_Terminal::draw(void) {
// First time shown? Force deferred font size calculations here (issue 837)
if (fontsize_defer_) {
fontsize_defer_ = false; // clear flag
current_style_->update(); // do deferred update here
update_screen(true); // update fonts
}
// Draw group first, terminal last
Fl_Group::draw();
@ -3255,7 +3375,7 @@ void Fl_Terminal::draw(void) {
This is used by the constructor to size the row/cols to fit the widget size.
*/
int Fl_Terminal::w_to_col(int W) const {
return int((float(W) / current_style_.charwidth()) + 0.0); // +.5 overshoots
return int((float(W) / current_style_->charwidth()) + 0.0); // +.5 overshoots
}
/**
@ -3263,7 +3383,7 @@ int Fl_Terminal::w_to_col(int W) const {
This is used by the constructor to size the row/cols to fit the widget size.
*/
int Fl_Terminal::h_to_row(int H) const {
return int((float(H) / current_style_.fontheight()) + -0.5); // +.5 overshoots
return int((float(H) / current_style_->fontheight()) + -0.5); // +.5 overshoots
}
/**