📄 zproplst.~pas
字号:
const
MINCOLSIZE = 32;
DROPDOWNROWS = 8;
procedure Register;
begin
RegisterComponents('Gena''s', [TZPropList]);
end;
{ Return mimimum of two signed integers }
function EMax(A, B: Integer): Integer;
asm
{ ->EAX A
EDX B
<-EAX Min(A, B) }
CMP EAX,EDX
JGE @@Exit
MOV EAX,EDX
@@Exit:
end;
{ Return maximum of two signed integers }
function EMin(A, B: Integer): Integer;
asm
{ ->EAX A
EDX B
<-EAX Max(A, B) }
CMP EAX,EDX
JLE @@Exit
MOV EAX,EDX
@@Exit:
end;
{ TZEditorList }
constructor TZEditorList.Create(APropList: TZPropList);
begin
inherited Create;
FPropList := APropList;
end;
procedure TZEditorList.DeleteEditor(Index: Integer);
var
P: PZEditor;
begin
P := Editors[Index];
P.peEditor.Free;
FreeMem(P);
end;
function TZEditorList.IndexOfPropName(const PropName: string;
StartIndex: Integer): Integer;
var
I: Integer;
begin
if StartIndex < Count then
begin
Result := 0;
for I := StartIndex to Count - 1 do
if Editors[I].peEditor.GetName = PropName then
begin
Result := I;
Exit;
end;
end
else
Result := -1;
end;
function TZEditorList.FindPropName(const PropName: string): Integer;
var
S, Prop: string;
I: Integer;
begin
Result := -1;
S := PropName;
while S <> '' do // Expand subproperties
begin
I := Pos('\', S);
if I > 0 then
begin
Prop := Copy(S, 1, I - 1);
System.Delete(S, 1, I);
end
else
begin
Prop := S;
S := '';
end;
I := IndexOfPropName(Prop, Succ(Result));
if I <= Result then Exit;
Result := I;
if S <> '' then
with Editors[Result]^ do
if peNode then
if not peExpanded then
begin
FPropList.FCurrentIdent := peIdent + 1;
FPropList.FCurrentPos := Result + 1;
try
peEditor.GetProperties(FPropList.PropEnumProc);
except
end;
peExpanded := True;
FPropList.FPropCount := Count;
end
else Exit;
end;
end;
procedure TZEditorList.Add(Editor: PZEditor);
begin
inherited Add(Editor);
end;
procedure TZEditorList.Clear;
var
I: Integer;
begin
for I := 0 to Count - 1 do DeleteEditor(I);
inherited;
end;
function TZEditorList.GetEditor(AIndex: Integer): PZEditor;
begin
Result := Items[AIndex];
end;
{ TZPopupList }
constructor TZPopupList.Create(AOwner: TComponent);
begin
inherited;
Parent := AOwner as TWinControl;
ParentCtl3D := False;
Ctl3D := False;
Visible := False;
TabStop := False;
{$IFDEF Delphi5}
Style := lbOwnerDrawVariable;
{$ELSE}
IntegralHeight := True;
{$ENDIF}
end;
procedure TZPopupList.CreateParams(var Params: TCreateParams);
begin
inherited;
with Params do
begin
Style := Style or WS_BORDER;
ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
X := -200; // move listbox offscreen
{$IFDEF Post4}
AddBiDiModeExStyle(ExStyle);
{$ENDIF}
WindowClass.Style := CS_SAVEBITS;
end;
end;
procedure TZPopupList.CreateWnd;
begin
inherited;
{ if not (csDesigning in ComponentState) then
begin}
Windows.SetParent(Handle, 0);
CallWindowProc(DefWndProc, Handle, WM_SETFOCUS, 0, 0);
// end;
end;
procedure TZPopupList.Hide;
begin
if HandleAllocated and IsWindowVisible(Handle) then
begin
SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
end;
end;
procedure TZPopupList.KeyPress(var Key: Char);
var
TickCount: Integer;
begin
case Key of
#8, #27: FSearchText := '';
#32..#255:
begin
TickCount := GetTickCount;
if TickCount - FSearchTickCount > 2000 then FSearchText := '';
FSearchTickCount := TickCount;
if Length(FSearchText) < 32 then FSearchText := FSearchText + Key;
SendMessage(Handle, LB_SELECTSTRING, WORD(-1), Longint(PChar(FSearchText)));
Key := #0;
end;
end;
inherited Keypress(Key);
end;
{ TZListButton }
constructor TZListButton.Create(AOwner: TComponent);
begin
inherited;
FEditor := AOwner as TZInplaceEdit;
FPropList := FEditor.FPropList;
FButtonWidth := GetSystemMetrics(SM_CXVSCROLL);
FActiveList := TZPopupList.Create(Self);
FActiveList.OnMouseUp := ListMouseUp;
{$IFDEF Delphi5}
FActiveList.OnMeasureItem := MeasureHeight;
FActiveList.OnDrawItem := DrawItem;
{$ENDIF}
end;
procedure TZListButton.Hide;
begin
if HandleAllocated and IsWindowVisible(Handle) then
begin
// Invalidate;
SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_HIDEWINDOW or SWP_NOZORDER or
SWP_NOREDRAW);
end;
end;
procedure TZListButton.Paint;
var
R: TRect;
Flags, X, Y, W: Integer;
begin
R := ClientRect;
InflateRect(R, 1, 1);
Flags := 0;
with Canvas do
if FArrow then
begin
if FPressed then Flags := DFCS_FLAT or DFCS_PUSHED;
DrawFrameControl(Handle, R, DFC_SCROLL, Flags or DFCS_SCROLLCOMBOBOX);
end
else
begin
if FPressed then Flags := BF_FLAT;
DrawEdge(Handle, R, EDGE_RAISED, BF_RECT or BF_MIDDLE or Flags);
X := R.Left + ((R.Right - R.Left) shr 1) - 1 + Ord(FPressed);
Y := R.Top + ((R.Bottom - R.Top) shr 1) - 1 + Ord(FPressed);
W := FButtonWidth shr 3;
if W = 0 then W := 1;
PatBlt(Handle, X, Y, W, W, BLACKNESS);
PatBlt(Handle, X - (W + W), Y, W, W, BLACKNESS);
PatBlt(Handle, X + W + W, Y, W, W, BLACKNESS);
end;
end;
procedure TZListButton.TrackButton(X, Y: Integer);
var
NewState: Boolean;
R: TRect;
begin
R := ClientRect;
NewState := PtInRect(R, Point(X, Y));
if FPressed <> NewState then
begin
FPressed := NewState;
Invalidate;
end;
end;
function TZListButton.Editor: TPropertyEditor;
begin
Result := FPropList.Editor;
end;
type
TGetStrFunc = function(const Value: string): Integer of object;
procedure TZListButton.DropDown;
var
I, M, W: Integer;
P: TPoint;
MCanvas: TCanvas;
AddValue: TGetStrFunc;
begin
if not FListVisible then
begin
FActiveList.Clear;
with Editor do
begin
FActiveList.Sorted := paSortList in GetAttributes;
AddValue := FActiveList.Items.Add;
GetValues(TGetStrProc(AddValue));
SendMessage(FActiveList.Handle, LB_SELECTSTRING, WORD(-1), Longint(PChar(GetValue)));
end;
with FActiveList do
begin
M := EMax(1, EMin(Items.Count, DROPDOWNROWS));
{$IFDEF Delphi5}
I := FListItemHeight;
MeasureHeight(nil, 0, I);
{$ELSE}
I := ItemHeight;
{$ENDIF}
Height := M * I + 2;
width := Self.Width + FEditor.Width + 1;
end;
with FActiveList do
begin
M := ClientWidth;
MCanvas := FPropList.Canvas;
for I := 0 to Items.Count - 1 do
begin
W := MCanvas.TextWidth(Items[I]) + 4;
{$IFDEF Delphi5}
with Editor do
ListMeasureWidth(GetName, MCanvas, W);
{$ENDIF}
if W > M then M := W;
end;
ClientWidth := M;
W := Self.Parent.ClientWidth;
if Width > W then Width := W;
end;
P := Parent.ClientToScreen(Point(Left + Width, Top + Height));
with FActiveList do
begin
if P.Y + Height > Screen.Height then P.Y := P.Y - Self.Height - Height;
SetWindowPos(Handle, HWND_TOP, P.X - Width, P.Y,
0, 0, SWP_NOSIZE + SWP_SHOWWINDOW);
SetActiveWindow(Handle);
end;
SetFocus;
FListVisible := True;
end;
end;
procedure TZListButton.CloseUp(Accept: Boolean);
var
ListValue: string;
Ch: Char;
begin
if FListVisible then
begin
with FActiveList do
begin
if (ItemIndex >= 0) and (ItemIndex < Items.Count) then
ListValue := Items[ItemIndex] else Accept := False;
// Invalidate;
Hide;
Ch := #27; // Emulate ESC
FEditor.KeyPress(Ch);
end;
FListVisible := False;
if Accept then // Emulate ENTER keypress
begin
FEditor.Text := ListValue;
FEditor.Modified := True;
Ch := #13;
FEditor.KeyPress(Ch);
end;
if Focused then FEditor.SetFocus;
end;
end;
procedure TZListButton.StopTracking;
begin
if FTracking then
begin
TrackButton(-1, -1);
FTracking := False;
// MouseCapture := False;
end;
end;
procedure TZListButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if Button = mbLeft then
begin
if FListVisible then
CloseUp(False)
else
begin
// MouseCapture := True;
FTracking := True;
TrackButton(X, Y);
if FArrow then DropDown;
end;
end;
inherited;
end;
procedure TZListButton.MouseMove(Shift: TShiftState; X, Y: Integer);
var
ListPos: TPoint;
MousePos: TSmallPoint;
begin
if FTracking then
begin
TrackButton(X, Y);
if FListVisible then
begin
ListPos := FActiveList.ScreenToClient(ClientToScreen(Point(X, Y)));
if PtInRect(FActiveList.ClientRect, ListPos) then
begin
StopTracking;
MousePos := PointToSmallPoint(ListPos);
SendMessage(FActiveList.Handle, WM_LBUTTONDOWN, 0, Integer(MousePos));
Exit;
end;
end;
end;
inherited;
end;
procedure TZListButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
WasPressed: Boolean;
begin
WasPressed := FPressed;
StopTracking;
if (Button = mbLeft) and not FArrow and WasPressed then FEditor.DblClick;
inherited;
end;
procedure TZListButton.ListMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
CloseUp(PtInRect(FActiveList.ClientRect, Point(X, Y)));
end;
procedure TZListButton.DoDropDownKeys(var Key: Word; Shift: TShiftState);
begin
case Key of
VK_RETURN, VK_ESCAPE:
if FListVisible and not (ssAlt in Shift) then
begin
CloseUp(Key = VK_RETURN);
Key := 0;
end;
else
end;
end;
procedure TZListButton.CMCancelMode(var Message: TCMCancelMode);
begin
inherited;
if (Message.Sender <> Self) and (Message.Sender <> FActiveList) then
CloseUp(False);
end;
procedure TZListButton.WMCancelMode(var Msg: TWMKillFocus);
begin
StopTracking;
inherited;
end;
procedure TZListButton.WMKillFocus(var Msg: TWMKillFocus);
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -