609 lines
13 KiB
Plaintext
609 lines
13 KiB
Plaintext
|
|
{*******************************************************}
|
|
{ }
|
|
{ Turbo Pascal Version 6.0 }
|
|
{ Turbo Vision Unit }
|
|
{ }
|
|
{ Copyright (c) 1990 Borland International }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit App;
|
|
|
|
{$F+,O+,S-,X+,D-}
|
|
|
|
interface
|
|
|
|
uses Objects, Drivers, Memory, HistList, Views, Menus;
|
|
|
|
const
|
|
|
|
{ TApplication palette entries }
|
|
|
|
apColor = 0;
|
|
apBlackWhite = 1;
|
|
apMonochrome = 2;
|
|
|
|
{ TApplication palettes }
|
|
|
|
CColor =
|
|
#$71#$70#$78#$74#$20#$28#$24#$17#$1F#$1A#$31#$31#$1E#$71#$00 +
|
|
#$37#$3F#$3A#$13#$13#$3E#$21#$00#$70#$7F#$7A#$13#$13#$70#$7F#$00 +
|
|
#$70#$7F#$7A#$13#$13#$70#$70#$7F#$7E#$20#$2B#$2F#$78#$2E#$70#$30 +
|
|
#$3F#$3E#$1F#$2F#$1A#$20#$72#$31#$31#$30#$2F#$3E#$31#$13#$00#$00;
|
|
|
|
CBlackWhite =
|
|
#$70#$70#$78#$7F#$07#$07#$0F#$07#$0F#$07#$70#$70#$07#$70#$00 +
|
|
#$07#$0F#$07#$70#$70#$07#$70#$00#$70#$7F#$7F#$70#$07#$70#$07#$00 +
|
|
#$70#$7F#$7F#$70#$07#$70#$70#$7F#$7F#$07#$0F#$0F#$78#$0F#$78#$07 +
|
|
#$0F#$0F#$0F#$70#$0F#$07#$70#$70#$70#$07#$70#$0F#$07#$07#$00#$00;
|
|
|
|
CMonochrome =
|
|
#$70#$07#$07#$0F#$70#$70#$70#$07#$0F#$07#$70#$70#$07#$70#$00 +
|
|
#$07#$0F#$07#$70#$70#$07#$70#$00#$70#$70#$70#$07#$07#$70#$07#$00 +
|
|
#$70#$70#$70#$07#$07#$70#$70#$70#$0F#$07#$07#$0F#$70#$0F#$70#$07 +
|
|
#$0F#$0F#$07#$70#$07#$07#$70#$07#$07#$07#$70#$0F#$07#$07#$00#$00;
|
|
|
|
|
|
{ TBackground palette }
|
|
|
|
CBackground = #1;
|
|
|
|
type
|
|
|
|
{ TBackground object }
|
|
|
|
PBackground = ^TBackground;
|
|
TBackground = object(TView)
|
|
Pattern: Char;
|
|
constructor Init(var Bounds: TRect; APattern: Char);
|
|
constructor Load(var S: TStream);
|
|
procedure Draw; virtual;
|
|
function GetPalette: PPalette; virtual;
|
|
procedure Store(var S: TStream);
|
|
end;
|
|
|
|
{ TDeskTop object }
|
|
|
|
PDeskTop = ^TDeskTop;
|
|
TDeskTop = object(TGroup)
|
|
Background: PBackground;
|
|
constructor Init(var Bounds: TRect);
|
|
procedure Cascade(var R: TRect);
|
|
procedure HandleEvent(var Event: TEvent); virtual;
|
|
procedure InitBackground; virtual;
|
|
procedure Tile(var R: TRect);
|
|
procedure TileError; virtual;
|
|
end;
|
|
|
|
{ TProgram object }
|
|
|
|
{ Palette layout }
|
|
{ 1 = TBackground }
|
|
{ 2- 7 = TMenuView and TStatusLine }
|
|
{ 8-15 = TWindow(Blue) }
|
|
{ 16-23 = TWindow(Cyan) }
|
|
{ 24-31 = TWindow(Gray) }
|
|
{ 32-63 = TDialog }
|
|
|
|
PProgram = ^TProgram;
|
|
TProgram = object(TGroup)
|
|
constructor Init;
|
|
destructor Done; virtual;
|
|
procedure GetEvent(var Event: TEvent); virtual;
|
|
function GetPalette: PPalette; virtual;
|
|
procedure HandleEvent(var Event: TEvent); virtual;
|
|
procedure Idle; virtual;
|
|
procedure InitDeskTop; virtual;
|
|
procedure InitMenuBar; virtual;
|
|
procedure InitScreen; virtual;
|
|
procedure InitStatusLine; virtual;
|
|
procedure OutOfMemory; virtual;
|
|
procedure PutEvent(var Event: TEvent); virtual;
|
|
procedure Run; virtual;
|
|
procedure SetScreenMode(Mode: Word);
|
|
function ValidView(P: PView): PView;
|
|
end;
|
|
|
|
{ TApplication object }
|
|
|
|
PApplication = ^TApplication;
|
|
TApplication = object(TProgram)
|
|
constructor Init;
|
|
destructor Done; virtual;
|
|
end;
|
|
|
|
{ App registration procedure }
|
|
|
|
procedure RegisterApp;
|
|
|
|
const
|
|
|
|
{ Public variables }
|
|
|
|
Application: PProgram = nil;
|
|
DeskTop: PDeskTop = nil;
|
|
StatusLine: PStatusLine = nil;
|
|
MenuBar: PMenuView = nil;
|
|
AppPalette: Integer = apColor;
|
|
|
|
{ Stream registration records }
|
|
|
|
RBackground: TStreamRec = (
|
|
ObjType: 30;
|
|
VmtLink: Ofs(TypeOf(TBackground)^);
|
|
Load: @TBackground.Load;
|
|
Store: @TBackground.Store);
|
|
|
|
RDeskTop: TStreamRec = (
|
|
ObjType: 31;
|
|
VmtLink: Ofs(TypeOf(TDeskTop)^);
|
|
Load: @TDeskTop.Load;
|
|
Store: @TDeskTop.Store);
|
|
|
|
implementation
|
|
|
|
const
|
|
|
|
{ Private variables }
|
|
|
|
Pending: TEvent = (What: evNothing);
|
|
|
|
{ TBackground }
|
|
|
|
constructor TBackground.Init(var Bounds: TRect; APattern: Char);
|
|
begin
|
|
TView.Init(Bounds);
|
|
GrowMode := gfGrowHiX + gfGrowHiY;
|
|
Pattern := APattern;
|
|
end;
|
|
|
|
constructor TBackground.Load(var S: TStream);
|
|
begin
|
|
TView.Load(S);
|
|
S.Read(Pattern, SizeOf(Pattern));
|
|
end;
|
|
|
|
procedure TBackground.Draw;
|
|
var
|
|
B: TDrawBuffer;
|
|
begin
|
|
MoveChar(B, Pattern, GetColor($01), Size.X);
|
|
WriteLine(0, 0, Size.X, Size.Y, B);
|
|
end;
|
|
|
|
function TBackground.GetPalette: PPalette;
|
|
const
|
|
P: string[Length(CBackground)] = CBackground;
|
|
begin
|
|
GetPalette := @P;
|
|
end;
|
|
|
|
procedure TBackground.Store(var S: TStream);
|
|
begin
|
|
TView.Store(S);
|
|
S.Write(Pattern, SizeOf(Pattern));
|
|
end;
|
|
|
|
{ TDeskTop object }
|
|
|
|
constructor TDeskTop.Init(var Bounds: TRect);
|
|
begin
|
|
TGroup.Init(Bounds);
|
|
GrowMode := gfGrowHiX + gfGrowHiY;
|
|
InitBackground;
|
|
if Background <> nil then Insert(Background);
|
|
end;
|
|
|
|
function Tileable(P: PView): Boolean;
|
|
begin
|
|
Tileable := (P^.Options and ofTileable <> 0) and
|
|
(P^.State and sfVisible <> 0);
|
|
end;
|
|
|
|
procedure TDeskTop.Cascade(var R: TRect);
|
|
var
|
|
CascadeNum: Integer;
|
|
LastView: PView;
|
|
Min, Max: TPoint;
|
|
|
|
|
|
procedure DoCount(P: PView); far;
|
|
begin
|
|
if Tileable(P) then
|
|
begin
|
|
Inc(CascadeNum);
|
|
LastView := P;
|
|
end;
|
|
end;
|
|
|
|
procedure DoCascade(P: PView); far;
|
|
var
|
|
NR: TRect;
|
|
begin
|
|
if Tileable(P) and (CascadeNum >= 0) then
|
|
begin
|
|
NR.Copy(R);
|
|
Inc(NR.A.X, CascadeNum); Inc(NR.A.Y, CascadeNum);
|
|
P^.Locate(NR);
|
|
Dec(CascadeNum);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
CascadeNum := 0;
|
|
ForEach(@DoCount);
|
|
if CascadeNum > 0 then
|
|
begin
|
|
LastView^.SizeLimits(Min, Max);
|
|
if (Min.X > R.B.X - R.A.X - CascadeNum) or
|
|
(Min.Y > R.B.Y - R.A.Y - CascadeNum) then TileError
|
|
else
|
|
begin
|
|
Dec(CascadeNum);
|
|
Lock;
|
|
ForEach(@DoCascade);
|
|
Unlock;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TDeskTop.HandleEvent(var Event: TEvent);
|
|
begin
|
|
TGroup.HandleEvent(Event);
|
|
if Event.What = evCommand then
|
|
begin
|
|
case Event.Command of
|
|
cmNext: SelectNext(False);
|
|
cmPrev: Current^.PutInFrontOf(Background);
|
|
else
|
|
Exit;
|
|
end;
|
|
ClearEvent(Event);
|
|
end;
|
|
end;
|
|
|
|
procedure TDeskTop.InitBackground;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
GetExtent(R);
|
|
New(Background, Init(R, #176));
|
|
end;
|
|
|
|
function ISqr(X: Integer): Integer; assembler;
|
|
asm
|
|
MOV CX,X
|
|
MOV BX,0
|
|
@@1: INC BX
|
|
MOV AX,BX
|
|
IMUL AX
|
|
CMP AX,CX
|
|
JLE @@1
|
|
MOV AX,BX
|
|
DEC AX
|
|
end;
|
|
|
|
procedure MostEqualDivisors(N: Integer; var X, Y: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := ISqr(N);
|
|
if ((N mod I) <> 0) then
|
|
if (N mod (I+1)) = 0 then Inc(I);
|
|
if I < (N div I) then I := N div I;
|
|
X := N div I;
|
|
Y := I;
|
|
end;
|
|
|
|
procedure TDeskTop.Tile(var R: TRect);
|
|
var
|
|
NumCols, NumRows, NumTileable, LeftOver, TileNum: Integer;
|
|
|
|
procedure DoCountTileable(P: PView); far;
|
|
begin
|
|
if Tileable(P) then Inc(NumTileable);
|
|
end;
|
|
|
|
function DividerLoc(Lo, Hi, Num, Pos: Integer): Integer;
|
|
begin
|
|
DividerLoc := LongDiv(LongMul(Hi - Lo, Pos), Num) + Lo;
|
|
end;
|
|
|
|
procedure CalcTileRect(Pos: Integer; var NR: TRect);
|
|
var
|
|
X,Y,D: Integer;
|
|
begin
|
|
D := (NumCols - LeftOver) * NumRows;
|
|
if Pos < D then
|
|
begin
|
|
X := Pos div NumRows;
|
|
Y := Pos mod NumRows;
|
|
end else
|
|
begin
|
|
X := (Pos - D) div (NumRows + 1) + (NumCols - LeftOver);
|
|
Y := (Pos - D) mod (NumRows + 1);
|
|
end;
|
|
NR.A.X := DividerLoc(R.A.X, R.B.X, NumCols, X);
|
|
NR.B.X := DividerLoc(R.A.X, R.B.X, NumCols, X+1);
|
|
if Pos >= D then
|
|
begin
|
|
NR.A.Y := DividerLoc(R.A.Y, R.B.Y, NumRows+1, Y);
|
|
NR.B.Y := DividerLoc(R.A.Y, R.B.Y, NumRows+1, Y+1);
|
|
end else
|
|
begin
|
|
NR.A.Y := DividerLoc(R.A.Y, R.B.Y, NumRows, Y);
|
|
NR.B.Y := DividerLoc(R.A.Y, R.B.Y, NumRows, Y+1);
|
|
end;
|
|
end;
|
|
|
|
procedure DoTile(P: PView); far;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if Tileable(P) then
|
|
begin
|
|
CalcTileRect(TileNum, R);
|
|
P^.Locate(R);
|
|
Dec(TileNum);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
NumTileable := 0;
|
|
ForEach(@DoCountTileable);
|
|
if NumTileable > 0 then
|
|
begin
|
|
MostEqualDivisors(NumTileable, NumCols, NumRows);
|
|
if ((R.B.X - R.A.X) div NumCols = 0) or
|
|
((R.B.Y - R.A.Y) div NumRows = 0) then TileError
|
|
else
|
|
begin
|
|
LeftOver := NumTileable mod NumCols;
|
|
TileNum := NumTileable-1;
|
|
Lock;
|
|
ForEach(@DoTile);
|
|
Unlock;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TDesktop.TileError;
|
|
begin
|
|
end;
|
|
|
|
{ TProgram }
|
|
|
|
constructor TProgram.Init;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
Application := @Self;
|
|
InitScreen;
|
|
R.Assign(0, 0, ScreenWidth, ScreenHeight);
|
|
TGroup.Init(R);
|
|
State := sfVisible + sfSelected + sfFocused + sfModal + sfExposed;
|
|
Options := 0;
|
|
Buffer := ScreenBuffer;
|
|
InitDeskTop;
|
|
InitStatusLine;
|
|
InitMenuBar;
|
|
if DeskTop <> nil then Insert(DeskTop);
|
|
if StatusLine <> nil then Insert(StatusLine);
|
|
if MenuBar <> nil then Insert(MenuBar);
|
|
end;
|
|
|
|
destructor TProgram.Done;
|
|
begin
|
|
if DeskTop <> nil then Dispose(DeskTop, Done);
|
|
if MenuBar <> nil then Dispose(MenuBar, Done);
|
|
if StatusLine <> nil then Dispose(StatusLine, Done);
|
|
Application := nil;
|
|
end;
|
|
|
|
procedure TProgram.GetEvent(var Event: TEvent);
|
|
var
|
|
R: TRect;
|
|
|
|
function ContainsMouse(P: PView): Boolean; far;
|
|
begin
|
|
ContainsMouse := (P^.State and sfVisible <> 0) and
|
|
P^.MouseInView(Event.Where);
|
|
end;
|
|
|
|
begin
|
|
if Pending.What <> evNothing then
|
|
begin
|
|
Event := Pending;
|
|
Pending.What := evNothing;
|
|
end else
|
|
begin
|
|
GetMouseEvent(Event);
|
|
if Event.What = evNothing then
|
|
begin
|
|
GetKeyEvent(Event);
|
|
if Event.What = evNothing then Idle;
|
|
end;
|
|
end;
|
|
if StatusLine <> nil then
|
|
if (Event.What and evKeyDown <> 0) or
|
|
(Event.What and evMouseDown <> 0) and
|
|
(FirstThat(@ContainsMouse) = PView(StatusLine)) then
|
|
StatusLine^.HandleEvent(Event);
|
|
end;
|
|
|
|
function TProgram.GetPalette: PPalette;
|
|
const
|
|
P: array[apColor..apMonochrome] of string[Length(CColor)] =
|
|
(CColor, CBlackWhite, CMonochrome);
|
|
begin
|
|
GetPalette := @P[AppPalette];
|
|
end;
|
|
|
|
procedure TProgram.HandleEvent(var Event: TEvent);
|
|
var
|
|
I: Word;
|
|
C: Char;
|
|
begin
|
|
if Event.What = evKeyDown then
|
|
begin
|
|
C := GetAltChar(Event.KeyCode);
|
|
if (C >= '1') and (C <= '9') then
|
|
if Message(DeskTop, evBroadCast, cmSelectWindowNum,
|
|
Pointer(Byte(C) - $30)) <> nil then ClearEvent(Event);
|
|
end;
|
|
TGroup.HandleEvent(Event);
|
|
if Event.What = evCommand then
|
|
if Event.Command = cmQuit then
|
|
begin
|
|
EndModal(cmQuit);
|
|
ClearEvent(Event);
|
|
end;
|
|
end;
|
|
|
|
procedure TProgram.Idle;
|
|
begin
|
|
if StatusLine <> nil then StatusLine^.Update;
|
|
if CommandSetChanged then
|
|
begin
|
|
Message(@Self, evBroadcast, cmCommandSetChanged, nil);
|
|
CommandSetChanged := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TProgram.InitDeskTop;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
GetExtent(R);
|
|
Inc(R.A.Y);
|
|
Dec(R.B.Y);
|
|
New(DeskTop, Init(R));
|
|
end;
|
|
|
|
procedure TProgram.InitMenuBar;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
GetExtent(R);
|
|
R.B.Y := R.A.Y + 1;
|
|
MenuBar := New(PMenuBar, Init(R, nil));
|
|
end;
|
|
|
|
procedure TProgram.InitScreen;
|
|
begin
|
|
if Lo(ScreenMode) <> smMono then
|
|
begin
|
|
if ScreenMode and smFont8x8 <> 0 then
|
|
ShadowSize.X := 1 else
|
|
ShadowSize.X := 2;
|
|
ShadowSize.Y := 1;
|
|
ShowMarkers := False;
|
|
if Lo(ScreenMode) = smBW80 then
|
|
AppPalette := apBlackWhite else
|
|
AppPalette := apColor;
|
|
end else
|
|
begin
|
|
ShadowSize.X := 0;
|
|
ShadowSize.Y := 0;
|
|
ShowMarkers := True;
|
|
AppPalette := apMonochrome;
|
|
end;
|
|
end;
|
|
|
|
procedure TProgram.InitStatusLine;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
GetExtent(R);
|
|
R.A.Y := R.B.Y - 1;
|
|
New(StatusLine, Init(R,
|
|
NewStatusDef(0, $FFFF,
|
|
NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
|
|
NewStatusKey('', kbF10, cmMenu,
|
|
NewStatusKey('', kbAltF3, cmClose,
|
|
NewStatusKey('', kbF5, cmZoom,
|
|
NewStatusKey('', kbCtrlF5, cmResize,
|
|
NewStatusKey('', kbF6, cmNext, nil)))))), nil)));
|
|
end;
|
|
|
|
procedure TProgram.OutOfMemory;
|
|
begin
|
|
end;
|
|
|
|
procedure TProgram.PutEvent(var Event: TEvent);
|
|
begin
|
|
Pending := Event;
|
|
end;
|
|
|
|
procedure TProgram.Run;
|
|
begin
|
|
Execute;
|
|
end;
|
|
|
|
procedure TProgram.SetScreenMode(Mode: Word);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
HideMouse;
|
|
SetVideoMode(Mode);
|
|
DoneMemory;
|
|
InitScreen;
|
|
Buffer := ScreenBuffer;
|
|
R.Assign(0, 0, ScreenWidth, ScreenHeight);
|
|
ChangeBounds(R);
|
|
ShowMouse;
|
|
end;
|
|
|
|
function TProgram.ValidView(P: PView): PView;
|
|
begin
|
|
ValidView := nil;
|
|
if P <> nil then
|
|
begin
|
|
if LowMemory then
|
|
begin
|
|
Dispose(P, Done);
|
|
OutOfMemory;
|
|
Exit;
|
|
end;
|
|
if not P^.Valid(cmValid) then
|
|
begin
|
|
Dispose(P, Done);
|
|
Exit;
|
|
end;
|
|
ValidView := P;
|
|
end;
|
|
end;
|
|
|
|
{ TApplication }
|
|
|
|
constructor TApplication.Init;
|
|
begin
|
|
InitMemory;
|
|
InitVideo;
|
|
InitEvents;
|
|
InitSysError;
|
|
InitHistory;
|
|
TProgram.Init;
|
|
end;
|
|
|
|
destructor TApplication.Done;
|
|
begin
|
|
TProgram.Done;
|
|
DoneHistory;
|
|
DoneSysError;
|
|
DoneEvents;
|
|
DoneVideo;
|
|
DoneMemory;
|
|
end;
|
|
|
|
{ App registration procedure }
|
|
|
|
procedure RegisterApp;
|
|
begin
|
|
RegisterType(RBackground);
|
|
RegisterType(RDeskTop);
|
|
end;
|
|
|
|
end.
|