UnitMain.pas 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. unit UnitMain;
  2. interface
  3. uses
  4. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  5. Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls,
  6. GR32,
  7. GR32_Layers,
  8. GR32_Image, Vcl.ComCtrls;
  9. const
  10. MSG_CLEAR = WM_USER;
  11. type
  12. TFormMain = class(TForm)
  13. PaintBox32: TPaintBox32;
  14. ImgView32: TImgView32;
  15. PanelTop: TPanel;
  16. Panel1: TPanel;
  17. Panel2: TPanel;
  18. Panel3: TPanel;
  19. Label1: TLabel;
  20. Label2: TLabel;
  21. Label3: TLabel;
  22. Label4: TLabel;
  23. Image32: TImage32;
  24. Panel4: TPanel;
  25. Label5: TLabel;
  26. ImgView32Layers: TImgView32;
  27. MemoHelp: TMemo;
  28. Panel5: TPanel;
  29. Panel6: TPanel;
  30. ButtonClear: TButton;
  31. RadioGroupRepaint: TRadioGroup;
  32. Splitter1: TSplitter;
  33. ButtonDraw: TButton;
  34. procedure PaintBox32MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  35. procedure PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  36. procedure ImgView32MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  37. procedure FormCreate(Sender: TObject);
  38. procedure PaintBox32PaintBuffer(Sender: TObject);
  39. procedure FormResize(Sender: TObject);
  40. procedure Image32MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  41. procedure ButtonClearClick(Sender: TObject);
  42. procedure RadioGroupRepaintClick(Sender: TObject);
  43. procedure ButtonDrawClick(Sender: TObject);
  44. procedure Image32MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  45. procedure PaintBox32MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  46. private
  47. FLayer: TBitmapLayer;
  48. FIsDrawing: boolean;
  49. procedure ClearBackBuffers;
  50. procedure ClearBackBuffer(Buffer: TCustomBitmap32);
  51. procedure DrawStuff(Buffer: TCustomBitmap32);
  52. procedure MsgClear(var Msg: TMessage); message MSG_CLEAR;
  53. public
  54. end;
  55. var
  56. FormMain: TFormMain;
  57. implementation
  58. {$R *.dfm}
  59. const
  60. ColorNotRepainted: TColor32 = clBlack32;
  61. ColorRepainted: TColor32 = clGreen32;
  62. ColorDraw: TColor32 = clRed32;
  63. const
  64. ImageScale: TFloat = 1.5;
  65. const
  66. sHelp = 'This example illustrates how repaint optimization works.'+#13+
  67. 'Each control has had its backbuffer cleared to black and has then been allowed to repaint itself. The backbuffer has then been cleared to green with repaint disabled.'+#13+
  68. 'When an area of the control is now repainted, for example by drawing something on it, the green color will reveal itself where the control is repainted.'+#13+
  69. 'Tip: If you compile this with UPDATERECT_DEBUGDRAW defined, the Windows update rects are made visible during repaint.';
  70. procedure TFormMain.ClearBackBuffer(Buffer: TCustomBitmap32);
  71. begin
  72. // What we see:
  73. Buffer.Clear(ColorNotRepainted);
  74. Update;
  75. // What's really there (and not visible until we repaint something):
  76. Buffer.BeginLockUpdate;
  77. try
  78. Buffer.Clear(ColorRepainted);
  79. finally
  80. Buffer.EndLockUpdate;
  81. end;
  82. end;
  83. procedure TFormMain.ClearBackBuffers;
  84. begin
  85. ClearBackBuffer(PaintBox32.Buffer);
  86. ClearBackBuffer(Image32.Bitmap);
  87. ClearBackBuffer(ImgView32.Bitmap);
  88. ClearBackBuffer(ImgView32Layers.Bitmap);
  89. ClearBackBuffer(FLayer.Bitmap);
  90. end;
  91. procedure TFormMain.DrawStuff(Buffer: TCustomBitmap32);
  92. begin
  93. // Single pixel
  94. Buffer.PixelS[150, 50] := ColorDraw;
  95. Buffer.Changed(MakeRect(150, 50, 151, 51));
  96. // Single pixel, update rect clips right boundary
  97. Buffer.PixelS[Buffer.Width-5, 220] := ColorDraw;
  98. Buffer.Changed(MakeRect(Buffer.Width-5, 220, Buffer.Width-5+1, 221));
  99. // Diagonal lines
  100. Buffer.MoveTo(10, 10);
  101. Buffer.LineToAS(110, 110);
  102. Buffer.MoveTo(110, 10);
  103. Buffer.LineToAS(10, 110);
  104. // Overlapping rects
  105. Buffer.FillRectS(10, 120, 40, 150, ColorDraw);
  106. Buffer.FillRectS(30, 140, 60, 170, ColorDraw);
  107. // Single rect
  108. Buffer.FrameRectS(100, 140, 150, 200, ColorDraw);
  109. end;
  110. procedure TFormMain.FormCreate(Sender: TObject);
  111. begin
  112. ImgView32.Bitmap.PenColor := ColorDraw;
  113. Image32.Bitmap.PenColor := ColorDraw;
  114. PaintBox32.Buffer.PenColor := ColorDraw;
  115. ImgView32Layers.Bitmap.PenColor := ColorDraw;
  116. FLayer := TBitmapLayer(ImgView32Layers.Layers.Add(TBitmapLayer));
  117. FLayer.Bitmap.PenColor := ColorDraw;
  118. FLayer.OnMouseDown := PaintBox32MouseDown;
  119. FLayer.Scaled := True;
  120. FLayer.Cursor := crCross;
  121. MemoHelp.Lines.Text := sHelp;
  122. end;
  123. procedure TFormMain.FormResize(Sender: TObject);
  124. var
  125. r: TFloatRect;
  126. begin
  127. Panel1.Width := ClientWidth div 4;
  128. Panel3.Width := Panel1.Width;
  129. Panel4.Width := Panel1.Width;
  130. Panel1.Left := 0;
  131. Panel2.Left := Panel1.Left+Panel1.Width;
  132. Panel3.Left := Panel2.Left+Panel2.Width;;
  133. Panel4.Left := Panel3.Left+Panel3.Width;;
  134. // Set bitmap sizes
  135. Image32.Bitmap.SetSize(Image32.ClientWidth, Image32.ClientHeight);
  136. ImgView32.Bitmap.SetSize(ImgView32.ClientWidth, ImgView32.ClientHeight);
  137. // Zoom & pan doesn't work without a base bitmap
  138. ImgView32Layers.Bitmap.SetSize(ImgView32.ClientWidth, ImgView32.ClientHeight);
  139. FLayer.Bitmap.SetSize(ImgView32Layers.ClientWidth, ImgView32Layers.ClientHeight);
  140. // Reset location & scale
  141. r := FloatRect(FLayer.Bitmap.BoundsRect);
  142. r.Inflate(-50, -50);
  143. FLayer.Location := r;
  144. Image32.OffsetHorz := 0;
  145. Image32.OffsetVert := 0;
  146. ImgView32.OffsetHorz := 0;
  147. ImgView32.OffsetVert := 0;
  148. ImgView32Layers.OffsetHorz := 0;
  149. ImgView32Layers.OffsetVert := 0;
  150. Image32.Scale := ImageScale;
  151. ImgView32.Scale := ImageScale;
  152. ImgView32Layers.Scale := ImageScale;
  153. ClearBackBuffers;
  154. end;
  155. procedure TFormMain.MsgClear(var Msg: TMessage);
  156. begin
  157. ClearBackBuffer(TCustomBitmap32(Msg.WParam));
  158. end;
  159. procedure TFormMain.ButtonClearClick(Sender: TObject);
  160. begin
  161. ClearBackBuffers;
  162. end;
  163. procedure TFormMain.ButtonDrawClick(Sender: TObject);
  164. begin
  165. DrawStuff(PaintBox32.Buffer);
  166. DrawStuff(Image32.Bitmap);
  167. DrawStuff(ImgView32.Bitmap);
  168. DrawStuff(FLayer.Bitmap);
  169. end;
  170. procedure TFormMain.Image32MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  171. var
  172. Buffer: TCustomBitmap32;
  173. p: TPoint;
  174. begin
  175. if (Sender is TCustomImage32) and (TCustomImage32(Sender).MousePan.MatchShiftState(Shift)) then
  176. exit;
  177. if (Layer <> nil) then
  178. Buffer := TBitmapLayer(Layer).Bitmap
  179. else
  180. if (Sender is TCustomImage32) then
  181. Buffer := TCustomImage32(Sender).Bitmap
  182. else
  183. if (Sender is TCustomPaintBox32) then
  184. Buffer := TCustomPaintBox32(Sender).Buffer
  185. else
  186. exit;
  187. if (Buffer.Empty) then
  188. exit;
  189. if (Button = mbLeft) then
  190. begin
  191. p := Point(X, Y);
  192. if (Layer <> nil) then
  193. begin
  194. p := Layer.ControlToLayer(p);
  195. p := Layer.LayerToContent(p);
  196. end else
  197. if (Sender is TCustomImage32) then
  198. p := TCustomImage32(Sender).ControlToBitmap(p);
  199. Buffer.MoveTo(p.X, p.Y);
  200. FIsDrawing := True;
  201. end else
  202. if (Button = mbRight) then
  203. DrawStuff(Buffer)
  204. else
  205. if (Button = mbMiddle) then
  206. begin
  207. // Because TCustomPaintBox32 by default batches paint updates inside the mouse event handlers
  208. // we need to defer the clear.
  209. PostMessage(Handle, MSG_CLEAR, WPARAM(Buffer), 0);
  210. end;
  211. end;
  212. procedure TFormMain.Image32MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  213. begin
  214. FIsDrawing := False;
  215. end;
  216. procedure TFormMain.ImgView32MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  217. var
  218. Buffer: TCustomBitmap32;
  219. p: TPoint;
  220. begin
  221. if (not FIsDrawing) then
  222. exit;
  223. if (Sender is TCustomImage32) and ((TCustomImage32(Sender).IsMousePanning) or (TCustomImage32(Sender).MousePan.MatchShiftState(Shift))) then
  224. exit;
  225. if (not (ssLeft in Shift)) then
  226. exit;
  227. if (Layer <> nil) and (Layer.LayerCollection.MouseListener <> Layer) then
  228. Layer := nil;
  229. if (Layer <> nil) then
  230. Buffer := TBitmapLayer(Layer).Bitmap
  231. else
  232. if (Sender is TCustomImage32) then
  233. Buffer := TCustomImage32(Sender).Bitmap
  234. else
  235. if (Sender is TCustomPaintBox32) then
  236. Buffer := TCustomPaintBox32(Sender).Buffer
  237. else
  238. exit;
  239. p := Point(X, Y);
  240. if (Layer <> nil) then
  241. begin
  242. p := Layer.ControlToLayer(p);
  243. p := Layer.LayerToContent(p);
  244. end else
  245. if (Sender is TCustomImage32) then
  246. p := TCustomImage32(Sender).ControlToBitmap(p);
  247. Buffer.LineToAS(p.X, p.Y);
  248. end;
  249. procedure TFormMain.PaintBox32MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  250. begin
  251. Image32MouseDown(Sender, Button, Shift, X, Y, nil);
  252. end;
  253. procedure TFormMain.PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  254. begin
  255. ImgView32MouseMove(Sender, Shift, X, Y, nil);
  256. end;
  257. procedure TFormMain.PaintBox32MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  258. begin
  259. Image32MouseUp(Sender, Button, Shift, X, Y, nil);
  260. end;
  261. procedure TFormMain.PaintBox32PaintBuffer(Sender: TObject);
  262. begin
  263. TPaintBox32(Sender).Buffer.BeginLockUpdate;
  264. try
  265. TPaintBox32(Sender).Buffer.Clear(ColorNotRepainted);
  266. finally
  267. TPaintBox32(Sender).Buffer.EndLockUpdate;
  268. end;
  269. end;
  270. procedure TFormMain.RadioGroupRepaintClick(Sender: TObject);
  271. var
  272. RepaintMode: TRepaintMode;
  273. begin
  274. RepaintMode := TRepaintMode(RadioGroupRepaint.ItemIndex);
  275. PaintBox32.RepaintMode := RepaintMode;
  276. Image32.RepaintMode := RepaintMode;
  277. ImgView32.RepaintMode := RepaintMode;
  278. ImgView32Layers.RepaintMode := RepaintMode;
  279. ClearBackBuffers;
  280. end;
  281. end.