Ignore:
Timestamp:
Apr 17, 2019, 10:42:18 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Updated Graphics32 library.
Location:
GraphicTest/Packages/Graphics32
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/Graphics32

    • Property svn:ignore set to
      lib
  • GraphicTest/Packages/Graphics32/GR32_Layers.pas

    r450 r522  
    6363  TCustomLayer = class;
    6464  TPositionedLayer = class;
     65  TRubberbandLayer = class;
    6566  TLayerClass = class of TCustomLayer;
    6667
     
    111112    function MouseMove(Shift: TShiftState; X, Y: Integer): TCustomLayer;
    112113    function MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
     114
    113115    property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
    114116    property OnChange: TNotifyEvent read FOnChange write FOnChange;
     
    122124    constructor Create(AOwner: TPersistent);
    123125    destructor Destroy; override;
     126
    124127    function  Add(ItemClass: TLayerClass): TCustomLayer;
    125128    procedure Assign(Source: TPersistent); override;
     
    131134    procedure GetViewportScale(out ScaleX, ScaleY: TFloat); virtual;
    132135    procedure GetViewportShift(out ShiftX, ShiftY: TFloat); virtual;
     136
    133137    property Count: Integer read GetCount;
    134138    property Owner: TPersistent read FOwner;
     
    137141    property MouseEvents: Boolean read FMouseEvents write SetMouseEvents;
    138142  end;
     143
     144{$IFDEF COMPILER2009_UP}
     145  TLayerEnum = class
     146   private
     147     FIndex: Integer;
     148     FLayerCollection: TLayerCollection;
     149   public
     150     constructor Create(ALayerCollection: TLayerCollection);
     151
     152     function GetCurrent: TCustomLayer;
     153     function MoveNext: Boolean;
     154
     155     property Current: TCustomLayer read GetCurrent;
     156   end;
     157
     158   TLayerCollectionHelper = class Helper for TLayerCollection
     159   public
     160     function GetEnumerator: TLayerEnum;
     161   end;
     162{$ENDIF}
    139163
    140164  TLayerState = (lsMouseLeft, lsMouseRight, lsMouseMiddle);
     
    151175    FLayerStates: TLayerStates;
    152176    FLayerOptions: Cardinal;
     177    FTag: Integer;
     178    FClicked: Boolean;
    153179    FOnHitTest: THitTestEvent;
    154180    FOnMouseDown: TMouseEvent;
     
    156182    FOnMouseUp: TMouseEvent;
    157183    FOnPaint: TPaintLayerEvent;
    158     FTag: Integer;
    159184    FOnDestroy: TNotifyEvent;
     185    FOnDblClick: TNotifyEvent;
     186    FOnClick: TNotifyEvent;
    160187    function  GetIndex: Integer;
    161188    function  GetMouseEvents: Boolean;
     
    170197    procedure AddNotification(ALayer: TCustomLayer);
    171198    procedure Changing;
     199    procedure Click;
     200    procedure DblClick;
    172201    function  DoHitTest(X, Y: Integer): Boolean; virtual;
    173202    procedure DoPaint(Buffer: TBitmap32);
     
    184213    procedure SetLayerCollection(Value: TLayerCollection); virtual;
    185214    procedure SetLayerOptions(Value: Cardinal); virtual;
     215
    186216    property Invalid: Boolean read GetInvalid write SetInvalid;
    187217    property ForceUpdate: Boolean read GetForceUpdate write SetForceUpdate;
     
    189219    constructor Create(ALayerCollection: TLayerCollection); virtual;
    190220    destructor Destroy; override;
     221
    191222    procedure BeforeDestruction; override;
    192223    procedure BringToFront;
     
    198229    procedure SendToBack;
    199230    procedure SetAsMouseListener;
     231
    200232    property Cursor: TCursor read FCursor write SetCursor;
    201233    property Index: Integer read GetIndex write SetIndex;
     
    206238    property Tag: Integer read FTag write FTag;
    207239    property Visible: Boolean read GetVisible write SetVisible;
     240
    208241    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
    209242    property OnHitTest: THitTestEvent read FOnHitTest write FOnHitTest;
    210243    property OnPaint: TPaintLayerEvent read FOnPaint write FOnPaint;
     244    property OnClick: TNotifyEvent read FOnClick write FOnClick;
     245    property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
    211246    property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
    212247    property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
     
    225260  public
    226261    constructor Create(ALayerCollection: TLayerCollection); override;
     262
    227263    function GetAdjustedRect(const R: TFloatRect): TFloatRect; virtual;
    228264    function GetAdjustedLocation: TFloatRect;
     265
    229266    property Location: TFloatRect read FLocation write SetLocation;
    230267    property Scaled: Boolean read FScaled write SetScaled;
     
    245282    constructor Create(ALayerCollection: TLayerCollection); override;
    246283    destructor Destroy; override;
     284
    247285    property AlphaHit: Boolean read FAlphaHit write FAlphaHit;
    248286    property Bitmap: TBitmap32 read FBitmap write SetBitmap;
     
    250288  end;
    251289
    252   TDragState = (dsNone, dsMove, dsSizeL, dsSizeT, dsSizeR, dsSizeB,
     290  TRBDragState = (dsNone, dsMove, dsSizeL, dsSizeT, dsSizeR, dsSizeB,
    253291    dsSizeTL, dsSizeTR, dsSizeBL, dsSizeBR);
    254292  TRBHandles = set of (rhCenter, rhSides, rhCorners, rhFrame,
    255293    rhNotLeftSide, rhNotRightSide, rhNotTopSide, rhNotBottomSide,
    256294    rhNotTLCorner, rhNotTRCorner, rhNotBLCorner, rhNotBRCorner);
    257   TRBOptions = set of (roProportional, roConstrained);
     295  TRBOptions = set of (roProportional, roConstrained, roQuantized);
    258296  TRBResizingEvent = procedure(
    259297    Sender: TObject;
    260298    const OldLocation: TFloatRect;
    261299    var NewLocation: TFloatRect;
    262     DragState: TDragState;
     300    DragState: TRBDragState;
    263301    Shift: TShiftState) of object;
    264302  TRBConstrainEvent = TRBResizingEvent;
     303
     304  TRubberbandPassMouse = class(TPersistent)
     305  private
     306    FOwner: TRubberbandLayer;
     307    FEnabled: Boolean;
     308    FToChild: Boolean;
     309    FLayerUnderCursor: Boolean;
     310    FCancelIfPassed: Boolean;
     311  protected
     312    function GetChildUnderCursor(X, Y: Integer): TPositionedLayer;
     313  public
     314    constructor Create(AOwner: TRubberbandLayer);
     315
     316    property Enabled: Boolean read FEnabled write FEnabled default False;
     317    property ToChild: Boolean read FToChild write FToChild default False;
     318    property ToLayerUnderCursor: Boolean read FLayerUnderCursor write FLayerUnderCursor default False;
     319    property CancelIfPassed: Boolean read FCancelIfPassed write FCancelIfPassed default False;
     320  end;
    265321
    266322  TRubberbandLayer = class(TPositionedLayer)
     
    273329    FHandleFill: TColor32;
    274330    FHandles: TRBHandles;
    275     FHandleSize: Integer;
     331    FHandleSize: TFloat;
    276332    FMinWidth: TFloat;
    277333    FMaxHeight: TFloat;
     
    282338    FOnConstrain: TRBConstrainEvent;
    283339    FOptions: TRBOptions;
     340    FQuantized: Integer;
     341    FPassMouse: TRubberbandPassMouse;
    284342    procedure SetFrameStippleStep(const Value: TFloat);
    285343    procedure SetFrameStippleCounter(const Value: TFloat);
     
    288346    procedure SetHandleFrame(Value: TColor32);
    289347    procedure SetHandles(Value: TRBHandles);
    290     procedure SetHandleSize(Value: Integer);
     348    procedure SetHandleSize(Value: TFloat);
    291349    procedure SetOptions(const Value: TRBOptions);
     350    procedure SetQuantized(const Value: Integer);
    292351  protected
    293     IsDragging: Boolean;
    294     DragState: TDragState;
    295     OldLocation: TFloatRect;
    296     MouseShift: TFloatPoint;
     352    FIsDragging: Boolean;
     353    FDragState: TRBDragState;
     354    FOldLocation: TFloatRect;
     355    FMouseShift: TFloatPoint;
    297356    function  DoHitTest(X, Y: Integer): Boolean; override;
    298     procedure DoResizing(var OldLocation, NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState); virtual;
    299     procedure DoConstrain(var OldLocation, NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState); virtual;
     357    procedure DoResizing(var OldLocation, NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState); virtual;
     358    procedure DoConstrain(var OldLocation, NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState); virtual;
    300359    procedure DoSetLocation(const NewLocation: TFloatRect); override;
    301     function  GetDragState(X, Y: Integer): TDragState; virtual;
     360    function  GetDragState(X, Y: Integer): TRBDragState; virtual;
    302361    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    303362    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
     
    306365    procedure Paint(Buffer: TBitmap32); override;
    307366    procedure SetLayerOptions(Value: Cardinal); override;
     367    procedure SetDragState(const Value: TRBDragState); overload;
     368    procedure SetDragState(const Value: TRBDragState; const X, Y: Integer); overload;
    308369    procedure UpdateChildLayer;
     370    procedure DrawHandle(Buffer: TBitmap32; X, Y: TFloat); virtual;
    309371  public
    310372    constructor Create(ALayerCollection: TLayerCollection); override;
     373    destructor Destroy; override;
     374
    311375    procedure SetFrameStipple(const Value: Array of TColor32);
     376    procedure Quantize;
     377
    312378    property ChildLayer: TPositionedLayer read FChildLayer write SetChildLayer;
    313379    property Options: TRBOptions read FOptions write SetOptions;
    314380    property Handles: TRBHandles read FHandles write SetHandles;
    315     property HandleSize: Integer read FHandleSize write SetHandleSize;
     381    property HandleSize: TFloat read FHandleSize write SetHandleSize;
    316382    property HandleFill: TColor32 read FHandleFill write SetHandleFill;
    317383    property HandleFrame: TColor32 read FHandleFrame write SetHandleFrame;
     
    322388    property MinHeight: TFloat read FMinHeight write FMinHeight;
    323389    property MinWidth: TFloat read FMinWidth write FMinWidth;
     390    property Quantized: Integer read FQuantized write SetQuantized default 8;
     391    property PassMouseToChild: TRubberbandPassMouse read FPassMouse;
     392
    324393    property OnUserChange: TNotifyEvent read FOnUserChange write FOnUserChange;
    325394    property OnConstrain: TRBConstrainEvent read FOnConstrain write FOnConstrain;
     
    330399
    331400uses
    332   TypInfo, GR32_Image, GR32_LowLevel, GR32_Resamplers, GR32_RepaintOpt;
     401  TypInfo, GR32_Image, GR32_LowLevel, GR32_Resamplers, GR32_RepaintOpt, Types;
    333402
    334403{ mouse state mapping }
     
    375444procedure TLayerCollection.BeginUpdate;
    376445begin
    377   if FUpdateCount = 0 then Changing;
     446  if FUpdateCount = 0 then
     447    Changing;
    378448  Inc(FUpdateCount);
    379449end;
     
    381451procedure TLayerCollection.Changed;
    382452begin
    383   if Assigned(FOnChange) then FOnChange(Self);
     453  if Assigned(FOnChange) then
     454    FOnChange(Self);
    384455end;
    385456
    386457procedure TLayerCollection.Changing;
    387458begin
    388   if Assigned(FOnChanging) then FOnChanging(Self);
     459  if Assigned(FOnChanging) then
     460    FOnChanging(Self);
    389461end;
    390462
     
    415487begin
    416488  FUpdateCount := 1; // disable update notification
    417   if Assigned(FItems) then Clear;
     489  if Assigned(FItems) then
     490    Clear;
    418491  FItems.Free;
    419492  inherited;
     
    423496begin
    424497  Dec(FUpdateCount);
    425   if FUpdateCount = 0 then Changed;
     498  if FUpdateCount = 0 then
     499    Changed;
    426500  Assert(FUpdateCount >= 0, 'Unpaired EndUpdate');
    427501end;
     
    434508  begin
    435509    Result := Items[I];
    436     if (Result.LayerOptions and OptionsMask) = 0 then Continue; // skip to the next one
     510    if (Result.LayerOptions and OptionsMask) = 0 then
     511      Continue; // skip to the next one
    437512    if Result.HitTest(X, Y) then Exit;
    438513  end;
     
    442517procedure TLayerCollection.GDIUpdate;
    443518begin
    444   if (FUpdateCount = 0) and Assigned(FOnGDIUpdate) then FOnGDIUpdate(Self);
     519  if (FUpdateCount = 0) and Assigned(FOnGDIUpdate) then
     520    FOnGDIUpdate(Self);
    445521end;
    446522
     
    538614begin
    539615  Result := MouseListener;
    540   if Result = nil then Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
    541   if Assigned(Result) then Result.MouseMove(Shift, X, Y)
    542   else if FOwner is TControl then Screen.Cursor := TControl(FOwner).Cursor;
     616  if Result = nil then
     617    Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
     618
     619  if Assigned(Result) then
     620    Result.MouseMove(Shift, X, Y)
     621  else if FOwner is TControl then
     622    Screen.Cursor := TControl(FOwner).Cursor;
    543623end;
    544624
     
    546626begin
    547627  Result := MouseListener;
    548   if Result = nil then Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
     628  if Result = nil then
     629    Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
    549630
    550631  if Assigned(Result) then
     
    562643procedure TLayerCollection.Notify(Action: TLayerListNotification; Layer: TCustomLayer; Index: Integer);
    563644begin
    564   if Assigned(FOnListNotify) then FOnListNotify(Self, Action, Layer, Index);
     645  if Assigned(FOnListNotify) then
     646    FOnListNotify(Self, Action, Layer, Index);
    565647end;
    566648
     
    607689procedure TLayerCollection.DoUpdateArea(const Rect: TRect);
    608690begin
    609   if Assigned(FOnAreaUpdated) then FOnAreaUpdated(Self, Rect, AREAINFO_RECT);
    610   Changed; 
     691  if Assigned(FOnAreaUpdated) then
     692    FOnAreaUpdated(Self, Rect, AREAINFO_RECT);
     693  Changed;
    611694end;
    612695
    613696procedure TLayerCollection.DoUpdateLayer(Layer: TCustomLayer);
    614697begin
    615   if Assigned(FOnLayerUpdated) then FOnLayerUpdated(Self, Layer);
     698  if Assigned(FOnLayerUpdated) then
     699    FOnLayerUpdated(Self, Layer);
    616700  Changed;
    617701end;
     
    639723end;
    640724
     725
     726{$IFDEF COMPILER2009_UP}
     727{ TLayerEnum }
     728
     729constructor TLayerEnum.Create(ALayerCollection: TLayerCollection);
     730begin
     731  inherited Create;
     732  FLayerCollection := ALayerCollection;
     733  FIndex := -1;
     734end;
     735
     736function TLayerEnum.GetCurrent: TCustomLayer;
     737begin
     738  Result := FLayerCollection.Items[FIndex];
     739end;
     740
     741function TLayerEnum.MoveNext: Boolean;
     742begin
     743  Result := FIndex < Pred(FLayerCollection.Count);
     744  if Result then
     745    Inc(FIndex);
     746end;
     747
     748
     749{ TLayerCollectionHelper }
     750
     751function TLayerCollectionHelper.GetEnumerator: TLayerEnum;
     752begin
     753  Result := TLayerEnum.Create(Self);
     754end;
     755{$ENDIF}
     756
     757
    641758{ TCustomLayer }
    642759
     760constructor TCustomLayer.Create(ALayerCollection: TLayerCollection);
     761begin
     762  LayerCollection := ALayerCollection;
     763  FLayerOptions := LOB_VISIBLE;
     764end;
     765
     766destructor TCustomLayer.Destroy;
     767var
     768  I: Integer;
     769begin
     770  if Assigned(FFreeNotifies) then
     771  begin
     772    for I := FFreeNotifies.Count - 1 downto 0 do
     773    begin
     774      TCustomLayer(FFreeNotifies[I]).Notification(Self);
     775      if FFreeNotifies = nil then Break;
     776    end;
     777    FFreeNotifies.Free;
     778    FFreeNotifies := nil;
     779  end;
     780  SetLayerCollection(nil);
     781  inherited;
     782end;
     783
    643784procedure TCustomLayer.AddNotification(ALayer: TCustomLayer);
    644785begin
    645   if not Assigned(FFreeNotifies) then FFreeNotifies := TList.Create;
    646   if FFreeNotifies.IndexOf(ALayer) < 0 then FFreeNotifies.Add(ALayer);
     786  if not Assigned(FFreeNotifies) then
     787    FFreeNotifies := TList.Create;
     788  if FFreeNotifies.IndexOf(ALayer) < 0 then
     789    FFreeNotifies.Add(ALayer);
    647790end;
    648791
    649792procedure TCustomLayer.BeforeDestruction;
    650793begin
    651   if Assigned(FOnDestroy) then FOnDestroy(Self);
     794  if Assigned(FOnDestroy) then
     795    FOnDestroy(Self);
    652796  inherited;
    653797end;
     
    664808  begin
    665809    Update;
    666     if Visible then FLayerCollection.Changed
     810    if Visible then
     811      FLayerCollection.Changed
    667812    else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
    668813      FLayerCollection.GDIUpdate;
     
    678823  begin
    679824    Update(Rect);
    680     if Visible then FLayerCollection.Changed
     825    if Visible then
     826      FLayerCollection.Changed
    681827    else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
    682828      FLayerCollection.GDIUpdate;
     
    694840end;
    695841
    696 constructor TCustomLayer.Create(ALayerCollection: TLayerCollection);
    697 begin
    698   LayerCollection := ALayerCollection;
    699   FLayerOptions := LOB_VISIBLE;
    700 end;
    701 
    702 destructor TCustomLayer.Destroy;
    703 var
    704   I: Integer;
    705 begin
    706   if Assigned(FFreeNotifies) then
    707   begin
    708     for I := FFreeNotifies.Count - 1 downto 0 do
    709     begin
    710       TCustomLayer(FFreeNotifies[I]).Notification(Self);
    711       if FFreeNotifies = nil then Break;
    712     end;
    713     FFreeNotifies.Free;
    714     FFreeNotifies := nil;
    715   end;
    716   SetLayerCollection(nil);
    717   inherited;
     842procedure TCustomLayer.Click;
     843begin
     844  FClicked := False;
     845  if Assigned(FOnClick) then
     846    FOnClick(Self);
     847end;
     848
     849procedure TCustomLayer.DblClick;
     850begin
     851  FClicked := False;
     852  if Assigned(FOnDblClick) then
     853    FOnDblClick(Self);
    718854end;
    719855
    720856function TCustomLayer.DoHitTest(X, Y: Integer): Boolean;
    721857begin
    722   Result := True;
     858  Result := Visible;
    723859end;
    724860
     
    726862begin
    727863  Paint(Buffer);
    728   if Assigned(FOnPaint) then FOnPaint(Self, Buffer);
     864  if Assigned(FOnPaint) then
     865    FOnPaint(Self, Buffer);
    729866end;
    730867
     
    755892begin
    756893  Result := DoHitTest(X, Y);
    757   if Assigned(FOnHitTest) then FOnHitTest(Self, X, Y, Result);
     894  if Assigned(FOnHitTest) then
     895    FOnHitTest(Self, X, Y, Result);
    758896end;
    759897
    760898procedure TCustomLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    761899begin
    762   if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
     900  if (Button = mbLeft) then
     901  begin
     902    if (ssDouble in Shift) then
     903      DblClick
     904    else
     905      FClicked := True;
     906  end;
     907  if Assigned(FOnMouseDown) then
     908    FOnMouseDown(Self, Button, Shift, X, Y);
    763909end;
    764910
     
    766912begin
    767913  Screen.Cursor := Cursor;
    768   if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y);
     914  if Assigned(FOnMouseMove) then
     915    FOnMouseMove(Self, Shift, X, Y);
    769916end;
    770917
     
    772919begin
    773920  Screen.Cursor := crDefault;
    774   if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y);
     921  if (Button = mbLeft) and FClicked then
     922    Click;
     923  if Assigned(FOnMouseUp) then
     924    FOnMouseUp(Self, Button, Shift, X, Y);
    775925end;
    776926
     
    819969  begin
    820970    FCursor := Value;
    821     if FLayerCollection.MouseListener = Self then Screen.Cursor := Value;
     971    if FLayerCollection.MouseListener = Self then
     972      Screen.Cursor := Value;
    822973  end;
    823974end;
     
    8571008    if Assigned(Value) then
    8581009      Value.InsertItem(Self);
     1010    FLayerCollection := Value;
    8591011  end;
    8601012end;
     
    9481100begin
    9491101  with GetAdjustedRect(FLocation) do
    950     Result := (X >= Left) and (X < Right) and (Y >= Top) and (Y < Bottom);
     1102    Result := (X >= Left) and (X < Right) and (Y >= Top) and (Y < Bottom) and
     1103      inherited DoHitTest(X, Y);
    9511104end;
    9521105
     
    10761229  DstRect := MakeRect(GetAdjustedRect(FLocation));
    10771230  ClipRect := Buffer.ClipRect;
    1078   IntersectRect(TempRect, ClipRect, DstRect);
    1079   if IsRectEmpty(TempRect) then Exit;
     1231  GR32.IntersectRect(TempRect, ClipRect, DstRect);
     1232  if GR32.IsRectEmpty(TempRect) then Exit;
    10801233
    10811234  SrcRect := MakeRect(0, 0, Bitmap.Width, Bitmap.Height);
     
    10901243    if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Exit;
    10911244    ImageRect := TCustomImage32(LayerCollection.FOwner).GetBitmapRect;
    1092     IntersectRect(ClipRect, ClipRect, ImageRect);
     1245    GR32.IntersectRect(ClipRect, ClipRect, ImageRect);
    10931246  end;
    10941247  StretchTransfer(Buffer, DstRect, ClipRect, FBitmap, SrcRect,
     
    11091262  end;
    11101263end;
     1264
     1265
     1266{ TRubberbandPassMouse }
     1267
     1268constructor TRubberbandPassMouse.Create(AOwner: TRubberbandLayer);
     1269begin
     1270  FOwner := AOwner;
     1271  FEnabled := False;
     1272  FToChild := False;
     1273  FLayerUnderCursor := False;
     1274  FCancelIfPassed := False;
     1275end;
     1276
     1277function TRubberbandPassMouse.GetChildUnderCursor(X, Y: Integer): TPositionedLayer;
     1278var
     1279  Layer: TCustomLayer;
     1280  Index: Integer;
     1281begin
     1282  Result := nil;
     1283  for Index := FOwner.LayerCollection.Count - 1 downto 0 do
     1284  begin
     1285    Layer := FOwner.LayerCollection.Items[Index];
     1286    if ((Layer.LayerOptions and LOB_MOUSE_EVENTS) > 0) and
     1287      (Layer is TPositionedLayer) and Layer.HitTest(X, Y) then
     1288    begin
     1289      Result := TPositionedLayer(Layer);
     1290      Exit;
     1291    end;
     1292  end;
     1293end;
     1294
    11111295
    11121296{ TRubberbandLayer }
     
    11211305  FMinWidth := 10;
    11221306  FMinHeight := 10;
     1307  FQuantized := 8;
    11231308  FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
    11241309  SetFrameStipple([clWhite32, clWhite32, clBlack32, clBlack32]);
     1310  FPassMouse := TRubberbandPassMouse.Create(Self);
    11251311  FFrameStippleStep := 1;
    11261312  FFrameStippleCounter := 0;
    11271313end;
    11281314
     1315destructor TRubberbandLayer.Destroy;
     1316begin
     1317  FPassMouse.Free;
     1318  inherited;
     1319end;
     1320
    11291321function TRubberbandLayer.DoHitTest(X, Y: Integer): Boolean;
    11301322begin
    1131   Result := GetDragState(X, Y) <> dsNone;
     1323  if (Visible) then
     1324    Result := (GetDragState(X, Y) <> dsNone)
     1325  else
     1326    Result := False;
    11321327end;
    11331328
    11341329procedure TRubberbandLayer.DoResizing(var OldLocation,
    1135   NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
     1330  NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState);
    11361331begin
    11371332  if Assigned(FOnResizing) then
     
    11401335
    11411336procedure TRubberbandLayer.DoConstrain(var OldLocation,
    1142   NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
     1337  NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState);
    11431338begin
    11441339  if Assigned(FOnConstrain) then
     
    11521347end;
    11531348
    1154 function TRubberbandLayer.GetDragState(X, Y: Integer): TDragState;
     1349function TRubberbandLayer.GetDragState(X, Y: Integer): TRBDragState;
    11551350var
    11561351  R: TRect;
     
    11581353  dl, dt, dr, db, dx, dy: Boolean;
    11591354  Sz: Integer;
     1355const
     1356  DragZone = 1;
    11601357begin
    11611358  Result := dsNone;
    1162   Sz := FHandleSize + 1;
     1359  Sz := Ceil(FHandleSize + DragZone);
    11631360  dh_center := rhCenter in FHandles;
    11641361  dh_sides := rhSides in FHandles;
     
    11861383  else if dl and dy and dh_sides and not(rhNotLeftSide in FHandles) then Result := dsSizeL
    11871384  else if dt and dx and dh_sides and not(rhNotTopSide in FHandles) then Result := dsSizeT
    1188   else if dh_center and PtInRect(R, Point(X, Y)) then Result := dsMove;
     1385  else if dh_center and GR32.PtInRect(R, GR32.Point(X, Y)) then Result := dsMove;
    11891386end;
    11901387
    11911388procedure TRubberbandLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    11921389var
    1193   ALoc: TFloatRect;
    1194 begin
    1195   if IsDragging then Exit;
    1196   DragState := GetDragState(X, Y);
    1197   IsDragging := DragState <> dsNone;
    1198   if IsDragging then
    1199   begin
    1200     OldLocation := Location;
    1201 
    1202     ALoc := GetAdjustedRect(FLocation);
    1203     case DragState of
    1204       dsMove: MouseShift := FloatPoint(X - ALoc.Left, Y - ALoc.Top);
     1390  PositionedLayer: TPositionedLayer;
     1391begin
     1392  if FPassMouse.Enabled then
     1393  begin
     1394    if FPassMouse.ToLayerUnderCursor then
     1395      PositionedLayer := FPassMouse.GetChildUnderCursor(X, Y)
    12051396    else
    1206       MouseShift := FloatPoint(0, 0);
    1207     end;
    1208   end;
     1397      PositionedLayer := ChildLayer;
     1398
     1399    if FPassMouse.ToChild and Assigned(ChildLayer) then
     1400    begin
     1401      ChildLayer.MouseDown(Button, Shift, X, Y);
     1402      if FPassMouse.CancelIfPassed then
     1403        Exit;
     1404    end;
     1405
     1406    if (PositionedLayer <> ChildLayer) and Assigned(PositionedLayer) then
     1407    begin
     1408      PositionedLayer.MouseDown(Button, Shift, X, Y);
     1409      if FPassMouse.CancelIfPassed then
     1410        Exit;
     1411    end;
     1412  end;
     1413
     1414  if FIsDragging then Exit;
     1415  SetDragState(GetDragState(X, Y), X, Y);
    12091416  inherited;
    12101417end;
     
    12121419procedure TRubberbandLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
    12131420const
    1214   CURSOR_ID: array [TDragState] of TCursor = (crDefault, crDefault, crSizeWE,
     1421  CURSOR_ID: array [TRBDragState] of TCursor = (crDefault, crDefault, crSizeWE,
    12151422    crSizeNS, crSizeWE, crSizeNS, crSizeNWSE, crSizeNESW, crSizeNESW, crSizeNWSE);
    12161423var
    12171424  Mx, My: TFloat;
    12181425  L, T, R, B, W, H: TFloat;
     1426  Quantize: Boolean;
    12191427  ALoc, NewLocation: TFloatRect;
    12201428
     
    12341442
    12351443begin
    1236   if not IsDragging then
    1237   begin
    1238     DragState := GetDragState(X, Y);
    1239     if DragState = dsMove then Screen.Cursor := Cursor
    1240     else Screen.Cursor := CURSOR_ID[DragState];
     1444  if not FIsDragging then
     1445  begin
     1446    FDragState := GetDragState(X, Y);
     1447    if FDragState = dsMove then
     1448      Screen.Cursor := Cursor
     1449    else
     1450      Screen.Cursor := CURSOR_ID[FDragState];
    12411451  end
    12421452  else
    12431453  begin
    1244     Mx := X - MouseShift.X;
    1245     My := Y - MouseShift.Y;
     1454    Mx := X - FMouseShift.X;
     1455    My := Y - FMouseShift.Y;
    12461456    if Scaled then
    12471457    with Location do
    12481458    begin
    12491459      ALoc := GetAdjustedRect(FLocation);
    1250       if IsRectEmpty(ALoc) then Exit;
     1460      if GR32.IsRectEmpty(ALoc) then Exit;
    12511461      Mx := (Mx - ALoc.Left) / (ALoc.Right - ALoc.Left) * (Right - Left) + Left;
    12521462      My := (My - ALoc.Top) / (ALoc.Bottom - ALoc.Top) * (Bottom - Top) + Top;
    12531463    end;
    12541464
    1255     with OldLocation do
     1465    with FOldLocation do
    12561466    begin
    12571467      L := Left;
     
    12631473    end;
    12641474
    1265     if DragState = dsMove then
     1475    Quantize := (roQuantized in Options) and not (ssAlt in Shift);
     1476
     1477    if FDragState = dsMove then
    12661478    begin
    12671479      L := Mx;
    12681480      T := My;
     1481      if Quantize then
     1482      begin
     1483        L := Round(L / FQuantized) * FQuantized;
     1484        T := Round(T / FQuantized) * FQuantized;
     1485      end;
    12691486      R := L + W;
    12701487      B := T + H;
     
    12721489    else
    12731490    begin
    1274       if DragState in [dsSizeL, dsSizeTL, dsSizeBL] then
     1491      if FDragState in [dsSizeL, dsSizeTL, dsSizeBL] then
     1492      begin
    12751493        IncLT(L, R, Mx - L, MinWidth, MaxWidth);
    1276 
    1277       if DragState in [dsSizeR, dsSizeTR, dsSizeBR] then
     1494        if Quantize then
     1495          L := Round(L / FQuantized) * FQuantized;
     1496      end;
     1497
     1498      if FDragState in [dsSizeR, dsSizeTR, dsSizeBR] then
     1499      begin
    12781500        IncRB(L, R, Mx - R, MinWidth, MaxWidth);
    1279 
    1280       if DragState in [dsSizeT, dsSizeTL, dsSizeTR] then
     1501        if Quantize then
     1502          R := Round(R / FQuantized) * FQuantized;
     1503      end;
     1504
     1505      if FDragState in [dsSizeT, dsSizeTL, dsSizeTR] then
     1506      begin
    12811507        IncLT(T, B, My - T, MinHeight, MaxHeight);
    1282 
    1283       if DragState in [dsSizeB, dsSizeBL, dsSizeBR] then
     1508        if Quantize then
     1509          T := Round(T / FQuantized) * FQuantized;
     1510      end;
     1511
     1512      if FDragState in [dsSizeB, dsSizeBL, dsSizeBR] then
     1513      begin
    12841514        IncRB(T, B, My - B, MinHeight, MaxHeight);
     1515        if Quantize then
     1516          B := Round(B / FQuantized) * FQuantized;
     1517      end;
    12851518    end;
    12861519
     
    12881521
    12891522    if roConstrained in FOptions then
    1290       DoConstrain(OldLocation, NewLocation, DragState, Shift);
     1523      DoConstrain(FOldLocation, NewLocation, FDragState, Shift);
    12911524
    12921525    if roProportional in FOptions then
    12931526    begin
    1294       case DragState of
     1527      case FDragState of
    12951528        dsSizeB, dsSizeBR:
    1296           NewLocation.Right := OldLocation.Left + (OldLocation.Right - OldLocation.Left) * (NewLocation.Bottom - NewLocation.Top) / (OldLocation.Bottom - OldLocation.Top);
     1529          NewLocation.Right := FOldLocation.Left + (FOldLocation.Right - FOldLocation.Left) * (NewLocation.Bottom - NewLocation.Top) / (FOldLocation.Bottom - FOldLocation.Top);
    12971530        dsSizeT, dsSizeTL:
    1298           NewLocation.Left := OldLocation.Right - (OldLocation.Right - OldLocation.Left) * (NewLocation.Bottom - NewLocation.Top) / (OldLocation.Bottom - OldLocation.Top);
     1531          NewLocation.Left := FOldLocation.Right - (FOldLocation.Right - FOldLocation.Left) * (NewLocation.Bottom - NewLocation.Top) / (FOldLocation.Bottom - FOldLocation.Top);
    12991532        dsSizeR, dsSizeBL:
    1300           NewLocation.Bottom := OldLocation.Top + (OldLocation.Bottom - OldLocation.Top) * (NewLocation.Right - NewLocation.Left) / (OldLocation.Right - OldLocation.Left);
     1533          NewLocation.Bottom := FOldLocation.Top + (FOldLocation.Bottom - FOldLocation.Top) * (NewLocation.Right - NewLocation.Left) / (FOldLocation.Right - FOldLocation.Left);
    13011534        dsSizeL, dsSizeTR:
    1302           NewLocation.Top := OldLocation.Bottom - (OldLocation.Bottom - OldLocation.Top) * (NewLocation.Right - NewLocation.Left) / (OldLocation.Right - OldLocation.Left);
     1535          NewLocation.Top := FOldLocation.Bottom - (FOldLocation.Bottom - FOldLocation.Top) * (NewLocation.Right - NewLocation.Left) / (FOldLocation.Right - FOldLocation.Left);
    13031536      end;
    13041537    end;
    13051538
    1306     DoResizing(OldLocation, NewLocation, DragState, Shift);
     1539    DoResizing(FOldLocation, NewLocation, FDragState, Shift);
    13071540
    13081541    if (NewLocation.Left <> Location.Left) or
     
    13121545    begin
    13131546      Location := NewLocation;
    1314       if Assigned(FOnUserChange) then FOnUserChange(Self);
     1547      if Assigned(FOnUserChange) then
     1548        FOnUserChange(Self);
    13151549    end;
    13161550  end;
     
    13181552
    13191553procedure TRubberbandLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    1320 begin
    1321   IsDragging := False;
     1554var
     1555  PositionedLayer: TPositionedLayer;
     1556begin
     1557  if FPassMouse.Enabled then
     1558  begin
     1559    if FPassMouse.ToLayerUnderCursor then
     1560      PositionedLayer := FPassMouse.GetChildUnderCursor(X, Y)
     1561    else
     1562      PositionedLayer := ChildLayer;
     1563
     1564    if FPassMouse.ToChild and Assigned(ChildLayer) then
     1565    begin
     1566      ChildLayer.MouseUp(Button, Shift, X, Y);
     1567      if FPassMouse.CancelIfPassed then
     1568        Exit;
     1569    end;
     1570
     1571    if (PositionedLayer <> ChildLayer) and Assigned(PositionedLayer) then
     1572    begin
     1573      PositionedLayer.MouseUp(Button, Shift, X, Y);
     1574      if FPassMouse.CancelIfPassed then
     1575        Exit;
     1576    end;
     1577  end;
     1578
     1579  FIsDragging := False;
    13221580  inherited;
    13231581end;
     
    13291587end;
    13301588
     1589procedure TRubberbandLayer.DrawHandle(Buffer: TBitmap32; X, Y: TFloat);
     1590var
     1591  HandleRect: TRect;
     1592begin
     1593  // Coordinate specifies exact center of handle. I.e. center of
     1594  // pixel if handle is odd number of pixels wide.
     1595
     1596  HandleRect.Left := Floor(X - FHandleSize);
     1597  HandleRect.Right := HandleRect.Left + Ceil(FHandleSize*2);
     1598  HandleRect.Top := Floor(Y - FHandleSize);
     1599  HandleRect.Bottom := HandleRect.Top + Ceil(FHandleSize*2);
     1600
     1601  Buffer.FrameRectTS(HandleRect, FHandleFrame);
     1602
     1603  GR32.InflateRect(HandleRect, -1, -1);
     1604  Buffer.FillRectTS(HandleRect, FHandleFill);
     1605end;
     1606
    13311607procedure TRubberbandLayer.Paint(Buffer: TBitmap32);
    1332 var
    1333   Cx, Cy: Integer;
     1608
     1609var
     1610  CenterX, CenterY: TFloat;
    13341611  R: TRect;
    1335 
    1336   procedure DrawHandle(X, Y: Integer);
    1337   begin
    1338     Buffer.FillRectTS(X - FHandleSize, Y - FHandleSize, X + FHandleSize, Y + FHandleSize, FHandleFill);
    1339     Buffer.FrameRectTS(X - FHandleSize, Y - FHandleSize, X + FHandleSize, Y + FHandleSize, FHandleFrame);
    1340   end;
    1341 
    13421612begin
    13431613  R := MakeRect(GetAdjustedRect(FLocation));
     
    13541624    if rhCorners in FHandles then
    13551625    begin
    1356       if not(rhNotTLCorner in FHandles) then DrawHandle(Left, Top);
    1357       if not(rhNotTRCorner in FHandles) then DrawHandle(Right, Top);
    1358       if not(rhNotBLCorner in FHandles) then DrawHandle(Left, Bottom);
    1359       if not(rhNotBRCorner in FHandles) then DrawHandle(Right, Bottom);
     1626      if not(rhNotTLCorner in FHandles) then DrawHandle(Buffer, Left+0.5, Top+0.5);
     1627      if not(rhNotTRCorner in FHandles) then DrawHandle(Buffer, Right-0.5, Top+0.5);
     1628      if not(rhNotBLCorner in FHandles) then DrawHandle(Buffer, Left+0.5, Bottom-0.5);
     1629      if not(rhNotBRCorner in FHandles) then DrawHandle(Buffer, Right-0.5, Bottom-0.5);
    13601630    end;
    13611631    if rhSides in FHandles then
    13621632    begin
    1363       Cx := (Left + Right) div 2;
    1364       Cy := (Top + Bottom) div 2;
    1365       if not(rhNotTopSide in FHandles) then DrawHandle(Cx, Top);
    1366       if not(rhNotLeftSide in FHandles) then DrawHandle(Left, Cy);
    1367       if not(rhNotRightSide in FHandles) then DrawHandle(Right, Cy);
    1368       if not(rhNotBottomSide in FHandles) then DrawHandle(Cx, Bottom);
    1369     end;
    1370   end;
     1633      CenterX := (Left + Right) / 2;
     1634      CenterY := (Top + Bottom) / 2;
     1635      if not(rhNotTopSide in FHandles) then DrawHandle(Buffer, CenterX, Top+0.5);
     1636      if not(rhNotLeftSide in FHandles) then DrawHandle(Buffer, Left+0.5, CenterY);
     1637      if not(rhNotRightSide in FHandles) then DrawHandle(Buffer, Right-0.5, CenterY);
     1638      if not(rhNotBottomSide in FHandles) then DrawHandle(Buffer, CenterX, Bottom-0.5);
     1639    end;
     1640  end;
     1641end;
     1642
     1643procedure TRubberbandLayer.Quantize;
     1644begin
     1645  Location := FloatRect(
     1646    Round(Location.Left / Quantized) * Quantized,
     1647    Round(Location.Top / Quantized) * Quantized,
     1648    Round(Location.Right / Quantized) * Quantized,
     1649    Round(Location.Bottom / Quantized) * Quantized);
    13711650end;
    13721651
     
    13851664end;
    13861665
     1666procedure TRubberbandLayer.SetDragState(const Value: TRBDragState);
     1667begin
     1668  SetDragState(Value, 0, 0);
     1669end;
     1670
     1671procedure TRubberbandLayer.SetDragState(const Value: TRBDragState; const X, Y: Integer);
     1672var
     1673  ALoc: TFloatRect;
     1674begin
     1675  FDragState := Value;
     1676  FIsDragging := FDragState <> dsNone;
     1677
     1678  if FIsDragging then
     1679  begin
     1680    FOldLocation := Location;
     1681
     1682    ALoc := GetAdjustedRect(FLocation);
     1683
     1684    case FDragState of
     1685      dsMove: FMouseShift := FloatPoint(X - ALoc.Left, Y - ALoc.Top);
     1686    else
     1687      FMouseShift := FloatPoint(0, 0);
     1688    end;
     1689  end;
     1690end;
     1691
    13871692procedure TRubberbandLayer.SetHandleFill(Value: TColor32);
    13881693begin
     
    14121717end;
    14131718
    1414 procedure TRubberbandLayer.SetHandleSize(Value: Integer);
    1415 begin
    1416   if Value < 1 then Value := 1;
     1719procedure TRubberbandLayer.SetHandleSize(Value: TFloat);
     1720begin
     1721  if Value < 1 then
     1722    Value := 1;
    14171723  if Value <> FHandleSize then
    14181724  begin
     
    14661772end;
    14671773
     1774procedure TRubberbandLayer.SetQuantized(const Value: Integer);
     1775begin
     1776  if Value < 1 then
     1777    raise Exception.Create('Value must be larger than zero!');
     1778
     1779  FQuantized := Value;
     1780end;
     1781
    14681782end.
Note: See TracChangeset for help on using the changeset viewer.