📄 adtrmbuf.pas
字号:
(***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is TurboPower Async Professional
*
* The Initial Developer of the Original Code is
* TurboPower Software
*
* Portions created by the Initial Developer are Copyright (C) 1991-2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** *)
{*********************************************************}
{* ADTRMBUF.PAS 4.06 *}
{*********************************************************}
{* Terminal: Screen buffer support class *}
{*********************************************************}
unit ADTrmBuf;
interface
{Notes: The TadTerminalArray class defines a matrix (rows by columns)
for storing a particular attribute of a terminal. The
attributes consist of
- the characters that should be shown on the screen
- the charset ids
- the colors for the characters
- the colors for the background
- a set of display flags (invisible, blink, etc)
The array class doesn't 'know' about the values it stores, it
just knows the size of the values (1, 2, or 4 bytes, default
1), and knows how to properly resize to take account of
changes in row or column count.
This class only knows about item sizes of 1, 2 or 4. The class
cannot be extended to other sizes that are not powers-of-two.
All row and column numbers are assumed to be zero-based. This
class is designed to be used internally by the terminal buffer
class. Consequently NO RANGE CHECKING IS DONE, unless the
unit is deliberately compiled with $R+.
A lot of methods have a case statement on the item size.
Although the code in each case switch block is duplicated, it
has been written like this to make the execution more
efficient. Multiplication by literal 2 or 4 is at least an
order of magnitude faster than multiplying by an object field
value.
The TAdTerminalBuffer class defines a buffer for storing the
data required to display a terminal display. Essentially, this
consists of
- the characters that should be shown on the screen
- the charset ids (word values)
- the color for the characters (TColor values)
- the color for the background (TColor values)
- a set of display flags (invisible, blink, etc) (bytes)
To make things more complex, the characters themselves can be
ANSI or wide/UNICODE.
There are two views of the data: the "scrollback view" and the
"display view". The scrollback view shows a history of
characters/attributes/etc that have scrolled off the top of
the display view. To make the access to the display view
easier, there is a pointer to the start of the displayed view.
There are typically more rows in the scrollback view than in
the display view (otherwise there wouldn't be anything to
scroll back through). The number of columns in both the
scrollback and display views is the same.
The methods implemented allow strings of characters to be
written to the buffer, colors to be set, attributes to be
defined. The class maintains a logical cursor and so also
supports cursor movement, scrolling, editing, and the like.
Notice that all row and column numbers external to this class
are assumed to be one-based. Internally to this class they
are zero-based for faster computation and are converted at the
entry/exit of the relevant routines. Also, externally, it is
only the display view that has positive row numbers. The
scrollback view uses negative numbers. For example, by default
there are 200 lines in the scrollback view and 24 lines in the
display view. Externally these would be known as rows -175..0
and 1..24, and internally as 0..175 and 176..199.
External row and column numbers generally refer to the current
scrolling region. If there is none, or it is inactive, the
external row and column numbers are counted from the upper
left corner (1, 1). If a scrolling region is in force,
external row and column numbers are counted from the upper
left corner of the scrolling region, not the whole display.
The row and column numbers are said to be relative to the
scrolling region, not absolute to the display as a whole.
Generally, the application sending control sequences to the
terminal will take account of this and there is nothing to
worry about. However, to simplify the coding of the redrawing
of the visual terminal, the methods that return an invalid
rect provide *absolute* row and column numbers, not relative
ones.
UseAutoWrap and UseAutoWrapDelay: automatic wrapping means
that characters being written to the screen automatically wrap
at the final column. For example, on an 80-column display if
we write 'abc' starting at column 79, then 'a' appears at
column 79, 'b' at col 80, and 'c' at col 1 on the next line.
If autowrap was off, the 'c' wouldn't appear or would
overwrite the 'b'. UseAutoWrapDelay encodes the behavior where
the text cursor doesn't move when you write a character at the
last column, it will only move when you write the next char.
So, if AutoWrap is on and UseAutoWrapDelay is off, writing
'abc' at column 79 would proceed as follows:
Write 'a' at 79, move cursor to 80
Write 'b' at 80, move cursor to 1 on the next line
Write 'c' at 1, move cursor to 2
With UseAutoWrapDelay on the following occurs:
Write 'a' at 79, move cursor to 80
Write 'b' at 80, do not move cursor
Move cursor to 1 on the next line, write 'c' at 1, move cursor
to 2
The important difference is that the cursor can move backwards
in the second case prior to attempting to write the 'c',
whereas in the first case it's too late. Note that
UseAutoWrapDelay is only used if AutoWrap is on. The internal
field used to store whether this case applies is the
FBeyondMargin boolean.
}
{$I AWDEFINE.INC}
{$Z-}
{$IFOPT R+}
{$DEFINE UseRangeChecks}
{$ENDIF}
uses
SysUtils,
{$IFDEF Win32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
Classes,
Graphics,
OOMisc, AdExcept;
const
{Buffer default property values}
adc_TermBufForeColor = clSilver;
adc_TermBufBackColor = clBlack;
adc_TermBufColCount = 80;
adc_TermBufRowCount = 24;
{$IFDEF Windows}
adc_TermBufScrollRowCount = 50;
{$ELSE}
adc_TermBufScrollRowCount = 200;
{$ENDIF}
adc_TermBufUseAbsAddress = true; {use absolute rows/col values}
adc_TermBufUseAutoWrap = true; {chars wrap at end of line}
adc_TermBufUseAutoWrapDelay = true; {..but delay slightly}
adc_TermBufUseInsertMode = false; {no insert mode}
adc_TermBufUseNewLineMode = false; {LF char is a pure linefeed}
adc_TermBufUseScrollRegion = false; {no scroll region used}
type
TadtWordArray = array [0..MaxInt div sizeof(word) - 1] of word;
PadtWordArray = ^TadtWordArray;
TadtLongArray = array [0..MaxInt div sizeof(longint) - 1] of longint;
PadtLongArray = ^TadtLongArray;
TAdTerminalCharAttr = ( {character attributes}
tcaBold, {..bold}
tcaUnderline, {..underlined}
tcaStrikethrough, {..struck through as if deleted}
tcaBlink, {..blinking}
tcaReverse, {..back/foreground colors reversed}
tcaInvisible, {..invisible}
tcaSelected); {..selected}
TAdTerminalCharAttrs = set of TAdTerminalCharAttr;
TAdScrollRowsNotifyEvent =
procedure (aSender : TObject;
aCount, aTop, aBottom : integer) of object;
TAdOnCursorMovedEvent =
procedure (ASender : TObject;
Row, Col : integer) of object;
TadTerminalArray = class
private
FActColCount : integer;
FColCount : integer;
FDefaultItem : longint;
FItems : PAnsiChar;
FItemSize : integer;
FRowCount : integer;
protected
procedure taSetColCount(aNewCount : integer);
procedure taSetRowCount(aNewCount : integer);
procedure taClearRows(aBuffer : PAnsiChar;
aActColCount : integer;
aStartRow, aEndRow : integer);
procedure taGrowArray(aRowCount,
aColCount, aActColCount : integer);
public
constructor Create(aItemSize : integer);
destructor Destroy; override;
procedure Clear;
{-clear the entire array, filling with DefaultItem}
procedure ClearItems(aRow : integer;
aFromCol, aToCol : integer);
{-clear the row in between the two inclusive columns, filling
with DefaultItem (equivalent to 'erase')}
procedure DeleteItems(aCount : integer;
aRow : integer;
aCol : integer);
{-delete aCount default items at aRow , aCol; items currently
beyond these positions are pulled left, and their original
positions filled with default items; this action does not
extend beyond the row}
function GetItemPtr(aRow, aCol : integer) : pointer;
{-return a pointer to the item at aRow, aCol; caller must
properly dereference, and not memory overread}
procedure InsertItems(aCount : integer;
aRow : integer;
aCol : integer);
{-insert aCount default items at aRow , aCol; items currently
in these positions are pushed right, but not beyond the row
boundary}
procedure ReplaceItems(aOldItem : pointer; {new !!.02}
aNewItem : pointer);
{-replace every incidence of aOldItem with aNewItem}
procedure SetDefaultItem(aDefaultItem : pointer);
{-define the default item to be used to fill new items, eg,
during scrolling, clearing or resizing}
procedure ScrollRows(aCount : integer;
aStartRow, aEndRow : integer);
{-scroll the data by aCount rows, filling new rows with
DefaultItem; scroll just between aStartRow and aEndRow
inclusive; if aCount is +ve it means scroll upwards (ie, the
usual sense), if -ve scroll downwards}
procedure WriteItems(aItems : pointer;
aCount : integer;
aRow, aCol : integer);
{-write aCount items to aRow, aCol, without wrapping at the
end of the row}
procedure WriteDupItems(aItem : pointer;
aCount : integer;
aRow, aCol : integer);
{-write aCount copies of aItem to aRow, aCol, without wrapping
at the end of the row}
property ColCount : integer read FColCount write taSetColCount;
property ItemSize : integer read FItemSize;
property RowCount : integer read FRowCount write taSetRowCount;
end;
type
TAdTerminalBuffer = class
private
FAttr : TAdTerminalCharAttrs; {current attributes}
FBackColor : TColor; {current background color}
FBeyondMargin : boolean; {true if cursor's beyond right margin}
FCharSet : byte; {current charset}
FColCount : integer; {count of columns in both views}
FCursorCol : integer; {current internal cursor col position}
FCursorMoved : boolean; {true if cursor has moved}
FCursorRow : integer; {current internal cursor row position}
FDefAnsiChar : AnsiChar; {default ANSI character}
FDefAttr : TAdTerminalCharAttrs; {default attributes}
FDefCharSet : byte; {default charset}
FDefBackColor : TColor; {default background color}
FDefForeColor : TColor; {default foreground color}
{$IFDEF Win32}
FDefWideChar : WideChar; {default wide character}
{$ENDIF}
FDisplayOriginCol : integer; {column origin of addressable area}
FDisplayOriginRow : integer; {row origin of addressable area}
FDisplayColCount : integer; {column count in addressable area}
FDisplayRowCount : integer; {row count in addressable area}
FForeColor : TColor; {current foreground color}
FHorzTabStops : PByteArray; {bitset of horizontal tab stops}
FInvRectList : pointer; {list of invalid rects}
FOnScrollRows : TAdScrollRowsNotifyEvent;
FRowCount : integer; {count of rows in display view}
FSRStartRow : integer; {start row of scrolling region}
FSREndRow : integer; {end row of scrolling region}
FSVRowCount : integer; {count of rows in scrollback view}
FUseAbsAddress: boolean; {true if absolute values for row/col}
FUseAutoWrap : boolean; {true if chars wrap to next line}
FUseAutoWrapDelay: boolean; {true if cursor stays at last col}
FUseInsertMode : boolean; {true if insert rather than replace}
FUseNewLineMode : boolean; {true if LF means CR+LF}
FUseScrollRegion : boolean; {true if limit to scroll region}
FUseWideChars : boolean; {true if expecting UNICODE chars}
FVertTabStops : PByteArray; {bitset of vertical tab stops}
FCharMatrix : TAdTerminalArray; {matrix of chars}
FCharSetMatrix: TAdTerminalArray; {matrix of charsets}
FAttrMatrix : TAdTerminalArray; {matrix of attrs}
FForeColorMatrix : TAdTerminalArray; {matrix of forecolors}
FBackColorMatrix : TAdTerminalArray; {matrix of backcolors}
FOnCursorMoved : TAdOnCursorMovedEvent; {Cursor moved event}
FTerminalHandle : THandle; {Handle of owning terminal} {!!.05}
protected
function tbGetCol : integer;
function tbGetOriginCol : integer;
function tbGetOriginRow : integer;
function tbGetRow : integer;
procedure tbSetBackColor(aValue : TColor);
procedure tbSetCharSet(aValue : byte);
procedure tbSetDefAnsiChar(aValue : AnsiChar);
procedure tbSetDefBackColor(aValue : TColor);
procedure tbSetDefForeColor(aValue : TColor);
procedure tbSetForeColor(aValue : TColor);
procedure tbSetSVRowCount(aNewCount : integer);
procedure tbSetCol(aCol : integer);
procedure tbSetColCount(aNewCount : integer);
procedure tbSetRow(aRow : integer);
procedure tbSetRowCount(aNewCount : integer);
procedure tbSetUseScrollRegion(aValue : boolean);
procedure tbInvalidateRect(aFromRow, aFromCol,
aToRow, aToCol : integer);
function tbCvtToInternalCol(aCol : integer;
aAbsolute : boolean) : integer;
function tbCvtToInternalRow(aRow : integer;
aAbsolute : boolean) : integer;
function tbCvtToExternalCol(aCol : integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -