#ifndef NDEBUG
#define NDEBUG
#endif
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <FL/Fl.H>
#include <FL/Fl_Terminal.H>
#include <FL/fl_utf8.h>
#include <FL/fl_draw.H>
#include <FL/fl_string_functions.h>
#include "Fl_String.H"
#define MIN(a,b) ((a)<=(b)) ? (a) : (b)
#define MAX(a,b) ((a)>=(b)) ? (a) : (b)
#define ABS(a) ((a)<0) ? -(a) : (a)
static int clamp(int val, int min, int max)
{ return (val<min) ? min : (val>max) ? max : val; }
static void swap(int &a, int &b)
{ int asave = a; a = b; b = asave; }
static int normalize(int row, int maxrows) {
row = row % maxrows;
if (row < 0) row = maxrows + row; return row;
}
static int red(Fl_Color val) { return (val & 0xff000000) >> 24; }
static int grn(Fl_Color val) { return (val & 0x00ff0000) >> 16; }
static int blu(Fl_Color val) { return (val & 0x0000ff00) >> 8; }
static Fl_Color rgb(int r,int g,int b) { return (r << 24) | (g << 16) | (b << 8); }
static Fl_Color dim_color(Fl_Color val) {
int r = clamp(red(val) - 0x20, 0, 255);
int g = clamp(grn(val) - 0x20, 0, 255);
int b = clamp(blu(val) - 0x20, 0, 255);
return rgb(r,g,b);
}
static Fl_Color bold_color(Fl_Color val) {
int r = clamp(red(val) + 0x20, 0, 255);
int g = clamp(grn(val) + 0x20, 0, 255);
int b = clamp(blu(val) + 0x20, 0, 255);
return rgb(r,g,b);
}
Fl_Color Fl_Terminal::CharStyle::fltk_fg_color(uchar ci) {
static const Fl_Color xterm_fg_colors_[] = {
0x00000000, 0xd0000000, 0x00d00000, 0xd0d00000, 0x0000d000, 0xd000d000, 0x00d0d000, 0xd0d0d000 };
if (ci==39) return defaultfgcolor_; if (ci==49) return defaultbgcolor_; ci &= 0x07; return xterm_fg_colors_[ci];
}
Fl_Color Fl_Terminal::CharStyle::fltk_bg_color(uchar ci) {
static const Fl_Color xterm_bg_colors_[] = {
0x00000000, 0xc0000000, 0x00c00000, 0xc0c00000, 0x0000c000, 0xc000c000, 0x00c0c000, 0xc0c0c000 };
if (ci==39) return defaultfgcolor_; if (ci==49) return defaultbgcolor_; ci &= 0x07; return xterm_bg_colors_[ci];
}
static bool is_frame(Fl_Boxtype b) {
if (b == FL_UP_FRAME || b == FL_DOWN_FRAME ||
b == FL_THIN_UP_FRAME || b == FL_THIN_DOWN_FRAME ||
b == FL_ENGRAVED_FRAME || b == FL_EMBOSSED_FRAME ||
b == FL_BORDER_FRAME) return true;
return false;
}
Fl_Terminal::Selection::Selection(Fl_Terminal *terminal)
: terminal_(terminal)
{
srow_ = scol_ = erow_ = ecol_ = 0;
push_clear();
selectionfgcolor_ = FL_BLACK;
selectionbgcolor_ = FL_WHITE;
state_ = 0;
is_selection_ = false;
}
bool Fl_Terminal::Selection::get_selection(int &srow,int &scol,
int &erow,int &ecol) const {
srow = srow_; scol = scol_;
erow = erow_; ecol = ecol_;
if (!is_selection_) return false;
if (srow_ == erow_ && scol_ > ecol_) swap(scol, ecol);
if (srow_ > erow_)
{ swap(srow, erow); swap(scol, ecol); }
return true;
}
bool Fl_Terminal::Selection::start(int row, int col, bool char_right) {
(void) char_right; srow_ = erow_ = row;
scol_ = ecol_ = col;
state_ = 1; is_selection_ = true;
return true;
}
bool Fl_Terminal::Selection::extend(int row, int col, bool char_right) {
int osrow = srow_, oerow = erow_, oscol = scol_, oecol = ecol_;
bool oselection = is_selection_;
if (state_ == 0) return start(row, col, char_right);
state_ = 2;
if ((row==push_row_) && (col+char_right==push_col_+push_char_right_)) {
srow_ = erow_ = row;
scol_ = ecol_ = col;
is_selection_ = false;
} else if ((row>push_row_) || ((row==push_row_) && (col+char_right>push_col_+push_char_right_))) {
scol_ = push_col_ + push_char_right_;
ecol_ = col - 1 + char_right;
is_selection_ = true;
} else {
scol_ = push_col_ - 1 + push_char_right_;
ecol_ = col + char_right;
is_selection_ = true;
}
if (scol_<0) scol_ = 0;
if (ecol_<0) ecol_ = 0;
int maxCol = terminal_->ring_cols()-1;
if (scol_>maxCol) scol_ = maxCol;
if (ecol_>maxCol) ecol_ = maxCol;
srow_ = push_row_;
erow_ = row;
bool changed = ( (osrow != srow_) || (oerow != erow_)
|| (oscol != scol_) || (oecol != ecol_)
|| (oselection != is_selection_) );
return !changed;
}
void Fl_Terminal::Selection::end(void) {
state_ = 3; if (erow_ < srow_)
{ swap(srow_, erow_); swap(scol_, ecol_); }
if (erow_ == srow_ && scol_ > ecol_) swap(scol_, ecol_);
}
void Fl_Terminal::Selection::select(int srow, int scol, int erow, int ecol) {
srow_ = srow; scol_ = scol;
erow_ = erow; ecol_ = ecol;
state_ = 3; is_selection_ = true;
}
bool Fl_Terminal::Selection::clear(void) {
bool was_selected = is_selection(); srow_ = scol_ = erow_ = ecol_ = 0;
state_ = 0;
is_selection_ = false;
return was_selected;
}
void Fl_Terminal::Selection::scroll(int nrows) {
if (is_selection()) {
srow_ -= nrows;
erow_ -= nrows;
if (srow_ < 0 || erow_ < 0) clear();
}
}
int Fl_Terminal::EscapeSeq::append_buff(char c) {
if (buffp_ >= buffendp_) return fail; *buffp_++ = c;
*buffp_ = 0; return success;
}
int Fl_Terminal::EscapeSeq::append_val(void) {
if (vali_ >= maxvals) { vali_ = maxvals-1; return fail; } if (!valbuffp_ || (*valbuffp_ == 0)) { vals_[vali_] = 0; return success; } if (sscanf(valbuffp_, "%d", &vals_[vali_]) != 1) { return fail; } vals_[vali_] &= 0x3ff; if (++vali_ >= maxvals) { vali_ = maxvals-1; return fail; } valbuffp_ = 0; return success;
}
Fl_Terminal::EscapeSeq::EscapeSeq(void) {
reset();
save_row_ = -1; save_col_ = -1;
}
void Fl_Terminal::EscapeSeq::reset(void) {
esc_mode_ = 0; csi_ = false; buffp_ = buff_; buffendp_ = buff_ + (maxbuff - 1); valbuffp_ = 0; vali_ = 0; buff_[0] = 0; vals_[0] = 0; memset(vals_, 0, sizeof(vals_));
}
char Fl_Terminal::EscapeSeq::esc_mode(void) const { return esc_mode_; }
void Fl_Terminal::EscapeSeq::esc_mode(char val) { esc_mode_ = val; }
int Fl_Terminal::EscapeSeq::total_vals(void) const { return vali_; }
int Fl_Terminal::EscapeSeq::val(int i) const { return vals_[i]; }
bool Fl_Terminal::EscapeSeq::parse_in_progress(void) const {
return (esc_mode_ == 0) ? false : true;
}
bool Fl_Terminal::EscapeSeq::is_csi(void) const { return csi_; }
int Fl_Terminal::EscapeSeq::defvalmax(int dval, int max) const {
if (total_vals() == 0) return dval;
else return clamp(vals_[0], 0, max);
}
void Fl_Terminal::EscapeSeq::save_cursor(int row, int col) {
save_row_ = row;
save_col_ = col;
}
void Fl_Terminal::EscapeSeq::restore_cursor(int &row, int &col) {
row = save_row_;
col = save_col_;
}
int Fl_Terminal::EscapeSeq::parse(char c) {
if (c == 0) { return success; } else if (c == 0x1b) { reset();
esc_mode(0x1b);
if (append_buff(c) < 0) goto pfail; return success;
} else if (c < ' ' || c >= 0x7f) { goto pfail; }
if (esc_mode() == 0x1b) { if (c == '[') { esc_mode(c); csi_ = true; vali_ = 0; valbuffp_ = 0; if (append_buff(c) < 0) goto pfail; return success; } else if ((c >= '@' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
esc_mode(c); csi_ = false; vali_ = 0;
valbuffp_ = 0; if (append_buff(c) < 0) goto pfail; return completed; } else { goto pfail; }
} else if (esc_mode() == '[') { if (c == ';') { if (append_val() < 0) goto pfail; if (append_buff(c) < 0) goto pfail; return success;
}
if (isdigit(c)) { if (!valbuffp_) { valbuffp_ = buffp_; } if (append_buff(c) < 0) goto pfail; return success;
}
} else { goto pfail;
}
if (( c >= '@' && c<= 'Z') || ( c >= 'a' && c<= 'z')) {
if (append_val() < 0 ) goto pfail; if (append_buff(c) < 0 ) goto pfail; esc_mode(c); return completed; }
pfail:
reset();
return fail;
}
Fl_Terminal::CharStyle::CharStyle(bool fontsize_defer) {
attrib_ = 0;
charflags_ = (FG_XTERM | BG_XTERM);
defaultfgcolor_ = 0xd0d0d000; defaultbgcolor_ = 0xffffffff; fgcolor_ = defaultfgcolor_;
bgcolor_ = defaultbgcolor_;
fontface_ = FL_COURIER;
fontsize_ = 14;
if (!fontsize_defer) update(); else update_fake(); }
void Fl_Terminal::CharStyle::update(void) {
fl_font(fontface_, fontsize_);
fontheight_ = int(fl_height() + 0.5);
fontdescent_ = int(fl_descent() + 0.5);
charwidth_ = int(fl_width("X") + 0.5);
}
void Fl_Terminal::CharStyle::update_fake(void) {
fontheight_ = 99; fontdescent_ = 99; charwidth_ = 99;
}
Fl_Color Fl_Terminal::CharStyle::fgcolor(void) const {
return fgcolor_;
}
Fl_Color Fl_Terminal::CharStyle::bgcolor(void) const {
return bgcolor_;
}
uchar Fl_Terminal::CharStyle::colorbits_only(uchar inflags) const {
return (inflags & ~COLORMASK) | (charflags_ & COLORMASK); }
void Fl_Terminal::CharStyle::fgcolor_xterm(uchar val) {
fgcolor_ = fltk_fg_color(val);
set_charflag(FG_XTERM);
}
void Fl_Terminal::CharStyle::bgcolor_xterm(uchar val) {
bgcolor_ = fltk_bg_color(val);
set_charflag(BG_XTERM);
}
bool Fl_Terminal::Cursor::is_rowcol(int drow,int dcol) const {
return(drow == row_ && dcol == col_);
}
void Fl_Terminal::Cursor::scroll(int nrows) {
row_ = MAX(row_ - nrows, 0); }
Fl_Terminal::Utf8Char::Utf8Char(void) {
text_[0] = ' ';
len_ = 1;
attrib_ = 0;
charflags_ = 0;
fgcolor_ = 0xffffff00;
bgcolor_ = 0xffffffff; }
Fl_Terminal::Utf8Char::Utf8Char(const Utf8Char& src) {
text_[0] = ' ';
len_ = 1;
attrib_ = src.attrib_;
charflags_ = src.charflags_;
fgcolor_ = src.fgcolor_;
bgcolor_ = src.bgcolor_;
text_utf8_(src.text_utf8(), src.length()); }
Fl_Terminal::Utf8Char& Fl_Terminal::Utf8Char::operator=(const Utf8Char& src) {
text_utf8_(src.text_utf8(), src.length()); attrib_ = src.attrib_;
charflags_ = src.charflags_;
fgcolor_ = src.fgcolor_;
bgcolor_ = src.bgcolor_;
return *this;
}
Fl_Terminal::Utf8Char::~Utf8Char(void) {
len_ = 0;
}
void Fl_Terminal::Utf8Char::text_utf8_(const char *text, int len) {
memcpy(text_, text, len);
len_ = len; }
void Fl_Terminal::Utf8Char::text_utf8(const char *text,
int len,
const CharStyle& style) {
text_utf8_(text, len); attrib_ = style.attrib();
charflags_ = style.colorbits_only(charflags_);
fgcolor_ = style.fgcolor();
bgcolor_ = style.bgcolor();
}
void Fl_Terminal::Utf8Char::text_ascii(char c, const CharStyle& style) {
if (c < 0x20 || c >= 0x7e) return; text_utf8(&c, 1, style);
}
void Fl_Terminal::Utf8Char::fl_font_set(const CharStyle& style) const {
int face = style.fontface() |
((attrib_ & Fl_Terminal::BOLD) ? FL_BOLD : 0) |
((attrib_ & Fl_Terminal::ITALIC) ? FL_ITALIC : 0);
fl_font(face, style.fontsize());
}
Fl_Color Fl_Terminal::Utf8Char::fgcolor(void) const {
return fgcolor_;
}
Fl_Color Fl_Terminal::Utf8Char::bgcolor(void) const {
return bgcolor_;
}
double Fl_Terminal::Utf8Char::pwidth(void) const {
return fl_width(text_, len_);
}
int Fl_Terminal::Utf8Char::pwidth_int(void) const {
return int(fl_width(text_, len_) + 0.5);
}
Fl_Color Fl_Terminal::Utf8Char::attr_color_(Fl_Color col, const Fl_Widget *grp) const {
if (grp && ((col == 0xffffffff) || (col == grp->color()))) return grp->color();
switch (attrib_ & (Fl_Terminal::BOLD|Fl_Terminal::DIM)) {
case 0: return col; case Fl_Terminal::BOLD: return bold_color(col); case Fl_Terminal::DIM : return dim_color(col); default: return col; }
}
Fl_Color Fl_Terminal::Utf8Char::attr_fg_color(const Fl_Widget *grp) const {
if (grp && (fgcolor_ == 0xffffffff)) { return grp->color(); } return (charflags_ & Fl_Terminal::FG_XTERM) ? attr_color_(fgcolor(), grp) : fgcolor(); }
Fl_Color Fl_Terminal::Utf8Char::attr_bg_color(const Fl_Widget *grp) const {
if (grp && (bgcolor_ == 0xffffffff)) { return grp->color(); } return (charflags_ & Fl_Terminal::BG_XTERM) ? attr_color_(bgcolor(), grp) : bgcolor(); }
void Fl_Terminal::RingBuffer::offset_adjust(int rows) {
if (!rows) return; if (rows>0) { offset_ = (offset_ + rows) % ring_rows_; } else {
rows = clamp(-rows, 1, ring_rows_); offset_ -= rows; if (offset_<0) offset_ += ring_rows_; }
}
void Fl_Terminal::RingBuffer::new_copy(int drows, int dcols, int hrows, const CharStyle& style) {
(void)style; int addhist = disp_rows() - drows; int new_ring_rows = (drows+hrows);
int new_hist_use = clamp(hist_use_ + addhist, 0, hrows); int new_nchars = (new_ring_rows * dcols);
Utf8Char *new_ring_chars = new Utf8Char[new_nchars]; int dst_cols = dcols;
int src_stop_row = hist_use_srow();
int tcols = MIN(ring_cols(), dcols);
int src_row = hist_use_srow() + hist_use_ + disp_rows_ - 1; int dst_row = new_ring_rows - 1;
while ((src_row >= src_stop_row) && (dst_row >= 0)) {
Utf8Char *src = u8c_ring_row(src_row);
Utf8Char *dst = new_ring_chars + (dst_row*dst_cols);
for (int col=0; col<tcols; col++ ) *dst++ = *src++;
--src_row;
--dst_row;
}
if (ring_chars_) delete[] ring_chars_;
ring_chars_ = new_ring_chars;
ring_rows_ = new_ring_rows;
ring_cols_ = dcols;
nchars_ = new_nchars;
hist_rows_ = hrows;
hist_use_ = new_hist_use;
disp_rows_ = drows;
offset_ = 0; }
void Fl_Terminal::RingBuffer::clear(void) {
if (ring_chars_) delete[] ring_chars_; ring_chars_ = 0;
ring_rows_ = 0;
ring_cols_ = 0;
nchars_ = 0;
hist_rows_ = 0;
hist_use_ = 0;
disp_rows_ = 0;
offset_ = 0;
}
void Fl_Terminal::RingBuffer::clear_hist(void) {
hist_use_ = 0;
}
Fl_Terminal::RingBuffer::RingBuffer(void) {
ring_chars_ = 0;
clear();
}
Fl_Terminal::RingBuffer::RingBuffer(int drows, int dcols, int hrows) {
ring_chars_ = 0;
clear();
create(drows, dcols, hrows);
}
Fl_Terminal::RingBuffer::~RingBuffer(void) {
if (ring_chars_) delete[] ring_chars_;
ring_chars_ = NULL;
}
bool Fl_Terminal::RingBuffer::is_hist_ring_row(int grow) const {
grow %= ring_rows_;
grow -= offset_; if (grow < 0) { grow = (ring_rows_ + grow); }
int htop = 0;
int hbot = (hist_rows_ - 1);
return ((grow >= htop) && (grow <= hbot));
}
bool Fl_Terminal::RingBuffer::is_disp_ring_row(int grow) const {
grow %= ring_rows_;
grow -= offset_;
if (grow < 0) { grow = (ring_rows_ + grow); }
int dtop = hist_rows_;
int dbot = hist_rows_ + disp_rows_ - 1;
return ((grow >= dtop) && (grow <= dbot));
}
void Fl_Terminal::RingBuffer::move_disp_row(int src_row, int dst_row) {
Utf8Char *src = u8c_disp_row(src_row);
Utf8Char *dst = u8c_disp_row(dst_row);
for (int col=0; col<disp_cols(); col++) *dst++ = *src++;
}
void Fl_Terminal::RingBuffer::clear_disp_rows(int sdrow, int edrow, const CharStyle& style) {
for (int drow=sdrow; drow<=edrow; drow++) {
int row = hist_rows_ + drow + offset_;
Utf8Char *u8c = u8c_ring_row(row);
for (int col=0; col<disp_cols(); col++) u8c++->clear(style);
}
}
void Fl_Terminal::RingBuffer::scroll(int rows, const CharStyle& style) {
if (rows > 0) {
rows = clamp(rows, 1, disp_rows()); offset_adjust(rows);
hist_use_ = clamp(hist_use_ + rows, 0, hist_rows_);
int srow = (disp_rows() - rows) % disp_rows();
int erow = disp_rows() - 1;
clear_disp_rows(srow, erow, style);
} else {
rows = clamp(-rows, 1, disp_rows()); for (int row=disp_rows()-1; row>=0; row--) { int src_row = (row - rows); int dst_row = row; if (src_row >= 0) move_disp_row(src_row, dst_row); else clear_disp_rows(dst_row, dst_row, style); }
}
}
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row) const {
row = normalize(row, ring_rows());
assert(row >= 0 && row < ring_rows_);
return &ring_chars_[row * ring_cols()];
}
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_row(int hrow) const {
int rowi = normalize(hrow, hist_rows());
rowi = (rowi + offset_) % ring_rows_;
assert(rowi >= 0 && rowi <= ring_rows_);
return &ring_chars_[rowi * ring_cols()];
}
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_use_row(int hurow) const {
if (hist_use_ == 0) return 0; hurow = hurow % hist_use_; hurow = hist_rows_ - hist_use_ + hurow; hurow = (hurow + offset_) % ring_rows_; assert(hurow >= 0 && hurow <= hist_use());
return &ring_chars_[hurow * ring_cols()];
}
const Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_disp_row(int drow) const {
int rowi = normalize(drow, disp_rows());
rowi = (hist_rows_ + rowi + offset_) % ring_rows_; assert(rowi >= 0 && rowi <= ring_rows_);
return &ring_chars_[rowi * ring_cols()];
}
Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_ring_row(int row)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_ring_row(row)); }
Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_hist_row(int hrow)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_hist_row(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)); }
Fl_Terminal::Utf8Char* Fl_Terminal::RingBuffer::u8c_disp_row(int drow)
{ return const_cast<Utf8Char*>(const_cast<const RingBuffer*>(this)->u8c_disp_row(drow)); }
void Fl_Terminal::RingBuffer::create(int drows, int dcols, int hrows) {
clear();
hist_rows_ = hrows;
hist_use_ = 0;
disp_rows_ = drows;
ring_rows_ = hist_rows_ + disp_rows_;
ring_cols_ = dcols;
nchars_ = ring_rows_ * ring_cols_;
ring_chars_ = new Utf8Char[nchars_];
}
void Fl_Terminal::RingBuffer::resize(int drows, int dcols, int hrows, const CharStyle& style) {
int new_rows = drows + hrows; int old_rows = disp_rows() + hist_rows(); bool cols_changed = (dcols != disp_cols()); bool rows_changed = (new_rows != old_rows); if (cols_changed || rows_changed) { new_copy(drows, dcols, hrows, style); } else {
int addhist = disp_rows() - drows; hist_rows_ = hrows; disp_rows_ = drows; hist_use_ = clamp(hist_use_ + addhist, 0, hrows);
}
}
void Fl_Terminal::RingBuffer::change_disp_rows(int drows, const CharStyle& style)
{ resize(drows, ring_cols(), hist_rows(), style); }
void Fl_Terminal::RingBuffer::change_disp_cols(int dcols, const CharStyle& style)
{ resize(disp_rows(), dcols, hist_rows(), style); }
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_ring_row(int grow) const
{ return ring_.u8c_ring_row(grow); }
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_row(int hrow) const
{ return ring_.u8c_hist_row(hrow); }
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_use_row(int hurow) const
{ return ring_.u8c_hist_use_row(hurow); }
const Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow) const
{ return ring_.u8c_disp_row(drow); }
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_ring_row(int grow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_ring_row(grow)); }
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_hist_row(int hrow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_hist_row(hrow)); }
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)); }
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_disp_row(int drow)
{ return const_cast<Utf8Char*>(const_cast<const Fl_Terminal*>(this)->u8c_disp_row(drow)); }
void Fl_Terminal::create_ring(int drows, int dcols, int hrows) {
if (dcols != ring_.ring_cols()) init_tabstops(dcols);
ring_.create(drows, dcols, hrows);
cursor_.home();
}
Fl_Terminal::Utf8Char* Fl_Terminal::u8c_cursor(void) {
return u8c_disp_row(cursor_.row()) + cursor_.col();
}
void Fl_Terminal::init_tabstops(int newsize) {
if (newsize > tabstops_size_) { char *oldstops = tabstops_; int oldsize = tabstops_size_; tabstops_ = (char*)malloc(newsize); for (int t=0; t<newsize; t++) { tabstops_[t] = (oldstops && t<oldsize)
? oldstops[t] : ((t % 8) == 0) ? 1 : 0; }
if (oldstops) free((void*)oldstops); tabstops_size_ = newsize;
} else {
}
}
void Fl_Terminal::default_tabstops(void) {
init_tabstops(ring_cols()); for (int t=1; t<tabstops_size_; t++) tabstops_[t] = ((t % 8) == 0) ? 1 : 0; }
void Fl_Terminal::clear_all_tabstops(void) {
memset(tabstops_, 0, tabstops_size_);
}
void Fl_Terminal::set_tabstop(void) {
int index = clamp(cursor_col(), 0, tabstops_size_-1); tabstops_[index] = 1; }
void Fl_Terminal::clear_tabstop(void) {
int index = clamp(cursor_col(), 0, tabstops_size_-1); tabstops_[index] = 0; }
void Fl_Terminal::set_scrollbar_params(Fl_Scrollbar* scroll, int min, int max) { bool is_hor = (scroll->type() == FL_HORIZONTAL);
int diff = max - min;
int length = is_hor ? scroll->w() : scroll->h(); float tabsize = min / float(max); float minpix = float(MAX(10, scrollbar_actual_size())); float minfrac = minpix / length; tabsize = MAX(minfrac, tabsize); scroll->slider_size(tabsize); if (is_hor) scroll->range(0, diff); else scroll->range(diff, 0); scroll->step(0.25); }
void Fl_Terminal::update_scrollbar(void) {
int value_before = scrollbar->value();
{
int trows = disp_rows() + history_use(); int vrows = disp_rows(); set_scrollbar_params(scrollbar, vrows, trows);
}
if (value_before == 0) scrollbar->value(0); update_screen_xywh(); int sx = scrn_.r() + margin_.right();
int sy = scrn_.y() - margin_.top();
int sw = scrollbar_actual_size();
int sh = scrn_.h() + margin_.top() + margin_.bottom();
bool vchanged = scrollbar->x() != sx ||
scrollbar->y() != sy ||
scrollbar->w() != sw ||
scrollbar->h() != sh;
if (vchanged) scrollbar->resize(sx, sy, sw, sh);
int hh;
int hx = scrn_.x() - margin_.left();
int hy = scrn_.b() + margin_.bottom();
int hw = scrn_.w() + margin_.left() + margin_.right();
unsigned int hv = hscrollbar->visible();
int vcols = w_to_col(scrn_.w()); int tcols = disp_cols(); if (vcols > tcols) vcols = tcols; set_scrollbar_params(hscrollbar, vcols, tcols);
if (hscrollbar_style_ == SCROLLBAR_OFF) {
hscrollbar->hide();
hh = 0;
} else if (vcols < tcols || hscrollbar_style_ == SCROLLBAR_ON) {
hscrollbar->show();
hh = scrollbar_actual_size();
} else {
hscrollbar->hide();
hh = 0;
}
bool hchanged = hscrollbar->x() != hx ||
hscrollbar->y() != hy ||
hscrollbar->w() != hw ||
hscrollbar->h() != hh ||
hscrollbar->visible() != hv;
if (hchanged) hscrollbar->resize(hx, hy, hw, hh);
if (vchanged || hchanged) {
init_sizes(); update_screen_xywh(); display_modified(); }
scrollbar->redraw(); }
void Fl_Terminal::refit_disp_to_screen(void) {
int dh = h_to_row(scrn_.h()); int dw = MAX(w_to_col(scrn_.w()), disp_cols()); int drows = clamp(dh, 2, dh); int dcols = clamp(dw, 10, dw); int drow_diff = drows - display_rows(); int is_enlarge = drows >= display_rows();
scrollbar->value(0);
if (drow_diff) { if (is_enlarge) { for (int i=0; i<drow_diff; i++) { if (history_use() > 0) { cursor_.scroll(-1); } else { scroll(1); }
ring_.resize(display_rows()+1, dcols, hist_rows(), *current_style_);
}
} else { for (int i=0; i<(-drow_diff); i++) { int cur_row = cursor_.row(); int below_cur = (drows > cur_row); if (below_cur) { ring_.disp_rows(display_rows() - 1); } else { cursor_up(-1, false); ring_.resize(display_rows()-1, dcols, hist_rows(), *current_style_);
}
}
}
}
clear_mouse_selection();
update_screen(false);
}
void Fl_Terminal::resize_display_rows(int drows) {
int drow_diff = drows - ring_.disp_rows(); if (drow_diff == 0) return; int new_dcols = ring_cols(); int new_hrows = hist_rows() - drow_diff; if (new_hrows<0) new_hrows = 0; ring_.resize(drows, new_dcols, new_hrows, *current_style_);
cursor_.scroll(-drow_diff);
select_.clear(); update_scrollbar();
}
void Fl_Terminal::resize_display_columns(int dcols) {
if (dcols == disp_cols()) return;
ring_.resize(disp_rows(), dcols, hist_rows(), *current_style_);
update_scrollbar();
}
void Fl_Terminal::update_screen_xywh(void) {
const Margin &m = margin_;
scrn_ = *this; scrn_.inset(box()); scrn_.inset(m.left(), m.top(), m.right(), m.bottom()); scrn_.inset(0, 0, scrollbar_actual_size(), 0); if (hscrollbar && hscrollbar->visible())
scrn_.inset(0, 0, 0, scrollbar_actual_size()); }
void Fl_Terminal::update_screen(bool font_changed) {
if (font_changed) {
if (!fontsize_defer_) { fl_font(current_style_->fontface(), current_style_->fontsize());
}
cursor_.h(current_style_->fontheight());
}
update_screen_xywh();
update_scrollbar();
}
int Fl_Terminal::history_rows(void) const {
return hist_rows();
}
void Fl_Terminal::history_rows(int hrows) {
if (hrows == history_rows()) return; ring_.resize(disp_rows(), disp_cols(), hrows, *current_style_);
update_screen(false); display_modified();
}
int Fl_Terminal::history_use(void) const {
return ring_.hist_use();
}
int Fl_Terminal::display_rows(void) const {
return ring_.disp_rows();
}
void Fl_Terminal::display_rows(int drows) {
if (drows == disp_rows()) return; ring_.resize(drows, disp_cols(), hist_rows(), *current_style_);
update_screen(false); refit_disp_to_screen();
}
int Fl_Terminal::display_columns(void) const {
return ring_.disp_cols();
}
void Fl_Terminal::display_columns(int dcols) {
if (dcols == disp_cols()) return; ring_.resize(disp_rows(), dcols, hist_rows(), *current_style_);
update_screen(false); refit_disp_to_screen();
}
Fl_Terminal::CharStyle& Fl_Terminal::current_style(void) const {
return *current_style_;
}
void Fl_Terminal::current_style(const CharStyle& sty) {
*current_style_ = sty;
}
void Fl_Terminal::margin_left(int val) {
val = clamp(val,0,w()-1);
margin_.left(val);
update_screen(true);
refit_disp_to_screen();
}
void Fl_Terminal::margin_right(int val) {
val = clamp(val,0,w()-1);
margin_.right(val);
update_screen(true);
refit_disp_to_screen();
}
void Fl_Terminal::margin_top(int val) {
val = clamp(val,0,h()-1);
margin_.top(val);
update_screen(true);
refit_disp_to_screen();
}
void Fl_Terminal::margin_bottom(int val) {
val = clamp(val,0,h()-1);
margin_.bottom(val);
update_screen(true);
refit_disp_to_screen();
}
void Fl_Terminal::textfont(Fl_Font val) {
current_style_->fontface(val);
update_screen(true);
display_modified();
}
void Fl_Terminal::textsize(Fl_Fontsize val) {
current_style_->fontsize(val);
update_screen(true);
refit_disp_to_screen();
display_modified();
}
void Fl_Terminal::textfgcolor_xterm(uchar val) {
current_style_->fgcolor_xterm(val);
}
void Fl_Terminal::textbgcolor_xterm(uchar val) {
current_style_->bgcolor_xterm(val);
}
void Fl_Terminal::textcolor(Fl_Color val) {
textfgcolor(val);
textfgcolor_default(val);
}
void Fl_Terminal::color(Fl_Color val) {
Fl_Group::color(val);
}
void Fl_Terminal::textfgcolor(Fl_Color val) {
current_style_->fgcolor(val); }
void Fl_Terminal::textbgcolor(Fl_Color val) {
current_style_->bgcolor(val); }
void Fl_Terminal::textfgcolor_default(Fl_Color val) {
current_style_->defaultfgcolor(val);
}
void Fl_Terminal::textbgcolor_default(Fl_Color val) {
current_style_->defaultbgcolor(val);
}
void Fl_Terminal::textattrib(uchar val) {
current_style_->attrib(val);
}
uchar Fl_Terminal::textattrib() const {
return current_style_->attrib();
}
int Fl_Terminal::x_to_glob_col(int X, int grow, int &gcol, bool &gcr) const {
int cx = scrn_.x(); const Utf8Char *u8c = utf8_char_at_glob(grow, 0);
for (gcol=0; gcol<ring_cols(); gcol++,u8c++) { u8c->fl_font_set(*current_style_); int cx2 = cx + u8c->pwidth_int(); if (X >= cx && X < cx2) {
gcr = (X > ((cx+cx2)/2)); return 1; }
cx += u8c->pwidth_int(); }
gcol = ring_cols()-1; return 0; }
int Fl_Terminal::xy_to_glob_rowcol(int X, int Y, int &grow, int &gcol, bool &gcr) const {
if (Y<scrn_.y()) return -1; if (Y>scrn_.b()) return -2; if (X<scrn_.x()) return -3; if (X>scrn_.r()) return -4; int toprow = disp_srow() - scrollbar->value();
grow = toprow + ( (Y-scrn_.y()) / current_style_->fontheight());
return x_to_glob_col(X, grow, gcol, gcr);
}
void Fl_Terminal::clear(void) {
clear_screen_home();
}
void Fl_Terminal::clear(Fl_Color val) {
Fl_Color save = textbgcolor();
textbgcolor(val);
clear_screen_home();
textbgcolor(save);
}
void Fl_Terminal::clear_screen(bool scroll_to_hist) {
if (scroll_to_hist) { scroll(disp_rows()); return; }
for (int drow=0; drow<disp_rows(); drow++)
for (int dcol=0; dcol<disp_cols(); dcol++)
clear_char_at_disp(drow, dcol);
clear_mouse_selection();
}
void Fl_Terminal::clear_screen_home(bool scroll_to_hist) {
cursor_home();
clear_screen(scroll_to_hist);
}
void Fl_Terminal::clear_sod(void) {
for (int drow=0; drow <= cursor_.row(); drow++)
if (drow == cursor_.row())
for (int dcol=0; dcol<=cursor_.col(); dcol++)
plot_char(' ', drow, dcol);
else
for (int dcol=0; dcol<disp_cols(); dcol++)
plot_char(' ', drow, dcol);
}
void Fl_Terminal::clear_eod(void) {
for (int drow=cursor_.row(); drow<disp_rows(); drow++)
if (drow == cursor_.row())
for (int dcol=cursor_.col(); dcol<disp_cols(); dcol++)
plot_char(' ', drow, dcol);
else
for (int dcol=0; dcol<disp_cols(); dcol++)
plot_char(' ', drow, dcol);
}
void Fl_Terminal::clear_eol(void) {
Utf8Char *u8c = u8c_disp_row(cursor_.row()) + cursor_.col(); for (int col=cursor_.col(); col<disp_cols(); col++) (u8c++)->clear(*current_style_);
}
void Fl_Terminal::clear_sol(void) {
Utf8Char *u8c = u8c_disp_row(cursor_.row()); for (int col=0; col<=cursor_.col(); col++) (u8c++)->clear(*current_style_);
}
void Fl_Terminal::clear_line(int drow) {
Utf8Char *u8c = u8c_disp_row(drow); for (int col=0; col<disp_cols(); col++) (u8c++)->clear(*current_style_);
}
void Fl_Terminal::clear_line(void) {
clear_line(cursor_.row());
}
bool Fl_Terminal::is_selection(void) const {
return select_.is_selection();
}
const Fl_Terminal::Utf8Char* Fl_Terminal::walk_selection(
const Utf8Char *u8c, int &row, int &col ) const {
if (u8c==NULL) {
int erow,ecol; if (!get_selection(row,col,erow,ecol)) return NULL; u8c = u8c_ring_row(row);
} else {
int srow,scol,erow,ecol;
if (!get_selection(srow,scol,erow,ecol)) return NULL; if (row == erow && col == ecol) return NULL;
if (++col >= ring_cols()) { col = 0; ++row; } }
return u8c_ring_row(row) + col;
}
bool Fl_Terminal::get_selection(int &srow, int &scol, int &erow, int &ecol ) const {
return select_.get_selection(srow, scol, erow, ecol);
}
bool Fl_Terminal::is_inside_selection(int grow, int gcol) const {
if (!is_selection()) return false;
int ncols = ring_cols();
int check = (grow * ncols) + gcol;
int start = (select_.srow() * ncols) + select_.scol();
int end = (select_.erow() * ncols) + select_.ecol();
if (start > end) swap(start, end); return (check >= start && check <= end);
}
bool Fl_Terminal::is_disp_ring_row(int grow) const {
return ring_.is_disp_ring_row(grow);
}
int Fl_Terminal::selection_text_len(void) const {
int row,col,len=0;
const Utf8Char *u8c = NULL; while ((u8c = walk_selection(u8c, row, col))) len += u8c->length();
return len;
}
const char* Fl_Terminal::selection_text(void) const {
if (!is_selection()) return fl_strdup(""); int clen = 0; int buflen = selection_text_len();
char *buf = (char*)malloc(buflen+1); char *bufp = buf;
char *nspc = bufp; int row,col;
const Utf8Char *u8c = NULL; while ((u8c = walk_selection(u8c, row, col))) { clen = u8c->length(); memcpy(bufp, u8c->text_utf8(), clen); if (!u8c->is_char(' ')) nspc = bufp + clen; bufp += clen; if (col >= (ring_cols()-1)) { if (nspc && nspc != bufp) { bufp = nspc; *bufp++ = '\n'; nspc = bufp; }
}
}
*bufp = 0;
return buf;
}
void Fl_Terminal::clear_mouse_selection(void) {
select_.clear();
}
bool Fl_Terminal::selection_extend(int X,int Y) {
if (is_selection()) { int grow, gcol;
bool gcr;
if (xy_to_glob_rowcol(X, Y, grow, gcol, gcr) > 0) {
select_.extend(grow, gcol, gcr); return true;
} else {
}
}
return false;
}
void Fl_Terminal::select_word(int grow, int gcol) {
int i, c0, c1;
int r = grow, c = gcol;
Utf8Char *row = u8c_ring_row(r);
int n = ring_cols();
if (c >= n) return;
if (row[c].text_utf8()[0]==' ') {
for (i=c; i>0; i--) if (row[i-1].text_utf8()[0]!=' ') break;
c0 = i;
for (i=c; i<n-2; i++) if (row[i+1].text_utf8()[0]!=' ') break;
c1 = i;
} else {
for (i=c; i>0; i--) if (row[i-1].text_utf8()[0]==' ') break;
c0 = i;
for (i=c; i<n-2; i++) if (row[i+1].text_utf8()[0]==' ') break;
c1 = i;
}
select_.select(r, c0, r, c1);
}
void Fl_Terminal::select_line(int grow) {
select_.select(grow, 0, grow, ring_cols()-1);
}
void Fl_Terminal::scroll(int rows) {
ring_.scroll(rows, *current_style_);
if (rows > 0) update_scrollbar(); else clear_mouse_selection(); }
void Fl_Terminal::insert_rows(int count) {
int dst_drow = disp_rows()-1; int src_drow = clamp((dst_drow-count), 1, (disp_rows()-1)); while (src_drow >= cursor_.row()) { Utf8Char *src = u8c_disp_row(src_drow--);
Utf8Char *dst = u8c_disp_row(dst_drow--);
for (int dcol=0; dcol<disp_cols(); dcol++) *dst++ = *src++; }
while (dst_drow >= cursor_.row()) { Utf8Char *dst = u8c_disp_row(dst_drow--);
for (int dcol=0; dcol<disp_cols(); dcol++)
dst++->clear(*current_style_);
}
clear_mouse_selection();
}
void Fl_Terminal::delete_rows(int count) {
int dst_drow = cursor_.row(); int src_drow = clamp((dst_drow+count), 1, (disp_rows()-1)); while (src_drow < disp_rows()) { Utf8Char *src = u8c_disp_row(src_drow++);
Utf8Char *dst = u8c_disp_row(dst_drow++);
for (int dcol=0; dcol<disp_cols(); dcol++)
*dst++ = *src++; }
while (dst_drow < disp_rows()) { Utf8Char *dst = u8c_disp_row(dst_drow++);
for (int dcol=0; dcol<disp_cols(); dcol++)
dst++->clear(*current_style_);
}
clear_mouse_selection();
}
void Fl_Terminal::repeat_char(char c, int rep) {
rep = clamp(rep, 1, disp_cols());
while ( rep-- > 0 && cursor_.col() < disp_cols() ) print_char(c);
}
void Fl_Terminal::insert_char_eol(char c, int drow, int dcol, int rep) {
rep = clamp(rep, 0, disp_cols()); if (rep == 0) return;
const CharStyle &style = *current_style_;
Utf8Char *src = u8c_disp_row(drow)+disp_cols()-1-rep; Utf8Char *dst = u8c_disp_row(drow)+disp_cols()-1; for (int col=(disp_cols()-1); col>=dcol; col--) { if (col >= (dcol+rep)) *dst-- = *src--; else (dst--)->text_ascii(c,style); }
}
void Fl_Terminal::insert_char(char c, int rep) {
insert_char_eol(c, cursor_.row(), cursor_.col(), rep);
}
void Fl_Terminal::delete_chars(int drow, int dcol, int rep) {
rep = clamp(rep, 0, disp_cols()); if (rep == 0) return;
const CharStyle &style = *current_style_;
Utf8Char *u8c = u8c_disp_row(drow);
for (int col=dcol; col<disp_cols(); col++) if (col+rep >= disp_cols()) u8c[col].text_ascii(' ', style); else u8c[col] = u8c[col+rep]; }
void Fl_Terminal::delete_chars(int rep) {
delete_chars(cursor_.row(), cursor_.col(), rep);
}
void Fl_Terminal::clear_history(void) {
ring_.clear_hist();
scrollbar->value(0); for (int hrow=0; hrow<hist_rows(); hrow++) {
Utf8Char *u8c = u8c_hist_row(hrow); for (int hcol=0; hcol<hist_cols(); hcol++) { (u8c++)->clear(*current_style_);
}
}
update_scrollbar();
}
void Fl_Terminal::reset_terminal(void) {
current_style_->sgr_reset(); clear_screen_home(); clear_history();
clear_mouse_selection();
default_tabstops(); }
void Fl_Terminal::cursorfgcolor(Fl_Color val) { cursor_.fgcolor(val); }
void Fl_Terminal::cursorbgcolor(Fl_Color val) { cursor_.bgcolor(val); }
Fl_Color Fl_Terminal::cursorfgcolor(void) const { return cursor_.fgcolor(); }
Fl_Color Fl_Terminal::cursorbgcolor(void) const { return cursor_.bgcolor(); }
void Fl_Terminal::cursor_row(int row) { cursor_.row( clamp(row,0,disp_rows()-1) ); }
void Fl_Terminal::cursor_col(int col) { cursor_.col( clamp(col,0,disp_cols()-1) ); }
int Fl_Terminal::cursor_row(void) const { return cursor_.row(); }
int Fl_Terminal::cursor_col(void) const { return cursor_.col(); }
void Fl_Terminal::cursor_up(int count, bool do_scroll) {
count = clamp(count, 1, disp_rows() * 2); while (count-- > 0) {
if (cursor_.up() <= 0) { cursor_.row(0); if (do_scroll) scroll(-1); else return; }
}
}
void Fl_Terminal::cursor_down(int count, bool do_scroll ) {
count = clamp(count, 1, ring_rows()); while (count-- > 0) {
if (cursor_.down() >= disp_rows()) { cursor_.row(disp_rows() - 1); if (!do_scroll) break; scroll(1); }
}
}
void Fl_Terminal::cursor_left(int count) {
count = clamp(count, 1, disp_cols()); while (count-- > 0 )
if (cursor_.left() < 0) { cursor_sol(); return; } }
void Fl_Terminal::cursor_right(int count, bool do_scroll) {
while (count-- > 0) {
if (cursor_.right() >= disp_cols()) { if (!do_scroll) { cursor_eol(); return; } else
{ cursor_crlf(1); } }
}
}
void Fl_Terminal::cursor_home(void) { cursor_.col(0); cursor_.row(0); }
void Fl_Terminal::cursor_eol(void) { cursor_.col(disp_cols()-1); }
void Fl_Terminal::cursor_sol(void) { cursor_.col(0); }
void Fl_Terminal::cursor_cr(void) { cursor_sol(); }
void Fl_Terminal::cursor_crlf(int count) {
const bool do_scroll = true;
count = clamp(count, 1, ring_rows()); cursor_sol();
cursor_down(count, do_scroll);
}
void Fl_Terminal::cursor_tab_right(int count) {
count = clamp(count, 1, disp_cols()); int X = cursor_.col();
while (count-- > 0) {
while (++X < disp_cols()) {
if ( (X<tabstops_size_) && tabstops_[X] ) { cursor_.col(X); return; } }
}
cursor_eol();
}
void Fl_Terminal::cursor_tab_left(int count) {
count = clamp(count, 1, disp_cols()); int X = cursor_.col();
while ( count-- > 0 )
while ( --X > 0 ) if ( (X<tabstops_size_) && tabstops_[X] ) { cursor_.col(X); return; } cursor_sol();
}
void Fl_Terminal::save_cursor(void) {
escseq.save_cursor(cursor_.row(), cursor_.col());
}
void Fl_Terminal::restore_cursor(void) {
int row,col;
escseq.restore_cursor(row, col);
if (row != -1 && col != 1) { cursor_.row(row); cursor_.col(col); }
}
void Fl_Terminal::handle_cr(void) {
const bool do_scroll = true;
if (oflags_ & CR_TO_LF) cursor_down(1, do_scroll);
else cursor_cr();
}
void Fl_Terminal::handle_lf(void) {
const bool do_scroll = true;
if (oflags_ & LF_TO_CR ) cursor_cr();
else if (oflags_ & LF_TO_CRLF) cursor_crlf();
else cursor_down(1, do_scroll);
}
void Fl_Terminal::handle_esc(void) {
if (!ansi_) { handle_unknown_char(); return; } if (escseq.esc_mode() == 0x1b) { handle_unknown_char(); } if (escseq.parse(0x1b) == EscapeSeq::fail) { handle_unknown_char(); return; } }
void Fl_Terminal::output_translate(Fl_Terminal::OutFlags val) {
oflags_ = val;
}
Fl_Terminal::OutFlags Fl_Terminal::output_translate(void) const {
return oflags_;
}
void Fl_Terminal::handle_ctrl(char c) {
switch (c) {
case '\b': cursor_left(); return; case '\r': handle_cr(); return; case '\n': handle_lf(); return; case '\t': cursor_tab_right(); return; case 0x1b: handle_esc(); return; default: handle_unknown_char(); return; }
}
bool Fl_Terminal::is_printable(char c) {
return ((c>=0x20) && (c<=0x7e));
}
bool Fl_Terminal::is_ctrl(char c) {
return ((c >= 0x00) && (c < 0x20)) ? true : false;
}
void Fl_Terminal::handle_SGR(void) { EscapeSeq &esc = escseq;
int tot = esc.total_vals();
if (tot == 0)
{ current_style_->sgr_reset(); return; }
int rgbcode = 0; int rgbmode = 0; int r=0,g=0,b=0;
for (int i=0; i<tot; i++) { int val = esc.val(i); switch (rgbmode) {
case 0:
switch (val) {
case 38: case 48: rgbmode = 1;
rgbcode = val;
continue;
}
break;
case 1: if (val == 2) { rgbmode++; continue; } rgbcode = rgbmode = 0; handle_unknown_char();
break;
case 2: r=clamp(val,0,255); ++rgbmode; continue; case 3: g=clamp(val,0,255); ++rgbmode; continue; case 4: b=clamp(val,0,255); switch (rgbcode) {
case 38: current_style_->fgcolor(r,g,b); break;
case 48: current_style_->bgcolor(r,g,b); break;
}
rgbcode = rgbmode = 0; continue; }
if (val < 10) { switch (val) {
case 0: current_style_->sgr_reset(); break; case 1: current_style_->sgr_bold(1); break; case 2: current_style_->sgr_dim(1); break; case 3: current_style_->sgr_italic(1); break; case 4: current_style_->sgr_underline(1);break; case 5: current_style_->sgr_blink(1); break; case 6: handle_unknown_char(); break; case 7: current_style_->sgr_inverse(1); break; case 8: handle_unknown_char(); break; case 9: current_style_->sgr_strike(1); break; }
} else if (val >= 21 && val <= 29) { switch (val) {
case 21: current_style_->sgr_dbl_under(1);break; case 22: current_style_->sgr_dim(0); current_style_->sgr_bold(0); break; case 23: current_style_->sgr_italic(0); break; case 24: current_style_->sgr_underline(0);break; case 25: current_style_->sgr_blink(0); break; case 26: handle_unknown_char(); break; case 27: current_style_->sgr_inverse(0); break; case 28: handle_unknown_char(); break; case 29: current_style_->sgr_strike(0); break; }
} else if (val >= 30 && val <= 37) { uchar uval = (val - 30);
current_style_->fgcolor_xterm(uval);
} else if (val == 39) { Fl_Color fg = current_style_->defaultfgcolor(); current_style_->fgcolor_xterm(fg); } else if (val >= 40 && val <= 47) { uchar uval = (val - 40);
current_style_->bgcolor_xterm(uval);
} else if (val == 49) { Fl_Color bg = current_style_->defaultbgcolor(); current_style_->bgcolor_xterm(bg); } else {
handle_unknown_char(); }
}
}
void Fl_Terminal::handle_DECRARA(void) {
}
void Fl_Terminal::handle_escseq(char c) {
const bool do_scroll = true;
const bool no_scroll = false;
switch (escseq.parse(c)) { case EscapeSeq::fail: escseq.reset(); handle_unknown_char(); print_char(c); return; case EscapeSeq::success: return; case EscapeSeq::completed: break; }
EscapeSeq &esc = escseq;
char mode = esc.esc_mode();
int tot = esc.total_vals();
int val0 = (tot==0) ? 0 : esc.val(0);
int val1 = (tot<2) ? 0 : esc.val(1);
const int& dw = disp_cols();
const int& dh = disp_rows();
if (esc.is_csi()) { switch (mode) {
case '@': insert_char(' ', esc.defvalmax(1,dw));
break;
case 'A': cursor_up(esc.defvalmax(1,dh));
break;
case 'B': cursor_down(esc.defvalmax(1,dh), no_scroll);
break;
case 'C': cursor_right(esc.defvalmax(1,dw), no_scroll);
break;
case 'D': cursor_left(esc.defvalmax(1,dw));
break;
case 'E': cursor_crlf(esc.defvalmax(1,dh));
break;
case 'F': cursor_cr();
cursor_up(esc.defvalmax(1,dh));
break;
case 'G': switch (clamp(tot,0,1)) { case 0: cursor_sol(); break; case 1: cursor_col(clamp(val0,1,dw)-1);
break;
}
break;
case 'H':
cup:
switch (clamp(tot,0,2)) { case 0: cursor_home(); break; case 1: cursor_row(clamp(val0,1,dh)-1); cursor_col(0); break; case 2: cursor_row(clamp(val0,1,dh)-1);
cursor_col(clamp(val1,1,dw)-1);
break;
}
break;
case 'I': switch (clamp(tot,0,1)) { case 0: cursor_tab_right(1); break; case 1: cursor_tab_right(clamp(val0,1,dw)); break;
}
break;
case 'J': switch (clamp(tot,0,1)) { case 0: clear_eol(); break; case 1: switch (clamp(val0,0,3)) { case 0: clear_eod(); break; case 1: clear_sod(); break; case 2: clear_screen(); break; case 3: clear_history(); break; }
break;
}
break;
case 'K':
switch (clamp(tot,0,1)) { case 0: clear_eol(); break; case 1: switch (clamp(val0,0,2)) { case 0: clear_eol(); break; case 1: clear_sol(); break; case 2: clear_line(); break; }
break;
}
break;
case 'L': insert_rows(esc.defvalmax(1,dh));
break;
case 'M': delete_rows(esc.defvalmax(1,dh));
break;
case 'P': delete_chars(esc.defvalmax(1,dh));
break;
case 'S': scroll( +(esc.defvalmax(1,dh)) );
break;
case 'T': scroll( -(esc.defvalmax(1,dh)) );
break;
case 'X': repeat_char(' ', esc.defvalmax(1,dw));
break;
case 'Z': switch (clamp(tot,0,1)) { case 0: cursor_tab_left(1); break; case 1: cursor_tab_left(clamp(val0,1,dw));
break;
}
break;
case 'a': case 'b': case 'd': case 'e': handle_unknown_char(); break;
case 'f': goto cup; case 'g': switch (val0) {
case 0: clear_tabstop(); break; case 3: clear_all_tabstops(); break; default:
handle_unknown_char(); break;
}
break;
case 'm': handle_SGR(); break; case 's': save_cursor(); break; case 'u': restore_cursor(); break; case 'q': case 'r': handle_unknown_char(); break;
case 't': handle_DECRARA(); break; default:
handle_unknown_char(); break;
}
} else {
switch (esc.esc_mode()) {
case 'c': reset_terminal(); break; case 'D': cursor_down(1, do_scroll); break; case 'E': cursor_crlf(); break; case 'H': set_tabstop(); break; case 'M': cursor_up(1, true); break; case '7': handle_unknown_char(); break; case '8': handle_unknown_char(); break; default:
handle_unknown_char(); break;
}
}
esc.reset(); }
void Fl_Terminal::display_modified_clear(void) {
redraw_modified_ = false;
}
void Fl_Terminal::display_modified(void) {
if (is_redraw_style(RATE_LIMITED)) {
if (!redraw_modified_) { if (!redraw_timer_) {
Fl::add_timeout(.01, redraw_timer_cb, this); redraw_timer_ = true;
}
redraw_modified_ = true;
}
} else if (is_redraw_style(PER_WRITE)) {
if (!redraw_modified_) {
redraw_modified_ = true;
redraw(); }
} else { }
}
void Fl_Terminal::clear_char_at_disp(int drow, int dcol) {
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
u8c->clear(*current_style_);
}
const Fl_Terminal::Utf8Char* Fl_Terminal::utf8_char_at_disp(int drow, int dcol) const {
return u8c_disp_row(drow) + dcol;
}
const Fl_Terminal::Utf8Char* Fl_Terminal::utf8_char_at_glob(int grow, int gcol) const {
return u8c_ring_row(grow) + gcol;
}
void Fl_Terminal::plot_char(const char *text, int len, int drow, int dcol) {
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
if (!text || len<1 || len>u8c->max_utf8() || len!=fl_utf8len(*text)) {
handle_unknown_char(drow, dcol);
return;
}
u8c->text_utf8(text, len, *current_style_);
}
void Fl_Terminal::plot_char(char c, int drow, int dcol) {
if (!is_printable(c)) {
handle_unknown_char(drow, dcol);
return;
}
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
u8c->text_ascii(c, *current_style_);
}
void Fl_Terminal::print_char(const char *text, int len) {
len = len<0 ? fl_utf8len(*text) : len; const bool do_scroll = true;
if (is_ctrl(text[0])) { handle_ctrl(*text);
} else if (escseq.parse_in_progress()) { handle_escseq(*text);
} else { plot_char(text, len, cursor_row(), cursor_col());
cursor_right(1, do_scroll);
}
}
void Fl_Terminal::print_char(char c) {
const bool do_scroll = true;
if (is_ctrl(c)) { handle_ctrl(c);
} else if (escseq.parse_in_progress()) { handle_escseq(c);
} else { plot_char(c, cursor_row(), cursor_col());
cursor_right(1, do_scroll);
return;
}
}
void Fl_Terminal::utf8_cache_clear(void) {
pub_.clear();
}
void Fl_Terminal::utf8_cache_flush(void) {
if (pub_.buflen() > 0) print_char(pub_.buf(), pub_.buflen());
pub_.clear();
}
void Fl_Terminal::append_utf8(const char *buf, int len) {
int mod = 0; if (!buf) { utf8_cache_clear(); return; } if (len == -1) len = int(strlen(buf)); if (len<=0) return;
if (pub_.buflen() > 0) { while (len>0 && pub_.is_continuation(*buf)) { if (pub_.append(buf, 1) == false) { mod |= handle_unknown_char(); break; } else { buf++; len--; } }
if (pub_.is_complete()) utf8_cache_flush(); if (len <= 0) { if (mod) display_modified();
return;
}
}
int clen; const char *p = buf; while (len>0) {
clen = fl_utf8len(*p); if (clen == -1) { mod |= handle_unknown_char();
p += 1;
len -= 1;
} else {
if (len && clen>len) { if (pub_.append(p, len) == false) { mod |= handle_unknown_char();
utf8_cache_clear();
}
break;
}
print_char(p, clen); p += clen; len -= clen; mod |= 1;
}
}
if (mod) display_modified();
}
void Fl_Terminal::append_ascii(const char *s) {
if (!s) return;
while ( *s ) print_char(*s++); display_modified();
}
void Fl_Terminal::append(const char *s, int len) {
append_utf8(s, len);
}
int Fl_Terminal::handle_unknown_char(void) {
if (!show_unknown_) return 0;
escseq.reset(); print_char(error_char_);
return 1;
}
int Fl_Terminal::handle_unknown_char(int drow, int dcol) {
if (!show_unknown_) return 0;
int len = (int)strlen(error_char_);
Utf8Char *u8c = u8c_disp_row(drow) + dcol;
u8c->text_utf8(error_char_, len, *current_style_);
return 1;
}
void Fl_Terminal::scrollbar_cb(Fl_Widget*, void* userdata) {
Fl_Terminal *o = (Fl_Terminal*)userdata;
o->redraw();
}
void Fl_Terminal::autoscroll_timer_cb2(void) {
int amt = autoscroll_amt_; int val = scrollbar->value();
int max = int(scrollbar->minimum()+.5); val = (amt<0) ? (val+clamp((-amt/10),1,5)) : (amt>0) ? (val-clamp((+amt/10),1,5)) : 0; val = clamp(val,0,max); int diff = ABS(val - scrollbar->value()); scrollbar->value(val);
if (diff) { int srow = select_.srow(), scol = select_.scol();
int erow = select_.erow(), ecol = select_.ecol();
int ltcol = 0, rtcol = ring_cols() - 1;
if (amt<0) { erow -= diff; ecol = ltcol; } if (amt>0) { erow += diff; ecol = rtcol; } select_.select(srow, scol, erow, ecol);
}
Fl::repeat_timeout(.1, autoscroll_timer_cb, this);
redraw();
}
void Fl_Terminal::autoscroll_timer_cb(void *udata) {
Fl_Terminal *tty = (Fl_Terminal*)udata;
tty->autoscroll_timer_cb2();
}
void Fl_Terminal::redraw_timer_cb2(void) {
if (redraw_modified_) {
redraw(); redraw_modified_ = false; Fl::repeat_timeout(redraw_rate_, redraw_timer_cb, this); } else {
Fl::remove_timeout(redraw_timer_cb, this);
redraw_timer_ = false;
}
}
void Fl_Terminal::redraw_timer_cb(void *udata) {
Fl_Terminal *tty = (Fl_Terminal*)udata;
tty->redraw_timer_cb2();
}
Fl_Terminal::Fl_Terminal(int X,int Y,int W,int H,const char*L)
: Fl_Group(X,Y,W,H,L),
select_(this)
{
bool fontsize_defer = false;
init_(X,Y,W,H,L,-1,-1,100,fontsize_defer);
}
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),
select_(this)
{
bool fontsize_defer = true;
init_(X,Y,W,H,L,rows,cols,hist,fontsize_defer);
}
void Fl_Terminal::init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer) {
error_char_ = "¿";
scrollbar = hscrollbar = 0; (void)X; (void)Y; (void)W; (void)H; (void)L;
fontsize_defer_ = fontsize_defer; current_style_ = new CharStyle(fontsize_defer);
oflags_ = LF_TO_CRLF; scrollbar_size_ = 0; Fl_Group::box(FL_DOWN_FRAME); update_screen_xywh();
tabstops_ = 0;
tabstops_size_ = 0;
if (rows == -1 || cols == -1) {
int newrows = h_to_row(scrn_.h()); int newcols = w_to_col(scrn_.w()); newrows = (newrows >= 1) ? newrows : 1;
newcols = (newcols >= 1) ? newcols : 1;
create_ring(newrows, newcols, hist);
} else {
create_ring(rows, cols, 100);
}
redraw_style_ = RATE_LIMITED; redraw_rate_ = 0.10f; redraw_modified_ = false; redraw_timer_ = false;
autoscroll_dir_ = 0;
autoscroll_amt_ = 0;
scrollbar = new Fl_Scrollbar(x(), y(), scrollbar_actual_size(), h()); scrollbar->type(FL_VERTICAL);
scrollbar->value(0);
scrollbar->callback(scrollbar_cb, (void*)this);
hscrollbar = new Fl_Scrollbar(x(), y(), w(), scrollbar_actual_size()); hscrollbar->type(FL_HORIZONTAL);
hscrollbar->value(0);
hscrollbar->callback(scrollbar_cb, (void *)this);
hscrollbar_style_ = SCROLLBAR_AUTO;
resizable(0);
Fl_Group::color(FL_BLACK); update_screen(true); clear_screen_home(); clear_history(); show_unknown_ = false; ansi_ = true; end();
}
Fl_Terminal::~Fl_Terminal(void) {
if (tabstops_)
{ free(tabstops_); tabstops_ = 0; }
if (autoscroll_dir_)
{ Fl::remove_timeout(autoscroll_timer_cb, this); autoscroll_dir_ = 0; }
if (redraw_timer_)
{ Fl::remove_timeout(redraw_timer_cb, this); redraw_timer_ = false; }
delete current_style_;
}
int Fl_Terminal::scrollbar_actual_size(void) const {
return scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
}
int Fl_Terminal::scrollbar_size(void) const {
return scrollbar_size_;
}
void Fl_Terminal::scrollbar_size(int val) {
scrollbar_size_ = val;
update_scrollbar();
refit_disp_to_screen();
}
Fl_Terminal::ScrollbarStyle Fl_Terminal::hscrollbar_style() const {
return hscrollbar_style_;
}
void Fl_Terminal::hscrollbar_style(ScrollbarStyle val) {
hscrollbar_style_ = val;
update_scrollbar();
refit_disp_to_screen();
}
void Fl_Terminal::draw_row_bg(int grow, int X, int Y) const {
int bg_h = current_style_->fontheight();
int bg_y = Y;
Fl_Color bg_col;
int pwidth = 9;
int start_col = hscrollbar->visible() ? hscrollbar->value() : 0;
int end_col = disp_cols();
const Utf8Char *u8c = u8c_ring_row(grow) + start_col; uchar lastattr = u8c->attrib();
for (int gcol=start_col; gcol<end_col; gcol++,u8c++) { if (gcol==0 || u8c->attrib() != lastattr) {
u8c->fl_font_set(*current_style_); lastattr = u8c->attrib();
}
pwidth = u8c->pwidth_int();
bg_col = is_inside_selection(grow, gcol) ? select_.selectionbgcolor() : (u8c->attrib() & Fl_Terminal::INVERSE) ? u8c->attr_fg_color(this) : u8c->attr_bg_color(this); if (bg_col != 0xffffffff && bg_col != Fl_Group::color()) {
fl_color(bg_col);
fl_rectf(X, bg_y, pwidth, bg_h);
}
X += pwidth; }
}
void Fl_Terminal::draw_row(int grow, int Y) const {
int X = scrn_.x();
draw_row_bg(grow, X, Y);
int baseline = Y + current_style_->fontheight() - current_style_->fontdescent();
int scrollval = scrollbar->value();
int disp_top = (disp_srow() - scrollval); int drow = grow - disp_top; bool inside_display = is_disp_ring_row(grow); int strikeout_y = baseline - (current_style_->fontheight() / 3);
int underline_y = baseline;
uchar lastattr = -1;
bool is_cursor;
Fl_Color fg;
int start_col = hscrollbar->visible() ? hscrollbar->value() : 0;
int end_col = disp_cols();
const Utf8Char *u8c = u8c_ring_row(grow) + start_col;
for (int gcol=start_col; gcol<end_col; gcol++,u8c++) { const int &dcol = gcol; is_cursor = inside_display ? cursor_.is_rowcol(drow-scrollval, dcol) : 0;
if (u8c->attrib() != lastattr) {
u8c->fl_font_set(*current_style_); lastattr = u8c->attrib();
}
int pwidth = u8c->pwidth_int();
if (is_cursor) {
int cx = X;
int cy = Y + current_style_->fontheight() - cursor_.h();
int cw = pwidth;
int ch = cursor_.h();
fl_color(cursorbgcolor());
if (Fl::focus() == this) fl_rectf(cx, cy, cw, ch);
else fl_rect(cx, cy, cw, ch);
}
if (is_cursor) fg = cursorfgcolor(); else fg = is_inside_selection(grow, gcol) ? select_.selectionfgcolor() : (u8c->attrib() & Fl_Terminal::INVERSE) ? u8c->attr_bg_color(this) : u8c->attr_fg_color(this); fl_color(fg);
if (is_cursor) {
fl_font(fl_font()|FL_BOLD, fl_size()); lastattr = -1; }
if (!u8c->is_char(' ')) fl_draw(u8c->text_utf8(), u8c->length(), X, baseline);
if (u8c->attrib() & Fl_Terminal::UNDERLINE) fl_line(X, underline_y, X+pwidth, underline_y);
if (u8c->attrib() & Fl_Terminal::STRIKEOUT) fl_line(X, strikeout_y, X+pwidth, strikeout_y);
X += pwidth;
}
}
void Fl_Terminal::draw_buff(int Y) const {
int srow = disp_srow() - scrollbar->value();
int erow = srow + disp_rows();
const int rowheight = current_style_->fontheight();
for (int grow=srow; (grow<erow) && (Y<scrn_.b()); grow++) {
draw_row(grow, Y); Y += rowheight; }
}
void Fl_Terminal::draw(void) {
if (fontsize_defer_) {
fontsize_defer_ = false; current_style_->update(); update_screen(true); }
if (scrollbar_size_ == 0 &&
((scrollbar->visible() && scrollbar->w() != Fl::scrollbar_size()) ||
(hscrollbar->visible() && hscrollbar->h() != Fl::scrollbar_size()))) {
update_scrollbar();
}
Fl_Group::draw();
if (scrollbar->visible() && hscrollbar->visible()) {
fl_color(parent()->color());
fl_rectf(scrollbar->x(), hscrollbar->y(), scrollbar_actual_size(), scrollbar_actual_size());
}
if (is_frame(box())) {
fl_color(Fl_Group::color());
int X = x() + Fl::box_dx(box());
int Y = y() + Fl::box_dy(box());
int W = w() - Fl::box_dw(box());
int H = h() - Fl::box_dh(box());
if (scrollbar->visible()) W -= scrollbar_actual_size();
if (hscrollbar->visible()) H -= scrollbar_actual_size();
fl_rectf(X,Y,W,H);
}
fl_push_clip(scrn_.x(), scrn_.y(), scrn_.w(), scrn_.h());
int Y = scrn_.y();
draw_buff(Y);
fl_pop_clip();
}
int Fl_Terminal::w_to_col(int W) const {
return W / current_style_->charwidth();
}
int Fl_Terminal::h_to_row(int H) const {
return H / current_style_->fontheight();
}
void Fl_Terminal::resize(int X,int Y,int W,int H) {
Fl_Group::resize(X,Y,W,H);
update_screen(false); refit_disp_to_screen();
}
void Fl_Terminal::handle_selection_autoscroll(void) {
int Y = Fl::event_y();
int top = scrn_.y();
int bot = scrn_.b();
int dist = (Y < top) ? Y - top : (Y > bot) ? Y - bot : 0; if (dist == 0) {
if (autoscroll_dir_) Fl::remove_timeout(autoscroll_timer_cb, this);
autoscroll_dir_ = 0;
} else {
if (!autoscroll_dir_) Fl::add_timeout(.01, autoscroll_timer_cb, this);
autoscroll_amt_ = dist; autoscroll_dir_ = (dist < 0) ? 3 : 4; }
}
int Fl_Terminal::handle_selection(int e) {
int grow=0, gcol=0;
bool gcr = false;
bool is_rowcol = (xy_to_glob_rowcol(Fl::event_x(), Fl::event_y(), grow, gcol, gcr) > 0)
? true : false;
switch (e) {
case FL_PUSH: {
if (Fl::event_state(FL_SHIFT)) {
if (is_selection()) { selection_extend(Fl::event_x(), Fl::event_y());
redraw();
return 1; }
} else { select_.push_rowcol(grow, gcol, gcr);
if (select_.clear()) redraw(); if (is_rowcol) {
switch (Fl::event_clicks()) {
case 1: select_word(grow, gcol); break;
case 2: select_line(grow); break;
}
return 1; }
}
if (!Fl::event_state(FL_SHIFT)) {
select_.push_clear();
clear_mouse_selection();
redraw();
}
return 0; }
case FL_DRAG: {
if (is_rowcol) {
if (!is_selection()) { if (select_.dragged_off(grow, gcol, gcr)) { select_.start_push(); }
} else {
if (select_.extend(grow, gcol, gcr)) redraw(); }
}
handle_selection_autoscroll();
return 1;
}
case FL_RELEASE: {
select_.end();
if (is_selection()) {
const char *copy = selection_text();
if (*copy) Fl::copy(copy, (int)strlen(copy), 0);
free((void*)copy);
}
return 1;
}
default:
break;
}
return 0;
}
int Fl_Terminal::handle(int e) {
int ret = Fl_Group::handle(e);
if (Fl::event_inside(scrollbar)) return ret; if (Fl::event_inside(hscrollbar)) return ret; switch (e) {
case FL_ENTER:
case FL_LEAVE:
return 1;
case FL_UNFOCUS:
case FL_FOCUS:
redraw();
return Fl::visible_focus() ? 1 : 0;
case FL_KEYBOARD:
if ((Fl::event_state()&(FL_CTRL|FL_COMMAND)) && Fl::event_key()=='c') {
const char *copy = is_selection() ? selection_text() : fl_strdup(" ");
if (*copy) Fl::copy(copy, (int)strlen(copy), 1); free((void*)copy);
return 1;
}
if ((Fl::event_state()&(FL_CTRL|FL_COMMAND)) && Fl::event_key()=='a') {
int srow = disp_srow() - hist_use();
int erow = disp_srow() + disp_rows()-1;
select_.select(srow, 0, erow, disp_cols()-1);
const char *copy = selection_text();
if (*copy) Fl::copy(copy, (int) strlen(copy), 0); free((void*)copy);
redraw();
return 1;
}
if (Fl::focus() == this) {
switch (Fl::event_key()) {
case FL_Page_Up: case FL_Page_Down:
case FL_Up: case FL_Down:
case FL_Left: case FL_Right:
return scrollbar->handle(e);
}
}
break;
case FL_PUSH:
if (handle(FL_FOCUS)) Fl::focus(this); if (Fl::event_button() == FL_LEFT_MOUSE) { ret = handle_selection(FL_PUSH); }
break;
case FL_DRAG:
if (Fl::event_button() == FL_LEFT_MOUSE) { ret = handle_selection(FL_DRAG); }
break;
case FL_RELEASE:
if (Fl::event_button() == FL_LEFT_MOUSE) { ret = handle_selection(FL_RELEASE); }
if (autoscroll_dir_)
{ Fl::remove_timeout(autoscroll_timer_cb, this); autoscroll_dir_ = 0; }
break;
} return ret;
}
const char* Fl_Terminal::text(bool lines_below_cursor) const {
Fl_String lines; int disprows = lines_below_cursor ? disp_rows() - 1 : cursor_row(); int srow = hist_use_srow(); int erow = srow + hist_use() + disprows; for (int row=srow; row<=erow; row++) { const Utf8Char *u8c = u8c_ring_row(row); int trim = 0;
for (int col=0; col<ring_cols(); col++,u8c++) { const char *s = u8c->text_utf8(); for (int i=0; i<u8c->length(); i++) lines += *s++; if (u8c->length()==1 && s[-1]==' ') trim++; else trim = 0; }
if (trim) lines.resize(lines.size() - trim);
lines += "\n";
}
return fl_strdup(lines.c_str());
}
Fl_Terminal::RedrawStyle Fl_Terminal::redraw_style() const {
return redraw_style_;
}
void Fl_Terminal::redraw_style(RedrawStyle val) {
redraw_style_ = val;
if (redraw_style_ != RATE_LIMITED && redraw_timer_)
{ Fl::remove_timeout(redraw_timer_cb, this); redraw_timer_ = false; }
}
float Fl_Terminal::redraw_rate(void) const {
return redraw_rate_;
}
void Fl_Terminal::redraw_rate(float val) {
redraw_rate_ = val;
}
bool Fl_Terminal::show_unknown(void) const {
return show_unknown_;
}
void Fl_Terminal::show_unknown(bool val) {
show_unknown_ = val;
}
bool Fl_Terminal::ansi(void) const {
return ansi_;
}
void Fl_Terminal::ansi(bool val) {
ansi_ = val;
if (!ansi_) escseq.reset();
}
int Fl_Terminal::history_lines(void) const { return history_rows(); }
void Fl_Terminal::history_lines(int val) { history_rows(val); }
void Fl_Terminal::printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
Fl_Terminal::vprintf(fmt, ap);
va_end(ap);
}
void Fl_Terminal::vprintf(const char *fmt, va_list ap) {
char buffer[1024]; ::vsnprintf(buffer, 1024, fmt, ap);
buffer[1024-1] = 0; append(buffer);
}