parent
83f6336f3b
commit
6842a43a31
1013
FL/Fl_Terminal.H
Normal file
1013
FL/Fl_Terminal.H
Normal file
File diff suppressed because it is too large
Load Diff
@ -789,6 +789,7 @@ INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src/index.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/coordinates.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/resize.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/editor.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/Fl_Terminal.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/drawing.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/events.dox \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/src/subclassing.dox \
|
||||
|
@ -48,7 +48,8 @@ HTMLFILES = \
|
||||
$(SRC_DOCDIR)/development.dox \
|
||||
$(SRC_DOCDIR)/license.dox \
|
||||
$(SRC_DOCDIR)/examples.dox \
|
||||
$(SRC_DOCDIR)/faq.dox
|
||||
$(SRC_DOCDIR)/faq.dox \
|
||||
$(SRC_DOCDIR)/Fl_Terminal.dox
|
||||
|
||||
MANPAGES = $(SRC_DOCDIR)/fltk.$(CAT3EXT) $(SRC_DOCDIR)/fltk-config.$(CAT1EXT) \
|
||||
$(SRC_DOCDIR)/fluid.$(CAT1EXT) $(SRC_DOCDIR)/blocks.$(CAT6EXT) \
|
||||
|
BIN
documentation/src/Fl_Terminal-24bit-colors.png
Normal file
BIN
documentation/src/Fl_Terminal-24bit-colors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
BIN
documentation/src/Fl_Terminal-3bit-colors.png
Normal file
BIN
documentation/src/Fl_Terminal-3bit-colors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
documentation/src/Fl_Terminal-demo.png
Normal file
BIN
documentation/src/Fl_Terminal-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
BIN
documentation/src/Fl_Terminal-utf8-demo.png
Normal file
BIN
documentation/src/Fl_Terminal-utf8-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
514
documentation/src/Fl_Terminal.dox
Normal file
514
documentation/src/Fl_Terminal.dox
Normal file
@ -0,0 +1,514 @@
|
||||
// vim:syntax=doxygen
|
||||
/**
|
||||
|
||||
\page Fl_Terminal_Tech_Docs Fl_Terminal Technical Documentation
|
||||
|
||||
This chapter covers the vt100/xterm style "escape codes" used by
|
||||
Fl_Terminal for cursor positioning, text colors, and other display
|
||||
screen control features such as full or partial screen clearing,
|
||||
up/down scrolling, character insert/delete, etc.
|
||||
|
||||
\section Fl_Terminal_escape_codes The Escape Codes Fl_Terminal Supports
|
||||
|
||||
These are the escape codes Fl_Terminal actually supports, and is not
|
||||
the 'complete' list that e.g. xterm supports. Most of the important stuff
|
||||
has been implemented, but esoteric features (such as scroll regions) has not.
|
||||
|
||||
Features will be added as the widget matures.
|
||||
|
||||
\code{.unparsed}
|
||||
│ --------------------------------------------------------
|
||||
│ --- The CSI (Control Sequence Introducer, or "ESC[") ---
|
||||
│ --------------------------------------------------------
|
||||
│
|
||||
│ ESC[#@ - (ICH) Insert blank Chars (default=1)
|
||||
│ ESC[#A - (CUU) Cursor Up, no scroll/wrap
|
||||
│ ESC[#B - (CUD) Cursor Down, no scroll/wrap
|
||||
│ ESC[#C - (CUF) Cursor Forward, no wrap
|
||||
│ ESC[#D - (CUB) Cursor Back, no wrap
|
||||
│ ESC[#E - (CNL) Cursor Next Line (crlf) xterm, !gnome
|
||||
│ ESC[#F - (CPL) Cursor Preceding Line: move to sol and up # lines
|
||||
│ ESC[#G - (CHA) Cursor Horizontal Absolute positioning
|
||||
│ │
|
||||
│ ├── ESC[G - move to column 1 (start of line, sol)
|
||||
│ └── ESC[#G - move to column #
|
||||
│
|
||||
│ ESC[#H - (CUP) Cursor Position (#'s are 1 based)
|
||||
│ │
|
||||
│ ├── ESC[H - go to row #1
|
||||
│ ├── ESC[#H - go to (row #) (default=1)
|
||||
│ └── ESC[#;#H - go to (row# ; col#)
|
||||
│
|
||||
│ ESC[#I - (CHT) Cursor Horizontal Tab: tab forward
|
||||
│ │
|
||||
│ └── ESC[#I - tab # times (default 1)
|
||||
│
|
||||
│ ESC[#J - (ED) Erase in Display
|
||||
│ │
|
||||
│ ├── ESC[0J - clear to end of display (default)
|
||||
│ ├── ESC[1J - clear to start of display
|
||||
│ ├── ESC[2J - clear all lines
|
||||
│ └── ESC[3J - clear screen history
|
||||
│
|
||||
│ ESC[#K - (EL) Erase in line
|
||||
│ │
|
||||
│ ├── ESC[0K - clear to end of line (default)
|
||||
│ ├── ESC[1K - clear to start of line
|
||||
│ └── ESC[2K - clear current line
|
||||
│
|
||||
│ ESC[#L - (IL) Insert # Lines (default=1)
|
||||
│ ESC[#M - (DL) Delete # Lines (default=1)
|
||||
│ ESC[#P - (DCH) Delete # Chars (default=1)
|
||||
│ ESC[#S - (SU) Scroll Up # lines (default=1)
|
||||
│ ESC[#T - (SD) Scroll Down # lines (default=1)
|
||||
│ ESC[#X - (ECH) Erase Characters (default=1)
|
||||
│
|
||||
│ ESC[#Z - (CBT) Cursor Backwards Tab
|
||||
│ │
|
||||
│ └── ESC[#Z - backwards tab # times (default=1)
|
||||
│
|
||||
│ ESC[#a - (HPR) move cursor relative [columns] (default=[row,col+1]) (NOT IMPLEMENTED)
|
||||
│ ESC[#b - (REP) repeat prev graphics char # times (NOT IMPLEMENTED)
|
||||
│ ESC[#d - (VPA) Line Position Absolute [row] (NOT IMPLEMENTED)
|
||||
│ ESC[#e - (LPA) Line Position Relative [row] (NOT IMPLEMENTED)
|
||||
│ ESC[#f - (CUP) cursor position (#'s 1 based), same as ESC[H
|
||||
│
|
||||
│ ESC[#g - (TBC)Tabulation Clear
|
||||
│ │
|
||||
│ ├── ESC[0g - Clear tabstop at cursor
|
||||
│ └── ESC[3g - Clear all tabstops
|
||||
│
|
||||
│ ESC[#m - (SGR) Set Graphic Rendition
|
||||
│ │
|
||||
│ │ *** Attribute Enable ***
|
||||
│ │
|
||||
│ ├── ESC[0m - reset: normal attribs/default fg/bg color (VT100)
|
||||
│ ├── ESC[1m - bold (VT100)
|
||||
│ ├── ESC[2m - dim
|
||||
│ ├── ESC[3m - italic
|
||||
│ ├── ESC[4m - underline (VT100)
|
||||
│ ├── ESC[5m - blink (NOT IMPLEMENTED) (VT100)
|
||||
│ ├── ESC[6m - (unused)
|
||||
│ ├── ESC[7m - inverse (VT100)
|
||||
│ ├── ESC[8m - (unused)
|
||||
│ ├── ESC[9m - strikeout
|
||||
│ ├── ESC[21m - doubly underline (Currently this just does single underline)
|
||||
│ │
|
||||
│ │ *** Attribute Disable ***
|
||||
│ │
|
||||
│ ├── ESC[22m - disable bold/dim
|
||||
│ ├── ESC[23m - disable italic
|
||||
│ ├── ESC[24m - disable underline
|
||||
│ ├── ESC[25m - disable blink (NOT IMPLEMENTED)
|
||||
│ ├── ESC[26m - (unused)
|
||||
│ ├── ESC[27m - disable inverse
|
||||
│ ├── ESC[28m - disable hidden
|
||||
│ ├── ESC[29m - disable strikeout
|
||||
│ │
|
||||
│ │ *** Foreground Text "8 Color" ***
|
||||
│ │
|
||||
│ ├── ESC[30m - fg Black
|
||||
│ ├── ESC[31m - fg Red
|
||||
│ ├── ESC[32m - fg Green
|
||||
│ ├── ESC[33m - fg Yellow
|
||||
│ ├── ESC[34m - fg Blue
|
||||
│ ├── ESC[35m - fg Magenta
|
||||
│ ├── ESC[36m - fg Cyan
|
||||
│ ├── ESC[37m - fg White
|
||||
│ ├── ESC[39m - fg default
|
||||
│ │
|
||||
│ │ *** Background Text "8 Color" ***
|
||||
│ │
|
||||
│ ├── ESC[40m - bg Black
|
||||
│ ├── ESC[41m - bg Red
|
||||
│ ├── ESC[42m - bg Green
|
||||
│ ├── ESC[43m - bg Yellow
|
||||
│ ├── ESC[44m - bg Blue
|
||||
│ ├── ESC[45m - bg Magenta
|
||||
│ ├── ESC[46m - bg Cyan
|
||||
│ ├── ESC[47m - bg White
|
||||
│ ├── ESC[49m - bg default
|
||||
│ │
|
||||
│ │ *** Special RGB Color ***
|
||||
│ │
|
||||
│ └── ESC [ 38 ; Red ; Grn ; Blue m - where Red,Grn,Blu are decimal (0-255)
|
||||
│
|
||||
│ ESC[s - save cursor pos (ansi.sys+xterm+gnome, but NOT vt100)
|
||||
│ ESC[u - rest cursor pos (ansi.sys+xterm+gnome, but NOT vt100)
|
||||
│
|
||||
│ ESC[>#q - (DECSCA) Set Cursor style (block/line/blink..) (NOT IMPLEMENTED)
|
||||
│ ESC[#;#r - (DECSTBM) Set scroll Region top;bot (NOT IMPLEMENTED)
|
||||
│ ESC[#..$t - (DECRARA) (NOT IMPLEMENTED)
|
||||
│
|
||||
│ ------------------------
|
||||
│ --- C1 Control Codes ---
|
||||
│ ------------------------
|
||||
│
|
||||
│ <ESC>c - (RIS) Reset term to Initial State
|
||||
│ <ESC>D - (IND) Index: move cursor down a line, scroll if at bottom
|
||||
│ <ESC>E - (NEL) Next Line: basically do a crlf, scroll if at bottom
|
||||
│ <ESC>H - (HTS) Horizontal Tab Set: set a tabstop
|
||||
│ <ESC>M - (RI) Reverse Index (up w/scroll)
|
||||
│
|
||||
│ NOTE: Acronyms in parens are Digital Equipment Corporation's names these VT features.
|
||||
│
|
||||
\endcode
|
||||
|
||||
\section external_escape_codes Useful Terminal Escape Code Documentation
|
||||
|
||||
Useful links for reference:
|
||||
|
||||
- https://vt100.net/docs/vt100-ug/chapter3.html
|
||||
- https://www.xfree86.org/current/ctlseqs.html
|
||||
- https://www.x.org/docs/xterm/ctlseqs.pdf
|
||||
- https://gist.github.com/justinmk/a5102f9a0c1810437885a04a07ef0a91 <-- alphabetic!
|
||||
- https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
|
||||
\section Fl_Terminal_design Fl_Terminal Design Document
|
||||
|
||||
When I started this project, I identified the key concepts needed to
|
||||
implement Fl_Terminal:
|
||||
|
||||
- Draw and manage multiline Unicode text in FLTK
|
||||
- Allow per-character colors and attributes
|
||||
- Efficient screen buffer to handle "scrollback history"
|
||||
- Efficient scrolling with vertical scrollbar for even large screen history
|
||||
- Mouse selection for copy/paste
|
||||
- Escape code management to implement VT100 style / ANSI escape codes.
|
||||
|
||||
A class was created for each character, since characters can be either ASCII
|
||||
or Utf8 encoded byte sequences. This class is called Utf8Char, and handles
|
||||
the character, its fg and bg color, and any attributes like dim, bold, italic, etc.
|
||||
|
||||
For managing the screen, after various experiments, I decided a ring buffer
|
||||
was the best way to manage things, the ring split in two:
|
||||
|
||||
- 'screen history' which is where lines scrolled off the top are saved
|
||||
- 'display screen' displayed to the user at all times, and where the cursor lives
|
||||
|
||||
Scrolling the display, either by scrollbar or by new text causing the display
|
||||
to scroll up one line, would simply change an 'offset' index# of where in the
|
||||
ring buffer the top of the screen is, automatically moving the top line
|
||||
into the history, all without moving memory around.
|
||||
|
||||
In fact the only time screen memory is moved around is during these infrequent
|
||||
operations:
|
||||
|
||||
- during scrolling "down"
|
||||
- character insert/delete operations within a line
|
||||
- changing the display size
|
||||
- changing the history size
|
||||
|
||||
So a class "RingBuffer" is defined to manage the ring, and accessing its various
|
||||
parts, either as the entire entity ring, just the history, or just the display.
|
||||
|
||||
These three concepts, "ring", "history" and "display" are given abbreviated
|
||||
names in the RingBuffer class's API:
|
||||
|
||||
┌─────────────────────────────────────────┬──────────────────────────────┐
|
||||
│ NOTE: Abbreviations "hist" and "disp" │ │
|
||||
├─────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ "history" may be abbreviated as "hist", and "display" as "disp" in │
|
||||
│ both this text and the source code. 4 character names are used so │
|
||||
│ they line up cleanly in the source, e.g. │
|
||||
│ │
|
||||
│ ring_rows() ring_cols() │
|
||||
│ hist_rows() hist_cols() │
|
||||
│ disp_rows() disp_cols() │
|
||||
│ └─┬┘ └─┬┘ └─┬┘ └─┬┘ │
|
||||
│ └────┴──────────┴────┴───────── 4 characters │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
These concepts were able to fit into C++ classes:
|
||||
|
||||
Utf8Char
|
||||
--------
|
||||
Each character on the screen is a "Utf8Char" which can manage
|
||||
the UTF-8 encoding of any character as one or more bytes. Also
|
||||
in that class is a byte for an attribute (underline, bold, etc),
|
||||
and two integers for fg/bg color.
|
||||
|
||||
RingBuffer
|
||||
----------
|
||||
The RingBuffer class keeps track of the buffer itself, a single
|
||||
array of Utf8Chars called "ring_chars" whose width is ring_cols()
|
||||
and whose height is ring_rows().
|
||||
|
||||
The "top" part of the ring is the history, whose width is hist_cols()
|
||||
and whose height is hist_rows(). hist_use_rows() is used to define
|
||||
what part of the history is currently in use.
|
||||
|
||||
The "bottom" part of the ring is the display, whose width is disp_cols()
|
||||
and whose height is disp_rows().
|
||||
|
||||
An index number called "offset" points to where in the ring buffer
|
||||
the top of the ring currently is. This index changes each time the
|
||||
screen is scrolled, and affects both where the top of the display is,
|
||||
and where the top of the history is.
|
||||
|
||||
The memory layout of the Utf8Char character array is:
|
||||
|
||||
ring_chars[]:
|
||||
___________________ _ _
|
||||
| | ʌ
|
||||
| | |
|
||||
| | |
|
||||
| H i s t o r y | | hist_rows
|
||||
| | |
|
||||
| | |
|
||||
|___________________| _v_
|
||||
| | ʌ
|
||||
| | |
|
||||
| D i s p l a y | | disp_rows
|
||||
| | |
|
||||
|___________________| _v_
|
||||
|
||||
|<----------------->|
|
||||
ring_cols
|
||||
hist_cols
|
||||
disp_cols
|
||||
|
||||
So it's basically a single continuous array of Utf8Char instances
|
||||
where any character can generally be accessed by index# using the formula:
|
||||
|
||||
ring_chars[ (row*ring_cols)+col ]
|
||||
|
||||
..where 'row' is the desired row, 'col' is the desired column,
|
||||
and 'ring_cols' is how many columns "wide" the buffer is.
|
||||
|
||||
The "offset" index affects that formula as an extra row offset,
|
||||
and the resulting index is then clamped within the range of the
|
||||
ring buffer using modulus.
|
||||
|
||||
Methods are used to allow direct access to the characters
|
||||
in the buffer that automatically handle the offset and modulus
|
||||
formulas, namely:
|
||||
|
||||
u8c_ring_row(row,col) // access the entire ring by row/col
|
||||
u8c_hist_row(row,col) // access just the history buffer
|
||||
u8c_disp_row(row,col) // access just the display buffer
|
||||
|
||||
A key concept is the use of the simple 'offset' index integer
|
||||
to allow the starting point of the history and display to be
|
||||
moved around to implement 'text scrolling', such as when
|
||||
crlf at the screen bottom causes a 'scroll up'.
|
||||
|
||||
This is simply an "index offset" integer applied to the
|
||||
hist and disp indexes when drawing the display. So after
|
||||
scrolling two lines up, the offset is just increased by 2,
|
||||
redefining where the top of the history and display are, e.g.
|
||||
|
||||
Offset is 0: 2 Offset now 2:
|
||||
┌───────────────────┐ ──┐ ┌───────────────────┐
|
||||
│ │ │ │ D i s p l a y │
|
||||
│ │ └─> ├───────────────────┤
|
||||
│ │ │ │
|
||||
│ H i s t o r y │ │ │
|
||||
│ │ │ H i s t o r y │
|
||||
│ │ 2 │ │
|
||||
├───────────────────┤ ──┐ │ │
|
||||
│ │ │ │ │
|
||||
│ │ └─> ├───────────────────┤
|
||||
│ D i s p l a y │ │ │
|
||||
│ │ │ D i s p l a y │
|
||||
│ │ │ │
|
||||
└───────────────────┘ └───────────────────┘
|
||||
|
||||
This 'offset' trivially implements "text scrolling", avoiding having
|
||||
to physically move memory around. Just the 'offset' changes, the
|
||||
text remains where it is in memory.
|
||||
|
||||
This also makes it appear the top line in the display is 'scrolled up'
|
||||
into the bottom of the scrollback 'history'.
|
||||
|
||||
If the offset exceeds the size of the ring buffer, it simply wraps
|
||||
around back to the beginning of the buffer with a modulo.
|
||||
|
||||
Indexes into the display and history are also modulo their respective
|
||||
rows, e.g.
|
||||
|
||||
act_ring_index = (hist_rows + disp_row + offset - scrollbar_pos) % ring_rows;
|
||||
|
||||
This way indexes for ranges can run beyond the bottom of the ring,
|
||||
and automatically wrap around the ring, e.g.
|
||||
|
||||
┌───────────────────┐
|
||||
┌─> 2 │ │
|
||||
│ 3 │ D i s p l a y │
|
||||
│ 4 │ │
|
||||
│ ├───────────────────┤ <-- offset points here
|
||||
│ │ │
|
||||
disp │ │ │
|
||||
index ┤ │ H i s t o r y │
|
||||
wraps │ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ├───────────────────┤
|
||||
│ 0 │ D i s p l a y │
|
||||
│ 1 └───────────────────┘ <- ring_rows points to end of ring
|
||||
└── 2 : :
|
||||
3 : :
|
||||
disp_row(5) -> 4 :...................:
|
||||
|
||||
The dotted lines show where the display would be if not for the fact
|
||||
it extends beyond the bottom of the ring buffer (due to the current offset),
|
||||
and therefore wraps up to the top of the ring.
|
||||
|
||||
So to find a particular row in the display, in this case a 5 line display
|
||||
whose lines lie between 0 and 4, some simple math calculates the row position
|
||||
into the ring:
|
||||
|
||||
act_ring_index = (histrows // the display exists AFTER the history, so offset the hist_rows
|
||||
+ offset // include the scroll 'offset'
|
||||
+ disp_row // add the desired row relative to the top of the display (0..disp_rows)
|
||||
) % ring_rows; // make sure the resulting index is within the ring buffer (0..ring_rows)
|
||||
|
||||
An additional bit of math makes sure if a negative result occurs, that
|
||||
negative value works relative to the end of the ring, e.g.
|
||||
|
||||
if (act_ring_index < 0) act_ring_index = ring_rows + act_ring_index;
|
||||
|
||||
This guarantees the act_ring_index is within the ring buffer's address space,
|
||||
with all offsets applied.
|
||||
|
||||
The math that implements this can be found in the u8c_xxxx_row() methods,
|
||||
where "xxxx" is one of the concept regions "ring", "hist" or "disp":
|
||||
|
||||
Utf8Char *u8c;
|
||||
u8c = u8c_ring_row(rrow); // address within ring, rrow can be 0..(ring_rows-1)
|
||||
u8c = u8c_hist_row(hrow); // address within hist, hrow can be 0..(hist_rows-1)
|
||||
u8c = u8c_disp_row(drow); // address within disp, drow can be 0..(disp_rows-1)
|
||||
|
||||
The small bit of math is only involved whenever a new row address is needed,
|
||||
so in a display that's 80x25, to walk all the characters in the screen, the
|
||||
math above would only be called 25 times, once for each row, and each column
|
||||
in the row is just a simple integer offset:
|
||||
|
||||
for ( int row=0; row<disp_rows(); row++ ) { // walk rows: disp_rows = 25
|
||||
Utf8Char *u8c = u8c_disp_row(row); // get first char in display 'row'
|
||||
for ( int col=0; col<disp_cols(); col++ ) { // walk cols: disp_cols = 80
|
||||
u8c[col].do_something(); // work with the char at row/col
|
||||
}
|
||||
}
|
||||
|
||||
So to recap, the concepts here are:
|
||||
|
||||
- The ring buffer itself, a linear array that is conceptually
|
||||
split into a 2 dimensional array of rows and columns whose
|
||||
height and width are:
|
||||
|
||||
ring_rows -- how many rows in the entire ring buffer
|
||||
ring_cols -- how many columns in the ring buffer
|
||||
nchars -- total chars in ring, e.g. (ring_rows * ring_cols)
|
||||
|
||||
- The "history" within the ring. For simplicity this is thought of
|
||||
as starting relative to the top of the ring buffer, occupying
|
||||
ring buffer rows:
|
||||
|
||||
0 .. hist_rows()-1
|
||||
|
||||
- The "display", or "disp", within the ring, just after the "history".
|
||||
It occupies the ring buffer rows:
|
||||
|
||||
hist_rows() .. hist_rows()+disp_rows()-1
|
||||
|
||||
..or similarly:
|
||||
|
||||
(hist_rows)..(ring_rows-1)
|
||||
|
||||
The following convenience methods provide access to the
|
||||
start and end indexes within the ring buffer for each entity:
|
||||
|
||||
// Entire ring
|
||||
ring_srow() -- start row index of the ring buffer (always 0)
|
||||
ring_erow() -- end row index of the ring buffer
|
||||
|
||||
// "history" part of ring
|
||||
hist_srow() -- start row index of the screen history
|
||||
hist_erow() -- end row index of the screen history
|
||||
|
||||
// "display" part of ring
|
||||
disp_srow() -- start row index of the display
|
||||
disp_erow() -- end row index of the display
|
||||
|
||||
The values returned by these are as described above.
|
||||
For the hist_xxx() and disp_xxx() methods the 'offset' included into
|
||||
the forumula. (For this reason hist_srow() won't always be zero
|
||||
the way ring_srow() is, due to the 'offset')
|
||||
|
||||
The values returned by these methods can all be passed to the
|
||||
u8c_ring_row() function to access the actual character buffer's contents.
|
||||
|
||||
- An "offset" used to move the "history" and "display" around within
|
||||
the ring buffer to implement the "text scrolling" concept. The offset
|
||||
is applied when new characters are added to the buffer, and during
|
||||
drawing to find where the display actually is within the ring.
|
||||
|
||||
- The "scrollbar", which only is used when redrawing the screen the user sees,
|
||||
and is simply an additional offset to all the above, where a scrollbar
|
||||
value of zero (the scrollbar tab at the bottom) shows the display rows,
|
||||
and as the scrollbar values increase as the user moves the scrollbar
|
||||
tab upwards, +1 per line, this is subtracted from the normal starting
|
||||
index to let the user work their way backwards into the scrollback history.
|
||||
Again, negative numbers wrap around within the ring buffer automatically.
|
||||
|
||||
The ring buffer allows new content to simply be appended to the ring buffer,
|
||||
and the index# for the start of the display and start of scrollback history are
|
||||
simply incremented. So the next time the display is "drawn", it starts at
|
||||
a different position in the ring.
|
||||
|
||||
This makes scrolling content at high speed trivial, without memory moves.
|
||||
It also makes the concept of "scrolling" with the scrollbar simple as well,
|
||||
simply being an extra index offset applied during drawing.
|
||||
|
||||
Mouse Selection
|
||||
---------------
|
||||
|
||||
Dragging the mouse across the screen should highlight the text, allowing the user
|
||||
to extend the selection either beyond or before the point started. Extending the
|
||||
drag to the top of the screen should automatically 'scroll up' to select more
|
||||
lines in the scrollback history, or below the bottom to do the opposite.
|
||||
|
||||
The mouse selection is implemented as a class to keep track of the start/end
|
||||
row/col positions of the selection, and other details such as a flag indicating
|
||||
if a selection has been made, what color the fg/bg text should appear when
|
||||
text is selected, and methods that allow setting and extending the selection,
|
||||
clearing the selection, and "scrolling" the selection, to ensure the row/col
|
||||
indexes adjust correctly to track when the screen or scrollbar is scrolled.
|
||||
|
||||
|
||||
Redraw Timer
|
||||
------------
|
||||
|
||||
Knowing when to redraw is tricky with a terminal, because sometimes high volumes
|
||||
of input will come in asynchronously, so in that case we need to determine when
|
||||
to redraw the screen to show the new content; too quickly will cause the screen
|
||||
to spend more time redrawing itself, preventing new input from being added. Too
|
||||
slowly, the user won't see new information appear in a timely manner.
|
||||
|
||||
To solve this, a rate timer is used to prevent too many redraws:
|
||||
|
||||
- When new data comes in, a 1/10 sec timer is started and a modify flag is set.
|
||||
|
||||
- redraw() is NOT called yet, allowing more data to continue to arrive quickly
|
||||
|
||||
- When the 1/10th second timer fires, the callback checks the modify flag:
|
||||
|
||||
- if set, calls redraw(), resets the modify to 0, and calls
|
||||
Fl::repeat_timeout() to repeat the callback in another 1/10th sec.
|
||||
|
||||
- if clear, no new data came in, so DISABLE the timer, done.
|
||||
|
||||
In this way, redraws don't happen more than 10x per second, and redraw() is called
|
||||
only when there's new content to see.
|
||||
|
||||
The redraw rate can be set by the user application using the Fl_Terminal::redraw_rate(),
|
||||
0.10 being the default.
|
||||
|
||||
Some terminal operations necessarily call redraw() directly, such as interactive mouse
|
||||
selection, or during user scrolling the terminal's scrollbar, where it's important there's
|
||||
no delay in what the user sees while interacting directly with the widget.
|
||||
|
||||
*/
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Simple Example app using Fl_Simple_Terminal. - erco 10/12/2017
|
||||
// Simple Example app using Fl_Terminal. - erco 10/12/2017
|
||||
//
|
||||
// Copyright 2017 Greg Ercolano.
|
||||
// Copyright 1998-2016 by Bill Spitzak and others.
|
||||
@ -15,17 +15,17 @@
|
||||
// https://www.fltk.org/bugs.php
|
||||
//
|
||||
|
||||
#include <time.h> //START
|
||||
#include <time.h>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
#define TERMINAL_HEIGHT 120
|
||||
|
||||
// Globals
|
||||
Fl_Double_Window *G_win = 0;
|
||||
Fl_Box *G_box = 0;
|
||||
Fl_Simple_Terminal *G_tty = 0;
|
||||
Fl_Terminal *G_tty = 0;
|
||||
|
||||
// Append a date/time message to the terminal every 2 seconds
|
||||
void tick_cb(void *data) {
|
||||
@ -43,7 +43,7 @@ int main(int argc, char **argv) {
|
||||
"Your app's debugging output in tty below");
|
||||
|
||||
// Add simple terminal to bottom of app window for scrolling history of status messages.
|
||||
G_tty = new Fl_Simple_Terminal(0,200,G_win->w(),TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Terminal(0,200,G_win->w(),TERMINAL_HEIGHT);
|
||||
G_tty->ansi(true); // enable use of "\033[32m"
|
||||
|
||||
G_win->end();
|
||||
@ -51,4 +51,4 @@ int main(int argc, char **argv) {
|
||||
G_win->show();
|
||||
Fl::add_timeout(0.5, tick_cb);
|
||||
return Fl::run();
|
||||
} //END
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ set (CPPFILES
|
||||
Fl_Table.cxx
|
||||
Fl_Table_Row.cxx
|
||||
Fl_Tabs.cxx
|
||||
Fl_Terminal.cxx
|
||||
Fl_Text_Buffer.cxx
|
||||
Fl_Text_Display.cxx
|
||||
Fl_Text_Editor.cxx
|
||||
|
3508
src/Fl_Terminal.cxx
Normal file
3508
src/Fl_Terminal.cxx
Normal file
File diff suppressed because it is too large
Load Diff
@ -94,6 +94,7 @@ CPPFILES = \
|
||||
Fl_Table.cxx \
|
||||
Fl_Table_Row.cxx \
|
||||
Fl_Tabs.cxx \
|
||||
Fl_Terminal.cxx \
|
||||
Fl_Text_Buffer.cxx \
|
||||
Fl_Text_Display.cxx \
|
||||
Fl_Text_Editor.cxx \
|
||||
|
586
src/README-Fl_Terminal.txt
Normal file
586
src/README-Fl_Terminal.txt
Normal file
@ -0,0 +1,586 @@
|
||||
// vim: autoindent tabstop=8 shiftwidth=4 expandtab softtabstop=4
|
||||
|
||||
Fl_Terminal Design Document
|
||||
===========================
|
||||
|
||||
When I started this project, I identified the key concepts needed to
|
||||
implement Fl_Terminal:
|
||||
|
||||
- Draw and manage multiline Unicode text in FLTK effectively,
|
||||
allowing per-character colors and attributes like underline,
|
||||
strikeout, background, etc.
|
||||
|
||||
- An efficient screen buffer to handle the "scrollback history"
|
||||
and "screen display" concepts; the "history" being a scrollback
|
||||
history of text that scrolls up and off screen from the "display",
|
||||
and the "display" being where the action is: the cursor can be
|
||||
moved around and text scrolled up or down.
|
||||
|
||||
- How the vertical scrollbar should provide the user with a way to
|
||||
scroll back into the scrollback history to allow the user to scroll back
|
||||
to view the "scrollback history", without stopping the "screen display"
|
||||
from operating
|
||||
|
||||
- How to manage mouse selection for copy/paste
|
||||
|
||||
- Escape code management to implement VT100 style / ANSI escape codes.
|
||||
|
||||
|
||||
┌─────────────────────────────────────────┬──────────────────────────────┐
|
||||
│ NOTE: Abbreviations "hist" and "disp" │ │
|
||||
├─────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ "history" may be abbreviated as "hist", and "display" as "disp" in │
|
||||
│ both this text and the source code. 4 character names are used so │
|
||||
│ they line up cleanly in the source, e.g. │
|
||||
│ │
|
||||
│ ring_cols = 0; ring_rows = 0; │
|
||||
│ hist_cols = 0; ring_cols = 0; │
|
||||
│ disp_cols = 0; ring_cols = 0; │
|
||||
│ └─┬┘ └─┬┘ │
|
||||
│ └────┴─── 4 characters │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
So the of these concepts were able to fit into C++ class concepts well.
|
||||
Those classes being:
|
||||
|
||||
Utf8Char
|
||||
========
|
||||
Each character on the screen is a "Utf8Char" which can manage
|
||||
the utf8 encoding of any character as one or more bytes. Also
|
||||
in that class is a byte for an attribute (underline, bold, etc),
|
||||
and two integers for fg/bg color.
|
||||
|
||||
RingBuffer
|
||||
==========
|
||||
The RingBuffer class keeps track of the buffer itself, a single
|
||||
array of Utf8Chars called "ring_chars", and some index numbers
|
||||
to keep track of how many rows are in the screen's history and
|
||||
display, named "hist_rows" and "disp_rows".
|
||||
|
||||
The memory layout of the Utf8Char array is:
|
||||
|
||||
___________________ _ _
|
||||
| | ʌ
|
||||
| | |
|
||||
| | |
|
||||
| H i s t o r y | | hist_rows
|
||||
| | |
|
||||
| | |
|
||||
|___________________| _v_
|
||||
| | ʌ
|
||||
| | |
|
||||
| D i s p l a y | | disp_rows
|
||||
| | |
|
||||
|___________________| _v_
|
||||
|
||||
|<----------------->|
|
||||
ring_cols
|
||||
|
||||
So it's basically a single continguous array of Utf8Char instances
|
||||
where any character can be accessed by index# using the formula:
|
||||
|
||||
ring_chars[ (row*ring_cols)+col ]
|
||||
|
||||
..where 'row' is the desired row, 'col' is the desired column,
|
||||
and 'ring_cols' is how many columns "wide" the buffer is.
|
||||
|
||||
Methods are used to give access the characters in the buffer.
|
||||
|
||||
A key concept is to allow the starting point of the history and
|
||||
display to be moved around to implement 'text scrolling', such
|
||||
as when crlf at the screen bottom causes a 'scroll up'.
|
||||
|
||||
This is simply an "index offset" integer applied to the
|
||||
hist and disp indexes when drawing the display, e.g.
|
||||
|
||||
Offset is 0: 2 Offset now 2:
|
||||
┌───────────────────┐ ──┐ ┌───────────────────┐
|
||||
│ │ │ │ D i s p l a y │
|
||||
│ │ └─> ├───────────────────┤
|
||||
│ │ │ │
|
||||
│ H i s t o r y │ │ │
|
||||
│ │ │ H i s t o r y │
|
||||
│ │ 2 │ │
|
||||
├───────────────────┤ ──┐ │ │
|
||||
│ │ │ │ │
|
||||
│ │ └─> ├───────────────────┤
|
||||
│ D i s p l a y │ │ │
|
||||
│ │ │ D i s p l a y │
|
||||
│ │ │ │
|
||||
└───────────────────┘ └───────────────────┘
|
||||
|
||||
Offset is 0: 4 Offset now 4:
|
||||
┌───────────────────┐ ──┐ ┌───────────────────┐
|
||||
│ │ │ │ │
|
||||
│ │ │ │ D i s p l a y │
|
||||
│ │ │ │ │
|
||||
│ H i s t o r y │ └─> ├───────────────────┤
|
||||
│ │ │ │
|
||||
│ │ 4 │ │
|
||||
├───────────────────┤ ──┐ │ H i s t o r y │
|
||||
│ │ │ │ │
|
||||
│ │ │ │ │
|
||||
│ D i s p l a y │ │ │ │
|
||||
│ │ └─> ├───────────────────┤
|
||||
│ │ │ D i s p l a y │
|
||||
└───────────────────┘ └───────────────────┘
|
||||
|
||||
The effect of applying an offset trivially implements "text scrolling",
|
||||
so that no screen memory has to physically moved around, simply changing
|
||||
the single integer "offset" is enough. The text remains where it was, and
|
||||
the offset is simply incremented to scroll up. This also automatically
|
||||
makes it appear the top line in the display is 'scrolled up' into the
|
||||
last line of the scrollback history.
|
||||
|
||||
If the offset exceeds the size of the ring buffer, it is simply wrapped
|
||||
back to the beginning of the buffer with a modulo: offset =% ring_rows;
|
||||
|
||||
Indexes into the display and history are also modulo their respective
|
||||
rows, e.g.
|
||||
|
||||
act_ring_index = (hist_rows + disp_row + offset - scrollbar_pos) % ring_rows;
|
||||
|
||||
This way indexes for ranges can run beyond the bottom of the ring,
|
||||
and automatically wrap around the ring, e.g.
|
||||
|
||||
Offset now 4:
|
||||
┌───────────────────┐
|
||||
2 │ │
|
||||
3 │ D i s p l a y │
|
||||
4 │ │ <- act_disp_row(4)
|
||||
├───────────────────┤
|
||||
│ │
|
||||
│ │
|
||||
│ H i s t o r y │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
├───────────────────┤
|
||||
0 │ D i s p l a y │
|
||||
1 └───────────────────┘ <- ring_rows
|
||||
2 : :
|
||||
3 : :
|
||||
disp_row(5) -> 4 :...................:
|
||||
|
||||
Here the "disp_row" is the desired offset into the display, but we
|
||||
need the actual index into the ring from the top, since that's the
|
||||
physical array.
|
||||
|
||||
So some simple math calculates the row position based on the "offset",
|
||||
and the "hist" vs "disp" concepts:
|
||||
|
||||
act_ring_index = (histrows // the display exists AFTER the history, so offset the hist_rows
|
||||
+ offset // include the scroll 'offset'
|
||||
+ disp_row // add the desired row relative to the top of the display (0..disp_rows)
|
||||
) % ring_rows; // make sure the resulting index is within the ring buffer (0..ring_rows)
|
||||
|
||||
An additional bit of math makes sure if a negative result occurs, that
|
||||
negative value works relative to the end of the ring, e.g.
|
||||
|
||||
if (act_ring_index < 0) act_ring_index = ring_rows + act_ring_index;
|
||||
|
||||
This guaratnees the act_ring_index is within the ring buffer's address space,
|
||||
with all offsets applied.
|
||||
|
||||
The math that implements this can be found in the u8c_xxxx_row() methods,
|
||||
where "xxxx" is one of the concept regions "ring", "hist" or "disp":
|
||||
|
||||
Utf8Char *u8c;
|
||||
u8c = u8c_ring_row(rrow); // address within ring, rrow can be 0..(ring_rows-1)
|
||||
u8c = u8c_hist_row(hrow); // address within hist, hrow can be 0..(hist_rows-1)
|
||||
u8c = u8c_disp_row(drow); // address within disp, drow can be 0..(disp_rows-1)
|
||||
|
||||
The small bit of math is only involved whenever a new row address is needed,
|
||||
so in a display that's 80x25, to walk all the characters in the screen, the
|
||||
math above would only be called 25 times, once for each row, e.g.
|
||||
|
||||
for ( int row=0; row<disp_rows(); row++ ) { // walk rows: disp_rows = 25
|
||||
Utf8Char *u8c = u8c_disp_row(row); // get first char in display 'row'
|
||||
for ( int col=0; col<disp_cols(); col++ ) { // walk cols: disp_cols = 80
|
||||
u8c[col].do_something(); // work with the character at row/col
|
||||
}
|
||||
}
|
||||
|
||||
So to recap, the concepts here are:
|
||||
|
||||
- The ring buffer itself, a linear array that is conceptually
|
||||
split into a 2 dimensional array of rows and columns whose
|
||||
height and width are:
|
||||
|
||||
ring_rows -- how many rows in the entire ring buffer
|
||||
ring_cols -- how many columns in the ring buffer
|
||||
nchars -- total chars in ring, e.g. (ring_rows * ring_cols)
|
||||
|
||||
- The "history" within the ring. For simplicity this is thought of
|
||||
as starting relative to the top of the ring buffer, occupying
|
||||
ring buffer rows:
|
||||
|
||||
0..(hist_rows-1)
|
||||
|
||||
- The "display", or "disp", within the ring, just after the "history".
|
||||
It occupies the ring buffer rows:
|
||||
|
||||
(hist_rows)..(hist_rows+disp_rows-1)
|
||||
|
||||
..or similarly:
|
||||
|
||||
(hist_rows)..(ring_rows-1)
|
||||
|
||||
- An "offset" used to move the "history" and "display" around within
|
||||
the ring buffer to implement the "text scrolling" concept. The offset
|
||||
is applied when new characters are added to the buffer, and during
|
||||
drawing to find where the display actually is within the ring.
|
||||
|
||||
- A "scrollbar", which only is used when redrawing the screen the user sees,
|
||||
and is simply an additional offset to all the above, where a scrollback
|
||||
value of zero (the scrollbar tab at the bottom) shows the display rows,
|
||||
and the values increase as the user moves the scrolltab upwards, 1 per line,
|
||||
which is subtracted from the normal starting index to let the user work their
|
||||
way backwards into the scrollback history.
|
||||
|
||||
The ring buffer allows new content to simply be appended to the ring buffer,
|
||||
and the index# for the start of the display and start of scrollback history are
|
||||
simply incremented. So the next time the display is "drawn", it starts at
|
||||
a different position in the ring.
|
||||
|
||||
This makes scrolling content at high speed trivial, without memory moves.
|
||||
It also makes the concept of "scrolling" with the scrollbar simple as well,
|
||||
simply being an extra index offset applied during drawing.
|
||||
|
||||
If the display is enlarged vertically, that's easy too; the display
|
||||
area is simply defined as being more rows, the history as less rows,
|
||||
the history use decreased (since what was in the history before is now
|
||||
being moved into the display), and all the math adjusts accordingly.
|
||||
|
||||
Mouse Selection
|
||||
===============
|
||||
|
||||
Dragging the mouse across the screen should highlight the text, allowing the user
|
||||
to extend the selection either beyond or before the point started. Extending the
|
||||
drag to the top of the screen should automatically 'scroll up' to select more
|
||||
lines in the scrollback history, or below the bottom to do the opposite.
|
||||
|
||||
The mouse selection is implemented as a class to keep track of the start/end
|
||||
row/col positions of the selection, and other details such as a flag indicating
|
||||
if a selection has been made, what color the fg/bg text should appear when
|
||||
text is selected, and methods that allow setting and extending the selection,
|
||||
clearing the selection, and "scrolling" the selection, to ensure the row/col
|
||||
indexes adjust correctly to track when the screen or scrollbar is scrolled.
|
||||
|
||||
|
||||
Redraw Timer
|
||||
============
|
||||
|
||||
Knowing when to redraw is tricky with a terminal, because sometimes high volumes
|
||||
of input will come in asynchronously, so in that case we need to determine when
|
||||
to redraw the screen to show the new content; too quickly will cause the screen
|
||||
to spend more time redrawing itself, preventing new input from being added. Too
|
||||
slowly, the user won't see new information appear in a timely manner.
|
||||
|
||||
To solve this, a rate timer is used to prevent too many redraws:
|
||||
|
||||
- When new data comes in, a 1/10 sec timer is started and a modify flag is set.
|
||||
|
||||
redraw() is NOT called at this time, allowing new data to continue to arrive
|
||||
quickly. Once the modify flag is set, nothing changes from there.
|
||||
|
||||
- When the 1/10th second timer fires, the callback checks the modify flag:
|
||||
|
||||
- if set, calls redraw(), resets the modify to 0, and calls
|
||||
Fl::repeat_timeout() to repeat the callback in another 1/10th sec.
|
||||
|
||||
- if clear, no new data came in, so DISABLE the timer, done.
|
||||
|
||||
In this way, redraws don't happen more than 10x per second, and redraw() is called
|
||||
only when there's new content to see.
|
||||
|
||||
The redraw rate can be set by the user application using the Fl_Terminal::redraw_rate(),
|
||||
0.10 being the default.
|
||||
|
||||
Some terminal operations necessarily call redraw() directly, such as interactive mouse
|
||||
selection, or during user scrolling the terminal's scrollbar, where it's important there's
|
||||
no delay in what the user sees while interacting directly with the widget.
|
||||
|
||||
|
||||
|
||||
|
||||
OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
|
||||
OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
|
||||
OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
|
||||
OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD OLD
|
||||
|
||||
|
||||
|
||||
RING BUFFER DESCRIPTION
|
||||
=======================
|
||||
|
||||
The history and display are defined by row indexes into this buffer
|
||||
which are adjusted whenever the text display is 'scrolled' (e.g. by crlfs)
|
||||
|
||||
The scrollbar is a secondary offset on top of that applied during drawing.
|
||||
the display.
|
||||
|
||||
Here's what the variables managing the split ring buffer look like:
|
||||
|
||||
|
||||
|
||||
RING BUFFER
|
||||
─ ring_chars[] ─┬─>┌───────────────┐
|
||||
ʌ [hist_srow] ──┘ │ │
|
||||
┊ │ │
|
||||
┊ │ H i s t o r y ┊
|
||||
hist_rows_┊ │ │
|
||||
┊ │ │
|
||||
┊ │ │
|
||||
┊ │ │
|
||||
v [hist_erow] ───>│ │
|
||||
─ [disp_srow] ───>├───────────────┤
|
||||
ʌ │ │
|
||||
┊ │ │
|
||||
disp_rows_┊ │ D i s p l a y │
|
||||
┊ │ │
|
||||
┊ │ │
|
||||
v [ring_erow] ───>│ +│<── ring_bot_
|
||||
─ └───────────────┘ (last valid ptr address in ring)
|
||||
|
||||
│<──────┬──────>│
|
||||
ring_cols
|
||||
hist_cols
|
||||
disp_cols
|
||||
|
||||
The concept here is the single ring buffer is split into two parts that can differ
|
||||
in height (rows) but not in width (cols). For instance, typically the history is
|
||||
many times larger than the display; a typical old school display might be 80x25,
|
||||
but the history might be 2000 lines.
|
||||
|
||||
ring_row() handles the fact that 'row' might run off the end of the buffer,
|
||||
depending on where hist_srow starts. For instance, if the display has scrolled
|
||||
a few lines, the ring buffer arrangement might look like:
|
||||
|
||||
RING BUFFER
|
||||
ring_chars[] ───>┌───────────────┐
|
||||
│ D i s p l a y │
|
||||
[disp_erow] ───>│ │
|
||||
├───────────────┤
|
||||
[hist_srow] ───>│ │
|
||||
│ │
|
||||
│ H i s t o r y │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
[hist_erow] ───>│ │
|
||||
├───────────────┤
|
||||
[disp_srow] ───>│ │
|
||||
│ D i s p l a y │
|
||||
│ │
|
||||
[ring_erow] ───>│ +│<── ring_bot_
|
||||
└───────────────┘ (last valid ptr address in ring)
|
||||
|
||||
|
||||
Note how the display 'wraps around', straddling the end of the ring buffer.
|
||||
So trivially walking ring_chars[] from 'disp_srow' for 'disp_rows' would run
|
||||
off the end of memory for the ring buffer. Example:
|
||||
|
||||
// BAD!
|
||||
for ( int row=disp_srow; row<disp_rows; row++ ) {
|
||||
for ( int col=0; col<disp_cols; col++ ) {
|
||||
ring_chars[row*disp_cols+col]->do_something(); // BAD! can run off end of array
|
||||
}
|
||||
}
|
||||
|
||||
The function u8c_row() can access the Utf8Char* of each row more safely,
|
||||
ensuring that even if the 'row' index runs off the end of the array,
|
||||
u8c_row() handles wrapping it for you. So the safe way to walk the chars
|
||||
of the display can be done this way:
|
||||
|
||||
// GOOD!
|
||||
for ( int row=disp_srow; row<disp_rows; row++ ) {
|
||||
Utf8Char *u8c = u8c_row(row); // safe: returns utf8 char for start of each row
|
||||
for ( int col=0; col<disp_cols; col++ ) { // walk the columns safely
|
||||
(u8c++)->do_something(); // get/set the utf8 char
|
||||
}
|
||||
}
|
||||
|
||||
Walking the history would be the same, just replace disp_xxxx with hist_xxxx.
|
||||
|
||||
One can also use ring_row_normalize() to return an index# that can be directly
|
||||
used with ring_chars[], the value kept in range of the buffer.
|
||||
|
||||
|
||||
RING BUFFER "SCROLLING"
|
||||
=======================
|
||||
A ring buffer is used to greatly simplify the act of 'scrolling', which happens a lot
|
||||
when large amounts of data come in, each CRLF triggering a "scroll" that moves the top
|
||||
line up into the history buffer. The history buffer can be quite large (1000's of lines),
|
||||
so it would suck if, on each line scroll, thousands of rows of Utf8Chars had to be
|
||||
physically moved in memory.
|
||||
|
||||
Much easier to just adjust the srow/erow pointers, which simply affect how drawing
|
||||
is done, and where the display area is. This trivially handles scrolling by just
|
||||
adjusting some integers by 1.
|
||||
|
||||
|
||||
-- -- HOW SCROLLING UP ONE LINE IS DONE -- --
|
||||
|
||||
|
||||
ring_chars[] ─┬─>┌───────────────┐ ─┐ ring_chars[] ──>┌─────────────────┐
|
||||
[hist_srow] ──┘ │ │ │ │x x x x x x x x x│ <-- blanks
|
||||
│ │ └─> [hist_srow] ──>├─────────────────┤
|
||||
│ H i s t │ │ │
|
||||
│ │ │ │
|
||||
│ │ │ H i s t │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
[hist_erow] ───>│ │ │ │
|
||||
[disp_srow] ───>├Line 1─────────┤ ─┐ [hist_erow] ──>│Line 1 │
|
||||
│Line 2 │ └─> [disp_srow] ──>├Line 2───────────┤
|
||||
│Line 3 │ │Line 3 │
|
||||
│ │ │ │
|
||||
│ D i s p │ │ D i s p │
|
||||
│ │ │ │
|
||||
[disp_erow][ring_erow] ───>│Line 24 +│ [ring_erow] ──>│Line 24 +│
|
||||
└───────────────┘ └─────────────────┘
|
||||
|
||||
In the above, Line 1 has effectively "moved" into history because the disp_s/erow
|
||||
and hist_s/erow variables have just been incremented.
|
||||
|
||||
During resize_display(), we need to preserve the display and history as much as possible
|
||||
when the ring buffer is enlarged/shrank; the hist_rows size should be maintained, and only
|
||||
display section changes size based on the FLTK window size.
|
||||
|
||||
|
||||
|
||||
===================== OLD ====================== OLD ====================== OLD ======================
|
||||
|
||||
Conventions used for the internals
|
||||
==================================
|
||||
This is a large widget, and these are some breadcrumbs for anyone
|
||||
working on the internals of this class.
|
||||
|
||||
> There is one utf8 char buffer, buff_chars[], the top part is the 'history buffer'
|
||||
(which the user can scroll back to see), and the 'display buffer' which is the
|
||||
'active display'.
|
||||
> glob or global - refers to global buffer buff_chars[]
|
||||
> disp or display - refers to display buffer disp_chars[]
|
||||
> Abbreviations glob/disp/buff/hist used because 4 chars line up nicely
|
||||
> row/col variable names use a 'g' or 'd' prefix to convey 'g'lobal or 'd'isplay.
|
||||
> The 'Cursor' class uses row/col for the display (disp_chars[]) because the
|
||||
cursor is only ever inside the display.
|
||||
> The 'Selection' class uses row/col for the global buffer (buff_chars[])
|
||||
because it can be in the 'history' or the 'display'
|
||||
> These concepts talk about the same thing:
|
||||
> global buffer == buff_chars[] == "history buffer" == hist == grow/gcol
|
||||
> display == disp_chars[] == "active display" == drow/dcol
|
||||
> There is no hist_chars[] because it's just the top half of buff_chars[]
|
||||
> There is no hist_height_ because it's the same as hist_max_
|
||||
> There is no hist_width_ because it's the same as buff_width_.
|
||||
|
||||
|
||||
Fl_Terminal's Class Hierarchy
|
||||
=============================
|
||||
|
||||
class Fl_Terminal -- Derived from Fl_Group (to parent scrollbars, popup menus, etc)
|
||||
We mainly use the group's background to draw over in draw().
|
||||
Within the terminal classes are the following private/protected classes
|
||||
that help with bookkeeping and operation of the terminal class:
|
||||
|
||||
class Margin -- Handles the margins around the terminal drawing area
|
||||
class CharStyle -- The styling for the characters: single byte color + attribute (bold/inverse/etc)
|
||||
class Cursor -- The attributes of the cursor -- position, color, etc, and some simple movement logic
|
||||
class Utf8Char -- Visible screen buffer is an array of these, one per character
|
||||
class RingBuffer -- The ring buffer of Utf8Char's, with the "history" and "display" concept.
|
||||
class EscapeSeq -- A class to handle parsing Esc sequences, and keeping state info between chars
|
||||
Single chars go in, and when a complete esc sequence is parsed, the caller
|
||||
can find out all the integer values and command code easily to figure out
|
||||
what op to do.
|
||||
|
||||
OVERALL DESIGN:
|
||||
To handle unicode, the terminal's visible display area is a linear array of pointers to
|
||||
instances of the 'Utf8Char' class, one instance per character. The arrangement of the array
|
||||
is much like the IBM PC's video memory, but instead of Char/Attrib byte pairs, the Utf8Char
|
||||
class handles the more complex per-character data and colors/attributes.
|
||||
|
||||
The cursor x,y value can be quickly converted to an index into this buffer.
|
||||
Strings are printed into the buffer, again, similar to the IBM PC video memory;
|
||||
one character at a time into the Utf8Char class instances.
|
||||
|
||||
When the screen redraws, it just walks this array, and calls fl_draw() to draw
|
||||
the text, one utf8 char at a time, with the colors/fonts/attributes from the Utf8Char class.
|
||||
|
||||
As characters are added, Esc sequences are intercepted and parsed into the EscapeSeq class,
|
||||
which has a single instance for the terminal.
|
||||
|
||||
For the scrollback history, as lines scrolls off the top of the active display area,
|
||||
the Utf8Char's are copied to the history buffer, and the active display's top line
|
||||
is simply rotated to the bottom line and cleared, allowing memory reuse of the Utf8Char's,
|
||||
to prevent memory churn for the display. The goal is to allow high volume output to the
|
||||
terminal with a minimum affect on realloc'ing memory.
|
||||
|
||||
OPTIMIZATIONS
|
||||
Where possible, caching is used to prevent repeated calls to cpu expensive operations,
|
||||
such as anything to do with calculating unicode character width/height/etc.
|
||||
|
||||
RingBuffer
|
||||
The ring buffer is split in two; the top part is the history, the bottom part is
|
||||
the "display area", where new text comes in, where the cursor can be positioned,
|
||||
and concepts like "scroll up" and "scroll down" all happen. The "history" is simply
|
||||
a linear buffer where lines pushed up from the display are moved into.
|
||||
|
||||
Methods let one access the ring with index#s:
|
||||
|
||||
- The entire ring buffer can be accessed with:
|
||||
|
||||
for (int i=0; i<ring.ring_rows(); i++) {
|
||||
Utf8Char *u8c_row = ring.u8c_ring_row(i);
|
||||
for (int col=0; i<ring.ring_cols(); i++) {
|
||||
u8c_row[col].xxx(); // access each Utf8Char at the row/col
|
||||
}
|
||||
}
|
||||
|
||||
Row#s can be given that are larger than the ring; these are automatically
|
||||
wrapped around to the top. The ring, "history" and "display" can each be
|
||||
accessed separately with index#s relative to their position
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
Moved this down to the bottom of the file for now -- not sure where to put this,
|
||||
but it's useful if one wants to reuse the EscapeSeq class somewhere else. -erco Dec 2022
|
||||
|
||||
Typical use pattern of EscapeSeq class.
|
||||
This is unverified code, but should give the general gist;
|
||||
|
||||
while ( *s ) { // walk text that may contain ESC sequences
|
||||
if ( *s == 0x1b ) {
|
||||
escseq.parse(*s++); // start parsing ESC seq (does a reset())
|
||||
continue;
|
||||
} else if ( escseq.parse_in_progress() ) { // continuing to parse an ESC seq?
|
||||
switch (escseq.parse(*s++)) { // parse char, advance s..
|
||||
case fail: escseq.reset(); continue; // failed? reset, continue..
|
||||
case success: continue; // keep parsing..
|
||||
case completed: // parsed complete esc sequence?
|
||||
break;
|
||||
}
|
||||
// Handle parsed esc sequence here..
|
||||
switch ( escseq.esc_mode() ) {
|
||||
case 'm': // ESC[...m?
|
||||
for ( int i=0; i<escseq.total_vals(); i++ ) {
|
||||
int val = escseq.val(i);
|
||||
..handle values here..
|
||||
}
|
||||
break;
|
||||
case 'J': // ESC[#J?
|
||||
..handle..
|
||||
break;
|
||||
}
|
||||
escseq.reset(); // done handling escseq, reset()
|
||||
continue;
|
||||
} else {
|
||||
..handle non-escape chars here..
|
||||
}
|
||||
++s; // advance thru string
|
||||
}
|
||||
|
||||
----------------------------------------------------------------------------------------
|
||||
|
@ -3878,6 +3878,28 @@ Fl_Tabs.o: ../FL/fl_utf8.h
|
||||
Fl_Tabs.o: ../FL/Fl_Widget.H
|
||||
Fl_Tabs.o: ../FL/Fl_Window.H
|
||||
Fl_Tabs.o: ../FL/platform_types.h
|
||||
Fl_Terminal.o: ../FL/Enumerations.H
|
||||
Fl_Terminal.o: ../FL/Fl.H
|
||||
Fl_Terminal.o: ../FL/fl_attr.h
|
||||
Fl_Terminal.o: ../FL/Fl_Bitmap.H
|
||||
Fl_Terminal.o: ../FL/Fl_Cairo.H
|
||||
Fl_Terminal.o: ../FL/fl_casts.H
|
||||
Fl_Terminal.o: ../FL/fl_config.h
|
||||
Fl_Terminal.o: ../FL/fl_draw.H
|
||||
Fl_Terminal.o: ../FL/Fl_Export.H
|
||||
Fl_Terminal.o: ../FL/Fl_Group.H
|
||||
Fl_Terminal.o: ../FL/Fl_Image.H
|
||||
Fl_Terminal.o: ../FL/Fl_Rect.H
|
||||
Fl_Terminal.o: ../FL/Fl_Scrollbar.H
|
||||
Fl_Terminal.o: ../FL/Fl_Slider.H
|
||||
Fl_Terminal.o: ../FL/fl_string_functions.h
|
||||
Fl_Terminal.o: ../FL/Fl_Terminal.H
|
||||
Fl_Terminal.o: ../FL/fl_types.h
|
||||
Fl_Terminal.o: ../FL/fl_utf8.h
|
||||
Fl_Terminal.o: ../FL/Fl_Valuator.H
|
||||
Fl_Terminal.o: ../FL/Fl_Widget.H
|
||||
Fl_Terminal.o: ../FL/Fl_Window.H
|
||||
Fl_Terminal.o: ../FL/platform_types.h
|
||||
Fl_Text_Buffer.o: ../config.h
|
||||
Fl_Text_Buffer.o: ../FL/Enumerations.H
|
||||
Fl_Text_Buffer.o: ../FL/Fl.H
|
||||
|
3
test/.gitignore
vendored
3
test/.gitignore
vendored
@ -103,6 +103,7 @@ sudoku
|
||||
symbols
|
||||
table
|
||||
tabs
|
||||
terminal
|
||||
threads
|
||||
tile
|
||||
tiled_image
|
||||
@ -141,6 +142,8 @@ resize.cxx
|
||||
resize.h
|
||||
tabs.cxx
|
||||
tabs.h
|
||||
terminal.cxx
|
||||
terminal.h
|
||||
tree.cxx
|
||||
tree.h
|
||||
valuators.cxx
|
||||
|
@ -157,6 +157,7 @@ CREATE_EXAMPLE (sudoku "sudoku.cxx;sudoku.plist;sudoku.icns;sudoku.rc" "fltk_ima
|
||||
CREATE_EXAMPLE (symbols symbols.cxx fltk)
|
||||
CREATE_EXAMPLE (tabs tabs.fl fltk)
|
||||
CREATE_EXAMPLE (table table.cxx fltk)
|
||||
CREATE_EXAMPLE (terminal terminal.fl fltk)
|
||||
CREATE_EXAMPLE (threads threads.cxx fltk)
|
||||
CREATE_EXAMPLE (tile tile.cxx fltk)
|
||||
CREATE_EXAMPLE (tiled_image tiled_image.cxx fltk)
|
||||
@ -185,7 +186,7 @@ SET (UNITTEST_SRCS
|
||||
unittest_viewport.cxx
|
||||
unittest_scrollbarsize.cxx
|
||||
unittest_schemes.cxx
|
||||
unittest_simple_terminal.cxx
|
||||
unittest_terminal.cxx
|
||||
)
|
||||
CREATE_EXAMPLE (unittests "${UNITTEST_SRCS}" "${GLDEMO_LIBS}")
|
||||
|
||||
|
@ -30,7 +30,7 @@ CPPUNITTEST = \
|
||||
unittest_viewport.cxx \
|
||||
unittest_scrollbarsize.cxx \
|
||||
unittest_schemes.cxx \
|
||||
unittest_simple_terminal.cxx \
|
||||
unittest_terminal.cxx \
|
||||
unittest_core.cxx
|
||||
|
||||
OBJUNITTEST = \
|
||||
@ -125,6 +125,7 @@ CPPFILES =\
|
||||
symbols.cxx \
|
||||
table.cxx \
|
||||
tabs.cxx \
|
||||
terminal.cxx \
|
||||
threads.cxx \
|
||||
tile.cxx \
|
||||
tiled_image.cxx \
|
||||
@ -206,6 +207,7 @@ ALL = \
|
||||
sudoku$(EXEEXT) \
|
||||
symbols$(EXEEXT) \
|
||||
table$(EXEEXT) \
|
||||
terminal$(EXEEXT) \
|
||||
$(THREADS) \
|
||||
tile$(EXEEXT) \
|
||||
tiled_image$(EXEEXT) \
|
||||
@ -268,6 +270,7 @@ clean:
|
||||
$(RM) radio.cxx radio.h
|
||||
$(RM) resize.cxx resize.h
|
||||
$(RM) tabs.cxx tabs.h
|
||||
$(RM) terminal.cxx terminal.h
|
||||
$(RM) tree.cxx tree.h
|
||||
$(RM) valuators.cxx valuators.h
|
||||
|
||||
@ -618,6 +621,9 @@ table$(EXEEXT): table.o
|
||||
tabs$(EXEEXT): tabs.o
|
||||
tabs.cxx: tabs.fl ../fluid/fluid$(EXEEXT)
|
||||
|
||||
terminal$(EXEEXT): terminal.o
|
||||
terminal.cxx: terminal.fl ../fluid/fluid$(EXEEXT)
|
||||
|
||||
threads$(EXEEXT): threads.o
|
||||
# This ensures that we have this dependency even if threads are not
|
||||
# enabled in the current tree...
|
||||
|
@ -64,7 +64,7 @@ That was a blank line above this.
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Int_Input.H>
|
||||
#include <FL/Fl_Choice.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
#include <FL/fl_ask.H>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -81,7 +81,7 @@ Fl_Button *top,
|
||||
Fl_Choice *btype;
|
||||
Fl_Choice *wtype;
|
||||
Fl_Int_Input *field;
|
||||
Fl_Simple_Terminal *tty = 0;
|
||||
Fl_Terminal *tty = 0;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
@ -219,7 +219,7 @@ int main(int argc, char **argv) {
|
||||
wtype->value(4); // FL_WHEN_RELEASE_ALWAYS is Fl_Browser's default
|
||||
|
||||
// Small terminal window for callback messages
|
||||
tty = new Fl_Simple_Terminal(0,400,720,120);
|
||||
tty = new Fl_Terminal(0,400,720,120);
|
||||
tty->history_lines(50);
|
||||
tty->ansi(true);
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <FL/Fl_Color_Chooser.H>
|
||||
#include <FL/Fl_Output.H>
|
||||
#include <FL/Fl_Hor_Value_Slider.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
#include <FL/fl_draw.H>
|
||||
|
||||
#include <math.h>
|
||||
@ -93,7 +93,7 @@ public:
|
||||
|
||||
// global variables
|
||||
|
||||
Fl_Simple_Terminal *term = 0;
|
||||
Fl_Terminal *term = 0;
|
||||
|
||||
double g_lfg; // perceived lightness of foreground color
|
||||
double g_lbg; // perceived lightness of background color
|
||||
@ -428,9 +428,9 @@ int main(int argc, char **argv) {
|
||||
int ttw = window.w() - 20;
|
||||
int tth = window.h() - tty - 10;
|
||||
|
||||
term = new Fl_Simple_Terminal(ttx, tty, ttw, tth);
|
||||
term = new Fl_Terminal(ttx, tty, ttw, tth);
|
||||
term->color(FL_WHITE);
|
||||
term->textcolor(FL_BLACK);
|
||||
term->textfgcolor(FL_BLACK);
|
||||
term->textsize(13);
|
||||
|
||||
term->printf("FLTK fl_contrast() test program with different contrast algorithms, version %s\n", version);
|
||||
|
@ -75,7 +75,7 @@
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Menu_Button.H> // right click popup menu
|
||||
#include <FL/Fl_Scheme_Choice.H>
|
||||
#include <FL/Fl_Simple_Terminal.H> // tty
|
||||
#include <FL/Fl_Terminal.H> // tty
|
||||
#include <FL/filename.H>
|
||||
#include <FL/platform.H>
|
||||
#include <FL/fl_ask.H> // fl_alert()
|
||||
@ -102,7 +102,7 @@ void dobut(Fl_Widget *, long);
|
||||
|
||||
Fl_Double_Window *form = 0;
|
||||
Fl_Group *demogrp = 0;
|
||||
Fl_Simple_Terminal *tty = 0;
|
||||
Fl_Terminal *tty = 0;
|
||||
Fl_Scheme_Choice *scheme_choice = 0;
|
||||
Fl_Button *but[9];
|
||||
Fl_Button *exit_button;
|
||||
@ -231,11 +231,15 @@ void create_the_forms() {
|
||||
demogrp->end();
|
||||
|
||||
// Small debug terminal window parented to window, not demogrp
|
||||
tty = new Fl_Simple_Terminal(10, FORM_H - 1, FORM_W - 20, 1);
|
||||
// To show/hide debug terminal, use demo's right-click menu
|
||||
//
|
||||
tty = new Fl_Terminal(10, FORM_H - 1, FORM_W - 20, 1);
|
||||
tty->history_lines(50);
|
||||
tty->display_rows(2); // make display at least 2 rows high, even if not seen
|
||||
tty->display_columns(100); // make display at least 100 cols wide, even if not seen
|
||||
tty->ansi(true);
|
||||
tty->hide();
|
||||
tty->textsize(10);
|
||||
tty->textsize(12);
|
||||
|
||||
// End window
|
||||
form->end();
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include <FL/Fl_PNM_Image.H>
|
||||
#include <FL/Fl_Light_Button.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -55,7 +55,7 @@ Fl_Input *filter;
|
||||
Fl_File_Browser *files;
|
||||
Fl_File_Chooser *fc;
|
||||
Fl_Shared_Image *image = 0;
|
||||
Fl_Simple_Terminal *tty = 0;
|
||||
Fl_Terminal *tty = 0;
|
||||
|
||||
// for choosing extra groups
|
||||
Fl_Choice *ch_extra;
|
||||
@ -109,8 +109,9 @@ main(int argc, // I - Number of command-line arguments
|
||||
// Make the main window...
|
||||
window = new Fl_Double_Window(400, 215+TERMINAL_HEIGHT, "File Chooser Test");
|
||||
|
||||
tty = new Fl_Simple_Terminal(0,215,window->w(),TERMINAL_HEIGHT);
|
||||
tty = new Fl_Terminal(0,215,window->w(),TERMINAL_HEIGHT);
|
||||
tty->ansi(true);
|
||||
tty->display_columns(100); // at least 100 cols wide, even tho actual window smaller
|
||||
|
||||
// Group: limit resizing to filter input (not browse button)
|
||||
grp = new Fl_Group(0,10,400,25);
|
||||
|
@ -26,12 +26,12 @@
|
||||
#include <FL/Fl_Toggle_Button.H>
|
||||
#include <FL/Fl_Light_Button.H>
|
||||
#include <FL/Fl_Color_Chooser.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
#define TERMINAL_HEIGHT 120
|
||||
|
||||
// Globals
|
||||
Fl_Simple_Terminal *G_tty = 0;
|
||||
Fl_Terminal *G_tty = 0;
|
||||
|
||||
void cb(Fl_Widget *ob) {
|
||||
G_tty->printf("Callback for %s '%s'\n",ob->label(),((Fl_Input*)ob)->value());
|
||||
@ -91,7 +91,7 @@ int main(int argc, char **argv) {
|
||||
Fl::args(argc, argv);
|
||||
Fl::get_system_colors();
|
||||
Fl_Window *window = new Fl_Window(400,420+TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Simple_Terminal(0,420,window->w(),TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Terminal(0,420,window->w(),TERMINAL_HEIGHT);
|
||||
|
||||
int y = 10;
|
||||
input[0] = new Fl_Input(70,y,300,30,"Normal:"); y += 35;
|
||||
|
@ -18,12 +18,12 @@
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Input_Choice.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
#define TERMINAL_HEIGHT 120
|
||||
|
||||
// Globals
|
||||
Fl_Simple_Terminal *G_tty = 0;
|
||||
Fl_Terminal *G_tty = 0;
|
||||
|
||||
void buttcb(Fl_Widget*,void*data) {
|
||||
Fl_Input_Choice *in=(Fl_Input_Choice *)data;
|
||||
@ -44,7 +44,7 @@ void input_choice_cb(Fl_Widget*,void*data) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Fl_Double_Window win(300, 200+TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Simple_Terminal(0,200,win.w(),TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Terminal(0,200,win.w(),TERMINAL_HEIGHT);
|
||||
|
||||
Fl_Input_Choice in(40,40,100,28,"Test");
|
||||
in.callback(input_choice_cb, (void*)&in);
|
||||
|
@ -222,7 +222,7 @@ browser.o: ../FL/Fl_Rect.H
|
||||
browser.o: ../FL/Fl_RGB_Image.H
|
||||
browser.o: ../FL/Fl_Scrollbar.H
|
||||
browser.o: ../FL/Fl_Select_Browser.H
|
||||
browser.o: ../FL/Fl_Simple_Terminal.H
|
||||
browser.o: ../FL/Fl_Terminal.H
|
||||
browser.o: ../FL/Fl_Slider.H
|
||||
browser.o: ../FL/Fl_Text_Buffer.H
|
||||
browser.o: ../FL/Fl_Text_Display.H
|
||||
@ -507,7 +507,7 @@ contrast.o: ../FL/Fl_Return_Button.H
|
||||
contrast.o: ../FL/Fl_RGB_Image.H
|
||||
contrast.o: ../FL/Fl_Round_Button.H
|
||||
contrast.o: ../FL/Fl_Scrollbar.H
|
||||
contrast.o: ../FL/Fl_Simple_Terminal.H
|
||||
contrast.o: ../FL/Fl_Terminal.H
|
||||
contrast.o: ../FL/Fl_Slider.H
|
||||
contrast.o: ../FL/Fl_Text_Buffer.H
|
||||
contrast.o: ../FL/Fl_Text_Display.H
|
||||
@ -693,7 +693,7 @@ demo.o: ../FL/Fl_RGB_Image.H
|
||||
demo.o: ../FL/Fl_Scheme.H
|
||||
demo.o: ../FL/Fl_Scheme_Choice.H
|
||||
demo.o: ../FL/Fl_Scrollbar.H
|
||||
demo.o: ../FL/Fl_Simple_Terminal.H
|
||||
demo.o: ../FL/Fl_Terminal.H
|
||||
demo.o: ../FL/Fl_Slider.H
|
||||
demo.o: ../FL/Fl_Text_Buffer.H
|
||||
demo.o: ../FL/Fl_Text_Display.H
|
||||
@ -911,7 +911,7 @@ file_chooser.o: ../FL/Fl_Return_Button.H
|
||||
file_chooser.o: ../FL/Fl_RGB_Image.H
|
||||
file_chooser.o: ../FL/Fl_Scrollbar.H
|
||||
file_chooser.o: ../FL/Fl_Shared_Image.H
|
||||
file_chooser.o: ../FL/Fl_Simple_Terminal.H
|
||||
file_chooser.o: ../FL/Fl_Terminal.H
|
||||
file_chooser.o: ../FL/Fl_Slider.H
|
||||
file_chooser.o: ../FL/Fl_Text_Buffer.H
|
||||
file_chooser.o: ../FL/Fl_Text_Display.H
|
||||
@ -1409,7 +1409,7 @@ input.o: ../FL/Fl_Return_Button.H
|
||||
input.o: ../FL/Fl_RGB_Image.H
|
||||
input.o: ../FL/Fl_Scrollbar.H
|
||||
input.o: ../FL/Fl_Secret_Input.H
|
||||
input.o: ../FL/Fl_Simple_Terminal.H
|
||||
input.o: ../FL/Fl_Terminal.H
|
||||
input.o: ../FL/Fl_Slider.H
|
||||
input.o: ../FL/Fl_Text_Buffer.H
|
||||
input.o: ../FL/Fl_Text_Display.H
|
||||
@ -1448,7 +1448,7 @@ input_choice.o: ../FL/Fl_Preferences.H
|
||||
input_choice.o: ../FL/Fl_Rect.H
|
||||
input_choice.o: ../FL/Fl_RGB_Image.H
|
||||
input_choice.o: ../FL/Fl_Scrollbar.H
|
||||
input_choice.o: ../FL/Fl_Simple_Terminal.H
|
||||
input_choice.o: ../FL/Fl_Terminal.H
|
||||
input_choice.o: ../FL/Fl_Slider.H
|
||||
input_choice.o: ../FL/Fl_Text_Buffer.H
|
||||
input_choice.o: ../FL/Fl_Text_Display.H
|
||||
@ -1626,7 +1626,7 @@ menubar.o: ../FL/Fl_RGB_Image.H
|
||||
menubar.o: ../FL/Fl_Scheme.H
|
||||
menubar.o: ../FL/Fl_Scheme_Choice.H
|
||||
menubar.o: ../FL/Fl_Scrollbar.H
|
||||
menubar.o: ../FL/Fl_Simple_Terminal.H
|
||||
menubar.o: ../FL/Fl_Terminal.H
|
||||
menubar.o: ../FL/Fl_Slider.H
|
||||
menubar.o: ../FL/fl_string_functions.h
|
||||
menubar.o: ../FL/Fl_Sys_Menu_Bar.H
|
||||
@ -1719,7 +1719,7 @@ native-filechooser.o: ../FL/Fl_Rect.H
|
||||
native-filechooser.o: ../FL/Fl_Return_Button.H
|
||||
native-filechooser.o: ../FL/Fl_RGB_Image.H
|
||||
native-filechooser.o: ../FL/Fl_Scrollbar.H
|
||||
native-filechooser.o: ../FL/Fl_Simple_Terminal.H
|
||||
native-filechooser.o: ../FL/Fl_Terminal.H
|
||||
native-filechooser.o: ../FL/Fl_Slider.H
|
||||
native-filechooser.o: ../FL/Fl_Text_Buffer.H
|
||||
native-filechooser.o: ../FL/Fl_Text_Display.H
|
||||
@ -2446,7 +2446,7 @@ table.o: ../FL/Fl_Rect.H
|
||||
table.o: ../FL/Fl_RGB_Image.H
|
||||
table.o: ../FL/Fl_Scroll.H
|
||||
table.o: ../FL/Fl_Scrollbar.H
|
||||
table.o: ../FL/Fl_Simple_Terminal.H
|
||||
table.o: ../FL/Fl_Terminal.H
|
||||
table.o: ../FL/Fl_Slider.H
|
||||
table.o: ../FL/Fl_Table.H
|
||||
table.o: ../FL/Fl_Table_Row.H
|
||||
@ -2595,7 +2595,7 @@ tree.o: ../FL/Fl_Rect.H
|
||||
tree.o: ../FL/Fl_Return_Button.H
|
||||
tree.o: ../FL/Fl_RGB_Image.H
|
||||
tree.o: ../FL/Fl_Scrollbar.H
|
||||
tree.o: ../FL/Fl_Simple_Terminal.H
|
||||
tree.o: ../FL/Fl_Terminal.H
|
||||
tree.o: ../FL/Fl_Slider.H
|
||||
tree.o: ../FL/Fl_Text_Buffer.H
|
||||
tree.o: ../FL/Fl_Text_Display.H
|
||||
@ -2660,7 +2660,7 @@ unittests.o: ../FL/Fl_Preferences.H
|
||||
unittests.o: ../FL/Fl_Rect.H
|
||||
unittests.o: ../FL/Fl_RGB_Image.H
|
||||
unittests.o: ../FL/Fl_Scrollbar.H
|
||||
unittests.o: ../FL/Fl_Simple_Terminal.H
|
||||
unittests.o: ../FL/Fl_Terminal.H
|
||||
unittests.o: ../FL/Fl_Slider.H
|
||||
unittests.o: ../FL/fl_string_functions.h
|
||||
unittests.o: ../FL/Fl_Text_Buffer.H
|
||||
@ -2788,7 +2788,7 @@ unittest_core.o: ../FL/Fl_Preferences.H
|
||||
unittest_core.o: ../FL/Fl_Rect.H
|
||||
unittest_core.o: ../FL/Fl_RGB_Image.H
|
||||
unittest_core.o: ../FL/Fl_Scrollbar.H
|
||||
unittest_core.o: ../FL/Fl_Simple_Terminal.H
|
||||
unittest_core.o: ../FL/Fl_Terminal.H
|
||||
unittest_core.o: ../FL/Fl_Slider.H
|
||||
unittest_core.o: ../FL/Fl_Text_Buffer.H
|
||||
unittest_core.o: ../FL/Fl_Text_Display.H
|
||||
@ -2980,37 +2980,26 @@ unittest_scrollbarsize.o: ../FL/Fl_Widget.H
|
||||
unittest_scrollbarsize.o: ../FL/Fl_Window.H
|
||||
unittest_scrollbarsize.o: ../FL/platform_types.h
|
||||
unittest_scrollbarsize.o: unittests.h
|
||||
unittest_simple_terminal.o: ../FL/Enumerations.H
|
||||
unittest_simple_terminal.o: ../FL/Fl.H
|
||||
unittest_simple_terminal.o: ../FL/fl_attr.h
|
||||
unittest_simple_terminal.o: ../FL/Fl_Bitmap.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Cairo.H
|
||||
unittest_simple_terminal.o: ../FL/fl_casts.H
|
||||
unittest_simple_terminal.o: ../FL/fl_config.h
|
||||
unittest_simple_terminal.o: ../FL/Fl_Device.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Double_Window.H
|
||||
unittest_simple_terminal.o: ../FL/fl_draw.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Export.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Graphics_Driver.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Group.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Image.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Pixmap.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Plugin.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Preferences.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Rect.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_RGB_Image.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Scrollbar.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Simple_Terminal.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Slider.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Text_Buffer.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Text_Display.H
|
||||
unittest_simple_terminal.o: ../FL/fl_types.h
|
||||
unittest_simple_terminal.o: ../FL/fl_utf8.h
|
||||
unittest_simple_terminal.o: ../FL/Fl_Valuator.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Widget.H
|
||||
unittest_simple_terminal.o: ../FL/Fl_Window.H
|
||||
unittest_simple_terminal.o: ../FL/platform_types.h
|
||||
unittest_simple_terminal.o: unittests.h
|
||||
unittest_terminal.o: ../FL/Enumerations.H
|
||||
unittest_terminal.o: ../FL/Fl.H
|
||||
unittest_terminal.o: ../FL/fl_attr.h
|
||||
unittest_terminal.o: ../FL/Fl_Bitmap.H
|
||||
unittest_terminal.o: ../FL/Fl_Cairo.H
|
||||
unittest_terminal.o: ../FL/fl_casts.H
|
||||
unittest_terminal.o: ../FL/fl_config.h
|
||||
unittest_terminal.o: ../FL/Fl_Double_Window.H
|
||||
unittest_terminal.o: ../FL/Fl_Export.H
|
||||
unittest_terminal.o: ../FL/Fl_Group.H
|
||||
unittest_terminal.o: ../FL/Fl_Image.H
|
||||
unittest_terminal.o: ../FL/Fl_Rect.H
|
||||
unittest_terminal.o: ../FL/Fl_Scrollbar.H
|
||||
unittest_terminal.o: ../FL/Fl_Terminal.H
|
||||
unittest_terminal.o: ../FL/fl_types.h
|
||||
unittest_terminal.o: ../FL/fl_utf8.h
|
||||
unittest_terminal.o: ../FL/Fl_Widget.H
|
||||
unittest_terminal.o: ../FL/Fl_Window.H
|
||||
unittest_terminal.o: ../FL/platform_types.h
|
||||
unittest_terminal.o: unittests.h
|
||||
unittest_symbol.o: ../FL/Enumerations.H
|
||||
unittest_symbol.o: ../FL/Fl.H
|
||||
unittest_symbol.o: ../FL/fl_attr.h
|
||||
@ -3203,7 +3192,7 @@ valuators.o: ../FL/Fl_Repeat_Button.H
|
||||
valuators.o: ../FL/Fl_RGB_Image.H
|
||||
valuators.o: ../FL/Fl_Roller.H
|
||||
valuators.o: ../FL/Fl_Scrollbar.H
|
||||
valuators.o: ../FL/Fl_Simple_Terminal.H
|
||||
valuators.o: ../FL/Fl_Terminal.H
|
||||
valuators.o: ../FL/Fl_Slider.H
|
||||
valuators.o: ../FL/Fl_Spinner.H
|
||||
valuators.o: ../FL/Fl_Text_Buffer.H
|
||||
|
@ -31,14 +31,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <FL/fl_draw.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
#include <FL/fl_ask.H>
|
||||
#include <FL/fl_string_functions.h>
|
||||
|
||||
#define TERMINAL_HEIGHT 120
|
||||
|
||||
// Globals
|
||||
Fl_Simple_Terminal *G_tty = 0;
|
||||
Fl_Terminal *G_tty = 0;
|
||||
|
||||
void window_cb(Fl_Widget* w, void*) {
|
||||
puts("window callback called"); // end of program, so stdout instead of G_tty
|
||||
@ -235,7 +235,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
Fl_Scheme_Choice scheme_choice(300, 50, 100, 25, "&scheme");
|
||||
|
||||
G_tty = new Fl_Simple_Terminal(0,400,WIDTH,TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Terminal(0,400,WIDTH,TERMINAL_HEIGHT);
|
||||
|
||||
window.callback(window_cb);
|
||||
Fl_Menu_Bar menubar(0,0,WIDTH,30); menubar.menu(menutable);
|
||||
|
@ -25,14 +25,14 @@
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
#include <FL/Fl_Help_View.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
#define TERMINAL_HEIGHT 120
|
||||
|
||||
// GLOBALS
|
||||
Fl_Input *G_filename = NULL;
|
||||
Fl_Multiline_Input *G_filter = NULL;
|
||||
Fl_Simple_Terminal *G_tty = NULL;
|
||||
Fl_Terminal *G_tty = NULL;
|
||||
|
||||
void PickFile_CB(Fl_Widget*, void*) {
|
||||
// Create native chooser
|
||||
@ -106,7 +106,7 @@ int main(int argc, char **argv) {
|
||||
win->size_range(win->w(), win->h(), 0, 0);
|
||||
win->begin();
|
||||
{
|
||||
G_tty = new Fl_Simple_Terminal(0,400,win->w(),TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Terminal(0,400,win->w(),TERMINAL_HEIGHT);
|
||||
|
||||
int x = 80, y = 10;
|
||||
G_filename = new Fl_Input(x, y, win->w()-80-10, 25, "Filename");
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <FL/fl_draw.H>
|
||||
#include <FL/fl_ask.H>
|
||||
#include <FL/Fl_Table_Row.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -19,7 +19,7 @@
|
||||
#define TERMINAL_HEIGHT 120
|
||||
|
||||
// Globals
|
||||
Fl_Simple_Terminal *G_tty = 0;
|
||||
Fl_Terminal *G_tty = 0;
|
||||
|
||||
// Simple demonstration class to derive from Fl_Table_Row
|
||||
class DemoTable : public Fl_Table_Row
|
||||
@ -349,7 +349,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
Fl_Window win(900, 730+TERMINAL_HEIGHT);
|
||||
|
||||
G_tty = new Fl_Simple_Terminal(0,730,win.w(),TERMINAL_HEIGHT);
|
||||
G_tty = new Fl_Terminal(0,730,win.w(),TERMINAL_HEIGHT);
|
||||
|
||||
G_table = new DemoTable(20, 20, 860, 460, "Demo");
|
||||
G_table->selection_color(FL_YELLOW);
|
||||
|
1972
test/terminal.fl
Normal file
1972
test/terminal.fl
Normal file
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@ decl {\#include <FL/Fl_Color_Chooser.H>} {public global
|
||||
decl {\#include <FL/Fl_Text_Display.H>} {public global
|
||||
}
|
||||
|
||||
decl {\#include <FL/Fl_Simple_Terminal.H>} {public global
|
||||
decl {\#include <FL/Fl_Terminal.H>} {public global
|
||||
}
|
||||
|
||||
decl {int G_cb_counter = 0;} {
|
||||
@ -1749,7 +1749,7 @@ helpwin->show();}
|
||||
Fl_Box tty {
|
||||
label label
|
||||
xywh {16 571 1014 149} box DOWN_BOX color 0
|
||||
class Fl_Simple_Terminal
|
||||
class Fl_Terminal
|
||||
}
|
||||
}
|
||||
code {// Initialize Tree
|
||||
|
@ -18,8 +18,9 @@
|
||||
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
#include "../src/Fl_String.H"
|
||||
#include <FL/Fl_Preferences.H>
|
||||
#include <FL/fl_callback_macros.H>
|
||||
#include <FL/filename.H>
|
||||
#include <FL/fl_utf8.h>
|
||||
@ -374,7 +375,7 @@ TEST(Fl_Callback_Macros, FL_INLINE_CALLBACK) {
|
||||
*/
|
||||
class Ut_Core_Test : public Fl_Group {
|
||||
|
||||
Fl_Simple_Terminal *tty;
|
||||
Fl_Terminal *tty;
|
||||
bool suite_ran_;
|
||||
|
||||
public:
|
||||
@ -390,7 +391,7 @@ public:
|
||||
tty(NULL),
|
||||
suite_ran_(false)
|
||||
{
|
||||
tty = new Fl_Simple_Terminal(x+4, y+4, w-8, h-8, "Unittest Log");
|
||||
tty = new Fl_Terminal(x+4, y+4, w-8, h-8, "Unittest Log");
|
||||
tty->ansi(true);
|
||||
end();
|
||||
Ut_Suite::tty = tty;
|
||||
|
@ -1,121 +0,0 @@
|
||||
//
|
||||
// Unit tests for the Fast Light Tool Kit (FLTK).
|
||||
//
|
||||
// Copyright 1998-2022 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
// file is missing or damaged, see the license at:
|
||||
//
|
||||
// https://www.fltk.org/COPYING.php
|
||||
//
|
||||
// Please see the following page on how to report bugs and issues:
|
||||
//
|
||||
// https://www.fltk.org/bugs.php
|
||||
//
|
||||
|
||||
#include "unittests.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
|
||||
//
|
||||
//------- test the Fl_Simple_Terminal drawing capabilities ----------
|
||||
//
|
||||
class Ut_Simple_Terminal_Test : public Fl_Group {
|
||||
Fl_Simple_Terminal *tty1;
|
||||
Fl_Simple_Terminal *tty2;
|
||||
Fl_Simple_Terminal *tty3;
|
||||
void ansi_test_pattern(Fl_Simple_Terminal *tty) {
|
||||
tty->append("\033[30mBlack Courier 14\033[0m Normal text\n"
|
||||
"\033[31mRed Courier 14\033[0m Normal text\n"
|
||||
"\033[32mGreen Courier 14\033[0m Normal text\n"
|
||||
"\033[33mYellow Courier 14\033[0m Normal text\n"
|
||||
"\033[34mBlue Courier 14\033[0m Normal text\n"
|
||||
"\033[35mMagenta Courier 14\033[0m Normal text\n"
|
||||
"\033[36mCyan Courier 14\033[0m Normal text\n"
|
||||
"\033[37mWhite Courier 14\033[0m Normal text\n"
|
||||
"\033[40mBright Black Courier 14\033[0m Normal text\n"
|
||||
"\033[41mBright Red Courier 14\033[0m Normal text\n"
|
||||
"\033[42mBright Green Courier 14\033[0m Normal text\n"
|
||||
"\033[43mBright Yellow Courier 14\033[0m Normal text\n"
|
||||
"\033[44mBright Blue Courier 14\033[0m Normal text\n"
|
||||
"\033[45mBright Magenta Courier 14\033[0m Normal text\n"
|
||||
"\033[46mBright Cyan Courier 14\033[0m Normal text\n"
|
||||
"\033[47mBright White Courier 14\033[0m Normal text\n"
|
||||
"\n"
|
||||
"\033[31mRed\033[32mGreen\033[33mYellow\033[34mBlue\033[35mMagenta\033[36mCyan\033[37mWhite\033[0m - "
|
||||
"\033[31mX\033[32mX\033[33mX\033[34mX\033[35mX\033[36mX\033[37mX\033[0m\n"
|
||||
"\033[41mRed\033[42mGreen\033[43mYellow\033[44mBlue\033[45mMagenta\033[46mCyan\033[47mWhite\033[0m - "
|
||||
"\033[41mX\033[42mX\033[43mX\033[44mX\033[45mX\033[46mX\033[47mX\033[0m\n");
|
||||
}
|
||||
void gray_test_pattern(Fl_Simple_Terminal *tty) {
|
||||
tty->append("Grayscale Test Pattern\n"
|
||||
"--------------------------\n"
|
||||
"\033[0m 100% white Courier 14\n"
|
||||
"\033[1m 90% white Courier 14\n"
|
||||
"\033[2m 80% white Courier 14\n"
|
||||
"\033[3m 70% white Courier 14\n"
|
||||
"\033[4m 60% white Courier 14\n"
|
||||
"\033[5m 50% white Courier 14\n"
|
||||
"\033[6m 40% white Courier 14\n"
|
||||
"\033[7m 30% white Courier 14\n"
|
||||
"\033[8m 20% white Courier 14\n"
|
||||
"\033[9m 10% white Courier 14\n"
|
||||
"\033[0m");
|
||||
}
|
||||
static void date_timer_cb(void *data) {
|
||||
Fl_Simple_Terminal *tty = (Fl_Simple_Terminal*)data;
|
||||
time_t lt = time(NULL);
|
||||
tty->printf("The time and date is now: %s", ctime(<));
|
||||
Fl::repeat_timeout(3.0, date_timer_cb, data);
|
||||
}
|
||||
public:
|
||||
static Fl_Widget *create() {
|
||||
return new Ut_Simple_Terminal_Test(UT_TESTAREA_X, UT_TESTAREA_Y, UT_TESTAREA_W, UT_TESTAREA_H);
|
||||
}
|
||||
Ut_Simple_Terminal_Test(int x, int y, int w, int h)
|
||||
: Fl_Group(x, y, w, h) {
|
||||
static Fl_Text_Display::Style_Table_Entry my_stable[] = { // 10 entry grayscale
|
||||
// Font Color Font Face Font Size ANSI Sequence
|
||||
// ---------- ---------------- --------- -------------
|
||||
{ 0xffffff00, FL_COURIER_BOLD, 14 }, // "\033[0m" 0 white 100%
|
||||
{ 0xe6e6e600, FL_COURIER_BOLD, 14 }, // "\033[1m" 1 white 90%
|
||||
{ 0xcccccc00, FL_COURIER_BOLD, 14 }, // "\033[2m" 2 white 80%
|
||||
{ 0xb3b3b300, FL_COURIER_BOLD, 14 }, // "\033[3m" 3 white 70%
|
||||
{ 0x99999900, FL_COURIER_BOLD, 14 }, // "\033[4m" 4 white 60%
|
||||
{ 0x80808000, FL_COURIER_BOLD, 14 }, // "\033[5m" 5 white 50% "\033[0m"
|
||||
{ 0x66666600, FL_COURIER_BOLD, 14 }, // "\033[6m" 6 white 40%
|
||||
{ 0x4d4d4d00, FL_COURIER_BOLD, 14 }, // "\033[7m" 7 white 30%
|
||||
{ 0x33333300, FL_COURIER_BOLD, 14 }, // "\033[8m" 8 white 20%
|
||||
{ 0x1a1a1a00, FL_COURIER_BOLD, 14 }, // "\033[9m" 9 white 10%
|
||||
};
|
||||
int tty_h = (int)(h/3.5);
|
||||
int tty_y1 = y+(tty_h*0)+20;
|
||||
int tty_y2 = y+(tty_h*1)+40;
|
||||
int tty_y3 = y+(tty_h*2)+60;
|
||||
|
||||
// TTY1
|
||||
tty1 = new Fl_Simple_Terminal(x, tty_y1, w, tty_h,"Tty 1: ANSI off");
|
||||
tty1->ansi(false);
|
||||
Fl::add_timeout(0.5, date_timer_cb, (void*)tty1);
|
||||
|
||||
// TTY2
|
||||
tty2 = new Fl_Simple_Terminal(x, tty_y2, w, tty_h,"Tty 2: ANSI on");
|
||||
tty2->ansi(true);
|
||||
ansi_test_pattern(tty2);
|
||||
Fl::add_timeout(0.5, date_timer_cb, (void*)tty2);
|
||||
|
||||
// TTY3
|
||||
tty3 = new Fl_Simple_Terminal(x, tty_y3, w, tty_h, "Tty 3: Grayscale Style Table");
|
||||
tty3->style_table(my_stable, sizeof(my_stable), 0);
|
||||
tty3->ansi(true);
|
||||
gray_test_pattern(tty3);
|
||||
Fl::add_timeout(0.5, date_timer_cb, (void*)tty3);
|
||||
|
||||
end();
|
||||
}
|
||||
};
|
||||
|
||||
UnitTest simple_terminal(UT_TEST_SIMPLE_TERMINAL, "Simple Terminal", Ut_Simple_Terminal_Test::create);
|
98
test/unittest_terminal.cxx
Normal file
98
test/unittest_terminal.cxx
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// Unit tests for the Fast Light Tool Kit (FLTK).
|
||||
//
|
||||
// Copyright 1998-2022 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
// file is missing or damaged, see the license at:
|
||||
//
|
||||
// https://www.fltk.org/COPYING.php
|
||||
//
|
||||
// Please see the following page on how to report bugs and issues:
|
||||
//
|
||||
// https://www.fltk.org/bugs.php
|
||||
//
|
||||
|
||||
#include "unittests.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
|
||||
//
|
||||
//------- test the Fl_Terminal drawing capabilities ----------
|
||||
//
|
||||
class Ut_Terminal_Test : public Fl_Group {
|
||||
Fl_Terminal *tty1;
|
||||
Fl_Terminal *tty2;
|
||||
void ansi_test_pattern(Fl_Terminal *tty) {
|
||||
tty->append("\033[30mBlack Courier 14\033[0m Normal text\n"
|
||||
"\033[31mRed Courier 14\033[0m Normal text\n"
|
||||
"\033[32mGreen Courier 14\033[0m Normal text\n"
|
||||
"\033[33mYellow Courier 14\033[0m Normal text\n"
|
||||
"\033[34mBlue Courier 14\033[0m Normal text\n"
|
||||
"\033[35mMagenta Courier 14\033[0m Normal text\n"
|
||||
"\033[36mCyan Courier 14\033[0m Normal text\n"
|
||||
"\033[37mWhite Courier 14\033[0m Normal text\n"
|
||||
"\033[1;30mBright Black Courier 14\033[0m Normal text\n"
|
||||
"\033[1;31mBright Red Courier 14\033[0m Normal text\n"
|
||||
"\033[1;32mBright Green Courier 14\033[0m Normal text\n"
|
||||
"\033[1;33mBright Yellow Courier 14\033[0m Normal text\n"
|
||||
"\033[1;34mBright Blue Courier 14\033[0m Normal text\n"
|
||||
"\033[1;35mBright Magenta Courier 14\033[0m Normal text\n"
|
||||
"\033[1;36mBright Cyan Courier 14\033[0m Normal text\n"
|
||||
"\033[1;37mBright White Courier 14\033[0m Normal text\n"
|
||||
"\n"
|
||||
"\033[31mRed\033[32mGreen\033[33mYellow\033[34mBlue\033[35mMagenta\033[36mCyan\033[37mWhite\033[0m - "
|
||||
"\033[31mX\033[32mX\033[33mX\033[34mX\033[35mX\033[36mX\033[37mX\033[0m\n"
|
||||
"\033[1;31mRed\033[1;32mGreen\033[1;33mYellow\033[34mBlue\033[35mMagenta\033[36mCyan\033[1;37mWhite\033[1;0m - "
|
||||
"\033[1;31mX\033[1;32mX\033[1;33mX\033[1;34mX\033[1;35mX\033[1;36mX\033[1;37mX\033[0m\n");
|
||||
}
|
||||
void gray_test_pattern(Fl_Terminal *tty) {
|
||||
tty->append("Grayscale Test Pattern\n"
|
||||
"--------------------------\n"
|
||||
"\033[38;2;255;255;255m 100% white Courier 14\n" // ESC xterm codes for setting r;g;b colors
|
||||
"\033[38;2;230;230;230m 90% white Courier 14\n"
|
||||
"\033[38;2;205;205;205m 80% white Courier 14\n"
|
||||
"\033[38;2;179;179;179m 70% white Courier 14\n"
|
||||
"\033[38;2;154;154;154m 60% white Courier 14\n"
|
||||
"\033[38;2;128;128;128m 50% white Courier 14\n"
|
||||
"\033[38;2;102;102;102m 40% white Courier 14\n"
|
||||
"\033[38;2;77;77;77m" " 30% white Courier 14\n"
|
||||
"\033[38;2;51;51;51m" " 20% white Courier 14\n"
|
||||
"\033[38;2;26;26;26m" " 10% white Courier 14\n"
|
||||
"\033[38;2;0;0;0m" " 0% white Courier 14\n"
|
||||
"\033[0m");
|
||||
}
|
||||
static void date_timer_cb(void *data) {
|
||||
Fl_Terminal *tty = (Fl_Terminal*)data;
|
||||
time_t lt = time(NULL);
|
||||
tty->printf("The time and date is now: %s", ctime(<));
|
||||
Fl::repeat_timeout(3.0, date_timer_cb, data);
|
||||
}
|
||||
public:
|
||||
static Fl_Widget *create() {
|
||||
return new Ut_Terminal_Test(UT_TESTAREA_X, UT_TESTAREA_Y, UT_TESTAREA_W, UT_TESTAREA_H);
|
||||
}
|
||||
Ut_Terminal_Test(int x, int y, int w, int h)
|
||||
: Fl_Group(x, y, w, h) {
|
||||
int tty_h = (int)(h/2.25+.5);
|
||||
int tty_y1 = y+(tty_h*0)+20;
|
||||
int tty_y2 = y+(tty_h*1)+40;
|
||||
|
||||
// TTY1
|
||||
tty1 = new Fl_Terminal(x, tty_y1, w, tty_h,"Tty 1: Colors");
|
||||
ansi_test_pattern(tty1);
|
||||
Fl::add_timeout(0.5, date_timer_cb, (void*)tty1);
|
||||
|
||||
// TTY2
|
||||
tty2 = new Fl_Terminal(x, tty_y2, w, tty_h,"Tty 2: Grayscale");
|
||||
gray_test_pattern(tty2);
|
||||
Fl::add_timeout(0.5, date_timer_cb, (void*)tty2);
|
||||
|
||||
end();
|
||||
}
|
||||
};
|
||||
|
||||
UnitTest simple_terminal(UT_TEST_SIMPLE_TERMINAL, "Terminal", Ut_Terminal_Test::create);
|
@ -29,7 +29,7 @@
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Hold_Browser.H>
|
||||
#include <FL/Fl_Help_View.H>
|
||||
#include <FL/Fl_Simple_Terminal.H>
|
||||
#include <FL/Fl_Terminal.H>
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/fl_draw.H> // fl_text_extents()
|
||||
@ -181,7 +181,7 @@ int Ut_Suite::num_failed_ = 0;
|
||||
const char *Ut_Suite::red = "\033[31m";
|
||||
const char *Ut_Suite::green = "\033[32m";
|
||||
const char *Ut_Suite::normal = "\033[0m";
|
||||
Fl_Simple_Terminal *Ut_Suite::tty = NULL;
|
||||
Fl_Terminal *Ut_Suite::tty = NULL;
|
||||
|
||||
/** Switch the user of color escape sequnces in the log text. */
|
||||
void Ut_Suite::color(int v) {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
class Fl_Simple_Terminal;
|
||||
class Fl_Terminal;
|
||||
|
||||
// WINDOW/WIDGET SIZES
|
||||
const int UT_MAINWIN_W = 700; // main window w()
|
||||
@ -153,7 +153,7 @@ public:
|
||||
static const char *red;
|
||||
static const char *green;
|
||||
static const char *normal;
|
||||
static Fl_Simple_Terminal *tty;
|
||||
static Fl_Terminal *tty;
|
||||
};
|
||||
|
||||
#define UT_CONCAT_(prefix, suffix) prefix##suffix
|
||||
|
@ -2,7 +2,7 @@
|
||||
version 1.0400
|
||||
header_name {.h}
|
||||
code_name {.cxx}
|
||||
decl {\#include <FL/Fl_Simple_Terminal.H>} {public global
|
||||
decl {\#include <FL/Fl_Terminal.H>} {public global
|
||||
}
|
||||
|
||||
Function {} {open
|
||||
@ -232,9 +232,9 @@ Function {} {open
|
||||
xywh {460 385 110 115} box BORDER_FRAME color 0 selection_color 0 labelsize 11 align 128
|
||||
}
|
||||
Fl_Box tty {selected
|
||||
xywh {10 513 560 117} color 0
|
||||
xywh {10 513 560 117} box DOWN_BOX color 0
|
||||
code0 {o->ansi(true);}
|
||||
class Fl_Simple_Terminal
|
||||
class Fl_Terminal
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,7 +242,7 @@ Function {} {open
|
||||
Function {callback(Fl_Widget* o, void*)} {open return_type void
|
||||
} {
|
||||
code {const char *name = (const char*)(o->user_data() ? o->user_data() : "???");
|
||||
tty->printf("callback(): %s value() = \\033[2m%g\\033[0m\\n",
|
||||
tty->printf("callback(): %s value() = \\033[1m%g\\033[0m\\n",
|
||||
name, ((Fl_Valuator*)o)->value());} {}
|
||||
}
|
||||
|
||||
@ -250,6 +250,6 @@ Function {callback_spinner(Fl_Widget* o, void*)} {
|
||||
comment {Spinner doesn't derive from Fl_Valuator..} open return_type void
|
||||
} {
|
||||
code {const char *name = (const char*)(o->user_data() ? o->user_data() : "???");
|
||||
tty->printf("callback(): %s value() = \\033[2m%g\\033[0m\\n",
|
||||
tty->printf("callback(): %s value() = \\033[1m%g\\033[0m\\n",
|
||||
name, ((Fl_Spinner*)o)->value());} {}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user