📄 gr32_layers.pas
字号:
procedure TLayerCollection.InsertItem(Item: TCustomLayer);
var
Index: Integer;
begin
BeginUpdate;
try
Index := FItems.Add(Item);
Item.FLayerCollection := Self;
Notify(lnLayerAdded, Item, Index);
finally
EndUpdate;
end;
end;
function TLayerCollection.LocalToViewport(const APoint: TFloatPoint; AScaled: Boolean): TFloatPoint;
var
ScaleX, ScaleY, ShiftX, ShiftY: Single;
begin
if AScaled then
begin
GetViewportShift(ShiftX, ShiftY);
GetViewportScale(ScaleX, ScaleY);
Result.X := APoint.X * ScaleX + ShiftX;
Result.Y := APoint.Y * ScaleY + ShiftY;
end
else
Result := APoint;
end;
function TLayerCollection.ViewportToLocal(const APoint: TFloatPoint; AScaled: Boolean): TFloatPoint;
var
ScaleX, ScaleY, ShiftX, ShiftY: Single;
begin
if AScaled then
begin
GetViewportShift(ShiftX, ShiftY);
GetViewportScale(ScaleX, ScaleY);
Result.X := (APoint.X - ShiftX) / ScaleX;
Result.Y := (APoint.Y - ShiftY) / ScaleY;
end
else
Result := APoint;
end;
function TLayerCollection.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
begin
if Assigned(MouseListener) then
Result := MouseListener
else
Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
if (Result <> MouseListener) and ((Result = nil) or ((Result.FLayerOptions and LOB_NO_CAPTURE) = 0)) then
MouseListener := Result; // capture the mouse
if Assigned(MouseListener) then
begin
Include(MouseListener.FLayerStates, CStateMap[Button]);
MouseListener.MouseDown(Button, Shift, X, Y);
end;
end;
function TLayerCollection.MouseMove(Shift: TShiftState; X, Y: Integer): TCustomLayer;
begin
Result := MouseListener;
if Result = nil then Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
if Assigned(Result) then Result.MouseMove(Shift, X, Y)
else if FOwner is TControl then Screen.Cursor := TControl(FOwner).Cursor;
end;
function TLayerCollection.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
begin
Result := MouseListener;
if Result = nil then Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
if Assigned(Result) then
begin
Exclude(Result.FLayerStates, CStateMap[Button]);
Result.MouseUp(Button, Shift, X, Y);
end;
if Assigned(MouseListener) and
(MouseListener.FLayerStates *
[lsMouseLeft, lsMouseRight, lsMouseMiddle] = []) then
MouseListener := nil; // reset mouse capture
end;
procedure TLayerCollection.Notify(Action: TLayerListNotification; Layer: TCustomLayer; Index: Integer);
begin
if Assigned(FOnListNotify) then FOnListNotify(Self, Action, Layer, Index);
end;
procedure TLayerCollection.RemoveItem(Item: TCustomLayer);
var
Index: Integer;
begin
BeginUpdate;
try
Index := FItems.IndexOf(Item);
if Index >= 0 then
begin
FItems.Delete(Index);
Item.FLayerCollection := nil;
Notify(lnLayerDeleted, Item, Index);
end;
finally
EndUpdate;
end;
end;
procedure TLayerCollection.SetItem(Index: Integer; Value: TCustomLayer);
begin
TCollectionItem(FItems[Index]).Assign(Value);
end;
procedure TLayerCollection.SetMouseEvents(Value: Boolean);
begin
FMouseEvents := Value;
MouseListener := nil;
end;
procedure TLayerCollection.SetMouseListener(Value: TCustomLayer);
begin
if Value <> FMouseListener then
begin
if Assigned(FMouseListener) then
FMouseListener.FLayerStates := FMouseListener.FLayerStates -
[lsMouseLeft, lsMouseRight, lsMouseMiddle];
FMouseListener := Value;
end;
end;
procedure TLayerCollection.DoUpdateArea(const Rect: TRect);
begin
if Assigned(FOnAreaUpdated) then FOnAreaUpdated(Self, Rect, AREAINFO_RECT);
Changed;
end;
procedure TLayerCollection.DoUpdateLayer(Layer: TCustomLayer);
begin
if Assigned(FOnLayerUpdated) then FOnLayerUpdated(Self, Layer);
Changed;
end;
procedure TLayerCollection.GetViewportScale(var ScaleX, ScaleY: Single);
begin
if Assigned(FOnGetViewportScale) then
FOnGetViewportScale(Self, ScaleX, ScaleY)
else
begin
ScaleX := 1;
ScaleY := 1;
end;
end;
procedure TLayerCollection.GetViewportShift(var ShiftX, ShiftY: Single);
begin
if Assigned(FOnGetViewportShift) then
FOnGetViewportShift(Self, ShiftX, ShiftY)
else
begin
ShiftX := 0;
ShiftY := 0;
end;
end;
{ TCustomLayer }
procedure TCustomLayer.AddNotification(ALayer: TCustomLayer);
begin
if not Assigned(FFreeNotifies) then FFreeNotifies := TList.Create;
if FFreeNotifies.IndexOf(ALayer) < 0 then FFreeNotifies.Add(ALayer);
end;
procedure TCustomLayer.BeforeDestruction;
begin
if Assigned(FOnDestroy) then FOnDestroy(Self);
inherited;
end;
procedure TCustomLayer.BringToFront;
begin
Index := LayerCollection.Count;
end;
procedure TCustomLayer.Changed;
begin
if UpdateCount > 0 then Exit;
if Assigned(FLayerCollection) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
begin
Update;
if Visible then FLayerCollection.Changed
else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
FLayerCollection.GDIUpdate;
inherited;
end;
end;
procedure TCustomLayer.Changed(const Rect: TRect);
begin
if UpdateCount > 0 then Exit;
if Assigned(FLayerCollection) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
begin
Update(Rect);
if Visible then FLayerCollection.Changed
else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
FLayerCollection.GDIUpdate;
inherited Changed;
end;
end;
procedure TCustomLayer.Changing;
begin
if UpdateCount > 0 then Exit;
if Visible and Assigned(FLayerCollection) and
((FLayerOptions and LOB_NO_UPDATE) = 0) then
FLayerCollection.Changing;
end;
constructor TCustomLayer.Create(ALayerCollection: TLayerCollection);
begin
LayerCollection := ALayerCollection;
FLayerOptions := LOB_VISIBLE;
end;
destructor TCustomLayer.Destroy;
var
I: Integer;
begin
if Assigned(FFreeNotifies) then
begin
for I := FFreeNotifies.Count - 1 downto 0 do
begin
TCustomLayer(FFreeNotifies[I]).Notification(Self);
if FFreeNotifies = nil then Break;
end;
FFreeNotifies.Free;
FFreeNotifies := nil;
end;
SetLayerCollection(nil);
inherited;
end;
function TCustomLayer.DoHitTest(X, Y: Integer): Boolean;
begin
Result := True;
end;
procedure TCustomLayer.DoPaint(Buffer: TBitmap32);
begin
Paint(Buffer);
if Assigned(FOnPaint) then FOnPaint(Self, Buffer);
end;
function TCustomLayer.GetIndex: Integer;
begin
if Assigned(FLayerCollection) then
Result := FLayerCollection.FItems.IndexOf(Self)
else
Result := -1;
end;
function TCustomLayer.GetMouseEvents: Boolean;
begin
Result := FLayerOptions and LOB_MOUSE_EVENTS <> 0;
end;
function TCustomLayer.GetOwner: TPersistent;
begin
Result := FLayerCollection;
end;
function TCustomLayer.GetVisible: Boolean;
begin
Result := FLayerOptions and LOB_VISIBLE <> 0;
end;
function TCustomLayer.HitTest(X, Y: Integer): Boolean;
begin
Result := DoHitTest(X, Y);
if Assigned(FOnHitTest) then FOnHitTest(Self, X, Y, Result);
end;
procedure TCustomLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
end;
procedure TCustomLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
Screen.Cursor := Cursor;
if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y);
end;
procedure TCustomLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Screen.Cursor := crDefault;
if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y);
end;
procedure TCustomLayer.Notification(ALayer: TCustomLayer);
begin
// do nothing by default
end;
procedure TCustomLayer.Paint(Buffer: TBitmap32);
begin
// descendants override this method
end;
procedure TCustomLayer.PaintGDI(Canvas: TCanvas);
begin
// descendants override this method
end;
procedure TCustomLayer.RemoveNotification(ALayer: TCustomLayer);
begin
if Assigned(FFreeNotifies) then
begin
FFreeNotifies.Remove(ALayer);
if FFreeNotifies.Count = 0 then
begin
FFreeNotifies.Free;
FFreeNotifies := nil;
end;
end;
end;
procedure TCustomLayer.SendToBack;
begin
Index := 0;
end;
procedure TCustomLayer.SetAsMouseListener;
begin
FLayerCollection.MouseListener := Self;
Screen.Cursor := Cursor;
end;
procedure TCustomLayer.SetCursor(Value: TCursor);
begin
if Value <> FCursor then
begin
FCursor := Value;
if FLayerCollection.MouseListener = Self then Screen.Cursor := Value;
end;
end;
procedure TCustomLayer.SetIndex(Value: Integer);
var
CurIndex: Integer;
begin
CurIndex := GetIndex;
if (CurIndex >= 0) and (CurIndex <> Value) then
with FLayerCollection do
begin
if Value < 0 then Value := 0;
if Value >= Count then Value := Count - 1;
if Value <> CurIndex then
begin
if Visible then BeginUpdate;
try
FLayerCollection.FItems.Move(CurIndex, Value);
finally
if Visible then EndUpdate;
end;
end;
end;
end;
procedure TCustomLayer.SetLayerCollection(Value: TLayerCollection);
begin
if FLayerCollection <> Value then
begin
if Assigned(FLayerCollection) then
begin
if FLayerCollection.MouseListener = Self then
FLayerCollection.MouseListener := nil;
FLayerCollection.RemoveItem(Self);
end;
if Assigned(Value) then
Value.InsertItem(Self);
end;
end;
procedure TCustomLayer.SetLayerOptions(Value: Cardinal);
begin
Changing;
FLayerOptions := Value;
Changed;
end;
procedure TCustomLayer.SetMouseEvents(Value: Boolean);
begin
if Value then
LayerOptions := LayerOptions or LOB_MOUSE_EVENTS
else
LayerOptions := LayerOptions and not LOB_MOUSE_EVENTS;
end;
procedure TCustomLayer.SetVisible(Value: Boolean);
begin
if Value then
LayerOptions := LayerOptions or LOB_VISIBLE
else
begin
ForceUpdate := True;
LayerOptions := LayerOptions and not LOB_VISIBLE;
ForceUpdate := False;
end;
end;
procedure TCustomLayer.Update;
begin
if Assigned(FLayerCollection) and
(Visible or (LayerOptions and LOB_FORCE_UPDATE <> 0)) then
FLayerCollection.DoUpdateLayer(Self);
end;
procedure TCustomLayer.Update(const Rect: TRect);
begin
if Assigned(FLayerCollection) then
FLayerCollection.DoUpdateArea(Rect);
end;
function TCustomLayer.GetInvalid: Boolean;
begin
Result := LayerOptions and LOB_INVALID <> 0;
end;
procedure TCustomLayer.SetInvalid(Value: Boolean);
begin
// don't use LayerOptions here since this is internal and we don't want to
// trigger Changing and Changed as this will definitely cause a stack overflow.
if Value then
FLayerOptions := FLayerOptions or LOB_INVALID
else
FLayerOptions := FLayerOptions and not LOB_INVALID;
end;
function TCustomLayer.GetForceUpdate: Boolean;
begin
Result := LayerOptions and LOB_FORCE_UPDATE <> 0;
end;
procedure TCustomLayer.SetForceUpdate(Value: Boolean);
begin
// don't use LayerOptions here since this is internal and we don't want to
// trigger Changing and Changed as this will definitely cause a stack overflow.
if Value then
FLayerOptions := FLayerOptions or LOB_FORCE_UPDATE
else
FLayerOptions := FLayerOptions and not LOB_FORCE_UPDATE;
end;
{ TPositionedLayer }
constructor TPositionedLayer.Create(ALayerCollection: TLayerCollection);
begin
inherited;
with FLocation do
begin
Left := 0;
Top := 0;
Right := 64;
Bottom := 64;
end;
FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
end;
function TPositionedLayer.DoHitTest(X, Y: Integer): Boolean;
begin
with GetAdjustedRect(FLocation) do
Result := (X >= Left) and (X < Right) and (Y >= Top) and (Y < Bottom);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -