📄 grids.pas
字号:
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;
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 := False;
end;
procedure TInplaceEdit.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or ES_MULTILINE;
end;
procedure TInplaceEdit.SetGrid(Value: TCustomGrid);
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
Selection: TSelection;
begin
Grid.KeyPress(Key);
if (Key in [#32..#255]) and not Grid.CanEditAcceptKey(Key) then
begin
Key := #0;
MessageBeep(0);
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -