📄 controls.pas
字号:
unit Controls;
{$O+,F+,S-,X+}
interface
uses Objects, Drivers, Views, Dialogs, TVars;
const
lfTop = 0;
lfLeft = $100;
cmDeleteWindow = 1070;
CDoubleTest = #7#8;
type
PIntField = ^TIntField;
TIntField = object(TInputLine)
Min, Max: Longint;
constructor Init(var Bounds: TRect; AMaxLen: Integer;
AMin, AMax: Longint);
constructor Load(var S: TStream);
function DataSize: Word; virtual;
procedure GetData(var Rec); virtual;
procedure SetData(var Rec); virtual;
procedure Store(var S: TStream);
function Valid(Command: Word): Boolean; virtual;
end;
PCenterText = ^TCenterText;
TCenterText = object(TStaticText)
function DataSize: Word; virtual;
procedure SetData(var Rec); virtual;
end;
PDoubleTest = ^TDoubleTest;
TDoubleTest = object(TStaticText)
Hilite: Boolean;
function GetPalette: PPalette; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure Draw; virtual;
end;
PWindowListViewer = ^TWindowListViewer;
TWindowListViewer = object(TListViewer)
function DataSize: Word; virtual;
procedure GetData(var Rec); virtual;
function GetText(Item: Integer; MaxLen: Integer): string; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure SetData(var Rec); virtual;
function WindowCount: Integer;
function WindowNum(I: Integer): PWindow;
end;
PEditLine = ^TEditLine;
TEditLine = object(TInputLine)
CanExpand: Boolean;
procedure HandleEvent(var Event: TEvent); virtual;
procedure SetData(var Rec); virtual;
function LegalCharSet: PCharSet; virtual;
end;
PAddressField = ^TAddressField;
TAddressField = object(TInputLine)
function DataSize: Word; virtual;
procedure GetData(var Rec); virtual;
procedure SetData(var Rec); virtual;
function Valid(Command: Word): Boolean; virtual;
function Value(var P: Pointer): Boolean;
end;
PCtrlPLine = ^TCtrlPLine;
TCtrlPLine = object(TEditLine)
procedure HandleEvent(var Event: TEvent); virtual;
end;
const
RIntField: TStreamRec = (
ObjType: 2001;
VmtLink: Ofs(TypeOf(TIntField)^);
Load: @TIntField.Load;
Store: @TIntField.Store
);
RCenterText: TStreamRec = (
ObjType: 2002;
VmtLink: Ofs(TypeOf(TCenterText)^);
Load: @TCenterText.Load;
Store: @TCenterText.Store
);
RDoubleTest: TStreamRec = (
ObjType: 2003;
VmtLink: Ofs(TypeOf(TDoubleTest)^);
Load: @TDoubleTest.Load;
Store: @TDoubleTest.Store
);
RWindowListViewer: TStreamRec = (
ObjType: 2004;
VmtLink: Ofs(TypeOf(TWindowListViewer)^);
Load: @TWindowListViewer.Load;
Store: @TWindowListViewer.Store
);
REditLine: TStreamRec = (
ObjType: 2005;
VmtLink: Ofs(TypeOf(TEditLine)^);
Load: @TEditLine.Load;
Store: @TEditLine.Store
);
RAddressField: TStreamRec = (
ObjType: 2006;
VmtLink: Ofs(TypeOf(TAddressField)^);
Load: @TAddressField.Load;
Store: @TAddressField.Store
);
RCtrlPLine: TStreamRec = (
ObjType: 2007;
VmtLink: Ofs(TypeOf(TCtrlPLine)^);
Load: @TCtrlPLine.Load;
Store: @TCtrlPLine.Store
);
function NewButton(AX, AY, AW: Integer;ATitle: TTitleStr; ACommand: Word;
AFlags: Byte; AHelpCtx: Word): PButton;
function OkButton(AX, AY: Integer): PButton;
function CnlButton(AX, AY: Integer): PButton;
function HelpButton(AX, AY: Integer; AHelpCtx: Word): PButton;
function StandardLabel(AText: string; ALink: PView; AFlags: Word): PLabel;
function StandardHistory(ALink: PInputLine; AHistoryId: Word): PHistory;
function SetHelp(P: PView; AHelpCtx: Word): PView;
function WindowListDialog: PDialog;
implementation
uses App, Utils, StrNames, Context;
constructor TIntField.Init(var Bounds: TRect; AMaxLen: Integer;
AMin, AMax: Longint);
begin
TInputLine.Init(Bounds, AMaxLen);
Min := AMin;
Max := AMax;
end;
constructor TIntField.Load(var S: TStream);
begin
TInputLine.Load(S);
S.Read(Min, SizeOf(Min) + SizeOf(Max));
end;
function TIntField.DataSize: Word;
begin
DataSize := SizeOf(Longint);
end;
procedure TIntField.GetData(var Rec);
var
Code: Integer;
begin
Val(Data^, Longint(Rec), Code);
end;
procedure TIntField.SetData(var Rec);
begin
Str(Longint(Rec), Data^);
DrawView;
end;
procedure TIntField.Store(var S: TStream);
begin
TInputLine.Store(S);
S.Write(Min, SizeOf(Min) + SizeOf(Max));
end;
function TIntField.Valid(Command: Word): Boolean;
var
Code: Integer;
Value: Longint;
L: array[0..5] of Longint;
begin
Valid := True;
if (Command <> cmCancel) and (Command <> cmValid) then
begin
Val(Data^, Value, Code);
if (Code <> 0) or (Value < Min) or (Value > Max) then
begin
L[0] := Min;
L[1] := Max;
MessageBox(sValueNotInRange, @L, mfError + mfOkButton);
SelectAll(True);
Select;
Valid := False;
end;
end;
end;
function TCenterText.DataSize: Word;
begin
DataSize := SizeOf(string);
end;
procedure TCenterText.SetData(var Rec);
var
R: string absolute Rec;
S: string;
I: Integer;
begin
if Length(R) < Size.X then
begin
I := (Size.X - Length(R)) shr 1;
FillChar(S[1], I, ' ');
S[0] := Chr(I);
S := S + R;
end else
begin
S := R;
S[0] := Chr(Size.X)
end;
DisposeStr(Text);
Text := NewStr(S);
DrawView;
end;
function TDoubleTest.GetPalette: PPalette;
const
P: string[Length(CDoubleTest)] = CDoubleTest;
begin
GetPalette := @P;
end;
procedure TDoubleTest.HandleEvent(var Event: TEvent);
begin
TStaticText.HandleEvent(Event);
if Event.What = evMouseDown then
begin
if Event.Double then
begin
Hilite := not Hilite;
DrawView;
end;
ClearEvent(Event);
end;
end;
procedure TDoubleTest.Draw;
var
B: TDrawBuffer;
Color: Byte;
begin
if Hilite then
Color := GetColor(2)
else
Color := GetColor(1);
MoveChar(B, ' ', Color, Size.X);
MoveStr(B, Text^, Color);
WriteLine(0, 0, Size.X, 1, B);
end;
function TWindowListViewer.WindowCount: Integer;
var
I: Integer;
procedure DoWindowCount(P: PView); far;
begin
if (P^.State and sfVisible <> 0) and (P^.Options and ofSelectable <> 0) then
Inc(I);
end;
begin
I := 0;
Desktop^.ForEach(@DoWindowCount);
WindowCount := I;
end;
function TWindowListViewer.DataSize: Word;
begin
DataSize := SizeOf(PWindow);
end;
procedure TWindowListViewer.GetData(var Rec);
function DoGetData(P: PView): Boolean; far;
begin
DoGetData := False;
if (P^.State and sfVisible <> 0) and (P^.Options and ofSelectable <> 0) then
if Focused = 0 then
DoGetData := True
else
Dec(Focused);
end;
begin
PView(Rec) := Desktop^.FirstThat(@DoGetData);
end;
function TWindowListViewer.WindowNum(I: Integer): PWindow;
function DoWindowNum(P: PView): Boolean; far;
begin
DoWindowNum := False;
if (P^.State and sfVisible <> 0) and (P^.Options and ofSelectable <> 0) and
(P <> PView(Owner)) then
if I = 0 then
DoWindowNum := True
else
Dec(I);
end;
begin
WindowNum := PWindow(Desktop^.FirstThat(@DoWindowNum));
end;
function TWindowListViewer.GetText(Item: Integer; MaxLen: Integer): string;
var
P: PWindow;
begin
P := WindowNum(Item);
if P <> nil then
GetText := P^.GetTitle(MaxLen)
else
GetText := '';
end;
procedure TWindowListViewer.HandleEvent(var Event: TEvent);
var
P: PWindow;
begin
if (Event.What = evMouseDown) and Event.Double then
begin
Event.What := evCommand;
Event.Command := cmOK;
PutEvent(Event);
ClearEvent(Event);
end;
if PDialog(Owner)^.Phase = phFocused then
TListViewer.HandleEvent(Event);
if ((Event.What = evCommand) and (Event.Command = cmDeleteWindow)) or
((Event.What = evKeyDown) and (Event.keycode = kbDel)) then
begin
P := WindowNum(Focused);
if (P <> nil) and (Message(P, evCommand, cmClose, nil) <> nil) then
begin
SetRange(WindowCount);
DrawView;
end;
ClearEvent(Event);
end;
end;
procedure TWindowListViewer.SetData(var Rec);
begin
SetRange(WindowCount);
if Range > 1 then FocusItem(1);
end;
function WindowListDialog: PDialog;
var
R: TRect;
Dialog: PDialog;
Control: PView;
begin
R.Assign(15, 3, 67, 18);
Dialog := New(PDialog, Init(R, 'Window List'));
with Dialog^ do
begin
Options := Options or ofCentered;
R.Assign(39, 3, 40, 13);
Control := New(PScrollBar, Init(R));
Insert(Control);
R.Assign(3, 3, 39, 13);
Control := SetHelp(New(PWindowListViewer,
Init(R, 1, nil, PScrollBar(Control))), hcWindowListViewer);
Control^.Options := Control^.Options or ofPostProcess;
Insert(Control);
Insert(StandardLabel('~W~indows', Control, lfTop));
Insert(OkButton(40, 3));
Insert(NewButton(40, 6, 10, '~D~elete', cmDeleteWindow, bfNormal,
hcDeleteWindowButton));
Insert(CnlButton(40, 9));
Insert(HelpButton(40, 12, hcWindowListDialog));
SelectNext(False);
end;
WindowListDialog := Dialog;
end;
procedure TEditLine.SetData(var Rec);
var
R: string absolute Rec;
begin
if Data^ = '' then
if R = '' then
Data ^:= GetEditWord(MaxLen, LegalCharSet)
else Data^ := R;
CanExpand := True;
end;
procedure TEditLine.HandleEvent(var Event: TEvent);
var
I: Integer;
C: Char;
begin
I := Length(Data^);
C := Event.CharCode;
if CanExpand and (Event.What = evKeyDown) then
case CtrlToArrow(Event.KeyCode) of
kbRight:
if Length(Data^) = CurPos then
begin
Event.CharCode := GetEditChar(CurPos + 1);
Inc(I);
end;
end;
TInputLine.HandleEvent(Event);
Event.CharCode := C;
CanExpand := CanExpand and (Length(Data^) = I);
end;
function TEditLine.LegalCharSet: PCharSet;
begin
LegalCharSet := @WordChars;
end;
function TAddressField.DataSize: Word;
begin
DataSize := SizeOf(Pointer);
end;
function TAddressField.Value(var P: Pointer): Boolean;
var
I, Code1, Code2: Integer;
begin
Value := False;
I := Pos(':', Data^);
if I <> 0 then
begin
Val('$' + Copy(Data^, 1, I - 1), PtrRec(P).Seg, Code1);
Val('$' + Copy(Data^, I + 1, 255), PtrRec(P).Ofs, Code2);
if Code1 + Code2 = 0 then
Value := True;
end;
end;
procedure TAddressField.GetData(var Rec);
begin
Value(Pointer(Rec));
end;
procedure TAddressField.SetData(var Rec);
var
L: array[0..1] of Longint;
begin
L[0] := PtrRec(Rec).Seg;
L[1] := PtrRec(Rec).Ofs;
FormatStr(Data^, '%04x:%04x', L);
end;
function TAddressField.Valid(Command: Word): Boolean;
var
P: Pointer;
begin
Valid := True;
if (Command <> cmCancel) and (Command <> cmValid) and not Value(P) then
begin
MessageBox(sInvalidAddress, nil, mfError + mfOkButton);
SelectAll(True);
Valid := False;
end;
end;
procedure TCtrlPLine.HandleEvent(var Event: TEvent);
procedure DeleteSelect;
begin
if SelStart <> SelEnd then
begin
Delete(Data^, SelStart + 1, SelEnd - SelStart);
CurPos := SelStart;
end;
end;
var
I: Integer;
begin
TEditLine.HandleEvent(Event);
if (Event.What = evKeyDown) and (Event.CharCode = ^P) and
(Length(Data^) < MaxLen) then
begin
KeyEvent(Event);
if State and sfCursorIns <> 0 then
Delete(Data^, CurPos + 1, 1)
else
DeleteSelect;
if FirstPos > CurPos then
FirstPos := CurPos;
Inc(CurPos);
Insert(Event.CharCode, Data^, CurPos);
SelStart := 0;
SelEnd := 0;
if FirstPos > CurPos then
FirstPos := CurPos;
I := CurPos - Size.X + 2;
if FirstPos < I then
FirstPos := I;
ClearEvent(Event);
DrawView;
end;
end;
function NewButton(AX, AY, AW: Integer; ATitle: TTitleStr; ACommand: Word;
AFlags: Byte; AHelpCtx: Word): PButton;
var
R: TRect;
begin
R.Assign(AX, AY, AX + AW, AY + 2);
NewButton := PButton(SetHelp(New(PButton,
Init(R, ATitle, ACommand, AFlags)), AHelpCtx));
end;
function OkButton(AX, AY: Integer): PButton;
begin
OkButton := NewButton(AX, AY, 10, 'O~K~', cmOK, bfDefault, hcOKButton);
end;
function CnlButton(AX, AY: Integer): PButton;
begin
CnlButton := NewButton(AX, AY, 10, 'Cancel', cmCancel, bfNormal, hcCnlButton);
end;
function HelpButton(AX, AY: Integer; AHelpCtx: Word): PButton;
begin
HelpButton := NewButton(AX, AY, 10, 'Help', cmHelp, bfNormal, AHelpCtx);
end;
function StandardLabel(AText: string; ALink: PView; AFlags: Word): PLabel;
var
R: TRect;
begin
ALink^.GetBounds(R);
if AFlags and lfLeft <> 0 then
begin
if Lo(AFlags) = 0 then
begin
R.B.X := R.A.X - 1;
Dec(R.A.X, CStrLen(AText) + 2);
end else
begin
R.A.X := Lo(AFlags);
R.B.X := R.A.X + CStrLen(AText) + 1;
end;
end else
begin
Dec(R.A.X);
Dec(R.A.Y);
R.B.X := R.A.X + CStrLen(AText) + 1;
R.B.Y := R.A.Y + 1;
end;
R.B.Y := R.A.Y + 1;
StandardLabel := New(PLabel, Init(R, AText, ALink));
end;
function StandardHistory(ALink: PInputLine; AHistoryId: Word): PHistory;
var
R: TRect;
begin
ALink^.GetBounds(R);
R.A.X := R.B.X;
Inc(R.B.X, 3);
StandardHistory := New(PHistory, Init(R, ALink, AHistoryId));
end;
function SetHelp(P: PView; AHelpCtx: Word): PView;
begin
P^.HelpCtx := AHelpCtx;
SetHelp := P;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -