WinSizeUtil.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. {
  2. 无标题窗口size控制
  3. v0.3
  4. by gale 2024-11-24
  5. }
  6. unit WinSizeUtil;
  7. interface
  8. uses
  9. System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  10. FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  11. FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects, FMX.Edit;
  12. type
  13. TWinSizeHelper = class(TComponent)
  14. private const
  15. c_CheckWidth = 5;
  16. private type
  17. TSizeType = (stNone, stLeft, stLeftTop, stTop, stRightTop, stRight, stRightBottom, stBottom, stLeftBottom);
  18. private
  19. FForm: TForm;
  20. FControl: TControl;
  21. FTitleBar: TControl;
  22. FSizeType: TSizeType;
  23. FCanMaximized: Boolean;
  24. private
  25. FOldMouseDown: TMouseEvent;
  26. FOldMouseUp: TMouseEvent;
  27. FOldMouseLeave: TNotifyEvent;
  28. FOldMouseMove: TMouseMoveEvent;
  29. FOldRectF: TRectF;
  30. FOldCursor: TCursor;
  31. procedure MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  32. procedure MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  33. procedure MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  34. procedure MouseLeave(Sender: TObject);
  35. public
  36. property CanMaximized: Boolean read FCanMaximized write FCanMaximized;
  37. private
  38. FIsMouseDown_TitleBar: Boolean;
  39. FOldFormPos_TitleBar: TPoint;
  40. FOldMousePos_TitleBar: TPointF;
  41. FOldMouseDown_TitleBar: TMouseEvent;
  42. FOldMouseUp_TitleBar: TMouseEvent;
  43. FOldMouseMove_TitleBar: TMouseMoveEvent;
  44. FOldDBClick_TitleBar: TNotifyEvent;
  45. procedure TitleBarMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  46. procedure TitleBarMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  47. procedure TitleBarMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  48. procedure TitleBarDblClick(Sender: TObject);
  49. private
  50. function CalcSizeType(X, Y: Single): TSizeType;
  51. public
  52. constructor Create(AOwner: TComponent); override;
  53. destructor Destroy; override;
  54. procedure SetControlled(AValue: TControl);
  55. procedure SetTitleBar(AValue: TControl);
  56. end;
  57. implementation
  58. { TWinSizeHelper }
  59. constructor TWinSizeHelper.Create(AOwner: TComponent);
  60. begin
  61. inherited;
  62. FForm := nil;
  63. FSizeType := stNone;
  64. FIsMouseDown_TitleBar := False;
  65. FCanMaximized := False;
  66. end;
  67. destructor TWinSizeHelper.Destroy;
  68. begin
  69. inherited;
  70. end;
  71. function TWinSizeHelper.CalcSizeType(X, Y: Single): TSizeType;
  72. var
  73. Width, Height: Single;
  74. begin
  75. Width := FControl.Width;
  76. Height := FControl.Height;
  77. if (X < c_CheckWidth * 3) and (Y < c_CheckWidth * 3) then
  78. Result := stLeftTop
  79. else if (X > Width - c_CheckWidth * 3) and (Y < c_CheckWidth * 3) then
  80. Result := stRightTop
  81. else if (X > Width - c_CheckWidth * 3) and (Y > Height - c_CheckWidth * 3) then
  82. Result := stRightBottom
  83. else if (X < c_CheckWidth * 3) and (Y > Height - c_CheckWidth * 3) then
  84. Result := stLeftBottom
  85. else if X < c_CheckWidth then
  86. Result := stLeft
  87. else if X > Width - c_CheckWidth then
  88. Result := stRight
  89. else if Y < c_CheckWidth then
  90. Result := stTop
  91. else if Y > Height - c_CheckWidth then
  92. Result := stBottom
  93. else
  94. Result := stNone;
  95. end;
  96. procedure TWinSizeHelper.SetControlled(AValue: TControl);
  97. begin
  98. if FControl = AValue then
  99. Exit;
  100. FControl := AValue;
  101. FForm := FControl.Root as TForm;
  102. FOldCursor := FControl.Cursor;
  103. FControl.AutoCapture := True;
  104. FOldMouseDown := FControl.OnMouseDown;
  105. FOldMouseUp := FControl.OnMouseUp;
  106. FOldMouseLeave := FControl.OnMouseLeave;
  107. FOldMouseMove := FControl.OnMouseMove;
  108. FControl.OnMouseDown := MouseDown;
  109. FControl.OnMouseUp := MouseUp;
  110. FControl.OnMouseMove := MouseMove;
  111. FControl.OnMouseLeave := MouseLeave;
  112. end;
  113. procedure TWinSizeHelper.MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  114. begin
  115. if Button = TMouseButton.mbLeft then
  116. begin
  117. FOldRectF := FForm.BoundsF;
  118. FSizeType := CalcSizeType(X, Y);
  119. end;
  120. if Assigned(FOldMouseDown) then
  121. begin
  122. FOldMouseDown(Sender, Button, Shift, X, Y);
  123. end;
  124. end;
  125. procedure TWinSizeHelper.MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  126. begin
  127. FSizeType := stNone;
  128. if Assigned(FOldMouseUp) then
  129. begin
  130. FOldMouseUp(Sender, Button, Shift, X, Y);
  131. end;
  132. end;
  133. procedure TWinSizeHelper.MouseLeave(Sender: TObject);
  134. begin
  135. FControl.Cursor := crDefault;
  136. if Assigned(FOldMouseLeave) then
  137. begin
  138. FOldMouseLeave(Sender);
  139. end;
  140. end;
  141. procedure TWinSizeHelper.MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  142. begin
  143. if FSizeType <> stNone then
  144. begin
  145. case FSizeType of
  146. stLeft:
  147. begin
  148. FOldRectF.Left := Screen.MousePos.X - FControl.Position.X - c_CheckWidth / 2;
  149. if FOldRectF.Width < FForm.Constraints.MinWidth then
  150. FOldRectF.Left := FOldRectF.Right - FForm.Constraints.MinWidth;
  151. FForm.SetBoundsF(FOldRectF);
  152. end;
  153. stTop:
  154. begin
  155. FOldRectF.Top := Screen.MousePos.Y - FControl.Position.Y - c_CheckWidth / 2;;
  156. if FOldRectF.Height < FForm.Constraints.MinHeight then
  157. FOldRectF.Top := FOldRectF.Bottom - FForm.Constraints.MinHeight;
  158. FForm.SetBoundsF(FOldRectF);
  159. end;
  160. stRight:
  161. begin
  162. FOldRectF.Right := Screen.MousePos.X + (FForm.BoundsF.Width - FControl.Position.X - FControl.Width) + c_CheckWidth / 2;
  163. FForm.SetBoundsF(FOldRectF);
  164. end;
  165. stBottom:
  166. begin
  167. FOldRectF.Bottom := Screen.MousePos.Y + (FForm.BoundsF.Height - FControl.Position.Y - FControl.Height) + c_CheckWidth / 2;
  168. FForm.SetBoundsF(FOldRectF);
  169. end;
  170. stLeftTop:
  171. begin
  172. FOldRectF.Left := Screen.MousePos.X - FControl.Position.X - c_CheckWidth / 2;
  173. FOldRectF.Top := Screen.MousePos.Y - FControl.Position.Y - c_CheckWidth / 2;;
  174. if FOldRectF.Width < FForm.Constraints.MinWidth then
  175. FOldRectF.Left := FOldRectF.Right - FForm.Constraints.MinWidth;
  176. if FOldRectF.Height < FForm.Constraints.MinHeight then
  177. FOldRectF.Top := FOldRectF.Bottom - FForm.Constraints.MinHeight;
  178. FForm.SetBoundsF(FOldRectF);
  179. end;
  180. stRightTop:
  181. begin
  182. FOldRectF.Right := Screen.MousePos.X + (FForm.BoundsF.Width - FControl.Position.X - FControl.Width) + c_CheckWidth / 2;
  183. FOldRectF.Top := Screen.MousePos.Y - FControl.Position.Y - c_CheckWidth / 2;;
  184. if FOldRectF.Height < FForm.Constraints.MinHeight then
  185. FOldRectF.Top := FOldRectF.Bottom - FForm.Constraints.MinHeight;
  186. FForm.SetBoundsF(FOldRectF);
  187. end;
  188. stRightBottom:
  189. begin
  190. FOldRectF.Right := Screen.MousePos.X + (FForm.BoundsF.Width - FControl.Position.X - FControl.Width) + c_CheckWidth / 2;
  191. FOldRectF.Bottom := Screen.MousePos.Y + (FForm.BoundsF.Height - FControl.Position.Y - FControl.Height) + c_CheckWidth / 2;
  192. FForm.SetBoundsF(FOldRectF);
  193. end;
  194. stLeftBottom:
  195. begin
  196. FOldRectF.Left := Screen.MousePos.X - FControl.Position.X - c_CheckWidth / 2;
  197. FOldRectF.Bottom := Screen.MousePos.Y + (FForm.BoundsF.Height - FControl.Position.Y - FControl.Height) + c_CheckWidth / 2;
  198. if FOldRectF.Width < FForm.Constraints.MinWidth then
  199. FOldRectF.Left := FOldRectF.Right - FForm.Constraints.MinWidth;
  200. FForm.SetBoundsF(FOldRectF);
  201. end;
  202. end;
  203. end
  204. else
  205. begin
  206. case CalcSizeType(X, Y) of
  207. stLeft, stRight:
  208. FControl.Cursor := crSizeWE;
  209. stTop, stBottom:
  210. FControl.Cursor := crSizeNS;
  211. stLeftTop, stRightBottom:
  212. FControl.Cursor := crSizeNWSE;
  213. stRightTop, stLeftBottom:
  214. FControl.Cursor := crSizeNESW;
  215. else
  216. FControl.Cursor := FOldCursor;
  217. end;
  218. end;
  219. if Assigned(FOldMouseMove) then
  220. begin
  221. FOldMouseMove(Sender, Shift, X, Y);
  222. end;
  223. end;
  224. procedure TWinSizeHelper.SetTitleBar(AValue: TControl);
  225. begin
  226. if FTitleBar = AValue then
  227. Exit;
  228. FTitleBar := AValue;
  229. if FForm = nil then
  230. FForm := FTitleBar.Root as TForm;
  231. FOldMouseDown_TitleBar := FTitleBar.OnMouseDown;
  232. FTitleBar.OnMouseDown := TitleBarMouseDown;
  233. FOldMouseUp_TitleBar := FTitleBar.OnMouseUp;
  234. FTitleBar.OnMouseUp := TitleBarMouseUp;
  235. FOldMouseMove_TitleBar := FTitleBar.OnMouseMove;
  236. FTitleBar.OnMouseMove := TitleBarMouseMove;
  237. FOldDBClick_TitleBar := FTitleBar.OnDblClick;
  238. FTitleBar.OnDblClick := TitleBarDblClick;
  239. FTitleBar.AutoCapture := True;
  240. end;
  241. procedure TWinSizeHelper.TitleBarMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  242. begin
  243. if (Button = TMouseButton.mbLeft) then
  244. begin
  245. FIsMouseDown_TitleBar := True;
  246. FOldFormPos_TitleBar.X := FForm.Left;
  247. FOldFormPos_TitleBar.Y := FForm.Top;
  248. FOldMousePos_TitleBar := Screen.MousePos;
  249. end;
  250. if Assigned(FOldMouseDown_TitleBar) then
  251. begin
  252. FOldMouseDown_TitleBar(Sender, Button, Shift, X, Y);
  253. end;
  254. end;
  255. procedure TWinSizeHelper.TitleBarMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  256. begin
  257. if (ssLeft in Shift) and FIsMouseDown_TitleBar then
  258. begin
  259. if FForm.WindowState = TWindowState.wsMaximized then
  260. begin
  261. if (ABS(FOldMousePos_TitleBar.X - Screen.MousePos.X) > 10) or (ABS(FOldMousePos_TitleBar.Y - Screen.MousePos.Y) > 10) then
  262. begin
  263. FForm.WindowState := TWindowState.wsNormal;
  264. FOldFormPos_TitleBar.X := Round(Screen.MousePos.X - FForm.Width / 2);
  265. FForm.Left := FOldFormPos_TitleBar.X + Round(Screen.MousePos.X - FOldMousePos_TitleBar.X);
  266. FForm.Top := FOldFormPos_TitleBar.Y + Round(Screen.MousePos.Y - FOldMousePos_TitleBar.Y);
  267. end;
  268. end
  269. else
  270. begin
  271. FForm.Left := FOldFormPos_TitleBar.X + Round(Screen.MousePos.X - FOldMousePos_TitleBar.X);
  272. FForm.Top := FOldFormPos_TitleBar.Y + Round(Screen.MousePos.Y - FOldMousePos_TitleBar.Y);
  273. end;
  274. end;
  275. if Assigned(FOldMouseMove_TitleBar) then
  276. begin
  277. FOldMouseMove_TitleBar(Sender, Shift, X, Y);
  278. end;
  279. end;
  280. procedure TWinSizeHelper.TitleBarMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  281. begin
  282. FIsMouseDown_TitleBar := False;
  283. if Assigned(FOldMouseUp_TitleBar) then
  284. begin
  285. FOldMouseUp_TitleBar(Sender, Button, Shift, X, Y);
  286. end;
  287. end;
  288. procedure TWinSizeHelper.TitleBarDblClick(Sender: TObject);
  289. begin
  290. if FCanMaximized then
  291. begin
  292. FIsMouseDown_TitleBar := False;
  293. if FForm.WindowState = TWindowState.wsMaximized then
  294. begin
  295. FForm.WindowState := TWindowState.wsNormal;
  296. end
  297. else
  298. begin
  299. FForm.WindowState := TWindowState.wsMaximized;
  300. end;
  301. end;
  302. if Assigned(FOldDBClick_TitleBar) then
  303. begin
  304. FOldDBClick_TitleBar(Sender);
  305. end;
  306. end;
  307. end.