📄 unitasgrids.pas
字号:
procedure StopTracking;
procedure TrackButton(X, Y: Integer);
procedure UpdateContents; override;
procedure WndProc(var Message: TMessage); override;
function GetEditRect: TRect; override;
public
constructor Create(Owner: TComponent); override;
procedure RestoreContents;
property ActiveList: TWinControl read FActiveList write FActiveList;
property ButtonWidth: Integer read FButtonWidth write FButtonWidth;
property DropDownRows: Integer read FDropDownRows write FDropDownRows;
property EditStyle: TEditStyle read FEditStyle;
property ListVisible: Boolean read FListVisible write FListVisible;
property PickList: TCustomListbox read GetPickList;
property PickListLoaded: Boolean read FPickListLoaded write FPickListLoaded;
property Pressed: Boolean read FPressed;
property OnEditButtonClick: TNotifyEvent read FOnEditButtonClick
write FOnEditButtonClick;
property OnGetPickListitems: TOnGetPickListItems read FOnGetPickListitems
write FOnGetPickListitems;
end;
implementation
uses Math, Consts, RTLConsts, Themes;
type
PIntArray = ^TIntArray;
TIntArray = array[0..MaxCustomExtents] of Integer;
PBooleanArray = ^TBooleanArray;
TBooleanArray = array[0..MaxCustomExtents] of Boolean;
procedure InvalidOp(const id: string);
begin
raise EInvalidGridOperation.Create(id);
end;
function GridRect(Coord1, Coord2: TGridCoord): TGridRect;
begin
with Result do
begin
Left := Coord2.X;
if Coord1.X < Coord2.X then
Left := Coord1.X;
Right := Coord1.X;
if Coord1.X < Coord2.X then
Right := Coord2.X;
Top := Coord2.Y;
if Coord1.Y < Coord2.Y then
Top := Coord1.Y;
Bottom := Coord1.Y;
if Coord1.Y < Coord2.Y then
Bottom := Coord2.Y;
end;
end;
function PointInGridRect(Col, Row: Longint; const Rect: TGridRect): Boolean;
begin
Result := (Col >= Rect.Left) and (Col <= Rect.Right) and (Row >= Rect.Top)
and (Row <= Rect.Bottom);
end;
type
TXorRects = array[0..3] of TRect;
procedure XorRects(const R1, R2: TRect; var XorRects: TXorRects);
var
Intersect, Union: TRect;
function PtInRect(X, Y: Integer; const Rect: TRect): Boolean;
begin
with Rect do
Result := (X >= Left) and (X <= Right) and (Y >= Top) and
(Y <= Bottom);
end;
function Includes(const P1: TPoint; var P2: TPoint): Boolean;
begin
with P1 do
begin
Result := PtInRect(X, Y, R1) or PtInRect(X, Y, R2);
if Result then
P2 := P1;
end;
end;
function Build(var R: TRect; const P1, P2, P3: TPoint): Boolean;
begin
Build := True;
with R do
if Includes(P1, TopLeft) then
begin
if not Includes(P3, BottomRight) then
BottomRight := P2;
end
else
if Includes(P2, TopLeft) then
BottomRight := P3
else
Build := False;
end;
begin
FillChar(XorRects, SizeOf(XorRects), 0);
if not Bool(IntersectRect(Intersect, R1, R2)) then
begin
{ Don't intersect so its simple }
XorRects[0] := R1;
XorRects[1] := R2;
end
else
begin
UnionRect(Union, R1, R2);
if Build(XorRects[0],
Point(Union.Left, Union.Top),
Point(Union.Left, Intersect.Top),
Point(Union.Left, Intersect.Bottom)) then
XorRects[0].Right := Intersect.Left;
if Build(XorRects[1],
Point(Intersect.Left, Union.Top),
Point(Intersect.Right, Union.Top),
Point(Union.Right, Union.Top)) then
XorRects[1].Bottom := Intersect.Top;
if Build(XorRects[2],
Point(Union.Right, Intersect.Top),
Point(Union.Right, Intersect.Bottom),
Point(Union.Right, Union.Bottom)) then
XorRects[2].Left := Intersect.Right;
if Build(XorRects[3],
Point(Union.Left, Union.Bottom),
Point(Intersect.Left, Union.Bottom),
Point(Intersect.Right, Union.Bottom)) then
XorRects[3].Top := Intersect.Bottom;
end;
end;
procedure ModifyExtents(var Extents: Pointer; Index, Amount: Longint;
Default: Integer);
var
LongSize, OldSize: LongInt;
NewSize: Integer;
I: Integer;
begin
if Amount <> 0 then
begin
if not Assigned(Extents) then
OldSize := 0
else
OldSize := PIntArray(Extents)^[0];
if (Index < 0) or (OldSize < Index) then
InvalidOp(SIndexOutOfRange);
LongSize := OldSize + Amount;
if LongSize < 0 then
InvalidOp(STooManyDeleted)
else
if LongSize >= MaxListSize - 1 then
InvalidOp(SGridTooLarge);
NewSize := Cardinal(LongSize);
if NewSize > 0 then
Inc(NewSize);
ReallocMem(Extents, NewSize * SizeOf(Integer));
if Assigned(Extents) then
begin
I := Index + 1;
while I < NewSize do
begin
PIntArray(Extents)^[I] := Default;
Inc(I);
end;
PIntArray(Extents)^[0] := NewSize - 1;
end;
end;
end;
procedure UpdateExtents(var Extents: Pointer; NewSize: Longint;
Default: Integer);
var
OldSize: Integer;
begin
OldSize := 0;
if Assigned(Extents) then
OldSize := PIntArray(Extents)^[0];
ModifyExtents(Extents, OldSize, NewSize - OldSize, Default);
end;
procedure MoveExtent(var Extents: Pointer; FromIndex, ToIndex: Longint);
var
Extent: Integer;
begin
if Assigned(Extents) then
begin
Extent := PIntArray(Extents)^[FromIndex];
if FromIndex < ToIndex then
Move(PIntArray(Extents)^[FromIndex + 1], PIntArray(Extents)^[FromIndex],
(ToIndex - FromIndex) * SizeOf(Integer))
else
if FromIndex > ToIndex then
Move(PIntArray(Extents)^[ToIndex], PIntArray(Extents)^[ToIndex + 1],
(FromIndex - ToIndex) * SizeOf(Integer));
PIntArray(Extents)^[ToIndex] := Extent;
end;
end;
function CompareExtents(E1, E2: Pointer): Boolean;
var
I: Integer;
begin
Result := False;
if E1 <> nil then
begin
if E2 <> nil then
begin
for I := 0 to PIntArray(E1)^[0] do
if PIntArray(E1)^[I] <> PIntArray(E2)^[I] then
Exit;
Result := True;
end
end
else
Result := E2 = nil;
end;
{ Private. LongMulDiv multiplys the first two arguments and then
divides by the third. This is used so that real number
(floating point) arithmetic is not necessary. This routine saves
the possible 64-bit value in a temp before doing the divide. Does
not do error checking like divide by zero. Also assumes that the
result is in the 32-bit range (Actually 31-bit, since this algorithm
is for unsigned). }
function LongMulDiv(Mult1, Mult2, Div1: Longint): Longint; stdcall;
{$IFDEF LINUX}
external 'libwine.borland.so' name 'MulDiv';
{$ENDIF}
{$IFDEF MSWINDOWS}
external 'kernel32.dll' name 'MulDiv';
{$ENDIF}
procedure KillMessage(Wnd: HWnd; Msg: Integer);
// Delete the requested message from the queue, but throw back
// any WM_QUIT msgs that PeekMessage may also return
var
M: TMsg;
begin
M.Message := 0;
if PeekMessage(M, Wnd, Msg, Msg, pm_Remove) and (M.Message = WM_QUIT) then
PostQuitMessage(M.wparam);
end;
type
TSelection = record
StartPos, EndPos: Integer;
end;
constructor TInplaceEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ParentCtl3D := False;
Ctl3D := False;
TabStop := False;
BorderStyle := bsNone;
DoubleBuffered := True;
end;
procedure TInplaceEdit.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or ES_MULTILINE;
end;
procedure TInplaceEdit.SetGrid(Value: TCustomASGrid);
begin
FGrid := Value;
end;
procedure TInplaceEdit.CMShowingChanged(var Message: TMessage);
begin
{ Ignore showing using the Visible property }
end;
procedure TInplaceEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
inherited;
if goTabs in Grid.Options then
Message.Result := Message.Result or DLGC_WANTTAB;
end;
procedure TInplaceEdit.WMPaste(var Message);
begin
if not EditCanModify then
Exit;
inherited
end;
procedure TInplaceEdit.WMClear(var Message);
begin
if not EditCanModify then
Exit;
inherited;
end;
procedure TInplaceEdit.WMCut(var Message);
begin
if not EditCanModify then
Exit;
inherited;
end;
procedure TInplaceEdit.DblClick;
begin
Grid.DblClick;
end;
function TInplaceEdit.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean;
begin
Result := Grid.DoMouseWheel(Shift, WheelDelta, MousePos);
end;
function TInplaceEdit.EditCanModify: Boolean;
begin
Result := Grid.CanEditModify;
end;
procedure TInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
procedure SendToParent;
begin
Grid.KeyDown(Key, Shift);
Key := 0;
end;
procedure ParentEvent;
var
GridKeyDown: TKeyEvent;
begin
GridKeyDown := Grid.OnKeyDown;
if Assigned(GridKeyDown) then
GridKeyDown(Grid, Key, Shift);
end;
function ForwardMovement: Boolean;
begin
Result := goAlwaysShowEditor in Grid.Options;
end;
function Ctrl: Boolean;
begin
Result := ssCtrl in Shift;
end;
function Selection: TSelection;
begin
SendMessage(Handle, EM_GETSEL, Longint(@Result.StartPos),
Longint(@Result.EndPos));
end;
function CaretPos: Integer;
var
P: TPoint;
begin
Windows.GetCaretPos(P);
Result := SendMessage(Handle, EM_CHARFROMPOS, 0, MakeLong(P.X, P.Y));
end;
function RightSide: Boolean;
begin
with Selection do
Result := (CaretPos = GetTextLen) and
((StartPos = 0) or (EndPos = StartPos)) and (EndPos = GetTextLen);
end;
function LeftSide: Boolean;
begin
with Selection do
Result := (CaretPos = 0) and (StartPos = 0) and
((EndPos = 0) or (EndPos = GetTextLen));
end;
begin
case Key of
VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_ESCAPE: SendToParent;
VK_INSERT:
if Shift = [] then
SendToParent
else
if (Shift = [ssShift]) and not Grid.CanEditModify then
Key := 0;
VK_LEFT:
if ForwardMovement and (Ctrl or LeftSide) then
SendToParent;
VK_RIGHT:
if ForwardMovement and (Ctrl or RightSide) then
SendToParent;
VK_HOME:
if ForwardMovement and (Ctrl or LeftSide) then
SendToParent;
VK_END:
if ForwardMovement and (Ctrl or RightSide) then
SendToParent;
VK_F2:
begin
ParentEvent;
if Key = VK_F2 then
begin
Deselect;
Exit;
end;
end;
VK_TAB:
if not (ssAlt in Shift) then
SendToParent;
VK_DELETE:
if Ctrl then
SendToParent
else
if not Grid.CanEditModify then
Key := 0;
end;
if Key <> 0 then
begin
ParentEvent;
inherited KeyDown(Key, Shift);
end;
end;
procedure TInplaceEdit.KeyPress(var Key: Char);
var
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -