CnDragResizer.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnDragResizer;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:不可视工具组件包
  24. * 单元名称:DragResizer 组件实现单元
  25. * 单元作者:匿名
  26. * 移 植:刘啸 (liuxiao@cnpack.org)
  27. * 备 注:能在运行期关联一可视化组件,使其具有拖动与改变大小的设计能力
  28. * 开发平台:PWinXP SP3 + Delphi 7
  29. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7 C++Builder 5/6
  30. * 本 地 化:该单元中的字符串均符合本地化处理方式
  31. * 单元标识:$Id$
  32. * 修改记录:2008.05.28
  33. * 移植单元
  34. ================================================================================
  35. |</PRE>}
  36. interface
  37. {$I CnPack.inc}
  38. uses
  39. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  40. ExtCtrls;
  41. const
  42. CN_GRID_DEF_INTERVAL = 4;
  43. type
  44. TCnDragResizer = class;
  45. TMover = class;
  46. TMovingEvent = procedure(Sender: TCnDragResizer; var NewLeft,
  47. NewTop: Integer) of object;
  48. TSizingEvent = procedure(Sender: TCnDragResizer; var NewLeft, NewTop, NewWidth,
  49. NewHeight: Integer) of object;
  50. TCnDragResizer = class(TComponent)
  51. protected
  52. FActive: Boolean;
  53. FControl: TControl;
  54. FSizers: TList;
  55. FGroupMovers : TList;
  56. FGroup: TWinControl;
  57. FGridX: Integer;
  58. FGridY: Integer;
  59. FOnSized: TNotifyEvent;
  60. FOnSizing: TSizingEvent;
  61. FOnMoved: TNotifyEvent;
  62. FOnMoving: TMovingEvent;
  63. FSizing: Boolean;
  64. FMoving: Boolean;
  65. FOrigSize: TRect;
  66. FNewSize: TRect;
  67. FDownX: Integer;
  68. FDownY: Integer;
  69. FAllowSize: Boolean;
  70. FAllowMove: Boolean;
  71. FKeepInParent: Boolean;
  72. FShowBounds: Boolean;
  73. FOneMover: TMover;
  74. FCurMover: TMover;
  75. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  76. procedure SetActive(b: Boolean);
  77. procedure SetControl(c: TControl);
  78. procedure SetGroup(p: TWinControl);
  79. procedure CreateSizers;
  80. procedure CheckSizers;
  81. procedure ShowSizers;
  82. procedure HideSizers;
  83. procedure SizerDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  84. procedure SizerUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  85. procedure SizerMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  86. procedure MoverDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  87. procedure MoverUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  88. procedure MoverMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  89. procedure DrawSizeRect(Rect: TRect);
  90. procedure Calc_Size_Rect(SizerNum, dx, dy: Integer);
  91. procedure DoSizingEvent;
  92. procedure Calc_Move_Rect(dx, dy: Integer);
  93. procedure DoMovingEvent;
  94. procedure Constrain_Size;
  95. procedure Constrain_Move;
  96. procedure MoverKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  97. procedure DoSizeMove(var Key: Word; Shift: TShiftState; dx, dy: Integer);
  98. procedure CreateGroupMovers;
  99. procedure CreateOneMover(m: TMover; c: TControl);
  100. function FindMoverByBuddy(c: TControl): TMover;
  101. property ResizeGroup: TWinControl read FGroup write SetGroup;
  102. public
  103. constructor Create(AOwner: TComponent); override;
  104. destructor Destroy; override;
  105. published
  106. property Active: Boolean read FActive write SetActive default True;
  107. {* 是否使能}
  108. property Control: TControl read FControl write SetControl;
  109. {* 关联的控件}
  110. property GridX: Integer read FGridX write FGridX default CN_GRID_DEF_INTERVAL;
  111. {* X 方向拖动的步长}
  112. property GridY: Integer read FGridY write FGridY default CN_GRID_DEF_INTERVAL;
  113. {* Y 方向拖动的步长}
  114. property AllowSize: Boolean read FAllowSize write FAllowSize default True;
  115. {* 是否允许改变大小}
  116. property AllowMove: Boolean read FAllowMove write FAllowMove default True;
  117. {* 是否允许拖动}
  118. property KeepInParent: Boolean read FKeepInParent write FKeepInParent default True;
  119. {* 是否限制在其Parent内}
  120. property ShowBounds: Boolean read FShowBounds write FShowBounds;
  121. {* 是否拖动时显示边框}
  122. property OnSized: TNotifyEvent read FOnSized write FOnSized;
  123. {* 所关联控件改变尺寸后触发}
  124. property OnSizing: TSizingEvent read FOnSizing write FOnSizing;
  125. {* 所关联控件改变尺寸时触发}
  126. property OnMoved: TNotifyEvent read FOnMoved write FOnMoved;
  127. {* 所关联控件拖动后触发}
  128. property OnMoving: TMovingEvent read FOnMoving write FOnMoving;
  129. {* 所关联控件拖动时触发}
  130. end;
  131. TInvisWin = class(TPanel)
  132. protected
  133. procedure WndProc(var Message: TMessage); override;
  134. procedure CreateParams(var Params: TCreateParams); override;
  135. procedure WMDLGCode(var Message: TMessage); message WM_GETDLGCODE;
  136. public
  137. property OnKeyDown;
  138. end;
  139. TMover = class(TInvisWin)
  140. public
  141. Buddy: TControl;
  142. procedure Show;
  143. end;
  144. implementation
  145. const
  146. SIZE = 6;
  147. HALFSIZE = SIZE div 2;
  148. type
  149. TSizer = class(TPanel)
  150. end;
  151. procedure TInvisWin.WndProc(var Message: TMessage);
  152. var
  153. ps : TPaintStruct;
  154. begin
  155. case Message.Msg of
  156. WM_ERASEBKGND: Message.Result := 1;
  157. WM_PAINT: begin
  158. BeginPaint(Handle, ps);
  159. EndPaint(Handle, ps);
  160. Message.Result := 1;
  161. end;
  162. else
  163. inherited WndProc(Message);
  164. end;
  165. end;
  166. procedure TInvisWin.CreateParams(var Params: TCreateParams);
  167. begin
  168. inherited;
  169. Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT;
  170. end;
  171. procedure TInvisWin.WMDLGCode(var Message: TMessage);
  172. begin
  173. Message.Result := DLGC_WANTARROWS or DLGC_WANTALLKEYS;
  174. end;
  175. // TMover
  176. procedure TMover.Show;
  177. begin
  178. Assert(Buddy <> nil);
  179. BoundsRect := Buddy.BoundsRect;
  180. Parent := Buddy.Parent;
  181. Visible := True;
  182. BringToFront;
  183. end;
  184. // TCnDragResizer
  185. constructor TCnDragResizer.Create(AOwner: TComponent);
  186. begin
  187. inherited;
  188. FActive := True;
  189. FKeepInParent := True;
  190. FGridX := CN_GRID_DEF_INTERVAL;
  191. FGridY := CN_GRID_DEF_INTERVAL;
  192. FAllowSize := True;
  193. FAllowMove := True;
  194. FGroupMovers := TList.Create;
  195. FSizers := TList.Create;
  196. FOneMover := TMover.Create(Self);
  197. CreateOneMover(FOneMover, nil);
  198. CreateSizers;
  199. end;
  200. destructor TCnDragResizer.Destroy;
  201. begin
  202. FGroupMovers.Free;
  203. FSizers.Free;
  204. FSizers := nil;
  205. inherited;
  206. end;
  207. procedure TCnDragResizer.Notification(AComponent: TComponent; Operation: TOperation);
  208. begin
  209. inherited;
  210. if csDestroying in ComponentState then
  211. Exit;
  212. if (AComponent = FControl) and (Operation = opRemove) then
  213. FControl := nil;
  214. end;
  215. procedure TCnDragResizer.SetActive(b: Boolean);
  216. begin
  217. if b <> FActive then
  218. begin
  219. FActive := b;
  220. CheckSizers;
  221. end;
  222. end;
  223. procedure TCnDragResizer.SetControl(c: TControl);
  224. begin
  225. if c <> FControl then
  226. begin
  227. if c <> nil then
  228. begin
  229. if ResizeGroup <> nil then
  230. begin
  231. Assert(c.Parent = ResizeGroup, 'FControl is not in ResizeGroup!');
  232. FCurMover := FindMoverByBuddy(c);
  233. end else begin
  234. FCurMover := FOneMover;
  235. FCurMover.Buddy := c;
  236. end;
  237. FCurMover.Show;
  238. end;
  239. FControl := c;
  240. CheckSizers;
  241. end;
  242. end;
  243. procedure TCnDragResizer.SetGroup(p: TWinControl);
  244. begin
  245. if p <> FGroup then
  246. begin
  247. FGroup := p;
  248. CreateGroupMovers;
  249. end;
  250. end;
  251. procedure TCnDragResizer.CreateGroupMovers;
  252. var
  253. i : Integer;
  254. m : TMover;
  255. c : TControl;
  256. begin
  257. if csDesigning in ComponentState then
  258. Exit;
  259. // Clear out the old Movers
  260. for i := 0 to FGroupMovers.Count - 1 do
  261. TObject(FGroupMovers[i]).Free;
  262. FGroupMovers.Clear;
  263. if ResizeGroup <> nil then
  264. begin
  265. for i := 0 to ResizeGroup.ControlCount-1 do
  266. begin
  267. c := ResizeGroup.Controls[i];
  268. if (c is TMover) or (c is TSizer) then
  269. Continue;
  270. m := TMover.Create(Self);
  271. CreateOneMover(m, c);
  272. FGroupMovers.Add(m);
  273. m.Show;
  274. end;
  275. end;
  276. end;
  277. procedure TCnDragResizer.CreateSizers;
  278. var
  279. i : Integer;
  280. p : TSizer;
  281. begin
  282. if csDesigning in ComponentState then
  283. Exit;
  284. for i := 0 to 7 do
  285. begin
  286. p := TSizer.Create(Self);
  287. FSizers.Add(p);
  288. p.BevelOuter := bvNone;
  289. p.Width := SIZE;
  290. p.Height := SIZE;
  291. p.Color := clBlack;
  292. p.Caption := '';
  293. p.Tag := i;
  294. p.OnMouseDown := SizerDown;
  295. p.OnMouseUp := SizerUp;
  296. p.OnMouseMove := SizerMove;
  297. p.TabStop := False;
  298. case i of
  299. 0, 7 : p.Cursor := crSizeNWSE;
  300. 2, 5 : p.Cursor := crSizeNESW;
  301. 1, 6 : p.Cursor := crSizeNS;
  302. 3, 4 : p.Cursor := crSizeWE;
  303. end;
  304. end;
  305. end;
  306. procedure TCnDragResizer.CreateOneMover(m: TMover; c: TControl);
  307. begin
  308. m.OnMouseDown := MoverDown;
  309. m.OnMouseUp := MoverUp;
  310. m.OnMouseMove := MoverMove;
  311. m.TabStop := True;
  312. m.OnKeyDown := MoverKeyDown;
  313. m.Buddy := c;
  314. end;
  315. procedure TCnDragResizer.CheckSizers;
  316. begin
  317. if (FControl <> nil) and Active and (not (csDesigning in ComponentState)) then
  318. ShowSizers
  319. else
  320. HideSizers;
  321. end;
  322. procedure TCnDragResizer.ShowSizers;
  323. var
  324. i : Integer;
  325. p : TPanel;
  326. c : TControl;
  327. begin
  328. c := FControl;
  329. Assert(c <> nil);
  330. for i := 0 to 7 do
  331. begin
  332. p := TPanel(FSizers[i]);
  333. case i of
  334. 0, 1, 2 : p.Top := c.Top - HALFSIZE;
  335. 3, 4 : p.Top := c.Top + c.Height div 2 - HALFSIZE;
  336. 5, 6, 7 : p.Top := c.Top + c.Height - HALFSIZE;
  337. end;
  338. case i of
  339. 0, 3, 5 : p.Left := c.Left - HALFSIZE;
  340. 1, 6 : p.Left := c.Left + c.Width div 2 - HALFSIZE;
  341. 2, 4, 7 : p.Left := c.Left + c.Width - HALFSIZE;
  342. end;
  343. end;
  344. Assert(FCurMover<>nil);
  345. FCurMover.Show;
  346. for i := 0 to FSizers.Count - 1 do
  347. begin
  348. p := TPanel(FSizers[i]);
  349. p.Parent := c.Parent;
  350. p.Visible := True;
  351. p.BringToFront;
  352. end;
  353. if FCurMover.HandleAllocated and FCurMover.CanFocus then
  354. FCurMover.SetFocus;
  355. end;
  356. procedure TCnDragResizer.HideSizers;
  357. var
  358. i : Integer;
  359. p : TPanel;
  360. begin
  361. for i := 0 to FSizers.Count - 1 do
  362. begin
  363. p := TPanel(FSizers[i]);
  364. p.Visible := False;
  365. p.Update;
  366. end;
  367. FOneMover.Visible := False;
  368. end;
  369. procedure TCnDragResizer.SizerDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  370. begin
  371. FSizing := True;
  372. FDownX := X;
  373. FDownY := Y;
  374. HideSizers;
  375. FControl.Parent.Update;
  376. FControl.Update;
  377. FOrigSize := FControl.BoundsRect;
  378. FNewSize := FOrigSize;
  379. DrawSizeRect(FNewSize);
  380. end;
  381. procedure DoSwap(DoSwap: Boolean; var a, b: Integer);
  382. var
  383. t : Integer;
  384. begin
  385. if DoSwap then
  386. begin
  387. t := a;
  388. a := b;
  389. b := t;
  390. end;
  391. end;
  392. procedure TCnDragResizer.SizerUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  393. begin
  394. if FNewSize.Right < FNewSize.Left then
  395. DoSwap(True, FNewSize.Right, FNewSize.Left);
  396. if FNewSize.Bottom < FNewSize.Top then
  397. DoSwap(True, FNewSize.Bottom, FNewSize.Top);
  398. FSizing := False;
  399. DrawSizeRect(FNewSize);
  400. FControl.Invalidate;
  401. FControl.BoundsRect := FNewSize;
  402. ShowSizers;
  403. if Assigned(FOnSized) then
  404. FOnSized(Self);
  405. end;
  406. procedure TCnDragResizer.SizerMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  407. begin
  408. if FSizing then
  409. begin
  410. DrawSizeRect(FNewSize);
  411. if AllowSize then
  412. begin
  413. Calc_Size_Rect((Sender as TSizer).Tag, X - FDownX, Y - FDownY);
  414. DoSizingEvent;
  415. end;
  416. DrawSizeRect(FNewSize);
  417. if FShowBounds then
  418. FControl.BoundsRect := FNewSize;
  419. end;
  420. end;
  421. procedure TCnDragResizer.DoSizingEvent;
  422. var
  423. tmpWid, tmpHgt : Integer;
  424. begin
  425. tmpWid := FNewSize.Right - FNewSize.Left;
  426. tmpHgt := FNewSize.Bottom - FNewSize.Top;
  427. if Assigned(FOnSizing) then
  428. FOnSizing(Self, FNewSize.Left, FNewSize.Top, tmpWid, tmpHgt);
  429. FNewSize.Right := FNewSize.Left + tmpWid;
  430. FNewSize.Bottom := FNewSize.Top + tmpHgt;
  431. end;
  432. procedure GetNonClientOffset(h: THandle; var nx, ny: Integer);
  433. var
  434. p : TPoint;
  435. R : TRect;
  436. begin
  437. p := Point(0, 0);
  438. Windows.ClientToScreen(h, p);
  439. Windows.GetWindowRect(h, R);
  440. nx := p.x - R.Left;
  441. ny := p.y - R.Top;
  442. end;
  443. procedure TCnDragResizer.DrawSizeRect(Rect: TRect);
  444. var
  445. h : THandle;
  446. dc : THandle;
  447. c : TCanvas;
  448. nx, ny : Integer;
  449. OldPen : TPen;
  450. OldBrush : TBrush;
  451. begin
  452. if not FShowBounds then
  453. Exit;
  454. h := (FControl.Parent as TWinControl).Handle;
  455. GetNonClientOffset(h, nx, ny);
  456. dc := GetWindowDC(h);
  457. try
  458. c := TCanvas.Create;
  459. c.Handle := dc;
  460. OldPen := TPen.Create;
  461. OldPen.Assign(c.Pen);
  462. OldBrush := TBrush.Create;
  463. OldBrush.Assign(c.Brush);
  464. c.Pen.Width := 2;
  465. c.Pen.Mode := pmXOR;
  466. c.Pen.Color := clWhite;
  467. c.Brush.Style := bsClear;
  468. c.Rectangle(Rect.Left + nx, Rect.Top + ny, Rect.Right + nx, Rect.Bottom + ny);
  469. c.Pen.Assign(OldPen);
  470. OldPen.Free;
  471. c.Brush.Assign(OldBrush);
  472. OldBrush.Free;
  473. c.Handle := 0;
  474. c.Free;
  475. finally
  476. ReleaseDC(h, dc);
  477. end;
  478. end;
  479. procedure TCnDragResizer.Calc_Size_Rect(SizerNum, dx, dy: Integer);
  480. begin
  481. dx := (dx div GridX) * GridX;
  482. dy := (dy div GridY) * GridY;
  483. case SizerNum of
  484. 0, 1, 2 : FNewSize.Top := FOrigSize.Top + dy;
  485. 5, 6, 7 : FNewSize.Bottom := FOrigSize.Bottom + dy;
  486. end;
  487. case SizerNum of
  488. 0, 3, 5 : FNewSize.Left := FOrigSize.Left + dx;
  489. 2, 4, 7 : FNewSize.Right := FOrigSize.Right + dx;
  490. end;
  491. if KeepInParent then
  492. Constrain_Size;
  493. end;
  494. procedure TCnDragResizer.MoverDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  495. begin
  496. FCurMover := Sender as TMover;
  497. FControl := FCurMover.Buddy;
  498. Assert(FControl<>nil);
  499. FControl.BringToFront;
  500. FCurMover.BringToFront;
  501. FMoving := True;
  502. FDownX := X;
  503. FDownY := Y;
  504. HideSizers;
  505. FControl.Parent.Update;
  506. FControl.Update;
  507. FOrigSize := FControl.BoundsRect;
  508. FNewSize := FOrigSize;
  509. DrawSizeRect(FNewSize);
  510. end;
  511. procedure TCnDragResizer.MoverUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  512. begin
  513. FMoving := False;
  514. FControl.BoundsRect := FNewSize;
  515. FCurMover.Invalidate;
  516. FControl.Refresh;
  517. DrawSizeRect(FNewSize);
  518. ShowSizers;
  519. if Assigned(FOnMoved) then
  520. FOnMoved(Self);
  521. end;
  522. procedure TCnDragResizer.Calc_Move_Rect(dx, dy: Integer);
  523. begin
  524. FNewSize := FOrigSize;
  525. dx := (dx div GridX) * GridX;
  526. dy := (dy div GridY) * GridY;
  527. OffsetRect(FNewSize, dx, dy);
  528. if KeepInParent then
  529. Constrain_Move;
  530. end;
  531. procedure TCnDragResizer.DoMovingEvent;
  532. var
  533. tmpWid, tmpHgt : Integer;
  534. begin
  535. tmpWid := FNewSize.Right - FNewSize.Left;
  536. tmpHgt := FNewSize.Bottom - FNewSize.Top;
  537. if Assigned(FOnMoving) then
  538. FOnMoving(Self, FNewSize.Left, FNewSize.Top);
  539. FNewSize.Right := FNewSize.Left + tmpWid;
  540. FNewSize.Bottom := FNewSize.Top + tmpHgt;
  541. end;
  542. procedure TCnDragResizer.MoverMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  543. var
  544. dx, dy: Integer;
  545. begin
  546. if FMoving then
  547. begin
  548. DrawSizeRect(FNewSize);
  549. if AllowMove then
  550. begin
  551. dx := X - FDownX;
  552. dy := Y - FDownY;
  553. Calc_Move_Rect(dx, dy);
  554. DoMovingEvent;
  555. end;
  556. DrawSizeRect(FNewSize);
  557. if FShowBounds then
  558. FControl.BoundsRect := FNewSize;
  559. end;
  560. end;
  561. procedure TCnDragResizer.Constrain_Size;
  562. var
  563. p : TWinControl;
  564. begin
  565. p := FControl.Parent;
  566. with FNewSize do
  567. begin
  568. if Left < 0 then
  569. Left := 0;
  570. if Top < 0 then
  571. Top := 0;
  572. if Right > p.ClientWidth then
  573. Right := p.ClientWidth;
  574. if Bottom > p.ClientHeight then
  575. Bottom := p.ClientHeight;
  576. if Right < Left + GridX then
  577. Right := Left + GridX;
  578. if Bottom < Top + GridY then
  579. Bottom := Top + GridY;
  580. end;
  581. end;
  582. procedure TCnDragResizer.Constrain_Move;
  583. begin
  584. if FNewSize.Left < 0 then
  585. OffsetRect(FNewSize, -FNewSize.Left, 0);
  586. if FNewSize.Top < 0 then
  587. OffsetRect(FNewSize, 0, -FNewSize.Top);
  588. if FNewSize.Right > FControl.Parent.ClientWidth then
  589. OffsetRect(FNewSize, FControl.Parent.ClientWidth - FNewSize.Right, 0);
  590. if FNewSize.Bottom > FControl.Parent.ClientHeight then
  591. OffsetRect(FNewSize, 0, FControl.Parent.ClientHeight - FNewSize.Bottom);
  592. end;
  593. procedure TCnDragResizer.MoverKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  594. begin
  595. if Active then
  596. begin
  597. case Key of
  598. VK_LEFT : DoSizeMove(Key, Shift, -GridX, 0);
  599. VK_RIGHT : DoSizeMove(Key, Shift, GridX, 0);
  600. VK_UP : DoSizeMove(Key, Shift, 0, -GridY);
  601. VK_DOWN : DoSizeMove(Key, Shift, 0, GridY);
  602. end;
  603. end;
  604. end;
  605. procedure TCnDragResizer.DoSizeMove(var Key: Word; Shift: TShiftState; dx, dy: Integer);
  606. begin
  607. if (ssCtrl in Shift) or (ssShift in Shift) then
  608. begin
  609. Key := 0;
  610. FNewSize := FControl.BoundsRect;
  611. if (ssCtrl in Shift) and AllowMove then
  612. begin
  613. OffsetRect(FNewSize, dx, dy);
  614. if KeepInParent then
  615. Constrain_Move;
  616. DoMovingEvent;
  617. end;
  618. if (ssShift in Shift) and AllowSize then
  619. begin
  620. FNewSize.Right := FNewSize.Right + dx;
  621. FNewSize.Bottom := FNewSize.Bottom + dy;
  622. if KeepInParent then
  623. Constrain_Size;
  624. DoSizingEvent;
  625. end;
  626. FControl.BoundsRect := FNewSize;
  627. ShowSizers;
  628. end;
  629. end;
  630. function TCnDragResizer.FindMoverByBuddy(c: TControl): TMover;
  631. var
  632. i : Integer;
  633. begin
  634. Result := nil;
  635. for i := 0 to FGroupMovers.Count - 1 do
  636. if TMover(FGroupMovers[i]).Buddy = c then
  637. Result := FGroupMovers[i];
  638. Assert(Result <> nil);
  639. end;
  640. end.