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

View File

@ -419,7 +419,10 @@ pfail:
////////////////////////////////////// //////////////////////////////////////
// Ctor // 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; attrib_ = 0;
flags_ = 0; flags_ = 0;
defaultfgcolor_ = 0xd0d0d000; // off white defaultfgcolor_ = 0xd0d0d000; // off white
@ -429,7 +432,8 @@ Fl_Terminal::CharStyle::CharStyle(void) {
flags_ |= (FG_XTERM | BG_XTERM); flags_ |= (FG_XTERM | BG_XTERM);
fontface_ = FL_COURIER; fontface_ = FL_COURIER;
fontsize_ = 14; 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 // Update fontheight/descent cache whenever font changes
@ -441,6 +445,16 @@ void Fl_Terminal::CharStyle::update(void) {
charwidth_ = int(fl_width("X") + 0.5); 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 // Return fg color
Fl_Color Fl_Terminal::CharStyle::fgcolor(void) const { Fl_Color Fl_Terminal::CharStyle::fgcolor(void) const {
return fgcolor_; return fgcolor_;
@ -545,7 +559,7 @@ void Fl_Terminal::Utf8Char::text_utf8(const char *text,
int len, int len,
const CharStyle& style) { const CharStyle& style) {
text_utf8_(text, len); // updates text_, len_ 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(); attrib_ = style.attrib();
flags_ = style.colorbits_only(flags_); flags_ = style.colorbits_only(flags_);
fgcolor_ = style.fgcolor(); 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 // 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: // Example:
// // Walk ALL rows in the ring buffer.. // // Walk ALL rows in the ring buffer..
// for (int row=0; row<ring.rows(); row++) { // for (int row=0; row<ring.rows(); row++) {
// Utf8Char *u8c = ring.u8c_ring_row(row); // Utf8Char *u8c = ring.u8c_ring_row(row);
// .. // ..
// } // }
// //
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row) const { const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row) const {
row = normalize(row, ring_rows()); row = normalize(row, ring_rows());
@ -892,8 +906,8 @@ const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_use_row(int hurow
// Example: // Example:
// // Walk ALL rows in display.. // // Walk ALL rows in display..
// for (int drow=0; drow<ring.drows(); drow++) { // 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 { 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()]; 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) Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_ring_row(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) 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 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) Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_disp_row(int drow)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_disp_row(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 ///// ///// Fl_Terminal Class Methods /////
///////////////////////////////////// /////////////////////////////////////
// Return u8c for beginning of a row inside the ring. /// See docs for non-const version of u8c_ring_row(int)
// '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.
//
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_ring_row(int grow) const const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_ring_row(int grow) const
{ return ring_.u8c_ring_row(grow); } { return ring_.u8c_ring_row(grow); }
// Return u8c for beginning of a row inside the history. /// See docs for non-const version of u8c_hist_row(int)
// 'hrow' is indexed relative to the beginning of the history buffer.
//
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_row(int hrow) const const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_row(int hrow) const
{ return ring_.u8c_hist_row(hrow); } { return ring_.u8c_hist_row(hrow); }
// Return u8c for beginning of a row inside the 'in use' history. /// See docs for non-const version of u8c_hist_use_row(int)
// 'hurow' is indexed relative to the beginning of the 'in use' buffer.
//
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_use_row(int hurow) const const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_use_row(int hurow) const
{ return ring_.u8c_hist_use_row(hurow); } { return ring_.u8c_hist_use_row(hurow); }
// Return u8c for beginning of a row inside the display /// See docs for non-const version of u8c_disp_row(int)
// 'drow' is indexed relative to the beginning of the display buffer.
//
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow) const const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow) const
{ return ring_.u8c_disp_row(drow); } { 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) 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 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) 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 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) 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 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) Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_disp_row(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(); 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. /// Return scrollbar width if visible, or 0 if not visible.
int Fl_Terminal::vscroll_width(void) const { int Fl_Terminal::vscroll_width(void) const {
return(vscroll_->visible() ? vscroll_->w() : 0); 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 drows = clamp(dh, 2, dh); // 2 rows minimum
int dcols = clamp(dw, 10, dw); // 10 cols minimum int dcols = clamp(dw, 10, dw); // 10 cols minimum
int drow_diff = drows - ring_.disp_rows(); // change in rows? 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); cursor_.scroll(-drow_diff);
clear_mouse_selection(); clear_mouse_selection();
update_screen(false); 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_dcols = ring_cols(); // keep cols the same
int new_hrows = hist_rows() - drow_diff; // keep disp:hist ratio 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 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 // ..update cursor/selections to track text position
cursor_.scroll(-drow_diff); cursor_.scroll(-drow_diff);
select_.clear(); // clear any mouse selection select_.clear(); // clear any mouse selection
@ -1177,7 +1257,7 @@ void Fl_Terminal::resize_display_columns(int dcols) {
// No changes? early exit // No changes? early exit
if (dcols == disp_cols()) return; if (dcols == disp_cols()) return;
// Change cols, preserves previous content if possible // 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(); update_scrollbar();
} }
@ -1200,8 +1280,11 @@ void Fl_Terminal::update_screen(bool font_changed) {
// current_style: update cursor's size for current font/size // current_style: update cursor's size for current font/size
if (font_changed) { if (font_changed) {
// Change font and current_style's font height // Change font and current_style's font height
fl_font(current_style_.fontface(), current_style_.fontsize()); if (!fontsize_defer_) { // issue 837
cursor_.h(current_style_.fontheight()); //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 the scrn_* values
update_screen_xywh(); update_screen_xywh();
@ -1221,7 +1304,7 @@ int Fl_Terminal::history_rows(void) const {
*/ */
void Fl_Terminal::history_rows(int hrows) { void Fl_Terminal::history_rows(int hrows) {
if (hrows == history_rows()) return; // no change? done 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 update_screen(false); // false: no font change
display_modified(); display_modified();
} }
@ -1258,7 +1341,7 @@ int Fl_Terminal::display_rows(void) const {
*/ */
void Fl_Terminal::display_rows(int drows) { void Fl_Terminal::display_rows(int drows) {
if (drows == disp_rows()) return; // no change? early exit 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? 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) { void Fl_Terminal::display_columns(int dcols) {
if (dcols == disp_cols()) return; // no change? early exit if (dcols == disp_cols()) return; // no change? early exit
// Change cols, preserves previous content if possible // 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? update_screen(false); // false: no font change ?NEED?
} }
/** Return current style for rendering text. */ /** Return current style for rendering text. */
const Fl_Terminal::CharStyle& Fl_Terminal::current_style(void) const { const Fl_Terminal::CharStyle& Fl_Terminal::current_style(void) const {
return current_style_; return *current_style_;
} }
/** Set current style for rendering text. */ /** Set current style for rendering text. */
void Fl_Terminal::current_style(const CharStyle& sty) { 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. as they are monospace.
*/ */
void Fl_Terminal::textfont(Fl_Font val) { void Fl_Terminal::textfont(Fl_Font val) {
current_style_.fontface(val); current_style_->fontface(val);
update_screen(true); update_screen(true);
display_modified(); display_modified();
} }
@ -1368,7 +1451,7 @@ void Fl_Terminal::textfont(Fl_Font val) {
Changing this will affect the display_rows() and display_columns(). Changing this will affect the display_rows() and display_columns().
*/ */
void Fl_Terminal::textsize(Fl_Fontsize val) { void Fl_Terminal::textsize(Fl_Fontsize val) {
current_style_.fontsize(val); current_style_->fontsize(val);
update_screen(true); update_screen(true);
// Changing font size affects #lines in display, so resize it // Changing font size affects #lines in display, so resize it
refit_disp_to_screen(); refit_disp_to_screen();
@ -1404,7 +1487,7 @@ void Fl_Terminal::textsize(Fl_Fontsize val) {
\see textfgcolor_default(Fl_Color) \see textfgcolor_default(Fl_Color)
*/ */
void Fl_Terminal::textfgcolor_xterm(uchar val) { 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) \see textbgcolor_default(Fl_Color)
*/ */
void Fl_Terminal::textbgcolor_xterm(uchar val) { 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) \see textfgcolor_default(Fl_Color)
*/ */
void Fl_Terminal::textfgcolor(Fl_Color val) { 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) \see textbgcolor_default(Fl_Color)
*/ */
void Fl_Terminal::textbgcolor(Fl_Color val) { 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) \see textfgcolor(Fl_Color)
*/ */
void Fl_Terminal::textfgcolor_default(Fl_Color val) { 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) \see textbgcolor(Fl_Color)
*/ */
void Fl_Terminal::textbgcolor_default(Fl_Color val) { 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 \see Fl_Terminal::Attrib
*/ */
void Fl_Terminal::textattrib(uchar val) { 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 int cx = x() + margin_.left(); // char x position
const Utf8Char *u8c = utf8_char_at_glob(grow, 0); const Utf8Char *u8c = utf8_char_at_glob(grow, 0);
for (gcol=0; gcol<ring_cols(); gcol++,u8c++) { // walk the cols looking for X 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) int cx2 = cx + u8c->pwidth_int(); // char x2 (right edge of char)
if (X >= cx && X < cx2) return 1; // found? return with gcol set if (X >= cx && X < cx2) return 1; // found? return with gcol set
cx += u8c->pwidth_int(); // move cx to start x of next char 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 // Find toprow of what's currently drawn on screen
int toprow = disp_srow() - vscroll_->value(); int toprow = disp_srow() - vscroll_->value();
// Find row the 'Y' value is in // 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); return x_to_glob_col(X, grow, gcol);
} }
@ -1676,7 +1759,7 @@ void Fl_Terminal::clear_eod(void) {
void Fl_Terminal::clear_eol(void) { void Fl_Terminal::clear_eol(void) {
Utf8Char *u8c = u8c_disp_row(cursor_.row()) + cursor_.col(); // start at cursor 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 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? //TODO: Clear mouse selection?
} }
@ -1684,7 +1767,7 @@ void Fl_Terminal::clear_eol(void) {
void Fl_Terminal::clear_sol(void) { void Fl_Terminal::clear_sol(void) {
Utf8Char *u8c = u8c_disp_row(cursor_.row()); // start at sol Utf8Char *u8c = u8c_disp_row(cursor_.row()); // start at sol
for (int col=0; col<=cursor_.col(); col++) // run from sol to cursor 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? //TODO: Clear mouse selection?
} }
@ -1692,7 +1775,7 @@ void Fl_Terminal::clear_sol(void) {
void Fl_Terminal::clear_line(int drow) { void Fl_Terminal::clear_line(int drow) {
Utf8Char *u8c = u8c_disp_row(drow); // start at sol Utf8Char *u8c = u8c_disp_row(drow); // start at sol
for (int col=0; col<disp_cols(); col++) // run to eol for (int col=0; col<disp_cols(); col++) // run to eol
(u8c++)->clear(current_style_); (u8c++)->clear(*current_style_);
//TODO: Clear mouse selection? //TODO: Clear mouse selection?
} }
@ -1908,7 +1991,7 @@ bool Fl_Terminal::selection_extend(int X,int Y) {
*/ */
void Fl_Terminal::scroll(int rows) { void Fl_Terminal::scroll(int rows) {
// Scroll the ring // 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 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 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 while ( dst_drow >= cursor_.row() ) { // walk srcrow to curs line
Utf8Char *dst = u8c_disp_row(dst_drow--); Utf8Char *dst = u8c_disp_row(dst_drow--);
for (int dcol=0; dcol<disp_cols(); dcol++) for (int dcol=0; dcol<disp_cols(); dcol++)
dst++->clear(current_style_); dst++->clear(*current_style_);
} }
clear_mouse_selection(); clear_mouse_selection();
} }
@ -1953,7 +2036,7 @@ void Fl_Terminal::delete_rows(int count) {
while ( dst_drow < disp_rows() ) { // walk srcrow to EOD while ( dst_drow < disp_rows() ) { // walk srcrow to EOD
Utf8Char *dst = u8c_disp_row(dst_drow++); Utf8Char *dst = u8c_disp_row(dst_drow++);
for (int dcol=0; dcol<disp_cols(); dcol++) for (int dcol=0; dcol<disp_cols(); dcol++)
dst++->clear(current_style_); dst++->clear(*current_style_);
} }
clear_mouse_selection(); 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 rep = clamp(rep, 0, disp_cols()); // sanity
if (rep == 0) return; 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 *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' 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 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) { void Fl_Terminal::delete_chars(int drow, int dcol, int rep) {
rep = clamp(rep, 0, disp_cols()); // sanity rep = clamp(rep, 0, disp_cols()); // sanity
if (rep == 0) return; if (rep == 0) return;
const CharStyle &style = current_style_; const CharStyle &style = *current_style_;
Utf8Char *u8c = u8c_disp_row(drow); Utf8Char *u8c = u8c_disp_row(drow);
for (int col=dcol; col<disp_cols(); col++) // delete left-to-right for (int col=dcol; col<disp_cols(); col++) // delete left-to-right
if (col+rep >= disp_cols()) u8c[col].text_ascii(' ', style); // blanks 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++) { for (int hrow=0; hrow<hist_rows(); hrow++) {
Utf8Char *u8c = u8c_hist_row(hrow); // walk history rows.. Utf8Char *u8c = u8c_hist_row(hrow); // walk history rows..
for (int hcol=0; hcol<hist_cols(); hcol++) { // ..and history cols for (int hcol=0; hcol<hist_cols(); hcol++) { // ..and history cols
(u8c++)->clear(current_style_); (u8c++)->clear(*current_style_);
} }
} }
// Adjust scrollbar (hist_use changed) // 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" mouse selection, homes cursor, resets tabstops. Same as \c "<ESC>c"
*/ */
void Fl_Terminal::reset_terminal(void) { 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_screen_home(); // clear screen, home cursor
clear_history(); clear_history();
clear_mouse_selection(); clear_mouse_selection();
@ -2302,7 +2385,7 @@ void Fl_Terminal::handle_SGR(void) { // ESC[...m?
int tot = esc.total_vals(); int tot = esc.total_vals();
// Handle ESC[m or ESC[;m // Handle ESC[m or ESC[;m
if (tot == 0) if (tot == 0)
{ current_style_.sgr_reset(); return; } { current_style_->sgr_reset(); return; }
// Handle ESC[#;#;#...m // Handle ESC[#;#;#...m
int rgbcode = 0; // 0=none, 38=fg, 48=bg int rgbcode = 0; // 0=none, 38=fg, 48=bg
int rgbmode = 0; // 0=none, 1="2", 2=<r>, 3=<g>, 4=<b> 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 3: g=clamp(val,0,255); ++rgbmode; continue; // parse grn value
case 4: b=clamp(val,0,255); // parse blu value case 4: b=clamp(val,0,255); // parse blu value
switch (rgbcode) { 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; break;
case 48: current_style_.bgcolor(r,g,b); // Set bg rgb case 48: current_style_->bgcolor(r,g,b); // Set bg rgb
break; break;
} }
rgbcode = rgbmode = 0; // done w/rgb mode parsing 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..) if (val < 10) { // Set attribute? (bold,underline..)
switch ( val ) { switch ( val ) {
case 0: current_style_.sgr_reset(); break; // ESC[0m - reset case 0: current_style_->sgr_reset(); break; // ESC[0m - reset
case 1: current_style_.sgr_bold(1); break; // ESC[1m - bold case 1: current_style_->sgr_bold(1); break; // ESC[1m - bold
case 2: current_style_.sgr_dim(1); break; // ESC[2m - dim case 2: current_style_->sgr_dim(1); break; // ESC[2m - dim
case 3: current_style_.sgr_italic(1); break; // ESC[3m - italic case 3: current_style_->sgr_italic(1); break; // ESC[3m - italic
case 4: current_style_.sgr_underline(1);break; // ESC[4m - underline case 4: current_style_->sgr_underline(1);break; // ESC[4m - underline
case 5: current_style_.sgr_blink(1); break; // ESC[5m - blink case 5: current_style_->sgr_blink(1); break; // ESC[5m - blink
case 6: handle_unknown_char(); break; // ESC[6m - (unused) case 6: handle_unknown_char(); break; // ESC[6m - (unused)
case 7: current_style_.sgr_inverse(1); break; // ESC[7m - inverse case 7: current_style_->sgr_inverse(1); break; // ESC[7m - inverse
case 8: handle_unknown_char(); break; // ESC[8m - (unused) case 8: handle_unknown_char(); break; // ESC[8m - (unused)
case 9: current_style_.sgr_strike(1); break; // ESC[9m - strikeout case 9: current_style_->sgr_strike(1); break; // ESC[9m - strikeout
} }
} else if (val >= 21 && val <= 29) { // attribute extras } else if (val >= 21 && val <= 29) { // attribute extras
switch ( val ) { switch ( val ) {
case 21: current_style_.sgr_dbl_under(1);break; // ESC[21m - doubly underline 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 case 22: current_style_->sgr_dim(0); // ESC[22m - disable bold/dim
current_style_.sgr_bold(0); break; // current_style_->sgr_bold(0); break; //
case 23: current_style_.sgr_italic(0); break; // ESC[23m - disable italic 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 24: current_style_->sgr_underline(0);break; // ESC[24m - disable underline
case 25: current_style_.sgr_blink(0); break; // ESC[25m - disable blink case 25: current_style_->sgr_blink(0); break; // ESC[25m - disable blink
case 26: handle_unknown_char(); break; // ESC[26m - (unused) case 26: handle_unknown_char(); break; // ESC[26m - (unused)
case 27: current_style_.sgr_inverse(0); break; // ESC[27m - disable inverse case 27: current_style_->sgr_inverse(0); break; // ESC[27m - disable inverse
case 28: handle_unknown_char(); break; // ESC[28m - disable hidden case 28: handle_unknown_char(); break; // ESC[28m - disable hidden
case 29: current_style_.sgr_strike(0); break; // ESC[29m - disable strikeout case 29: current_style_->sgr_strike(0); break; // ESC[29m - disable strikeout
} }
} else if (val >= 30 && val <= 37) { // Set fg color? } else if (val >= 30 && val <= 37) { // Set fg color?
current_style_.fgcolor_uchar(val - 30); current_style_->fgcolor_uchar(val - 30);
} else if (val == 39) { // ESC[39m -- "normal" fg color: } else if (val == 39) { // ESC[39m -- "normal" fg color:
Fl_Color fg = current_style_.defaultfgcolor(); // ..get default color Fl_Color fg = current_style_->defaultfgcolor(); // ..get default color
current_style_.fgcolor(fg); // ..set current color current_style_->fgcolor(fg); // ..set current color
} else if (val >= 40 && val <= 47) { // Set bg color? } else if (val >= 40 && val <= 47) { // Set bg color?
current_style_.bgcolor_uchar(val - 40); current_style_->bgcolor_uchar(val - 40);
} else if (val == 49) { // ESC[49m -- "normal" bg color: } else if (val == 49) { // ESC[49m -- "normal" bg color:
Fl_Color bg = current_style_.defaultbgcolor(); // ..get default bg color Fl_Color bg = current_style_->defaultbgcolor(); // ..get default bg color
current_style_.bgcolor(bg); // ..set current bg color current_style_->bgcolor(bg); // ..set current bg color
} else { } 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) { void Fl_Terminal::clear_char_at_disp(int drow, int dcol) {
Utf8Char *u8c = u8c_disp_row(drow) + 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 // text_utf8() warns we must do invalid checks first
if (!text || len<1 || len>u8c->max_utf8() || len!=fl_utf8len(*text)) if (!text || len<1 || len>u8c->max_utf8() || len!=fl_utf8len(*text))
{ handle_unknown_char(); return; } { 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) { void Fl_Terminal::putchar(char c, int drow, int dcol) {
if (!is_printable(c)) { handle_unknown_char(); return; } if (!is_printable(c)) { handle_unknown_char(); return; }
Utf8Char *u8c = u8c_disp_row(drow) + dcol; 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. \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) { 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 must be set before scrn_
scrollbar_size_ = 0; // 0 uses Fl::scrollbar_size() scrollbar_size_ = 0; // 0 uses Fl::scrollbar_size()
update_screen_xywh(); update_screen_xywh();
// Tabs // Tabs
tabstops_ = 0; tabstops_ = 0;
tabstops_size_ = 0; tabstops_size_ = 0;
// Init ringbuffer. Also creates default tabstops // Init ringbuffer. Also creates default tabstops
create_ring(h_to_row(scrn_.h()), // desired row if ( rows == -1 || cols == -1 ) {
w_to_col(scrn_.w()), // desired col int newrows = h_to_row(scrn_.h()); // rows based on height
100); // history size: use 100 for production release 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 // Misc
redraw_style_ = RATE_LIMITED; // NO_REDRAW, RATE_LIMITED, PER_WRITE redraw_style_ = RATE_LIMITED; // NO_REDRAW, RATE_LIMITED, PER_WRITE
redraw_rate_ = 0.10f; // maximum rate in seconds (1/10=10fps) 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. no pixels are drawn.
*/ */
void Fl_Terminal::draw_row_bg(int grow, int X, int Y) const { void Fl_Terminal::draw_row_bg(int grow, int X, int Y) const {
int bg_h = current_style_.fontheight(); int bg_h = current_style_->fontheight();
int bg_y = Y - current_style_.fontheight() + current_style_.fontdescent(); int bg_y = Y - current_style_->fontheight() + current_style_->fontdescent();
Fl_Color bg_col; Fl_Color bg_col;
int pwidth = 9; int pwidth = 9;
const Utf8Char *u8c = u8c_ring_row(grow); // start of spec'd row 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 for (int gcol=0; gcol<ring_cols(); gcol++,u8c++) { // walk columns
// Attribute changed since last char? // Attribute changed since last char?
if (gcol==0 || u8c->attrib() != lastattr) { 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(); lastattr = u8c->attrib();
} }
pwidth = u8c->pwidth_int(); 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 disp_top = (disp_srow() - scrollval); // top row we need to view
int drow = grow - disp_top; // disp row int drow = grow - disp_top; // disp row
bool inside_display = is_disp_ring_row(grow); // row inside 'display'? 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; int underline_y = Y;
const Utf8Char *u8c = u8c_ring_row(grow); const Utf8Char *u8c = u8c_ring_row(grow);
uchar lastattr = -1; 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; is_cursor = inside_display ? cursor_.is_rowcol(drow-scrollval, dcol) : 0;
// Attribute changed since last char? // Attribute changed since last char?
if (u8c->attrib() != lastattr) { 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(); lastattr = u8c->attrib();
} }
int pwidth = u8c->pwidth_int(); int pwidth = u8c->pwidth_int();
// DRAW CURSOR BLOCK - TODO: support other cursor types? // DRAW CURSOR BLOCK - TODO: support other cursor types?
if (is_cursor) { if (is_cursor) {
int cx = X; int cx = X;
int cy = Y - cursor_.h() + current_style_.fontdescent(); int cy = Y - cursor_.h() + current_style_->fontdescent();
int cw = pwidth; int cw = pwidth;
int ch = cursor_.h(); int ch = cursor_.h();
fl_color(cursorbgcolor()); 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 { void Fl_Terminal::draw_buff(int Y) const {
int srow = disp_srow() - vscroll_->value(); int srow = disp_srow() - vscroll_->value();
int erow = srow + disp_rows(); 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++) { for (int grow=srow; (grow<erow) && (Y<scrn_.b()); grow++) {
Y += rowheight; // advance Y to bottom left corner of row Y += rowheight; // advance Y to bottom left corner of row
draw_row(grow, Y); // draw global row at Y 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. followed by the terminal's screen contents.
*/ */
void Fl_Terminal::draw(void) { 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 // Draw group first, terminal last
Fl_Group::draw(); 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. 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 { 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. 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 { 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
} }
/** /**