📄 gr32_layers.pas
字号:
end;
procedure TPositionedLayer.DoSetLocation(const NewLocation: TFloatRect);
begin
FLocation := NewLocation;
end;
function TPositionedLayer.GetAdjustedLocation: TFloatRect;
begin
Result := GetAdjustedRect(FLocation);
end;
function TPositionedLayer.GetAdjustedRect(const R: TFloatRect): TFloatRect;
var
ScaleX, ScaleY, ShiftX, ShiftY: Single;
begin
if Scaled and Assigned(FLayerCollection) then
begin
FLayerCollection.GetViewportShift(ShiftX, ShiftY);
FLayerCollection.GetViewportScale(ScaleX, ScaleY);
with Result do
begin
Left := R.Left * ScaleX + ShiftX;
Top := R.Top * ScaleY + ShiftY;
Right := R.Right * ScaleX + ShiftX;
Bottom := R.Bottom * ScaleY + ShiftY;
end;
end
else
Result := R;
end;
procedure TPositionedLayer.SetLocation(const Value: TFloatRect);
begin
Changing;
DoSetLocation(Value);
Changed;
end;
procedure TPositionedLayer.SetScaled(Value: Boolean);
begin
if Value <> FScaled then
begin
Changing;
FScaled := Value;
Changed;
end;
end;
{ TBitmapLayer }
procedure TBitmapLayer.BitmapAreaChanged(Sender: TObject; const Area: TRect; const Info: Cardinal);
var
T: TRect;
ScaleX, ScaleY: Single;
Width: Integer;
begin
if Bitmap.Empty then Exit;
if Assigned(FLayerCollection) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
begin
with GetAdjustedLocation do
begin
{ TODO : Optimize me! }
ScaleX := (Right - Left) / FBitmap.Width;
ScaleY := (Bottom - Top) / FBitmap.Height;
T.Left := Floor(Left + Area.Left * ScaleX);
T.Top := Floor(Top + Area.Top * ScaleY);
T.Right := Ceil(Left + Area.Right * ScaleX);
T.Bottom := Ceil(Top + Area.Bottom * ScaleY);
end;
Width := Trunc(FBitmap.Resampler.Width) + 1;
InflateArea(T, Width, Width);
Changed(T);
end;
end;
constructor TBitmapLayer.Create(ALayerCollection: TLayerCollection);
begin
inherited;
FBitmap := TBitmap32.Create;
FBitmap.OnAreaChanged := BitmapAreaChanged;
end;
function TBitmapLayer.DoHitTest(X, Y: Integer): Boolean;
var
BitmapX, BitmapY: Integer;
LayerWidth, LayerHeight: Integer;
begin
Result := inherited DoHitTest(X, Y);
if Result and AlphaHit then
begin
with GetAdjustedRect(FLocation) do
begin
LayerWidth := Round(Right - Left);
LayerHeight := Round(Bottom - Top);
if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Result := False
else
begin
// check the pixel alpha at (X, Y) position
BitmapX := Round((X - Left) * Bitmap.Width / LayerWidth);
BitmapY := Round((Y - Top) * Bitmap.Height / LayerHeight);
if Bitmap.PixelS[BitmapX, BitmapY] and $FF000000 = 0 then Result := False;
end;
end;
end;
end;
destructor TBitmapLayer.Destroy;
begin
FBitmap.Free;
inherited;
end;
procedure TBitmapLayer.Paint(Buffer: TBitmap32);
var
SrcRect, DstRect, ClipRect, TempRect: TRect;
ImageRect: TRect;
LayerWidth, LayerHeight: Single;
begin
if Bitmap.Empty then Exit;
DstRect := MakeRect(GetAdjustedRect(FLocation));
ClipRect := Buffer.ClipRect;
IntersectRect(TempRect, ClipRect, DstRect);
if IsRectEmpty(TempRect) then Exit;
SrcRect := MakeRect(0, 0, Bitmap.Width, Bitmap.Height);
if Cropped and (LayerCollection.FOwner is TCustomImage32) and
not (TImage32Access(LayerCollection.FOwner).PaintToMode) then
begin
with DstRect do
begin
LayerWidth := Right - Left;
LayerHeight := Bottom - Top;
end;
if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Exit;
ImageRect := TCustomImage32(LayerCollection.FOwner).GetBitmapRect;
IntersectRect(ClipRect, ClipRect, ImageRect);
end;
StretchTransfer(Buffer, DstRect, ClipRect, FBitmap, SrcRect,
FBitmap.Resampler, FBitmap.DrawMode, FBitmap.OnPixelCombine);
end;
procedure TBitmapLayer.SetBitmap(Value: TBitmap32);
begin
FBitmap.Assign(Value);
end;
procedure TBitmapLayer.SetCropped(Value: Boolean);
begin
if Value <> FCropped then
begin
FCropped := Value;
Changed;
end;
end;
{ TRubberbandLayer }
constructor TRubberbandLayer.Create(ALayerCollection: TLayerCollection);
begin
inherited;
FHandleFrame := clBlack32;
FHandleFill := clWhite32;
FHandles := [rhCenter, rhSides, rhCorners, rhFrame];
FHandleSize := 3;
FMinWidth := 10;
FMinHeight := 10;
FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
SetFrameStipple([clWhite32, clWhite32, clBlack32, clBlack32]);
FFrameStippleStep := 1;
FFrameStippleCounter := 0;
end;
function TRubberbandLayer.DoHitTest(X, Y: Integer): Boolean;
begin
Result := GetDragState(X, Y) <> dsNone;
end;
procedure TRubberbandLayer.DoResizing(var OldLocation,
NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
begin
if Assigned(FOnResizing) then
FOnResizing(Self, OldLocation, NewLocation, DragState, Shift);
end;
procedure TRubberbandLayer.DoSetLocation(const NewLocation: TFloatRect);
begin
inherited;
UpdateChildLayer;
end;
function TRubberbandLayer.GetDragState(X, Y: Integer): TDragState;
var
R: TRect;
dh_center, dh_sides, dh_corners: Boolean;
dl, dt, dr, db, dx, dy: Boolean;
Sz: Integer;
begin
Result := dsNone;
Sz := FHandleSize + 1;
dh_center := rhCenter in FHandles;
dh_sides := rhSides in FHandles;
dh_corners := rhCorners in FHandles;
R := MakeRect(GetAdjustedRect(FLocation));
with R do
begin
Dec(Right);
Dec(Bottom);
dl := Abs(Left - X) <= Sz;
dr := Abs(Right - X) <= Sz;
dx := Abs((Left + Right) div 2 - X) <= Sz;
dt := Abs(Top - Y) <= Sz;
db := Abs(Bottom - Y) <= Sz;
dy := Abs((Top + Bottom) div 2 - Y) <= Sz;
end;
if dr and db and dh_corners and not(rhNotBRCorner in FHandles) then Result := dsSizeBR
else if dl and db and dh_corners and not(rhNotBLCorner in FHandles) then Result := dsSizeBL
else if dr and dt and dh_corners and not(rhNotTRCorner in FHandles) then Result := dsSizeTR
else if dl and dt and dh_corners and not(rhNotTLCorner in FHandles) then Result := dsSizeTL
else if dr and dy and dh_sides and not(rhNotRightSide in FHandles) then Result := dsSizeR
else if db and dx and dh_sides and not(rhNotBottomSide in FHandles) then Result := dsSizeB
else if dl and dy and dh_sides and not(rhNotLeftSide in FHandles) then Result := dsSizeL
else if dt and dx and dh_sides and not(rhNotTopSide in FHandles) then Result := dsSizeT
else if dh_center and PtInRect(R, Point(X, Y)) then Result := dsMove;
end;
procedure TRubberbandLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
ALoc: TFloatRect;
begin
if IsDragging then Exit;
DragState := GetDragState(X, Y);
IsDragging := DragState <> dsNone;
if IsDragging then
begin
OldLocation := Location;
ALoc := GetAdjustedRect(FLocation);
case DragState of
dsMove: MouseShift := FloatPoint(X - ALoc.Left, Y - ALoc.Top);
else
MouseShift := FloatPoint(0, 0);
end;
end;
inherited;
end;
procedure TRubberbandLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
const
CURSOR_ID: array [TDragState] of TCursor = (crDefault, crDefault, crSizeWE,
crSizeNS, crSizeWE, crSizeNS, crSizeNWSE, crSizeNESW, crSizeNESW, crSizeNWSE);
var
Mx, My: Single;
L, T, R, B, W, H: Single;
ALoc, NewLocation: TFloatRect;
procedure IncLT(var LT, RB: Single; Delta, MinSize, MaxSize: Single);
begin
LT := LT + Delta;
if RB - LT < MinSize then LT := RB - MinSize;
if MaxSize >= MinSize then if RB - LT > MaxSize then LT := RB - MaxSize;
end;
procedure IncRB(var LT, RB: Single; Delta, MinSize, MaxSize: Single);
begin
RB := RB + Delta;
if RB - LT < MinSize then RB := LT + MinSize;
if MaxSize >= MinSize then if RB - LT > MaxSize then RB := LT + MaxSize;
end;
begin
if not IsDragging then
begin
DragState := GetDragState(X, Y);
if DragState = dsMove then Screen.Cursor := Cursor
else Screen.Cursor := CURSOR_ID[DragState];
end
else
begin
Mx := X - MouseShift.X;
My := Y - MouseShift.Y;
if Scaled then with Location do
begin
ALoc := GetAdjustedRect(FLocation);
if IsRectEmpty(ALoc) then Exit;
Mx := (Mx - ALoc.Left) / (ALoc.Right - ALoc.Left) * (Right - Left) + Left;
My := (My - ALoc.Top) / (ALoc.Bottom - ALoc.Top) * (Bottom - Top) + Top;
end;
with OldLocation do
begin
L := Left; T := Top; R := Right; B := Bottom; W := R - L; H := B - T;
end;
if DragState = dsMove then
begin
L := Mx; T := My; R := L + W; B := T + H;
end
else
begin
if DragState in [dsSizeL, dsSizeTL, dsSizeBL] then
IncLT(L, R, Mx - L, MinWidth, MaxWidth);
if DragState in [dsSizeR, dsSizeTR, dsSizeBR] then
IncRB(L, R, Mx - R, MinWidth, MaxWidth);
if DragState in [dsSizeT, dsSizeTL, dsSizeTR] then
IncLT(T, B, My - T, MinHeight, MaxHeight);
if DragState in [dsSizeB, dsSizeBL, dsSizeBR] then
IncRB(T, B, My - B, MinHeight, MaxHeight);
end;
NewLocation := FloatRect(L, T, R, B);
DoResizing(OldLocation, NewLocation, DragState, Shift);
if (NewLocation.Left <> Location.Left) or
(NewLocation.Right <> Location.Right) or
(NewLocation.Top <> Location.Top) or
(NewLocation.Bottom <> Location.Bottom) then
begin
Location := NewLocation;
if Assigned(FOnUserChange) then FOnUserChange(Self);
end;
end;
end;
procedure TRubberbandLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
IsDragging := False;
inherited;
end;
procedure TRubberbandLayer.Notification(ALayer: TCustomLayer);
begin
if ALayer = FChildLayer then
FChildLayer := nil;
end;
procedure TRubberbandLayer.Paint(Buffer: TBitmap32);
var
Cx, Cy: Integer;
R: TRect;
procedure DrawHandle(X, Y: Integer);
begin
Buffer.FillRectTS(X - FHandleSize, Y - FHandleSize, X + FHandleSize, Y + FHandleSize, FHandleFill);
Buffer.FrameRectTS(X - FHandleSize, Y - FHandleSize, X + FHandleSize, Y + FHandleSize, FHandleFrame);
end;
begin
R := MakeRect(GetAdjustedRect(FLocation));
with R do
begin
if rhFrame in FHandles then
begin
Buffer.SetStipple(FFrameStipplePattern);
Buffer.StippleCounter := 0;
Buffer.StippleStep := FFrameStippleStep;
Buffer.StippleCounter := FFrameStippleCounter;
Buffer.FrameRectTSP(Left, Top, Right, Bottom);
end;
if rhCorners in FHandles then
begin
if not(rhNotTLCorner in FHandles) then DrawHandle(Left, Top);
if not(rhNotTRCorner in FHandles) then DrawHandle(Right, Top);
if not(rhNotBLCorner in FHandles) then DrawHandle(Left, Bottom);
if not(rhNotBRCorner in FHandles) then DrawHandle(Right, Bottom);
end;
if rhSides in FHandles then
begin
Cx := (Left + Right) div 2;
Cy := (Top + Bottom) div 2;
if not(rhNotTopSide in FHandles) then DrawHandle(Cx, Top);
if not(rhNotLeftSide in FHandles) then DrawHandle(Left, Cy);
if not(rhNotRightSide in FHandles) then DrawHandle(Right, Cy);
if not(rhNotBottomSide in FHandles) then DrawHandle(Cx, Bottom);
end;
end;
end;
procedure TRubberbandLayer.SetChildLayer(Value: TPositionedLayer);
begin
if Assigned(FChildLayer) then
RemoveNotification(FChildLayer);
FChildLayer := Value;
if Assigned(Value) then
begin
Location := Value.Location;
Scaled := Value.Scaled;
AddNotification(FChildLayer);
end;
end;
procedure TRubberbandLayer.SetHandleFill(Value: TColor32);
begin
if Value <> FHandleFill then
begin
FHandleFill := Value;
FLayerCollection.GDIUpdate;
end;
end;
procedure TRubberbandLayer.SetHandleFrame(Value: TColor32);
begin
if Value <> FHandleFrame then
begin
FHandleFrame := Value;
FLayerCollection.GDIUpdate;
end;
end;
procedure TRubberbandLayer.SetHandles(Value: TRBHandles);
begin
if Value <> FHandles then
begin
FHandles := Value;
FLayerCollection.GDIUpdate;
end;
end;
procedure TRubberbandLayer.SetHandleSize(Value: Integer);
begin
if Value < 1 then Value := 1;
if Value <> FHandleSize then
begin
FHandleSize := Value;
FLayerCollection.GDIUpdate;
end;
end;
procedure TRubberbandLayer.SetFrameStipple(const Value: Array of TColor32);
var
L: Integer;
begin
L := High(Value) + 1;
SetLength(FFrameStipplePattern, L);
MoveLongword(Value[0], FFrameStipplePattern[0], L);
end;
procedure TRubberbandLayer.SetFrameStippleStep(const Value: Single);
begin
if Value <> FFrameStippleStep then
begin
FFrameStippleStep := Value;
FLayerCollection.GDIUpdate;
end;
end;
procedure TRubberbandLayer.UpdateChildLayer;
begin
if Assigned(FChildLayer) then FChildLayer.Location := Location;
end;
procedure TRubberbandLayer.SetFrameStippleCounter(const Value: Single);
begin
if Value <> FFrameStippleCounter then
begin
FFrameStippleCounter := Value;
FLayerCollection.GDIUpdate;
end;
end;
procedure TRubberbandLayer.SetLayerOptions(Value: Cardinal);
begin
Changing;
FLayerOptions := Value and not LOB_NO_UPDATE; // workaround for changed behaviour
Changed;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -