home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS 1
/
BBS#1.iso
/
for-dos
/
newtvsrc.arj
/
VIEWS.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-04-04
|
97KB
|
3,902 lines
{*******************************************************}
{ }
{ Turbo Pascal Version 7.0 }
{ Turbo Vision Unit }
{ }
{ Copyright (c) 1992 Borland International }
{ Copyright (c) 1993 ACD Group }
{*******************************************************}
unit Views;
{$O+,F+,X+,I-,S-}
interface
uses Objects, Drivers, Memory;
const
{ TView State masks }
sfVisible = $0001;
sfCursorVis = $0002;
sfCursorIns = $0004;
sfShadow = $0008;
sfActive = $0010;
sfSelected = $0020;
sfFocused = $0040;
sfDragging = $0080;
sfDisabled = $0100;
sfModal = $0200;
sfDefault = $0400;
sfExposed = $0800;
{ TView Option masks }
ofSelectable = $0001;
ofTopSelect = $0002;
ofFirstClick = $0004;
ofFramed = $0008;
ofPreProcess = $0010;
ofPostProcess = $0020;
ofBuffered = $0040;
ofTileable = $0080;
ofCenterX = $0100;
ofCenterY = $0200;
ofCentered = $0300;
ofValidate = $0400;
ofVersion = $3000;
ofVersion10 = $0000;
ofVersion20 = $1000;
{ TView GrowMode masks }
gfGrowLoX = $01;
gfGrowLoY = $02;
gfGrowHiX = $04;
gfGrowHiY = $08;
gfGrowAll = $0F;
gfGrowRel = $10;
{ TView DragMode masks }
dmDragMove = $01;
dmDragGrow = $02;
dmLimitLoX = $10;
dmLimitLoY = $20;
dmLimitHiX = $40;
dmLimitHiY = $80;
dmLimitAll = $F0;
{ TView Help context codes }
hcNoContext = 0;
hcDragging = 1;
{ TScrollBar part codes }
sbLeftArrow = 0;
sbRightArrow = 1;
sbPageLeft = 2;
sbPageRight = 3;
sbUpArrow = 4;
sbDownArrow = 5;
sbPageUp = 6;
sbPageDown = 7;
sbIndicator = 8;
{ TScrollBar options for TWindow.StandardScrollBar }
sbHorizontal = $0000;
sbVertical = $0001;
sbHandleKeyboard = $0002;
{ TWindow Flags masks }
wfMove = $01;
wfGrow = $02;
wfClose = $04;
wfZoom = $08;
wfBottomLine = $10;
{ TWindow number constants }
wnNoNumber = 0;
{ TWindow palette entries }
wpBlueWindow = 0;
wpCyanWindow = 1;
wpGrayWindow = 2;
{ Standard command codes }
cmValid = 0;
cmQuit = 1;
cmError = 2;
cmMenu = 3;
cmClose = 4;
cmZoom = 5;
cmResize = 6;
cmNext = 7;
cmPrev = 8;
cmHelp = 9;
{ Application command codes }
cmCut = 20;
cmCopy = 21;
cmPaste = 22;
cmUndo = 23;
cmClear = 24;
cmTile = 25;
cmCascade = 26;
{ TDialog standard commands }
cmOK = 10;
cmCancel = 11;
cmYes = 12;
cmNo = 13;
cmDefault = 14;
{ Standard messages }
cmReceivedFocus = 50;
cmReleasedFocus = 51;
cmCommandSetChanged = 52;
{ TScrollBar messages }
cmScrollBarChanged = 53;
cmScrollBarClicked = 54;
{ TWindow select messages }
cmSelectWindowNum = 55;
{ TWindow popup-menu message }
cmWindowMenu = 57;
{ TListViewer messages }
cmListItemSelected = 56;
{ Color palettes }
CFrame = #1#9#2#10#3;
CScrollBar = #4#5#5;
CScroller = #6#7;
CListViewer = #36#36#37#38#39;
CBlueWindow = #8#9#10#11#12#13#14#15#129#130#2#3#4#5#6#7;
CCyanWindow = #16#17#18#19#20#21#22#23#131#132#2#3#4#5#6#7;
CGrayWindow = #24#25#26#27#28#29#30#31#133#134#2#3#4#5#6#7;
{ TDrawBuffer maximum view width }
MaxViewWidth = 132;
type
{ Command sets }
PCommandSet = ^TCommandSet;
TCommandSet = set of Byte;
{ Color palette type }
PPalette = ^TPalette;
TPalette = String;
{ TDrawBuffer, buffer used by draw methods }
TDrawBuffer = array[0..MaxViewWidth - 1] of Word;
{ TView object Pointer }
PView = ^TView;
{ TGroup object Pointer }
PGroup = ^TGroup;
{ TView object }
TView = object(TObject)
Owner: PGroup;
Next: PView;
Origin: TPoint;
Size: TPoint;
Cursor: TPoint;
GrowMode: Byte;
DragMode: Byte;
HelpCtx: Word;
State: Word;
Options: Word;
EventMask: Word;
constructor Init(var Bounds: TRect);
constructor Load(var S: TStream);
destructor Done; virtual;
procedure Awaken; virtual;
procedure BlockCursor;
procedure CalcBounds(var Bounds: TRect; Delta: TPoint); virtual;
procedure ChangeBounds(var Bounds: TRect); virtual;
procedure ClearEvent(var Event: TEvent);
function CommandEnabled(Command: Word): Boolean;
function DataSize: Word; virtual;
procedure DisableCommands(Commands: TCommandSet);
procedure DragView(Event: TEvent; Mode: Byte;
var Limits: TRect; MinSize, MaxSize: TPoint);
procedure Draw; virtual;
procedure DrawView;
procedure EnableCommands(Commands: TCommandSet);
procedure EndModal(Command: Word); virtual;
function EventAvail: Boolean;
function Execute: Word; virtual;
function Exposed: Boolean;
function Focus: Boolean;
procedure GetBounds(var Bounds: TRect);
procedure GetClipRect(var Clip: TRect);
function GetColor(Color: Word): Word;
procedure GetCommands(var Commands: TCommandSet);
procedure GetData(var Rec); virtual;
procedure GetEvent(var Event: TEvent); virtual;
procedure GetExtent(var Extent: TRect);
function GetHelpCtx: Word; virtual;
function GetPalette: PPalette; virtual;
procedure GetPeerViewPtr(var S: TStream; var P);
function GetState(AState: Word): Boolean;
procedure GrowTo(X, Y: Integer);
procedure HandleEvent(var Event: TEvent); virtual;
procedure Hide;
procedure HideCursor;
procedure KeyEvent(var Event: TEvent);
procedure Locate(var Bounds: TRect);
procedure MakeFirst;
procedure MakeGlobal(Source: TPoint; var Dest: TPoint);
procedure MakeLocal(Source: TPoint; var Dest: TPoint);
function MouseEvent(var Event: TEvent; Mask: Word): Boolean;
function MouseInView(Mouse: TPoint): Boolean;
procedure MoveTo(X, Y: Integer);
function NextView: PView;
procedure NormalCursor;
function Prev: PView;
function PrevView: PView;
procedure PutEvent(var Event: TEvent); virtual;
procedure PutInFrontOf(Target: PView);
procedure PutPeerViewPtr(var S: TStream; P: PView);
procedure Select;
procedure SetBounds(var Bounds: TRect);
procedure SetCommands(Commands: TCommandSet);
procedure SetCmdState(Commands: TCommandSet; Enable: Boolean);
procedure SetCursor(X, Y: Integer);
procedure SetData(var Rec); virtual;
procedure SetState(AState: Word; Enable: Boolean); virtual;
procedure Show;
procedure ShowCursor;
procedure SizeLimits(var Min, Max: TPoint); virtual;
procedure Store(var S: TStream);
function TopView: PView;
function Valid(Command: Word): Boolean; virtual;
procedure WriteBuf(X, Y, W, H: Integer; var Buf);
procedure WriteChar(X, Y: Integer; C: Char; Color: Byte;
Count: Integer);
procedure WriteLine(X, Y, W, H: Integer; var Buf);
procedure WriteStr(X, Y: Integer; Str: String; Color: Byte);
private
procedure DrawCursor;
procedure DrawHide(LastView: PView);
procedure DrawShow(LastView: PView);
procedure DrawUnderRect(var R: TRect; LastView: PView);
procedure DrawUnderView(DoShadow: Boolean; LastView: PView);
procedure ResetCursor; virtual;
end;
{ TFrame types }
TTitleStr = string[80];
{ TFrame object }
{ Palette layout }
{ 1 = Passive frame }
{ 2 = Passive title }
{ 3 = Active frame }
{ 4 = Active title }
{ 5 = Icons }
PFrame = ^TFrame;
TFrame = object(TView)
constructor Init(var Bounds: TRect);
procedure Draw; virtual;
function GetPalette: PPalette; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure SetState(AState: Word; Enable: Boolean); virtual;
private
FrameMode: Word;
procedure FrameLine(var FrameBuf; Y, N: Integer; Color: Byte); virtual;
end;
{ ScrollBar characters }
TScrollChars = array[0..9] of Char;
{ TScrollBar object }
{ Palette layout }
{ 1 = Page areas }
{ 2 = Arrows }
{ 3 = Indicator }
PScrollBar = ^TScrollBar;
TScrollBar = object(TView)
Value: Integer;
Min: Integer;
Max: Integer;
PgStep: Integer;
ArStep: Integer;
constructor Init(var Bounds: TRect);
constructor Load(var S: TStream);
procedure Draw; virtual;
function GetPalette: PPalette; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure ScrollDraw; virtual;
function ScrollStep(Part: Integer): Integer; virtual;
procedure SetParams(AValue, AMin, AMax, APgStep, AArStep: Integer);
procedure SetRange(AMin, AMax: Integer);
procedure SetState(AState: Word; Enable: Boolean); virtual;
procedure SetStep(APgStep, AArStep: Integer);
procedure SetValue(AValue: Integer);
procedure Store(var S: TStream);
private
Chars: TScrollChars;
PrevSize: TPoint;
procedure DrawPos(Pos: Integer);
function GetPos: Integer;
function GetSize: Integer;
end;
{ TScroller object }
{ Palette layout }
{ 1 = Normal text }
{ 2 = Selected text }
PScroller = ^TScroller;
TScroller = object(TView)
HScrollBar: PScrollBar;
VScrollBar: PScrollBar;
Delta: TPoint;
Limit: TPoint;
constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
constructor Load(var S: TStream);
procedure ChangeBounds(var Bounds: TRect); virtual;
function GetPalette: PPalette; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure ScrollDraw; virtual;
procedure ScrollTo(X, Y: Integer);
procedure SetLimit(X, Y: Integer);
procedure SetState(AState: Word; Enable: Boolean); virtual;
procedure Store(var S: TStream);
private
DrawLock: Byte;
DrawFlag: Boolean;
procedure CheckDraw;
end;
{ TListViewer }
{ Palette layout }
{ 1 = Active }
{ 2 = Inactive }
{ 3 = Focused }
{ 4 = Selected }
{ 5 = Divider }
PListViewer = ^TListViewer;
TListViewer = object(TView)
HScrollBar: PScrollBar;
VScrollBar: PScrollBar;
NumCols: Integer;
TopItem: Integer;
Focused: Integer;
Range: Integer;
constructor Init(var Bounds: TRect; ANumCols: Word;
AHScrollBar, AVScrollBar: PScrollBar);
constructor Load(var S: TStream);
procedure ChangeBounds(var Bounds: TRect); virtual;
procedure Draw; virtual;
procedure FocusItem(Item: Integer); virtual;
function GetPalette: PPalette; virtual;
function GetText(Item: Integer; MaxLen: Integer): String; virtual;
function IsSelected(Item: Integer): Boolean; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure SelectItem(Item: Integer); virtual;
procedure SetRange(ARange: Integer);
procedure SetState(AState: Word; Enable: Boolean); virtual;
procedure Store(var S: TStream);
private
procedure FocusItemNum(Item: Integer); virtual;
end;
{ Video buffer }
PVideoBuf = ^TVideoBuf;
TVideoBuf = array[0..3999] of Word;
{ Selection modes }
SelectMode = (NormalSelect, EnterSelect, LeaveSelect);
{ TGroup object }
TGroup = object(TView)
Last: PView;
Current: PView;
Phase: (phFocused, phPreProcess, phPostProcess);
Buffer: PVideoBuf;
EndState: Word;
constructor Init(var Bounds: TRect);
constructor Load(var S: TStream);
destructor Done; virtual;
procedure Awaken; virtual;
procedure ChangeBounds(var Bounds: TRect); virtual;
function DataSize: Word; virtual;
procedure Delete(P: PView);
procedure Draw; virtual;
procedure EndModal(Command: Word); virtual;
procedure EventError(var Event: TEvent); virtual;
function ExecView(P: PView): Word;
function Execute: Word; virtual;
function First: PView;
function FirstThat(P: Pointer): PView;
function FocusNext(Forwards: Boolean): Boolean;
procedure ForEach(P: Pointer);
procedure GetData(var Rec); virtual;
function GetHelpCtx: Word; virtual;
procedure GetSubViewPtr(var S: TStream; var P);
procedure HandleEvent(var Event: TEvent); virtual;
procedure Insert(P: PView);
procedure InsertBefore(P, Target: PView);
procedure Lock;
procedure PutSubViewPtr(var S: TStream; P: PView);
procedure Redraw;
procedure SelectNext(Forwards: Boolean);
procedure SetData(var Rec); virtual;
procedure SetState(AState: Word; Enable: Boolean); virtual;
procedure Store(var S: TStream);
procedure Unlock;
function Valid(Command: Word): Boolean; virtual;
private
Clip: TRect;
LockFlag: Byte;
function At(Index: Integer): PView;
procedure DrawSubViews(P, Bottom: PView);
function FirstMatch(AState: Word; AOptions: Word): PView;
function FindNext(Forwards: Boolean): PView;
procedure FreeBuffer;
procedure GetBuffer;
function IndexOf(P: PView): Integer;
procedure InsertView(P, Target: PView);
procedure RemoveView(P: PView);
procedure ResetCurrent;
procedure ResetCursor; virtual;
procedure SetCurrent(P: PView; Mode: SelectMode);
end;
{ TWindow object }
{ Palette layout }
{ 1 = Frame passive }
{ 2 = Frame active }
{ 3 = Frame icon }
{ 4 = ScrollBar page area }
{ 5 = ScrollBar controls }
{ 6 = Scroller normal text }
{ 7 = Scroller selected text }
{ 8 = Reserved }
PWindow = ^TWindow;
TWindow = object(TGroup)
Flags: Byte;
ZoomRect: TRect;
Number: Integer;
Palette: Integer;
Frame: PFrame;
Title: PString;
constructor Init(var Bounds: TRect; ATitle: TTitleStr; ANumber: Integer);
constructor Load(var S: TStream);
destructor Done; virtual;
procedure Close; virtual;
function GetPalette: PPalette; virtual;
function GetTitle(MaxSize: Integer): TTitleStr; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure InitFrame; virtual;
procedure SetState(AState: Word; Enable: Boolean); virtual;
procedure SizeLimits(var Min, Max: TPoint); virtual;
function StandardScrollBar(AOptions: Word): PScrollBar;
procedure Store(var S: TStream);
procedure Zoom; virtual;
end;
{ Message dispatch function }
function Message(Receiver: PView; What, Command: Word;
InfoPtr: Pointer): Pointer;
{ Views registration procedure }
procedure RegisterViews;
const
{ Event masks }
PositionalEvents: Word = evMouse;
FocusedEvents: Word = evKeyboard + evCommand;
{ Minimum window size }
MinWinSize: TPoint = (X: 16; Y: 6);
{ Shadow definitions }
ShadowSize: TPoint = (X: 2; Y: 1);
ShadowAttr: Byte = $08;
{ Markers control }
ShowMarkers: Boolean = False;
{ MapColor error return value }
ErrorAttr: Byte = $CF;
{ Stream Registration Records }
const
RView: TStreamRec = (
ObjType: 1;
VmtLink: Ofs(TypeOf(TView)^);
Load: @TView.Load;
Store: @TView.Store
);
const
RFrame: TStreamRec = (
ObjType: 2;
VmtLink: Ofs(TypeOf(TFrame)^);
Load: @TFrame.Load;
Store: @TFrame.Store
);
const
RScrollBar: TStreamRec = (
ObjType: 3;
VmtLink: Ofs(TypeOf(TScrollBar)^);
Load: @TScrollBar.Load;
Store: @TScrollBar.Store
);
const
RScroller: TStreamRec = (
ObjType: 4;
VmtLink: Ofs(TypeOf(TScroller)^);
Load: @TScroller.Load;
Store: @TScroller.Store
);
const
RListViewer: TStreamRec = (
ObjType: 5;
VmtLink: Ofs(TypeOf(TListViewer)^);
Load: @TListViewer.Load;
Store: @TLIstViewer.Store
);
const
RGroup: TStreamRec = (
ObjType: 6;
VmtLink: Ofs(TypeOf(TGroup)^);
Load: @TGroup.Load;
Store: @TGroup.Store
);
const
RWindow: TStreamRec = (
ObjType: 7;
VmtLink: Ofs(TypeOf(TWindow)^);
Load: @TWindow.Load;
Store: @TWindow.Store
);
{ Characters used for drawing selected and default items in }
{ monochrome color sets }
SpecialChars: array[0..5] of Char = (#16, #17, #26, #27, ' ', ' ');
{ True if the command set has changed since being set to false }
CommandSetChanged: Boolean = False;
procedure InvertColor(var Color: Byte);
implementation
uses
Menus;
type
PFixupList = ^TFixupList;
TFixupList = array[1..4096] of Pointer;
const
OwnerGroup: PGroup = nil;
FixupList: PFixupList = nil;
TheTopView: PView = nil;
const
{ Bit flags to determine how to draw the frame icons }
fmCloseClicked = $0001;
fmZoomClicked = $0002;
{ Current command set. All but window commands are active by default }
CurCommandSet: TCommandSet =
[0..255] - [cmZoom, cmClose, cmResize, cmNext, cmPrev];
{ Convert color into attribute }
{ In AL = Color }
{ Out AL = Attribute }
procedure MapColor; near; assembler;
const
Self = 6;
TView_GetPalette = vmtHeaderSize + $2C;
asm
OR AL,AL
JE @@3
LES DI,[BP].Self
@@1: PUSH ES
PUSH DI
PUSH AX
PUSH ES
PUSH DI
MOV DI,ES:[DI]
CALL DWORD PTR [DI].TView_GetPalette
MOV BX,AX
MOV ES,DX
OR AX,DX
POP AX
POP DI
POP DX
JE @@2
CMP AL,ES:[BX]
JA @@3
SEGES XLAT
OR AL,AL
JE @@3
@@2: MOV ES,DX
LES DI,ES:[DI].TView.Owner
MOV SI,ES
OR SI,DI
JNE @@1
JMP @@4
@@3: MOV AL,ErrorAttr
@@4:
end;
{ Convert color pair into attribute pair }
{ In AX = Color pair }
{ Out AX = Attribute pair }
procedure MapCPair; near; assembler;
asm
OR AH,AH
JE @@1
XCHG AL,AH
CALL MapColor
XCHG AL,AH
@@1: CALL MapColor
end;
{ Write to view }
{ In AX = Y coordinate }
{ BX = X coordinate }
{ CX = Count }
{ ES:DI = Buffer Pointer }
procedure WriteView; near; assembler;
const
Self = 6;
Target = -4;
Buffer = -8;
BufOfs = -10;
MW1: TPoint = (X:0;Y:0);
asm
PUSH AX
MOV AX,MouseWhere.X
INC AX
MOV MW1.X,AX
MOV AX,MouseWhere.Y
INC AX
MOV MW1.Y,AX
POP AX
MOV [BP].BufOfs,BX
MOV [BP].Buffer[0],DI
MOV [BP].Buffer[2],ES
ADD CX,BX
XOR DX,DX
LES DI,[BP].Self
OR AX,AX
JL @@3
CMP AX,ES:[DI].TView.Size.Y
JGE @@3
OR BX,BX
JGE @@1
XOR BX,BX
@@1: CMP CX,ES:[DI].TView.Size.X
JLE @@2
MOV CX,ES:[DI].TView.Size.X
@@2: CMP BX,CX
JL @@10
@@3: RET
@@10: TEST ES:[DI].TView.State,sfVisible
JE @@3
CMP ES:[DI].TView.Owner.Word[2],0
JE @@3
MOV [BP].Target[0],DI
MOV [BP].Target[2],ES
ADD AX,ES:[DI].TView.Origin.Y
MOV SI,ES:[DI].TView.Origin.X
ADD BX,SI
ADD CX,SI
ADD [BP].BufOfs,SI
LES DI,ES:[DI].TView.Owner
CMP AX,ES:[DI].TGroup.Clip.A.Y
JL @@3
CMP AX,ES:[DI].TGroup.Clip.B.Y
JGE @@3
CMP BX,ES:[DI].TGroup.Clip.A.X
JGE @@11
MOV BX,ES:[DI].TGroup.Clip.A.X
@@11: CMP CX,ES:[DI].TGroup.Clip.B.X
JLE @@12
MOV CX,ES:[DI].TGroup.Clip.B.X
@@12: CMP BX,CX
JGE @@3
LES DI,ES:[DI].TGroup.Last
@@20: LES DI,ES:[DI].TView.Next
CMP DI,[BP].Target[0]
JNE @@21
MOV SI,ES
CMP SI,[BP].Target[2]
JNE @@21
JMP @@40
@@21: TEST ES:[DI].TView.State,sfVisible
JE @@20
MOV SI,ES:[DI].TView.Origin.Y
CMP AX,SI
JL @@20
ADD SI,ES:[DI].TView.Size.Y
CMP AX,SI
JL @@23
TEST ES:[DI].TView.State,sfShadow
JE @@20
ADD SI,ShadowSize.Y
CMP AX,SI
JGE @@20
MOV SI,ES:[DI].TView.Origin.X
ADD SI,ShadowSize.X
CMP BX,SI
JGE @@22
CMP CX,SI
JLE @@20
CALL @@30
@@22: ADD SI,ES:[DI].TView.Size.X
JMP @@26
@@23: MOV SI,ES:[DI].TView.Origin.X
CMP BX,SI
JGE @@24
CMP CX,SI
JLE @@20
CALL @@30
@@24: ADD SI,ES:[DI].TView.Size.X
CMP BX,SI
JGE @@25
CMP CX,SI
JLE @@31
MOV BX,SI
@@25: TEST ES:[DI].TView.State,sfShadow
JE @@20
PUSH SI
MOV SI,ES:[DI].TView.Origin.Y
ADD SI,ShadowSize.Y
CMP AX,SI
POP SI
JL @@27
ADD SI,ShadowSize.X
@@26: CMP BX,SI
JGE @@27
INC DX
CMP CX,SI
JLE @@27
CALL @@30
DEC DX
@@27: JMP @@20
@@30: PUSH [BP].Target.Word[2]
PUSH [BP].Target.Word[0]
PUSH [BP].BufOfs.Word[0]
PUSH ES
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH AX
MOV CX,SI
CALL @@20
POP AX
POP CX
POP DX
POP SI
POP DI
POP ES
POP [BP].BufOfs.Word[0]
POP [BP].Target.Word[0]
POP [BP].Target.Word[2]
MOV BX,SI
@@31: RET
@@40: LES DI,ES:[DI].TView.Owner
MOV SI,ES:[DI].TGroup.Buffer.Word[2]
OR SI,SI
JE @@44
CMP SI,ScreenBuffer.Word[2]
JE @@41
CALL @@50
JMP @@44
@@41: CLI
CMP AX,MouseWhere.Y
JE @@101
CMP AX,MW1.Y
JNE @@42
@@101: CMP BX,MW1.X
JA @@42
CMP CX,MouseWhere.X
JA @@43
@@42: MOV MouseIntFlag,0
STI
CALL @@50
CMP MouseIntFlag,0
JE @@44
@@43: STI
CALL HideMouse
CALL @@50
CALL ShowMouse
@@44: CMP ES:[DI].TGroup.LockFlag,0
JNE @@31
JMP @@10
@@50: PUSH ES
PUSH DS
PUSH DI
PUSH CX
PUSH AX
MUL ES:[DI].TView.Size.X.Byte[0]
ADD AX,BX
SHL AX,1
ADD AX,ES:[DI].TGroup.Buffer.Word[0]
MOV DI,AX
MOV ES,SI
XOR AL,AL
CMP SI,ScreenBuffer.Word[2]
JNE @@51
MOV AL,CheckSnow
@@51: MOV AH,ShadowAttr
SUB CX,BX
MOV SI,BX
SUB SI,[BP].BufOfs
SHL SI,1
ADD SI,[BP].Buffer.Word[0]
MOV DS,[BP].Buffer.Word[2]
CLD
OR AL,AL
JNE @@60
OR DX,DX
JNE @@52
REP MOVSW
JMP @@70
@@52: LODSB
INC SI
STOSW
LOOP @@52
JMP @@70
@@60: PUSH DX
PUSH BX
OR DX,DX
MOV DX,03DAH
JNE @@65
@@61: LODSW
MOV BX,AX
@@62: IN AL,DX
TEST AL,1
JNE @@62
CLI
@@63: IN AL,DX
TEST AL,1
JE @@63
MOV AX,BX
STOSW
STI
LOOP @@61
JMP @@68
@@65: LODSB
MOV BL,AL
INC SI
@@66: IN AL,DX
TEST AL,1
JNE @@66
CLI
@@67: IN AL,DX
TEST AL,1
JE @@67
MOV AL,BL
STOSW
STI
LOOP @@65
@@68: POP BX
POP DX
@@70: MOV SI,ES
POP AX
POP CX
POP DI
POP DS
POP ES
RET
end;
{ TView }
constructor TView.Init(var Bounds: TRect);
begin
TObject.Init;
Owner := nil;
State := sfVisible;
SetBounds(Bounds);
DragMode := dmLimitLoY;
HelpCtx := hcNoContext;
EventMask := evMouseDown + evKeyDown + evCommand;
end;
constructor TView.Load(var S: TStream);
begin
TObject.Init;
S.Read(Origin,
SizeOf(TPoint) * 3 +
SizeOf(Byte) * 2 +
SizeOf(Word) * 4);
end;
destructor TView.Done;
begin
Hide;
if Owner <> nil then Owner^.Delete(@Self);
end;
procedure TView.Awaken;
begin
end;
procedure TView.BlockCursor;
begin
SetState(sfCursorIns, True);
end;
procedure TView.CalcBounds(var Bounds: TRect; Delta: TPoint);
var
S, D: Integer;
Min, Max: TPoint;
procedure Grow(var I: Integer);
begin
if GrowMode and gfGrowRel = 0 then Inc(I, D) else
I := (I * S + (S - D) shr 1) div (S - D);
end;
function Range(Val, Min, Max: Integer): Integer;
begin
if Val < Min then Range := Min else
if Val > Max then Range := Max else
Range := Val;
end;
begin
GetBounds(Bounds);
S := Owner^.Size.X;
D := Delta.X;
if GrowMode and gfGrowLoX <> 0 then Grow(Bounds.A.X);
if GrowMode and gfGrowHiX <> 0 then Grow(Bounds.B.X);
if Bounds.B.X - Bounds.A.X > MaxViewWidth then
Bounds.B.X := Bounds.A.X + MaxViewWidth;
S := Owner^.Size.Y;
D := Delta.Y;
if GrowMode and gfGrowLoY <> 0 then Grow(Bounds.A.Y);
if GrowMode and gfGrowHiY <> 0 then Grow(Bounds.B.Y);
SizeLimits(Min, Max);
Bounds.B.X := Bounds.A.X + Range(Bounds.B.X - Bounds.A.X, Min.X, Max.X);
Bounds.B.Y := Bounds.A.Y + Range(Bounds.B.Y - Bounds.A.Y, Min.Y, Max.Y);
end;
procedure TView.ChangeBounds(var Bounds: TRect);
begin
SetBounds(Bounds);
DrawView;
end;
procedure TView.ClearEvent(var Event: TEvent);
begin
Event.What := evNothing;
Event.InfoPtr := @Self;
end;
function TView.CommandEnabled(Command: Word): Boolean;
begin
CommandEnabled := (Command > 255) or (Command in CurCommandSet);
end;
function TView.DataSize: Word;
begin
DataSize := 0;
end;
procedure TView.DisableCommands(Commands: TCommandSet);
begin
CommandSetChanged := CommandSetChanged or (CurCommandSet * Commands <> []);
CurCommandSet := CurCommandSet - Commands;
end;
procedure TView.DragView(Event: TEvent; Mode: Byte;
var Limits: TRect; MinSize, MaxSize: TPoint);
var
P, S: TPoint;
SaveBounds: TRect;
function Min(I, J: Integer): Integer;
begin
if I < J then Min := I else Min := J;
end;
function Max(I, J: Integer): Integer;
begin
if I > J then Max := I else Max := J;
end;
procedure MoveGrow(P, S: TPoint);
var
R: TRect;
begin
S.X := Min(Max(S.X, MinSize.X), MaxSize.X);
S.Y := Min(Max(S.Y, MinSize.Y), MaxSize.Y);
P.X := Min(Max(P.X, Limits.A.X - S.X + 1), Limits.B.X - 1);
P.Y := Min(Max(P.Y, Limits.A.Y - S.Y + 1), Limits.B.Y - 1);
if Mode and dmLimitLoX <> 0 then P.X := Max(P.X, Limits.A.X);
if Mode and dmLimitLoY <> 0 then P.Y := Max(P.Y, Limits.A.Y);
if Mode and dmLimitHiX <> 0 then P.X := Min(P.X, Limits.B.X - S.X);
if Mode and dmLimitHiY <> 0 then P.Y := Min(P.Y, Limits.B.Y - S.Y);
R.Assign(P.X, P.Y, P.X + S.X, P.Y + S.Y);
Locate(R);
end;
procedure Change(DX, DY: Integer);
begin
if (Mode and dmDragMove <> 0) and (GetShiftState and $03 = 0) then
begin
Inc(P.X, DX);
Inc(P.Y, DY);
end else
if (Mode and dmDragGrow <> 0) and (GetShiftState and $03 <> 0) then
begin
Inc(S.X, DX);
Inc(S.Y, DY);
end;
end;
procedure Update(X, Y: Integer);
begin
if Mode and dmDragMove <> 0 then
begin
P.X := X;
P.Y := Y;
end;
end;
begin
SetState(sfDragging, True);
if Event.What = evMouseDown then
begin
if Mode and dmDragMove <> 0 then
begin
P.X := Origin.X - Event.Where.X;
P.Y := Origin.Y - Event.Where.Y;
repeat
Inc(Event.Where.X, P.X);
Inc(Event.Where.Y, P.Y);
MoveGrow(Event.Where, Size);
until not MouseEvent(Event, evMouseMove);
end else
begin
P.X := Size.X - Event.Where.X;
P.Y := Size.Y - Event.Where.Y;
repeat
Inc(Event.Where.X, P.X);
Inc(Event.Where.Y, P.Y);
MoveGrow(Origin, Event.Where);
until not MouseEvent(Event, evMouseMove);
end;
end else
begin
GetBounds(SaveBounds);
repeat
P := Origin;
S := Size;
KeyEvent(Event);
case Event.KeyCode and $FF00 of
kbLeft: Change(-1, 0);
kbRight: Change(1, 0);
kbUp: Change(0, -1);
kbDown: Change(0, 1);
kbCtrlLeft: Change(-8, 0);
kbCtrlRight: Change(8, 0);
kbHome: Update(Limits.A.X, P.Y);
kbEnd: Update(Limits.B.X - S.X, P.Y);
kbPgUp: Update(P.X, Limits.A.Y);
kbPgDn: Update(P.X, Limits.B.Y - S.Y);
end;
MoveGrow(P, S);
until (Event.KeyCode = kbEnter) or (Event.KeyCode = kbEsc);
if Event.KeyCode = kbEsc then Locate(SaveBounds);
end;
SetState(sfDragging, False);
end;
procedure TView.Draw;
var
B: TDrawBuffer;
begin
MoveChar(B, ' ', GetColor(1), Size.X);
WriteLine(0, 0, Size.X, Size.Y, B);
end;
procedure TView.DrawCursor;
begin
if State and sfFocused <> 0 then ResetCursor;
end;
procedure TView.DrawHide(LastView: PView);
begin
DrawCursor;
DrawUnderView(State and sfShadow <> 0, LastView);
end;
procedure TView.DrawShow(LastView: PView);
begin
DrawView;
if State and sfShadow <> 0 then DrawUnderView(True, LastView);
end;
procedure TView.DrawUnderRect(var R: TRect; LastView: PView);
begin
Owner^.Clip.Intersect(R);
Owner^.DrawSubViews(NextView, LastView);
Owner^.GetExtent(Owner^.Clip);
end;
procedure TView.DrawUnderView(DoShadow: Boolean; LastView: PView);
var
R: TRect;
begin
GetBounds(R);
if DoShadow then
begin
Inc(R.B.X, ShadowSize.X);
Inc(R.B.Y, ShadowSize.Y);
end;
DrawUnderRect(R, LastView);
end;
procedure TView.DrawView;
begin
if Exposed then
begin
Draw;
DrawCursor;
end;
end;
procedure TView.EnableCommands(Commands: TCommandSet);
begin
CommandSetChanged := CommandSetChanged or
(CurCommandSet * Commands <> Commands);
CurCommandSet := CurCommandSet + Commands;
end;
procedure TView.EndModal(Command: Word);
var
P: PView;
begin
P := TopView;
if TopView <> nil then TopView^.EndModal(Command);
end;
function TView.EventAvail: Boolean;
var
Event: TEvent;
begin
GetEvent(Event);
if Event.What <> evNothing then PutEvent(Event);
EventAvail := Event.What <> evNothing;
end;
procedure TView.GetBounds(var Bounds: TRect); assembler;
asm
PUSH DS
LDS SI,Self
ADD SI,OFFSET TView.Origin
LES DI,Bounds
CLD
LODSW {Origin.X}
MOV CX,AX
STOSW
LODSW {Origin.Y}
MOV DX,AX
STOSW
LODSW {Size.X}
ADD AX,CX
STOSW
LODSW {Size.Y}
ADD AX,DX
STOSW
POP DS
end;
function TView.Execute: Word;
begin
Execute := cmCancel;
end;
function TView.Exposed: Boolean; assembler;
var
Target: Pointer;
asm
LES DI,Self
TEST ES:[DI].TView.State,sfExposed
JE @@2
XOR AX,AX
CMP AX,ES:[DI].TView.Size.X
JGE @@2
CMP AX,ES:[DI].TView.Size.Y
JGE @@2
@@1: XOR BX,BX
MOV CX,ES:[DI].TView.Size.X
PUSH AX
CALL @@11
POP AX
JNC @@3
LES DI,Self
INC AX
CMP AX,ES:[DI].TView.Size.Y
JL @@1
@@2: MOV AL,0
JMP @@30
@@3: MOV AL,1
JMP @@30
@@8: STC
@@9: RETN
@@10: LES DI,ES:[DI].TView.Owner
CMP ES:[DI].TGroup.Buffer.Word[2],0
JNE @@9
@@11: MOV Target.Word[0],DI
MOV Target.Word[2],ES
ADD AX,ES:[DI].TView.Origin.Y
MOV SI,ES:[DI].TView.Origin.X
ADD BX,SI
ADD CX,SI
LES DI,ES:[DI].TView.Owner
MOV SI,ES
OR SI,DI
JE @@9
CMP AX,ES:[DI].TGroup.Clip.A.Y
JL @@8
CMP AX,ES:[DI].TGroup.Clip.B.Y
JGE @@8
CMP BX,ES:[DI].TGroup.Clip.A.X
JGE @@12
MOV BX,ES:[DI].TGroup.Clip.A.X
@@12: CMP CX,ES:[DI].TGroup.Clip.B.X
JLE @@13
MOV CX,ES:[DI].TGroup.Clip.B.X
@@13: CMP BX,CX
JGE @@8
LES DI,ES:[DI].TGroup.Last
@@20: LES DI,ES:[DI].TView.Next
CMP DI,Target.Word[0]
JNE @@21
MOV SI,ES
CMP SI,Target.Word[2]
JE @@10
@@21: TEST ES:[DI].TView.State,sfVisible
JE @@20
MOV SI,ES:[DI].TView.Origin.Y
CMP AX,SI
JL @@20
ADD SI,ES:[DI].TView.Size.Y
CMP AX,SI
JGE @@20
MOV SI,ES:[DI].TView.Origin.X
CMP BX,SI
JL @@22
ADD SI,ES:[DI].TView.Size.X
CMP BX,SI
JGE @@20
MOV BX,SI
CMP BX,CX
JL @@20
STC
RETN
@@22: CMP CX,SI
JLE @@20
ADD SI,ES:[DI].TView.Size.X
CMP CX,SI
JG @@23
MOV CX,ES:[DI].TView.Origin.X
JMP @@20
@@23: PUSH Target.Word[2]
PUSH Target.Word[0]
PUSH ES
PUSH DI
PUSH SI
PUSH CX
PUSH AX
MOV CX,ES:[DI].TView.Origin.X
CALL @@20
POP AX
POP CX
POP BX
POP DI
POP ES
POP Target.Word[0]
POP Target.Word[2]
JC @@20
RETN
@@30:
end;
function TView.Focus: Boolean;
var
Result: Boolean;
begin
Result := True;
if State and (sfSelected + sfModal) = 0 then
begin
if Owner <> nil then
begin
Result := Owner^.Focus;
if Result then
if ((Owner^.Current = nil) or
(Owner^.Current^.Options and ofValidate = 0) or
(Owner^.Current^.Valid(cmReleasedFocus))) then
Select
else
Result := False;
end;
end;
Focus := Result;
end;
procedure TView.GetClipRect(var Clip: TRect);
begin
GetBounds(Clip);
if Owner <> nil then Clip.Intersect(Owner^.Clip);
Clip.Move(-Origin.X, -Origin.Y);
end;
function TView.GetColor(Color: Word): Word; assembler;
asm
MOV AX,Color
CALL MapCPair
end;
procedure TView.GetCommands(var Commands: TCommandSet);
begin
Commands := CurCommandSet;
end;
procedure TView.GetData(var Rec);
begin
end;
procedure TView.GetEvent(var Event: TEvent);
begin
if Owner <> nil then Owner^.GetEvent(Event);
end;
procedure TView.GetExtent(var Extent: TRect); assembler;
asm
PUSH DS
LDS SI,Self
ADD SI,OFFSET TView.Size
LES DI,Extent
CLD
XOR AX,AX
STOSW
STOSW
MOVSW
MOVSW
POP DS
end;
function TView.GetHelpCtx: Word;
begin
if State and sfDragging <> 0 then
GetHelpCtx := hcDragging else
GetHelpCtx := HelpCtx;
end;
function TView.GetPalette: PPalette;
begin
GetPalette := nil;
end;
procedure TView.GetPeerViewPtr(var S: TStream; var P);
var
Index: Integer;
begin
S.Read(Index, SizeOf(Word));
if (Index = 0) or (OwnerGroup = nil) then Pointer(P) := nil
else
begin
Pointer(P) := FixupList^[Index];
FixupList^[Index] := @P;
end;
end;
function TView.GetState(AState: Word): Boolean;
begin
GetState := State and AState = AState;
end;
procedure TView.GrowTo(X, Y: Integer);
var
R: TRect;
begin
R.Assign(Origin.X, Origin.Y, Origin.X + X, Origin.Y + Y);
Locate(R);
end;
procedure TView.HandleEvent(var Event: TEvent);
begin
if Event.What = evMouseDown then
if (State and (sfSelected + sfDisabled) = 0) and
(Options and ofSelectable <> 0) then
if not Focus or (Options and ofFirstClick = 0) then
ClearEvent(Event);
end;
procedure TView.Hide;
begin
if State and sfVisible <> 0 then SetState(sfVisible, False);
end;
procedure TView.HideCursor;
begin
SetState(sfCursorVis, False);
end;
procedure TView.KeyEvent(var Event: TEvent);
begin
repeat GetEvent(Event) until Event.What = evKeyDown;
end;
procedure TView.Locate(var Bounds: TRect);
var
R: TRect;
Min, Max: TPoint;
function Range(Val, Min, Max: Integer): Integer;
begin
if Val < Min then Range := Min else
if Val > Max then Range := Max else
Range := Val;
end;
begin
SizeLimits(Min, Max);
Bounds.B.X := Bounds.A.X + Range(Bounds.B.X - Bounds.A.X, Min.X, Max.X);
Bounds.B.Y := Bounds.A.Y + Range(Bounds.B.Y - Bounds.A.Y, Min.Y, Max.Y);
GetBounds(R);
if not Bounds.Equals(R) then
begin
ChangeBounds(Bounds);
if (Owner <> nil) and (State and sfVisible <> 0) then
begin
if State and sfShadow <> 0 then
begin
R.Union(Bounds);
Inc(R.B.X, ShadowSize.X);
Inc(R.B.Y, ShadowSize.Y);
end;
DrawUnderRect(R, nil);
end;
end;
end;
procedure TView.MakeFirst;
begin
PutInFrontOf(Owner^.First);
end;
procedure TView.MakeGlobal(Source: TPoint; var Dest: TPoint); assembler;
asm
LES DI,Self
XOR AX,AX
MOV DX,AX
@@1: ADD AX,ES:[DI].TView.Origin.X
ADD DX,ES:[DI].TView.Origin.Y
LES DI,ES:[DI].TView.Owner
MOV SI,ES
OR SI,DI
JNE @@1
ADD AX,Source.X
ADD DX,Source.Y
LES DI,Dest
CLD
STOSW
XCHG AX,DX
STOSW
end;
procedure TView.MakeLocal(Source: TPoint; var Dest: TPoint); assembler;
asm
LES DI,Self
XOR AX,AX
MOV DX,AX
@@1: ADD AX,ES:[DI].TView.Origin.X
ADD DX,ES:[DI].TView.Origin.Y
LES DI,ES:[DI].TView.Owner
MOV SI,ES
OR SI,DI
JNE @@1
NEG AX
NEG DX
ADD AX,Source.X
ADD DX,Source.Y
LES DI,Dest
CLD
STOSW
XCHG AX,DX
STOSW
end;
function TView.MouseEvent(var Event: TEvent; Mask: Word): Boolean;
begin
repeat GetEvent(Event) until Event.What and (Mask or evMouseUp) <> 0;
MouseEvent := Event.What <> evMouseUp;
end;
function TView.MouseInView(Mouse: TPoint): Boolean;
var
Extent: TRect;
begin
MakeLocal(Mouse, Mouse);
GetExtent(Extent);
MouseInView := Extent.Contains(Mouse);
end;
procedure TView.MoveTo(X, Y: Integer);
var
R: TRect;
begin
R.Assign(X, Y, X + Size.X, Y + Size.Y);
Locate(R);
end;
function TView.NextView: PView;
begin
if @Self = Owner^.Last then NextView := nil else NextView := Next;
end;
procedure TView.NormalCursor;
begin
SetState(sfCursorIns, False);
end;
function TView.Prev: PView; assembler;
asm
LES DI,Self
MOV CX,DI
MOV BX,ES
@@1: MOV AX,DI
MOV DX,ES
LES DI,ES:[DI].TView.Next
CMP DI,CX
JNE @@1
MOV SI,ES
CMP SI,BX
JNE @@1
end;
function TView.PrevView: PView;
begin
if @Self = Owner^.First then PrevView := nil else PrevView := Prev;
end;
procedure TView.PutEvent(var Event: TEvent);
begin
if Owner <> nil then Owner^.PutEvent(Event);
end;
procedure TView.PutInFrontOf(Target: PView);
var
P, LastView: PView;
procedure MoveView;
begin
Owner^.RemoveView(@Self);
Owner^.InsertView(@Self, Target);
end;
begin
if (Owner <> nil) and (Target <> @Self) and (Target <> NextView) and
((Target = nil) or (Target^.Owner = Owner)) then
if State and sfVisible = 0 then MoveView else
begin
LastView := NextView;
if LastView <> nil then
begin
P := Target;
while (P <> nil) and (P <> LastView) do P := P^.NextView;
if P = nil then LastView := Target;
end;
State := State and not sfVisible;
if LastView = Target then DrawHide(LastView);
MoveView;
State := State or sfVisible;
if LastView <> Target then DrawShow(LastView);
if Options and ofSelectable <> 0 then
begin
Owner^.ResetCurrent;
Owner^.ResetCursor;
end;
end;
end;
procedure TView.PutPeerViewPtr(var S: TStream; P: PView);
var
Index: Integer;
begin
if (P = nil) or (OwnerGroup = nil) then Index := 0
else Index := OwnerGroup^.IndexOf(P);
S.Write(Index, SizeOf(Word));
end;
procedure TView.ResetCursor; assembler;
asm
LES DI,Self
MOV AX,ES:[DI].TView.State
NOT AX
TEST AX,sfVisible+sfCursorVis+sfFocused
JNE @@4
MOV AX,ES:[DI].TView.Cursor.Y
MOV DX,ES:[DI].TView.Cursor.X
@@1: OR AX,AX
JL @@4
CMP AX,ES:[DI].TView.Size.Y
JGE @@4
OR DX,DX
JL @@4
CMP DX,ES:[DI].TView.Size.X
JGE @@4
ADD AX,ES:[DI].TView.Origin.Y
ADD DX,ES:[DI].TView.Origin.X
MOV CX,DI
MOV BX,ES
LES DI,ES:[DI].TView.Owner
MOV SI,ES
OR SI,DI
JE @@5
TEST ES:[DI].TView.State,sfVisible
JE @@4
LES DI,ES:[DI].TGroup.Last
@@2: LES DI,ES:[DI].TView.Next
CMP CX,DI
JNE @@3
MOV SI,ES
CMP BX,SI
JNE @@3
LES DI,ES:[DI].TView.Owner
JMP @@1
@@3: TEST ES:[DI].TView.State,sfVisible
JE @@2
MOV SI,ES:[DI].TView.Origin.Y
CMP AX,SI
JL @@2
ADD SI,ES:[DI].TView.Size.Y
CMP AX,SI
JGE @@2
MOV SI,ES:[DI].TView.Origin.X
CMP DX,SI
JL @@2
ADD SI,ES:[DI].TView.Size.X
CMP DX,SI
JGE @@2
@@4: MOV CX,2000H
JMP @@6
@@5: MOV DH,AL
XOR BH,BH
MOV AH,2
INT 10H
MOV CX,CursorLines
LES DI,Self
TEST ES:[DI].TView.State,sfCursorIns
JE @@6
MOV CH,0
OR CL,CL
JNE @@6
MOV CL,7
@@6: MOV AH,1
INT 10H
end;
procedure TView.Select;
begin
if Options and ofSelectable <> 0 then
if Options and ofTopSelect <> 0 then MakeFirst else
if Owner <> nil then Owner^.SetCurrent(@Self, NormalSelect);
end;
procedure TView.SetBounds(var Bounds: TRect); assembler;
asm
PUSH DS
LES DI,Self
LDS SI,Bounds
MOV AX,[SI].TRect.A.X
MOV ES:[DI].Origin.X,AX
MOV AX,[SI].TRect.A.Y
MOV ES:[DI].Origin.Y,AX
MOV AX,[SI].TRect.B.X
SUB AX,[SI].TRect.A.X
MOV ES:[DI].Size.X,AX
MOV AX,[SI].TRect.B.Y
SUB AX,[SI].TRect.A.Y
MOV ES:[DI].Size.Y,AX
POP DS
end;
procedure TView.SetCmdState(Commands: TCommandSet; Enable: Boolean);
begin
if Enable then EnableCommands(Commands)
else DisableCommands(Commands);
end;
procedure TView.SetCommands(Commands: TCommandSet);
begin
CommandSetChanged := CommandSetChanged or (CurCommandSet <> Commands);
CurCommandSet := Commands;
end;
procedure TView.SetCursor(X, Y: Integer);
begin
Cursor.X := X;
Cursor.Y := Y;
DrawCursor;
end;
procedure TView.SetData(var Rec);
begin
end;
procedure TView.SetState(AState: Word; Enable: Boolean);
var
Command: Word;
begin
if Enable then
State := State or AState else
State := State and not AState;
if Owner <> nil then
case AState of
sfVisible:
begin
if Owner^.State and sfExposed <> 0 then
SetState(sfExposed, Enable);
if Enable then DrawShow(nil) else DrawHide(nil);
if Options and ofSelectable <> 0 then Owner^.ResetCurrent;
end;
sfCursorVis, sfCursorIns:
DrawCursor;
sfShadow:
DrawUnderView(True, nil);
sfFocused:
begin
ResetCursor;
if Enable then
Command := cmReceivedFocus else
Command := cmReleasedFocus;
Message(Owner, evBroadcast, Command, @Self);
end;
end;
end;
procedure TView.Show;
begin
if State and sfVisible = 0 then SetState(sfVisible, True);
end;
procedure TView.ShowCursor;
begin
SetState(sfCursorVis, True);
end;
procedure TView.SizeLimits(var Min, Max: TPoint);
begin
Longint(Min) := 0;
if Owner <> nil then
Max := Owner^.Size else
Longint(Max) := $7FFF7FFF;
end;
procedure TView.Store(var S: TStream);
var
SaveState: Word;
begin
SaveState := State;
State := State and not (sfActive + sfSelected + sfFocused + sfExposed);
S.Write(Origin,
SizeOf(TPoint) * 3 +
SizeOf(Byte) * 2 +
SizeOf(Word) * 4);
State := SaveState;
end;
function TView.TopView: PView;
var
P: PView;
begin
if TheTopView = nil then
begin
P := @Self;
while (P <> nil) and (P^.State and sfModal = 0) do P := P^.Owner;
TopView := P;
end
else TopView := TheTopView;
end;
function TView.Valid(Command: Word): Boolean;
begin
Valid := True;
end;
procedure TView.WriteBuf(X, Y, W, H: Integer; var Buf); assembler;
var
Target: Pointer; {Variables used by WriteView}
Buffer: Pointer;
Offset: Word;
asm
CMP H,0
JLE @@2
@@1: MOV AX,Y
MOV BX,X
MOV CX,W
LES DI,Buf
CALL WriteView
MOV AX,W
SHL AX,1
ADD WORD PTR Buf[0],AX
INC Y
DEC H
JNE @@1
@@2:
end;
procedure TView.WriteChar(X, Y: Integer; C: Char; Color: Byte;
Count: Integer); assembler;
var
Target: Pointer; {Variables used by WriteView}
Buffer: Pointer;
Offset: Word;
asm
MOV AL,Color
CALL MapColor
MOV AH,AL
MOV AL,C
MOV CX,Count
OR CX,CX
JLE @@2
CMP CX,256
JLE @@1
MOV CX,256
@@1: MOV DI,CX
SHL DI,1
SUB SP,DI
MOV DI,SP
PUSH SS
POP ES
MOV DX,CX
CLD
REP STOSW
MOV CX,DX
MOV DI,SP
MOV AX,Y
MOV BX,X
CALL WriteView
@@2:
end;
procedure TView.WriteLine(X, Y, W, H: Integer; var Buf); assembler;
var
Target: Pointer; {Variables used by WriteView}
Buffer: Pointer;
Offset: Word;
asm
CMP H,0
JLE @@2
@@1: MOV AX,Y
MOV BX,X
MOV CX,W
LES DI,Buf
CALL WriteView
INC Y
DEC H
JNE @@1
@@2:
end;
procedure TView.WriteStr(X, Y: Integer; Str: String; Color: Byte); assembler;
var
Target: Pointer; {Variables used by WriteView}
Buffer: Pointer;
Offset: Word;
asm
MOV AL,Color
CALL MapColor
MOV AH,AL
MOV BX,DS
LDS SI,Str
CLD
LODSB
MOV CL,AL
XOR CH,CH
JCXZ @@3
MOV DI,CX
SHL DI,1
SUB SP,DI
MOV DI,SP
PUSH SS
POP ES
MOV DX,CX
@@1: LODSB
STOSW
LOOP @@1
MOV DS,BX
MOV CX,DX
MOV DI,SP
MOV AX,Y
MOV BX,X
CALL WriteView
JMP @@2
@@3: MOV DS,BX
@@2:
end;
{ TFrame }
constructor TFrame.Init(var Bounds: TRect);
begin
TView.Init(Bounds);
GrowMode := gfGrowHiX + gfGrowHiY;
EventMask := EventMask or evBroadcast;
end;
procedure TFrame.FrameLine(var FrameBuf; Y, N: Integer; Color: Byte);
const
InitFrame: array[0..17] of Byte =
(4, 4, 4, 3, 4, 9, 4, 4, 4,
0, 1, 2, 3, 4, 5, 6, 7, 8);
FrameChars: array[0..9] of Char =
'┼┴╟┤ ═╔╦╚'#3;
var
B: array[0..1] of Word absolute FrameBuf;
procedure DL(P: PView); far;
var
R: TRect;
begin
if (P^.State and sfVisible <> 0) and (P^.Options and ofFramed <> 0) then
begin
P^.GetBounds(R);
R.Grow(1, 1);
if R.A.Y = Y then
begin
if R.A.X <> 0 then MoveChar(B[R.A.X], #218, Color, 1);
MoveChar(B[R.A.X+1], #196, Color, P^.Size.X);
if R.B.X <> Size.X then MoveChar(B[R.B.X-1], #191, Color, 1);
Exit;
end;
if R.B.Y = Y+1 then
begin
if R.A.X <> 0 then MoveChar(B[R.A.X], #192, Color, 1);
MoveChar(B[R.A.X+1], #196, Color, P^.Size.X);
if R.B.X <> Size.X then MoveChar(B[R.B.X-1], #11, Color, 1);
Exit;
end;
if (R.A.Y < Y) and (R.B.Y > Y+1) then
begin
if R.A.X <> 0 then MoveChar(B[R.A.X], #179, Color, 1);
MoveChar(B[R.A.X+1], #32, Color, P^.Size.X);
if R.B.X <> Size.X then MoveChar(B[R.B.X-1], #179, Color, 1);
end;
end;
end;
begin
MoveChar(B, FrameChars[InitFrame[N]], Color, 1);
MoveChar(B[1], FrameChars[InitFrame[N+1]], Color, Size.X-2);
MoveChar(B[Size.X-1], FrameChars[InitFrame[N+2]], Color, 1);
Owner^.ForEach(@DL);
end;
procedure TFrame.Draw;
var
CIcons, CFrame, CTitle: Word;
F, I, L, Width: Integer;
B: TDrawBuffer;
Title: TTitleStr;
Min, Max: TPoint;
begin
if State and sfActive = 0 then
begin
CFrame := $0101;
CTitle := $0202;
F := 9;
end else
begin
CFrame := $0503;
CTitle := $0404;
CIcons := GetColor($0505);
InvertColor(WordRec(CIcons).Hi);
if PWindow(Owner)^.Flags and wfBottomLine <> 0
then F := 0
else F := 9;
end;
CFrame := GetColor(CFrame);
CTitle := GetColor(CTitle);
Width := Size.X;
L := Width - 10;
if PWindow(Owner)^.Flags and (wfClose+wfZoom) <> 0 then Dec(L, 6);
MoveChar(B, ' ', Byte(CTitle), Size.X);
if (PWindow(Owner)^.Number <> wnNoNumber) and
(PWindow(Owner)^.Number < 10) then
begin
Dec(L, 4);
if PWindow(Owner)^.Flags and wfZoom <> 0 then I := 7
else I := 3;
WordRec(B[Width - I]).Lo := PWindow(Owner)^.Number + $30;
end;
if Owner <> nil then Title := PWindow(Owner)^.GetTitle(L)
else Title := '';
if Title <> '' then
begin
L := Length(Title);
if L > Width - 10 then L := Width - 10;
if L < 0 then L := 0;
I := (Width - L) shr 1;
MoveChar(B[I - 1], ' ', CTitle, 1);
MoveBuf(B[I], Title[1], CTitle, L);
MoveChar(B[I + L], ' ', CTitle, 1);
end;
if State and sfActive <> 0 then
begin
MoveCStr(B[0], #207#4, CIcons);
if PWindow(Owner)^.Flags and wfZoom <> 0 then
begin
MoveCStr(B[Width - 2], '~'#195'~'#7, CIcons);
Owner^.SizeLimits(Min, Max);
if Longint(Owner^.Size) = Longint(Max) then
MoveCStr(B[Width - 2], '~'#194'~'#6, CIcons);
end;
end;
WriteLine(0, 0, Size.X, 1, B);
for I := 1 to Size.Y - 2 do
begin
FrameLine(B, I, F + 3, Byte(CFrame));
WriteLine(0, I, Size.X, 1, B);
end;
if F = 0 then
begin
MoveChar(B, ' ', Byte(CTitle), Size.X );
MoveChar(B, '┤', (Byte(CTitle) and $F0) or (Byte(CFrame) and $0F), 1);
end else
FrameLine(B, Size.Y - 1, F + 6, Byte(CFrame));
if State and sfActive <> 0 then
if PWindow(Owner)^.Flags and wfGrow <> 0 then
MoveCStr(B[Width - 2], '~'#217'~'#15, CIcons);
WriteLine(0, Size.Y - 1, Size.X, 1, B);
end;
function TFrame.GetPalette: PPalette;
const
P: String[Length(CFrame)] = CFrame;
begin
GetPalette := @P;
end;
procedure TFrame.HandleEvent(var Event: TEvent);
var
Mouse: TPoint;
procedure DragWindow(Mode: Byte);
var
Limits: TRect;
Min, Max: TPoint;
begin
Owner^.Owner^.GetExtent(Limits);
Owner^.SizeLimits(Min, Max);
Owner^.DragView(Event, Owner^.DragMode or Mode, Limits, Min, Max);
ClearEvent(Event);
end;
procedure CallWindowMenu;
var
P: PMenuView;
R: TRect;
begin
R.Assign(0, 1, 25, 5);
P := New(PMenuPopup, Init(R, NewMenu(
NewItem('~ç~á¬αδΓ∞', 'Alt+F3', kbAltF3, cmClose, hcNoContext,
NewItem('~É~ẼÑα/îÑßΓ«', 'Ctrl+F5', kbCtrlF5, cmResize, hcNoContext,
NewItem('~ô~óѽ¿τ¿Γ∞', 'F5', kbF5, cmZoom, hcNoContext, nil))))));
Event.Command := PGroup(Owner)^.ExecView(P);
Dispose(P, Done);
Event.What := evCommand;
Event.InfoPtr := Owner;
PutEvent(Event);
end;
begin
TView.HandleEvent(Event);
case Event.What of
evBroadcast:
if Event.Command = cmWindowMenu then
begin
CallWindowMenu;
ClearEvent(Event);
end;
evMouseDown:
begin
MakeLocal(Event.Where, Mouse);
if Mouse.Y = 0 then
begin
if (State and sfActive <> 0) and (Mouse.X >= 0) and (Mouse.X <= 1) then
begin
repeat
MakeLocal(Event.Where, Mouse);
if (Mouse.X >= 0) and (Mouse.X <= 1) and (Mouse.Y = 0) then
FrameMode := fmCloseClicked
else FrameMode := 0;
DrawView;
until not MouseEvent(Event, evMouseMove + evMouseAuto);
FrameMode := 0;
if (Mouse.X >= 0) and (Mouse.X <= 1) and (Mouse.Y = 0) then
CallWindowMenu;
ClearEvent(Event);
DrawView;
end else
if (PWindow(Owner)^.Flags and wfZoom <> 0) and
(State and sfActive <> 0) and (Event.Double or
(Mouse.X >= Size.X - 2) and
(Mouse.X <= Size.X - 1)) then
begin
if not Event.Double then
repeat
MakeLocal(Event.Where, Mouse);
if (Mouse.X >= Size.X - 2) and (Mouse.X <= Size.X - 1) and
(Mouse.Y = 0) then
FrameMode := fmZoomClicked
else FrameMode := 0;
DrawView;
until not MouseEvent(Event, evMouseMove + evMouseAuto);
FrameMode := 0;
if ((Mouse.X >= Size.X - 2) and (Mouse.X <= Size.X - 1) and
(Mouse.Y = 0)) or Event.Double then
begin
Event.What := evCommand;
Event.Command := cmZoom;
Event.InfoPtr := Owner;
PutEvent(Event);
end;
ClearEvent(Event);
DrawView;
end else
if PWindow(Owner)^.Flags and wfMove <> 0 then
DragWindow(dmDragMove);
end else
if (State and sfActive <> 0) and (Mouse.X >= Size.X - 2) and
(Mouse.Y >= Size.Y - 1) then
if PWindow(Owner)^.Flags and wfGrow <> 0 then
DragWindow(dmDragGrow);
end;
end;
end;
procedure TFrame.SetState(AState: Word; Enable: Boolean);
begin
TView.SetState(AState, Enable);
if AState and (sfActive + sfDragging) <> 0 then DrawView;
end;
{ TScrollBar }
constructor TScrollBar.Init(var Bounds: TRect);
const
VChars: TScrollChars = (#202,#12, #204,#14, #180,#003, #254,#254, #211,#28);
HChars: TScrollChars = (#208,#21, #198,#19, #209,#209, #254,#254, #215,#212);
begin
TView.Init(Bounds);
Value := 0;
Min := 0;
Max := 0;
PgStep := 1;
ArStep := 1;
if Size.X = 2 then
begin
GrowMode := gfGrowLoX + gfGrowHiX + gfGrowHiY;
Chars := VChars;
end else
begin
GrowMode := gfGrowLoY + gfGrowHiX + gfGrowHiY;
Chars := HChars;
end;
end;
constructor TScrollBar.Load(var S: TStream);
begin
TView.Load(S);
S.Read(Value, SizeOf(Integer) * 5 + SizeOf(TScrollChars));
end;
procedure TScrollBar.Draw;
begin
DrawPos(GetPos);
end;
procedure TScrollBar.DrawPos(Pos: Integer);
var
I, S, M: Integer;
B: TDrawBuffer;
CPage, CIcons: Word;
begin
CPage := GetColor(1);
CIcons := GetColor($0202);
InvertColor(Byte(CIcons));
if Size.X = 2
then M := 2
else M := 1;
S := GetSize * M;
if Size.X = 2
then MoveCStr(B, Chars[0]+'~'+Chars[1]+'~', CIcons)
else MoveCStr(B, Chars[0]+Chars[1], CIcons);
if Max = Min then
MoveChar(B[2], Chars[8], CPage, S * M)
else
begin
I := 2;
while I <= (S - 4) * M + 2 do
begin
MoveStr(B[I], Chars[4]+Chars[5], CPage);
Inc(I, 2);
end;
MoveCStr(B[Pos * M], Chars[8]+Chars[9], CPage);
end;
MoveCStr(B[S - 2], Chars[2]+'~'+Chars[3]+'~', CIcons);
WriteBuf(0, 0, Size.X, Size.Y, B);
end;
function TScrollBar.GetPalette: PPalette;
const
P: String[Length(CScrollBar)] = CScrollBar;
begin
GetPalette := @P;
end;
function TScrollBar.GetPos: Integer;
var
M, R: Integer;
begin
R := Max - Min;
if Size.X = 2 then M := 0 else M := 1;
if R = 0 then GetPos := 1 else
R := LongDiv(LongMul(Value - Min, GetSize - 3 - 2*M) + R shr 1, R) + 1 + M;
if (M = 1) and (R = GetSize - 3) then Dec(R);
GetPos := R;
end;
function TScrollBar.GetSize: Integer;
var
S: Integer;
begin
if Size.X = 2 then S := Size.Y else S := Size.X;
if S < 3 then GetSize := 3 else GetSize := S;
end;
procedure TScrollBar.HandleEvent(var Event: TEvent);
var
Tracking: Boolean;
I, P, S, M, ClickPart: Integer;
Mouse: TPoint;
Extent: TRect;
function GetPartCode: Integer;
var
Mark, Part: Integer;
begin
Part := -1;
if Extent.Contains(Mouse) then
begin
if Size.X = 2 then Mark := Mouse.Y else Mark := Mouse.X;
if (Mark = P) or (Mark = P+M-1) then Part := sbIndicator else
begin
if Mark < M then Part := sbLeftArrow else
if Mark < P then Part := sbPageLeft else
if Mark < S-M then Part := sbPageRight else
Part := sbRightArrow;
if Size.X = 2 then Inc(Part, 4);
end;
end;
GetPartCode := Part;
end;
procedure Clicked;
begin
Message(Owner, evBroadcast, cmScrollBarClicked, @Self);
end;
begin
TView.HandleEvent(Event);
case Event.What of
evMouseDown:
begin
Clicked;
MakeLocal(Event.Where, Mouse);
GetExtent(Extent);
Extent.Grow(1, 1);
P := GetPos;
if Size.X = 2 then M := 1 else M := 2;
S := GetSize;
ClickPart := GetPartCode;
if ClickPart <> sbIndicator then
begin
repeat
MakeLocal(Event.Where, Mouse);
if GetPartCode = ClickPart then
SetValue(Value + ScrollStep(ClickPart));
until not MouseEvent(Event, evMouseAuto);
end else
begin
repeat
MakeLocal(Event.Where, Mouse);
Tracking := Extent.Contains(Mouse);
if Tracking then
begin
if Size.X = 2 then I := Mouse.Y else I := Mouse.X;
if I < M then I := M;
if I > S-M*2 then I := S-M*2;
end else I := GetPos;
if I <> P then
begin
DrawPos(I);
P := I;
end;
until not MouseEvent(Event, evMouseMove);
if Tracking and (S > M*2+1) then
begin
Dec(S, M*2+1);
SetValue(LongDiv(LongMul(P - M, Max - Min) + S shr 1, S) + Min);
end;
end;
ClearEvent(Event);
end;
evKeyDown:
if State and sfVisible <> 0 then
begin
ClickPart := sbIndicator;
if Size.Y = 1 then
case CtrlToArrow(Event.KeyCode) of
kbLeft: ClickPart := sbLeftArrow;
kbRight: ClickPart := sbRightArrow;
kbCtrlLeft: ClickPart := sbPageLeft;
kbCtrlRight: ClickPart := sbPageRight;
kbHome: I := Min;
kbEnd: I := Max;
else
Exit;
end
else
case CtrlToArrow(Event.KeyCode) of
kbUp: ClickPart := sbUpArrow;
kbDown: ClickPart := sbDownArrow;
kbPgUp: ClickPart := sbPageUp;
kbPgDn: ClickPart := sbPageDown;
kbCtrlPgUp: I := Min;
kbCtrlPgDn: I := Max;
else
Exit;
end;
Clicked;
if ClickPart <> sbIndicator then I := Value + ScrollStep(ClickPart);
SetValue(I);
ClearEvent(Event);
end;
end;
end;
procedure TScrollBar.ScrollDraw;
begin
Message(Owner, evBroadcast, cmScrollBarChanged, @Self);
end;
function TScrollBar.ScrollStep(Part: Integer): Integer;
var
Step: Integer;
begin
if Part and 2 = 0 then Step := ArStep else Step := PgStep;
if Part and 1 = 0 then ScrollStep := -Step else ScrollStep := Step;
end;
procedure TScrollBar.SetParams(AValue, AMin, AMax, APgStep,
AArStep: Integer);
var
SValue: Integer;
IsVisible: Boolean;
begin
if AMax < AMin then AMax := AMin;
if AValue < AMin then AValue := AMin;
if AValue > AMax then AValue := AMax;
SValue := Value;
if (SValue <> AValue) or (Min <> AMin) or (Max <> AMax) then
begin
Value := AValue;
Min := AMin;
Max := AMax;
IsVisible := GetState(sfVisible);
if AMin = AMax
then if IsVisible then Hide else {}
else if not IsVisible and GetState(sfActive) then Show;
DrawView;
if SValue <> AValue then ScrollDraw;
end;
PgStep := APgStep;
ArStep := AArStep;
end;
procedure TScrollBar.SetRange(AMin, AMax: Integer);
begin
SetParams(Value, AMin, AMax, PgStep, ArStep);
end;
procedure TScrollBar.SetState(AState: Word; Enable: Boolean);
begin
if (AState and sfVisible <> 0) and Enable and (Min = Max) then Exit;
inherited SetState(AState, Enable);
end;
procedure TScrollBar.SetStep(APgStep, AArStep: Integer);
begin
SetParams(Value, Min, Max, APgStep, AArStep);
end;
procedure TScrollBar.SetValue(AValue: Integer);
begin
SetParams(AValue, Min, Max, PgStep, ArStep);
end;
procedure TScrollBar.Store(var S: TStream);
begin
TView.Store(S);
S.Write(Value, SizeOf(Integer) * 5 + SizeOf(TScrollChars));
end;
{ TScroller }
constructor TScroller.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
begin
TView.Init(Bounds);
Options := Options or ofSelectable;
EventMask := EventMask or evBroadcast;
HScrollBar := AHScrollBar;
VScrollBar := AVScrollBar;
end;
constructor TScroller.Load(var S: TStream);
begin
TView.Load(S);
GetPeerViewPtr(S, HScrollBar);
GetPeerViewPtr(S, VScrollBar);
S.Read(Delta, SizeOf(TPoint)*2);
end;
procedure TScroller.ChangeBounds(var Bounds: TRect);
begin
SetBounds(Bounds);
Inc(DrawLock);
SetLimit(Limit.X, Limit.Y);
Dec(DrawLock);
DrawFlag := False;
DrawView;
end;
procedure TScroller.CheckDraw;
begin
if (DrawLock = 0) and DrawFlag then
begin
DrawFlag := False;
DrawView;
end;
end;
function TScroller.GetPalette: PPalette;
const
P: String[Length(CScroller)] = CScroller;
begin
GetPalette := @P;
end;
procedure TScroller.HandleEvent(var Event: TEvent);
begin
TView.HandleEvent(Event);
if (Event.What = evBroadcast) and (Event.Command = cmScrollBarChanged) and
((Event.InfoPtr = HScrollBar) or (Event.InfoPtr = VScrollBar)) then
ScrollDraw;
end;
procedure TScroller.ScrollDraw;
var
D: TPoint;
begin
if HScrollBar <> nil then D.X := HScrollBar^.Value
else D.X := 0;
if VScrollBar <> nil then D.Y := VScrollBar^.Value
else D.Y := 0;
if (D.X <> Delta.X) or (D.Y <> Delta.Y) then
begin
SetCursor(Cursor.X + Delta.X - D.X, Cursor.Y + Delta.Y - D.Y);
Delta := D;
if DrawLock <> 0 then DrawFlag := True else DrawView;
end;
end;
procedure TScroller.ScrollTo(X, Y: Integer);
begin
Inc(DrawLock);
if HScrollBar <> nil then HScrollBar^.SetValue(X);
if VScrollBar <> nil then VScrollBar^.SetValue(Y);
Dec(DrawLock);
CheckDraw;
end;
procedure TScroller.SetLimit(X, Y: Integer);
begin
Limit.X := X;
Limit.Y := Y;
Inc(DrawLock);
if HScrollBar <> nil then
HScrollBar^.SetParams(HScrollBar^.Value, 0, X - Size.X, Size.X - 1,
HScrollBar^.ArStep);
if VScrollBar <> nil then
VScrollBar^.SetParams(VScrollBar^.Value, 0, Y - Size.Y, Size.Y - 1,
VScrollBar^.ArStep);
Dec(DrawLock);
CheckDraw;
end;
procedure TScroller.SetState(AState: Word; Enable: Boolean);
procedure ShowSBar(SBar: PScrollBar);
begin
if (SBar <> nil) then
if GetState(sfActive + sfSelected) then SBar^.Show
else SBar^.Hide;
end;
begin
TView.SetState(AState, Enable);
if AState and (sfActive + sfSelected) <> 0 then
begin
ShowSBar(HScrollBar);
ShowSBar(VScrollBar);
end;
end;
procedure TScroller.Store(var S: TStream);
begin
TView.Store(S);
PutPeerViewPtr(S, HScrollBar);
PutPeerViewPtr(S, VScrollBar);
S.Write(Delta, SizeOf(TPoint)*2);
end;
{ TListViewer }
constructor TListViewer.Init(var Bounds: TRect; ANumCols: Word;
AHScrollBar, AVScrollBar: PScrollBar);
var
ArStep, PgStep: Integer;
begin
TView.Init(Bounds);
Options := Options or (ofFirstClick + ofSelectable);
EventMask := EventMask or evBroadcast;
Range := 0;
NumCols := ANumCols;
Focused := 0;
if AVScrollBar <> nil then
begin
if NumCols = 1 then
begin
PgStep := Size.Y -1;
ArStep := 1;
end else
begin
PgStep := Size.Y * NumCols;
ArStep := Size.Y;
end;
AVScrollBar^.SetStep(PgStep, ArStep);
end;
if AHScrollBar <> nil then AHScrollBar^.SetStep(Size.X div NumCols, 1);
HScrollBar := AHScrollBar;
VScrollBar := AVScrollBar;
end;
constructor TListViewer.Load(var S: TStream);
begin
TView.Load(S);
GetPeerViewPtr(S, HScrollBar);
GetPeerViewPtr(S, VScrollBar);
S.Read(NumCols, SizeOf(Word) * 4);
end;
procedure TListViewer.ChangeBounds(var Bounds: TRect);
begin
TView.ChangeBounds(Bounds);
if HScrollBar <> nil then
HScrollBar^.SetStep(Size.X div NumCols, HScrollBar^.ArStep);
if VScrollBar <> nil then
VScrollBar^.SetStep(Size.Y, VScrollBar^.ArStep);
end;
procedure TListViewer.Draw;
var
I, J, Item: Integer;
NormalColor, SelectedColor, FocusedColor, Color: Word;
ColWidth, CurCol, Indent: Integer;
B: TDrawBuffer;
Text: String;
SCOff: Byte;
begin
if State and (sfSelected + sfActive) = (sfSelected + sfActive) then
begin
NormalColor := GetColor(1);
FocusedColor := GetColor(3);
SelectedColor := GetColor(4);
end else
begin
NormalColor := GetColor(2);
SelectedColor := GetColor(4);
end;
if HScrollBar <> nil then Indent := HScrollBar^.Value
else Indent := 0;
ColWidth := Size.X div NumCols + 1;
for I := 0 to Size.Y - 1 do
begin
for J := 0 to NumCols-1 do
begin
Item := J*Size.Y + I + TopItem;
CurCol := J*ColWidth;
if (State and (sfSelected + sfActive) = (sfSelected + sfActive)) and
(Focused = Item) and (Range > 0) then
begin
Color := FocusedColor;
SetCursor(CurCol+1,I);
SCOff := 0;
end
else if (Item < Range) and IsSelected(Item) then
begin
Color := SelectedColor;
SCOff := 2;
end
else
begin
Color := NormalColor;
SCOff := 4;
end;
MoveChar(B[CurCol], ' ', Color, ColWidth);
if Item < Range then
begin
Text := GetText(Item, ColWidth + Indent);
Text := Copy(Text,Indent,ColWidth);
MoveStr(B[CurCol+1], Text, Color);
if ShowMarkers then
begin
WordRec(B[CurCol]).Lo := Byte(SpecialChars[SCOff]);
WordRec(B[CurCol+ColWidth-2]).Lo := Byte(SpecialChars[SCOff+1]);
end;
end;
MoveChar(B[CurCol+ColWidth-1], #179, GetColor(5), 1);
end;
WriteLine(0, I, Size.X, 1, B);
end;
end;
procedure TListViewer.FocusItem(Item: Integer);
begin
Focused := Item;
if VScrollBar <> nil then VScrollBar^.SetValue(Item);
if Item < TopItem then
if NumCols = 1 then TopItem := Item
else TopItem := Item - Item mod Size.Y
else if Item >= TopItem + (Size.Y*NumCols) then
if NumCols = 1 then TopItem := Item - Size.Y + 1
else TopItem := Item - Item mod Size.Y - (Size.Y*(NumCols - 1));
end;
procedure TListViewer.FocusItemNum(Item: Integer);
begin
if Item < 0 then Item := 0
else if (Item >= Range) and (Range > 0) then Item := Range-1;
if Range <> 0 then FocusItem(Item);
end;
function TListViewer.GetPalette: PPalette;
const
P: String[Length(CListViewer)] = CListViewer;
begin
GetPalette := @P;
end;
function TListViewer.GetText(Item: Integer; MaxLen: Integer): String;
begin
Abstract;
end;
function TListViewer.IsSelected(Item: Integer): Boolean;
begin
IsSelected := Item = Focused;
end;
procedure TListViewer.HandleEvent(var Event: TEvent);
const
MouseAutosToSkip = 4;
var
Mouse: TPoint;
ColWidth: Word;
OldItem, NewItem: Integer;
Count: Word;
begin
TView.HandleEvent(Event);
if Event.What = evMouseDown then
begin
ColWidth := Size.X div NumCols + 1;
OldItem := Focused;
MakeLocal(Event.Where, Mouse);
if MouseInView(Event.Where) then
NewItem := Mouse.Y + (Size.Y * (Mouse.X div ColWidth)) + TopItem
else NewItem := OldItem;
Count := 0;
repeat
if NewItem <> OldItem then
begin
FocusItemNum(NewItem);
DrawView;
end;
OldItem := NewItem;
MakeLocal(Event.Where, Mouse);
if MouseInView(Event.Where) then
NewItem := Mouse.Y + (Size.Y * (Mouse.X div ColWidth)) + TopItem
else
begin
if NumCols = 1 then
begin
if Event.What = evMouseAuto then Inc(Count);
if Count = MouseAutosToSkip then
begin
Count := 0;
if Mouse.Y < 0 then NewItem := Focused-1
else if Mouse.Y >= Size.Y then NewItem := Focused+1;
end;
end
else
begin
if Event.What = evMouseAuto then Inc(Count);
if Count = MouseAutosToSkip then
begin
Count := 0;
if Mouse.X < 0 then NewItem := Focused-Size.Y
else if Mouse.X >= Size.X then NewItem := Focused+Size.Y
else if Mouse.Y < 0 then
NewItem := Focused - Focused mod Size.Y
else if Mouse.Y > Size.Y then
NewItem := Focused - Focused mod Size.Y + Size.Y - 1;
end
end;
end;
until not MouseEvent(Event, evMouseMove + evMouseAuto);
FocusItemNum(NewItem);
DrawView;
if Event.Double and (Range > Focused) then SelectItem(Focused);
ClearEvent(Event);
end
else if Event.What = evKeyDown then
begin
if (Event.CharCode = ' ') and (Focused < Range) then
begin
SelectItem(Focused);
NewItem := Focused;
end
else case CtrlToArrow(Event.KeyCode) of
kbUp: NewItem := Focused - 1;
kbDown: NewItem := Focused + 1;
kbRight: if NumCols > 1 then NewItem := Focused + Size.Y else Exit;
kbLeft: if NumCols > 1 then NewItem := Focused - Size.Y else Exit;
kbPgDn: NewItem := Focused + Size.Y * NumCols;
kbPgUp: NewItem := Focused - Size.Y * NumCols;
kbHome: NewItem := TopItem;
kbEnd: NewItem := TopItem + (Size.Y * NumCols) - 1;
kbCtrlPgDn: NewItem := Range - 1;
kbCtrlPgUp: NewItem := 0;
else
Exit;
end;
FocusItemNum(NewItem);
DrawView;
ClearEvent(Event);
end else if Event.What = evBroadcast then
if Options and ofSelectable <> 0 then
if (Event.Command = cmScrollBarClicked) and
((Event.InfoPtr = HScrollBar) or (Event.InfoPtr = VScrollBar)) then
Select
else if (Event.Command = cmScrollBarChanged) then
begin
if (VScrollBar = Event.InfoPtr) then
begin
FocusItemNum(VScrollBar^.Value);
DrawView;
end else if (HScrollBar = Event.InfoPtr) then DrawView;
end;
end;
procedure TListViewer.SelectItem(Item: Integer);
begin
Message(Owner, evBroadcast, cmListItemSelected, @Self);
end;
procedure TListViewer.SetRange(ARange: Integer);
begin
Range := ARange;
if VScrollBar <> nil then
begin
if Focused > ARange then Focused := 0;
VScrollbar^.SetParams(Focused, 0, ARange-1, VScrollBar^.PgStep,
VScrollBar^.ArStep);
end;
end;
procedure TListViewer.SetState(AState: Word; Enable: Boolean);
procedure ShowSBar(SBar: PScrollBar);
begin
if (SBar <> nil) then
if GetState(sfActive) and GetState(sfVisible) then SBar^.Show
else SBar^.Hide;
end;
begin
TView.SetState(AState, Enable);
if AState and (sfSelected + sfActive + sfVisible) <> 0 then
begin
ShowSBar(HScrollBar);
ShowSBar(VScrollBar);
DrawView;
end;
end;
procedure TListViewer.Store(var S: TStream);
begin
TView.Store(S);
PutPeerViewPtr(S, HScrollBar);
PutPeerViewPtr(S, VScrollBar);
S.Write(NumCols, SizeOf(Word) * 4);
end;
{ TGroup }
constructor TGroup.Init(var Bounds: TRect);
begin
TView.Init(Bounds);
Options := Options or (ofSelectable + ofBuffered);
GetExtent(Clip);
EventMask := $FFFF;
end;
constructor TGroup.Load(var S: TStream);
var
FixupSave: PFixupList;
Count, I: Integer;
P, Q: ^Pointer;
V: PView;
OwnerSave: PGroup;
begin
TView.Load(S);
GetExtent(Clip);
OwnerSave := OwnerGroup;
OwnerGroup := @Self;
FixupSave := FixupList;
S.Read(Count, SizeOf(Word));
asm
MOV CX,Count
SHL CX,1
SHL CX,1
SUB SP,CX
MOV FixupList.Word[0],SP
MOV FixupList.Word[2],SS
MOV DI,SP
PUSH SS
POP ES
XOR AL,AL
CLD
REP STOSB
end;
for I := 1 to Count do
begin
V := PView(S.Get);
if V <> nil then InsertView(V, nil);
end;
V := Last;
for I := 1 to Count do
begin
V := V^.Next;
P := FixupList^[I];
while P <> nil do
begin
Q := P;
P := P^;
Q^ := V;
end;
end;
OwnerGroup := OwnerSave;
FixupList := FixupSave;
GetSubViewPtr(S, V);
SetCurrent(V, NormalSelect);
if OwnerGroup = nil then Awaken;
end;
destructor TGroup.Done;
var
P, T: PView;
begin
Hide;
P := Last;
if P <> nil then
begin
repeat
P^.Hide;
P := P^.Prev;
until P = Last;
repeat
T := P^.Prev;
Dispose(P, Done);
P := T;
until Last = nil;
end;
FreeBuffer;
TView.Done;
end;
function TGroup.At(Index: Integer): PView; assembler;
asm
LES DI,Self
LES DI,ES:[DI].TGroup.Last
MOV CX,Index
@@1: LES DI,ES:[DI].TView.Next
LOOP @@1
MOV AX,DI
MOV DX,ES
end;
procedure TGroup.Awaken;
procedure DoAwaken(P: PView); far;
begin
P^.Awaken;
end;
begin
ForEach(@DoAwaken);
end;
procedure TGroup.ChangeBounds(var Bounds: TRect);
var
D: TPoint;
procedure DoCalcChange(P: PView); far;
var
R: TRect;
begin
P^.CalcBounds(R, D);
P^.ChangeBounds(R);
end;
begin
D.X := Bounds.B.X - Bounds.A.X - Size.X;
D.Y := Bounds.B.Y - Bounds.A.Y - Size.Y;
if Longint(D) = 0 then
begin
SetBounds(Bounds);
DrawView;
end else
begin
FreeBuffer;
SetBounds(Bounds);
GetExtent(Clip);
GetBuffer;
Lock;
ForEach(@DoCalcChange);
Unlock;
end;
end;
function TGroup.DataSize: Word;
var
T: Word;
procedure AddSubviewDataSize(P: PView); far;
begin
Inc(T, P^.DataSize);
end;
begin
T := 0;
ForEach(@AddSubviewDataSize);
DataSize := T;
end;
procedure TGroup.Delete(P: PView);
var
SaveState: Word;
begin
SaveState := P^.State;
P^.Hide;
RemoveView(P);
P^.Owner := nil;
P^.Next := nil;
if SaveState and sfVisible <> 0 then P^.Show;
end;
procedure TGroup.Draw;
var
R: TRect;
begin
if Buffer = nil then
begin
GetBuffer;
if Buffer <> nil then
begin
Inc(LockFlag);
Redraw;
Dec(LockFlag);
end;
end;
if Buffer <> nil then WriteBuf(0, 0, Size.X, Size.Y, Buffer^) else
begin
GetClipRect(Clip);
Redraw;
GetExtent(Clip);
end;
end;
procedure TGroup.DrawSubViews(P, Bottom: PView);
begin
if P <> nil then
while P <> Bottom do
begin
P^.DrawView;
P := P^.NextView;
end;
end;
procedure TGroup.EndModal(Command: Word);
begin
if State and sfModal <> 0 then EndState := Command
else TView.EndModal(Command);
end;
procedure TGroup.EventError(var Event: TEvent);
begin
if Owner <> nil then Owner^.EventError(Event);
end;
function TGroup.Execute: Word;
var
E: TEvent;
begin
repeat
EndState := 0;
repeat
GetEvent(E);
HandleEvent(E);
if E.What <> evNothing then EventError(E);
until EndState <> 0;
until Valid(EndState);
Execute := EndState;
end;
function TGroup.ExecView(P: PView): Word;
var
SaveOptions: Word;
SaveOwner: PGroup;
SaveTopView: PView;
SaveCurrent: PView;
SaveCommands: TCommandSet;
begin
if P <> nil then
begin
SaveOptions := P^.Options;
SaveOwner := P^.Owner;
SaveTopView := TheTopView;
SaveCurrent := Current;
GetCommands(SaveCommands);
TheTopView := P;
P^.Options := P^.Options and not ofSelectable;
P^.SetState(sfModal, True);
SetCurrent(P, EnterSelect);
if SaveOwner = nil then Insert(P);
ExecView := P^.Execute;
if SaveOwner = nil then Delete(P);
SetCurrent(SaveCurrent, LeaveSelect);
P^.SetState(sfModal, False);
P^.Options := SaveOptions;
TheTopView := SaveTopView;
SetCommands(SaveCommands);
end else ExecView := cmCancel;
end;
function TGroup.First: PView;
begin
if Last = nil then First := nil else First := Last^.Next;
end;
function TGroup.FirstMatch(AState: Word; AOptions: Word): PView;
function Matches(P: PView): Boolean; far;
begin
Matches := (P^.State and AState = AState) and
(P^.Options and AOptions = AOptions);
end;
begin
FirstMatch := FirstThat(@Matches);
end;
function TGroup.FirstThat(P: Pointer): PView; assembler;
var
ALast: Pointer;
asm
LES DI,Self
LES DI,ES:[DI].TGroup.Last
MOV AX,ES
OR AX,DI
JE @@3
MOV WORD PTR ALast[2],ES
MOV WORD PTR ALast[0],DI
@@1: LES DI,ES:[DI].TView.Next
PUSH ES
PUSH DI
PUSH ES
PUSH DI
PUSH WORD PTR [BP]
CALL P
POP DI
POP ES
OR AL,AL
JNE @@2
CMP DI,WORD PTR ALast[0]
JNE @@1
MOV AX,ES
CMP AX,WORD PTR ALast[2]
JNE @@1
XOR DI,DI
MOV ES,DI
@@2: MOV SP,BP
@@3: MOV AX,DI
MOV DX,ES
end;
function TGroup.FindNext(Forwards: Boolean): PView;
var
P: PView;
begin
FindNext := nil;
if Current <> nil then
begin
P := Current;
repeat
if Forwards then P := P^.Next else P := P^.Prev;
until ((P^.State and (sfVisible + sfDisabled) = sfVisible) and
(P^.Options and ofSelectable <> 0)) or (P = Current);
if P <> Current then FindNext := P;
end;
end;
function TGroup.FocusNext(Forwards: Boolean): Boolean;
var
P: PView;
begin
P := FindNext(Forwards);
FocusNext := True;
if P <> nil then FocusNext := P^.Focus;
end;
procedure TGroup.ForEach(P: Pointer); assembler;
var
ALast: Pointer;
asm
LES DI,Self
LES DI,ES:[DI].TGroup.Last
MOV AX,ES
OR AX,DI
JE @@4
MOV WORD PTR ALast[2],ES
MOV WORD PTR ALast[0],DI
LES DI,ES:[DI].TView.Next
@@1: CMP DI,WORD PTR ALast[0]
JNE @@2
MOV AX,ES
CMP AX,WORD PTR ALast[2]
JE @@3
@@2: PUSH WORD PTR ES:[DI].TView.Next[2]
PUSH WORD PTR ES:[DI].TView.Next[0]
PUSH ES
PUSH DI
PUSH WORD PTR [BP]
CALL P
POP DI
POP ES
JMP @@1
@@3: PUSH WORD PTR [BP]
CALL P
@@4:
end;
procedure TGroup.FreeBuffer;
begin
if (Options and ofBuffered <> 0) and (Buffer <> nil) then
DisposeCache(Pointer(Buffer));
end;
{ Allocate a group buffer if the group is exposed, buffered, and
its area is less than 32768 bytes }
procedure TGroup.GetBuffer; assembler;
asm
LES DI,Self
TEST ES:[DI].State,sfExposed
JZ @@1
TEST ES:[DI].Options,ofBuffered
JZ @@1
MOV AX,ES:[DI].Buffer.Word[0]
OR AX,ES:[DI].Buffer.Word[2]
JNZ @@1
MOV AX,ES:[DI].TView.Size.X
MUL ES:[DI].TView.Size.Y
JO @@1
SHL AX,1
JC @@1
JS @@1
LEA DI,[DI].TView.Buffer
PUSH ES
PUSH DI
PUSH AX
CALL NewCache
@@1:
end;
procedure TGroup.GetData(var Rec);
type
Bytes = array[0..65534] of Byte;
var
I: Word;
V: PView;
begin
I := 0;
if Last <> nil then
begin
V := Last;
repeat
V^.GetData(Bytes(Rec)[I]);
Inc(I, V^.DataSize);
V := V^.Prev;
until V = Last;
end;
end;
function TGroup.GetHelpCtx: Word;
var
H: Word;
begin
H:= hcNoContext;
if Current <> nil then H := Current^.GetHelpCtx;
if H = hcNoContext then H := TView.GetHelpCtx;
GetHelpCtx := H;
end;
procedure TGroup.GetSubViewPtr(var S: TStream; var P);
var
Index: Word;
begin
S.Read(Index, SizeOf(Word));
if Index > 0 then
Pointer(P) := At(Index)
else
Pointer(P) := nil;
end;
procedure TGroup.HandleEvent(var Event: TEvent);
procedure DoHandleEvent(P: PView); far;
begin
if (P = nil) or ((P^.State and sfDisabled <> 0)
and (Event.What and (PositionalEvents or FocusedEvents) <> 0)) then Exit;
case Phase of
phPreProcess: if P^.Options and ofPreProcess = 0 then Exit;
phPostProcess: if P^.Options and ofPostProcess = 0 then Exit;
end;
if Event.What and P^.EventMask <> 0 then P^.HandleEvent(Event);
end;
function ContainsMouse(P: PView): Boolean; far;
begin
ContainsMouse := (P^.State and sfVisible <> 0) and
P^.MouseInView(Event.Where);
end;
begin
TView.HandleEvent(Event);
if Event.What and FocusedEvents <> 0 then
begin
Phase := phPreProcess;
ForEach(@DoHandleEvent);
Phase := phFocused;
DoHandleEvent(Current);
Phase := phPostProcess;
ForEach(@DoHandleEvent);
end else
begin
Phase := phFocused;
if (Event.What and PositionalEvents <> 0) then
DoHandleEvent(FirstThat(@ContainsMouse)) else
ForEach(@DoHandleEvent);
end;
end;
function TGroup.IndexOf(P: PView): Integer; assembler;
asm
LES DI,Self
LES DI,ES:[DI].TGroup.Last
MOV AX,ES
OR AX,DI
JE @@3
MOV CX,DI
MOV BX,ES
XOR AX,AX
@@1: INC AX
LES DI,ES:[DI].TView.Next
MOV DX,ES
CMP DI,P.Word[0]
JNE @@2
CMP DX,P.Word[2]
JE @@3
@@2: CMP DI,CX
JNE @@1
CMP DX,BX
JNE @@1
XOR AX,AX
@@3:
end;
procedure TGroup.Insert(P: PView);
begin
InsertBefore(P, First);
end;
procedure TGroup.InsertBefore(P, Target: PView);
var
SaveState: Word;
begin
if (P <> nil) and (P^.Owner = nil) and
((Target = nil) or (Target^.Owner = @Self)) then
begin
if P^.Options and ofCenterX <> 0 then
P^.Origin.X := (Size.X - P^.Size.X) div 2;
if P^.Options and ofCenterY <> 0 then
P^.Origin.Y := (Size.Y - P^.Size.Y) div 2;
SaveState := P^.State;
P^.Hide;
InsertView(P, Target);
if SaveState and sfVisible <> 0 then P^.Show;
if State and sfActive <> 0 then
P^.SetState(sfActive, True);
end;
end;
procedure TGroup.InsertView(P, Target: PView);
begin
P^.Owner := @Self;
if Target <> nil then
begin
Target := Target^.Prev;
P^.Next := Target^.Next;
Target^.Next := P;
end else
begin
if Last = nil then P^.Next := P else
begin
P^.Next := Last^.Next;
Last^.Next := P;
end;
Last := P;
end;
end;
procedure TGroup.Lock;
begin
if (Buffer <> nil) or (LockFlag <> 0) then Inc(LockFlag);
end;
procedure TGroup.PutSubViewPtr(var S: TStream; P: PView);
var
Index: Word;
begin
if P = nil then Index := 0
else Index := IndexOf(P);
S.Write(Index, SizeOf(Word));
end;
procedure TGroup.Redraw;
begin
DrawSubViews(First, nil);
end;
procedure TGroup.RemoveView(P: PView); assembler;
asm
PUSH DS
LDS SI,Self
LES DI,P
LDS SI,DS:[SI].TGroup.Last
PUSH BP
MOV AX,DS
OR AX,SI
JE @@7
MOV AX,SI
MOV DX,DS
MOV BP,ES
@@1: MOV BX,WORD PTR DS:[SI].TView.Next[0]
MOV CX,WORD PTR DS:[SI].TView.Next[2]
CMP CX,BP
JE @@5
@@2: CMP CX,DX
JE @@4
@@3: MOV SI,BX
MOV DS,CX
JMP @@1
@@4: CMP BX,AX
JNE @@3
JMP @@7
@@5: CMP BX,DI
JNE @@2
MOV BX,WORD PTR ES:[DI].TView.Next[0]
MOV CX,WORD PTR ES:[DI].TView.Next[2]
MOV DS:WORD PTR [SI].TView.Next[0],BX
MOV DS:WORD PTR [SI].TView.Next[2],CX
CMP DX,BP
JNE @@7
CMP AX,DI
JNE @@7
CMP CX,BP
JNE @@6
CMP BX,DI
JNE @@6
XOR SI,SI
MOV DS,SI
@@6: POP BP
PUSH BP
LES DI,Self
MOV WORD PTR ES:[DI].TView.Last[0],SI
MOV WORD PTR ES:[DI].TView.Last[2],DS
@@7: POP BP
POP DS
end;
procedure TGroup.ResetCurrent;
begin
SetCurrent(FirstMatch(sfVisible, ofSelectable), NormalSelect);
end;
procedure TGroup.ResetCursor;
begin
if Current <> nil then Current^.ResetCursor;
end;
procedure TGroup.SelectNext(Forwards: Boolean);
var
P: PView;
begin
P := FindNext(Forwards);
if P <> nil then P^.Select;
end;
procedure TGroup.SetCurrent(P: PView; Mode: SelectMode);
procedure SelectView(P: PView; Enable: Boolean);
begin
if P <> nil then P^.SetState(sfSelected, Enable);
end;
procedure FocusView(P: PView; Enable: Boolean);
begin
if (State and sfFocused <> 0) and (P <> nil) then
P^.SetState(sfFocused, Enable);
end;
begin
if Current <> P then
begin
Lock;
FocusView(Current, False);
if Mode <> EnterSelect then SelectView(Current, False);
if Mode <> LeaveSelect then SelectView(P, True);
FocusView(P, True);
Current := P;
Unlock;
end;
end;
procedure TGroup.SetData(var Rec);
type
Bytes = array[0..65534] of Byte;
var
I: Word;
V: PView;
begin
I := 0;
if Last <> nil then
begin
V := Last;
repeat
V^.SetData(Bytes(Rec)[I]);
Inc(I, V^.DataSize);
V := V^.Prev;
until V = Last;
end;
end;
procedure TGroup.SetState(AState: Word; Enable: Boolean);
procedure DoSetState(P: PView); far;
begin
P^.SetState(AState, Enable);
end;
procedure DoExpose(P: PView); far;
begin
if P^.State and sfVisible <> 0 then P^.SetState(sfExposed, Enable);
end;
begin
TView.SetState(AState, Enable);
case AState of
sfActive, sfDragging:
begin
Lock;
ForEach(@DoSetState);
Unlock;
end;
sfFocused:
if Current <> nil then Current^.SetState(sfFocused, Enable);
sfExposed:
begin
ForEach(@DoExpose);
if not Enable then FreeBuffer;
end;
end;
end;
procedure TGroup.Store(var S: TStream);
var
Count: Integer;
OwnerSave: PGroup;
procedure DoPut(P: PView); far;
begin
S.Put(P);
end;
begin
TView.Store(S);
OwnerSave := OwnerGroup;
OwnerGroup := @Self;
Count := IndexOf(Last);
S.Write(Count, SizeOf(Word));
ForEach(@DoPut);
PutSubViewPtr(S, Current);
OwnerGroup := OwnerSave;
end;
procedure TGroup.Unlock;
begin
if LockFlag <> 0 then
begin
Dec(LockFlag);
if LockFlag = 0 then DrawView;
end;
end;
function TGroup.Valid(Command: Word): Boolean;
function IsInvalid(P: PView): Boolean; far;
begin
IsInvalid := not P^.Valid(Command);
end;
begin
Valid := True;
if Command = cmReleasedFocus then
begin
if (Current <> nil) and (Current^.Options and ofValidate <> 0) then
Valid := Current^.Valid(Command);
end
else
Valid := FirstThat(@IsInvalid) = nil;
end;
{ TWindow }
constructor TWindow.Init(var Bounds: TRect; ATitle: TTitleStr;
ANumber: Integer);
begin
TGroup.Init(Bounds);
State := State or sfShadow;
Options := Options or (ofSelectable + ofTopSelect);
GrowMode := gfGrowAll + gfGrowRel;
Flags := wfMove + wfGrow + wfClose + wfZoom;
Title := NewStr(ATitle);
Number := ANumber;
Palette := wpBlueWindow;
InitFrame;
if Frame <> nil then Insert(Frame);
GetBounds(ZoomRect);
end;
constructor TWindow.Load(var S: TStream);
begin
TGroup.Load(S);
S.Read(Flags, SizeOf(Byte) + SizeOf(TRect) + 2 * SizeOf(Integer));
GetSubViewPtr(S, Frame);
Title := S.ReadStr;
end;
destructor TWindow.Done;
begin
TGroup.Done;
DisposeStr(Title);
end;
procedure TWindow.Close;
begin
if Valid(cmClose) then Free;
end;
function TWindow.GetPalette: PPalette;
const
P: array[wpBlueWindow..wpGrayWindow] of string[Length(CBlueWindow)] =
(CBlueWindow, CCyanWindow, CGrayWindow);
begin
GetPalette := @P[Palette];
end;
function TWindow.GetTitle(MaxSize: Integer): TTitleStr;
begin
if Title <> nil then GetTitle := Title^
else GetTitle := '';
end;
procedure TWindow.HandleEvent(var Event: TEvent);
var
Limits: TRect;
Min, Max: TPoint;
begin
TGroup.HandleEvent(Event);
if (Event.What = evCommand) then
case Event.Command of
cmResize:
if Flags and (wfMove + wfGrow) <> 0 then
begin
Owner^.GetExtent(Limits);
SizeLimits(Min, Max);
DragView(Event, DragMode or (Flags and (wfMove + wfGrow)),
Limits, Min, Max);
ClearEvent(Event);
end;
cmClose:
if (Flags and wfClose <> 0) and
((Event.InfoPtr = nil) or (Event.InfoPtr = @Self)) then
begin
ClearEvent(Event);
if State and sfModal = 0 then Close else
begin
Event.What := evCommand;
Event.Command := cmCancel;
PutEvent(Event);
ClearEvent(Event);
end;
end;
cmZoom:
if (Flags and wfZoom <> 0) and
((Event.InfoPtr = nil) or (Event.InfoPtr = @Self)) then
begin
Zoom;
ClearEvent(Event);
end;
end
else if Event.What = evKeyDown then
case Event.KeyCode of
kbTab:
begin
FocusNext(False);
ClearEvent(Event);
end;
kbShiftTab:
begin
FocusNext(True);
ClearEvent(Event);
end;
else
if GetAltChar(Event.KeyCode) = #240 then
if Message(Frame, evBroadcast, cmWindowMenu, nil) <> nil then
ClearEvent(Event);
end
else if (Event.What = evBroadcast) and (Event.Command = cmSelectWindowNum)
and (Event.InfoInt = Number) and (Options and ofSelectable <> 0) then
begin
Select;
ClearEvent(Event);
end;
end;
procedure TWindow.InitFrame;
var
R: TRect;
begin
GetExtent(R);
Frame := New(PFrame, Init(R));
end;
procedure TWindow.SetState(AState: Word; Enable: Boolean);
var
WindowCommands: TCommandSet;
begin
TGroup.SetState(AState, Enable);
if AState = sfSelected then
SetState(sfActive, Enable);
if (AState = sfSelected) or ((AState = sfExposed) and
(State and sfSelected <> 0)) then
begin
WindowCommands := [cmNext, cmPrev];
if Flags and wfGrow + wfMove <> 0 then
WindowCommands := WindowCommands + [cmResize];
if Flags and wfClose <> 0 then
WindowCommands := WindowCommands + [cmClose];
if Flags and wfZoom <> 0 then
WindowCommands := WindowCommands + [cmZoom];
if Enable then EnableCommands(WindowCommands)
else DisableCommands(WindowCommands);
end;
end;
function TWindow.StandardScrollBar(AOptions: Word): PScrollBar;
var
R: TRect;
S: PScrollBar;
begin
GetExtent(R);
if AOptions and sbVertical = 0 then
R.Assign(R.A.X, R.B.Y-1, R.B.X-2, R.B.Y) else
R.Assign(R.B.X-2,R.A.Y+1,R.B.X,R.B.Y-1);
S := New(PScrollBar, Init(R));
Insert(S);
if AOptions and sbHandleKeyboard <> 0 then
S^.Options := S^.Options or ofPostProcess;
StandardScrollBar := S;
Flags := Flags or wfBottomLine;
end;
procedure TWindow.SizeLimits(var Min, Max: TPoint);
begin
TView.SizeLimits(Min, Max);
Min.X := MinWinSize.X;
Min.Y := MinWinSize.Y;
end;
procedure TWindow.Store(var S: TStream);
begin
TGroup.Store(S);
S.Write(Flags, SizeOf(Byte) + SizeOf(TRect) + 2 * SizeOf(Integer));
PutSubViewPtr(S, Frame);
S.WriteStr(Title);
end;
procedure TWindow.Zoom;
var
R: TRect;
Max, Min: TPoint;
begin
SizeLimits(Min, Max);
if Longint(Size) <> Longint(Max) then
begin
GetBounds(ZoomRect);
Longint(R.A) := 0;
R.B := Max;
Locate(R);
end else Locate(ZoomRect);
end;
{ Message dispatch function }
function Message(Receiver: PView; What, Command: Word;
InfoPtr: Pointer): Pointer;
var
Event: TEvent;
begin
Message := nil;
if Receiver <> nil then
begin
Event.What := What;
Event.Command := Command;
Event.InfoPtr := InfoPtr;
Receiver^.HandleEvent(Event);
if Event.What = evNothing then Message := Event.InfoPtr;
end;
end;
{ Views registration procedure }
procedure RegisterViews;
begin
RegisterType(RView);
RegisterType(RFrame);
RegisterType(RScrollBar);
RegisterType(RScroller);
RegisterType(RListViewer);
RegisterType(RGroup);
RegisterType(RWindow);
end;
procedure InvertColor(var Color: Byte);
begin
Color := ((Color and $F0) shr 4) or ((Color and $0F) shl 4);
end;
end.