bgravirtualscreen.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. // SPDX-License-Identifier: LGPL-3.0-linking-exception
  2. {
  3. Created by BGRA Controls Team
  4. Dibo, Circular, lainz (007) and contributors.
  5. For detailed information see readme.txt
  6. Site: https://sourceforge.net/p/bgra-controls/
  7. Wiki: http://wiki.lazarus.freepascal.org/BGRAControls
  8. Forum: http://forum.lazarus.freepascal.org/index.php/board,46.0.html
  9. }
  10. {******************************* CONTRIBUTOR(S) ******************************
  11. - Edivando S. Santos Brasil | [email protected]
  12. (Compatibility with delphi VCL 11/2018)
  13. ***************************** END CONTRIBUTOR(S) *****************************}
  14. unit BGRAVirtualScreen;
  15. {$I bgracontrols.inc}
  16. interface
  17. uses
  18. Classes, SysUtils, {$IFDEF FPC}LMessages, LResources, LCLIntf,{$ENDIF} Types, Forms, BCBaseCtrls, Controls, Graphics, Dialogs,
  19. {$IFNDEF FPC}Windows, Messages, BGRAGraphics, GraphType, FPImage, {$ENDIF}
  20. ExtCtrls, BGRABitmap, BCTypes;
  21. type
  22. { TCustomBGRAVirtualScreen }
  23. TCustomBGRAVirtualScreen = class(TBGRACustomPanel)
  24. private
  25. { Private declarations }
  26. FBGRA: TBGRABitmap;
  27. FOnRedraw: TBGRARedrawEvent;
  28. FDiscardedRect: TRect;
  29. FBevelInner, FBevelOuter: TPanelBevel;
  30. FBevelWidth: TBevelWidth;
  31. FBorderWidth: TBorderWidth;
  32. FAlignment: TAlignment;
  33. FBitmapAutoScale: boolean;
  34. function GetBitmapHeight: integer;
  35. function GetBitmapScale: double;
  36. function GetBitmapWidth: integer;
  37. function GetVSCaption: string;
  38. procedure SetAlignment(const Value: TAlignment);
  39. procedure SetBevelInner(const AValue: TPanelBevel);
  40. procedure SetBevelOuter(const AValue: TPanelBevel);
  41. procedure SetBevelWidth(const AValue: TBevelWidth);
  42. procedure SetBitmapAutoScale(AValue: boolean);
  43. procedure SetBorderWidth(const AValue: TBorderWidth);
  44. procedure SetVSCaption(AValue: string);
  45. protected
  46. { Protected declarations }
  47. procedure Paint; override;
  48. procedure Resize; override;
  49. procedure BGRASetSize(AWidth, AHeight: integer);
  50. procedure RedrawBitmapContent; virtual;
  51. procedure SetColor(Value: TColor); {$IFDEF FPC}override;{$ENDIF}
  52. procedure WMEraseBkgnd(var Message: {$IFDEF FPC}TLMEraseBkgnd{$ELSE}TWMEraseBkgnd{$ENDIF}); message {$IFDEF FPC}LM_ERASEBKGND{$ELSE}WM_ERASEBKGND{$ENDIF};
  53. procedure SetEnabled(Value: boolean); override;
  54. public
  55. { Public declarations }
  56. constructor Create(TheOwner: TComponent); override;
  57. function BitmapRectToClient(ARect: TRect): TRect;
  58. procedure RedrawBitmap; overload;
  59. procedure RedrawBitmap(ARect: TRect); overload;
  60. procedure RedrawBitmap(ARectArray: array of TRect); overload;
  61. procedure DiscardBitmap; overload;
  62. procedure DiscardBitmap(ARect: TRect); overload;
  63. procedure InvalidateBitmap(ARect: TRect);
  64. destructor Destroy; override;
  65. public
  66. property OnRedraw: TBGRARedrawEvent Read FOnRedraw Write FOnRedraw;
  67. property Bitmap: TBGRABitmap Read FBGRA;
  68. property BitmapAutoScale: boolean read FBitmapAutoScale write SetBitmapAutoScale default true;
  69. property BitmapScale: double read GetBitmapScale;
  70. property BitmapWidth: integer read GetBitmapWidth;
  71. property BitmapHeight: integer read GetBitmapHeight;
  72. property BorderWidth: TBorderWidth Read FBorderWidth Write SetBorderWidth default 0;
  73. property BevelInner: TPanelBevel Read FBevelInner Write SetBevelInner default bvNone;
  74. property BevelOuter: TPanelBevel Read FBevelOuter Write SetBevelOuter default bvNone;
  75. property BevelWidth: TBevelWidth Read FBevelWidth Write SetBevelWidth default 1;
  76. property Alignment: TAlignment Read FAlignment Write SetAlignment;
  77. property Caption: string read GetVSCaption write SetVSCaption;
  78. end;
  79. TBGRAVirtualScreen = class(TCustomBGRAVirtualScreen)
  80. published
  81. property OnRedraw;
  82. property Bitmap;
  83. property BitmapAutoScale;
  84. // TPanel
  85. property Align;
  86. property Alignment;
  87. property Anchors;
  88. property AutoSize;
  89. property BorderSpacing;
  90. property ChildSizing;
  91. {$IFDEF FPC} //#
  92. property OnGetDockCaption;
  93. {$ENDIF}
  94. property BevelInner;
  95. property BevelOuter;
  96. property BevelWidth;
  97. property BidiMode;
  98. property BorderWidth;
  99. property BorderStyle;
  100. property Caption;
  101. property ClientHeight;
  102. property ClientWidth;
  103. property Color;
  104. property Constraints;
  105. property DockSite;
  106. property DragCursor;
  107. property DragKind;
  108. property DragMode;
  109. property Enabled;
  110. property Font;
  111. property FullRepaint;
  112. property ParentBidiMode;
  113. property ParentColor;
  114. property ParentFont;
  115. property ParentShowHint;
  116. property PopupMenu;
  117. property ShowHint;
  118. property TabOrder;
  119. property TabStop;
  120. property UseDockManager default True;
  121. property Visible;
  122. property OnClick;
  123. property OnContextPopup;
  124. property OnDockDrop;
  125. property OnDockOver;
  126. property OnDblClick;
  127. property OnDragDrop;
  128. property OnDragOver;
  129. property OnEndDock;
  130. property OnEndDrag;
  131. property OnEnter;
  132. property OnExit;
  133. property OnGetSiteInfo;
  134. property OnMouseDown;
  135. property OnMouseEnter;
  136. property OnMouseLeave;
  137. property OnMouseMove;
  138. property OnMouseUp;
  139. property OnMouseWheel;
  140. property OnMouseWheelDown;
  141. property OnMouseWheelUp;
  142. property OnResize;
  143. property OnStartDock;
  144. property OnStartDrag;
  145. property OnUnDock;
  146. end;
  147. {$IFDEF FPC}procedure Register;{$ENDIF}
  148. implementation
  149. uses BGRABitmapTypes, math, LazVersion;
  150. {$IFDEF FPC}
  151. procedure Register;
  152. begin
  153. RegisterComponents('BGRA Controls', [TBGRAVirtualScreen]);
  154. end;
  155. {$ENDIF}
  156. { TCustomBGRAVirtualScreen }
  157. procedure TCustomBGRAVirtualScreen.SetAlignment(const Value: TAlignment);
  158. begin
  159. if FAlignment = Value then
  160. exit;
  161. FAlignment := Value;
  162. DiscardBitmap;
  163. end;
  164. function TCustomBGRAVirtualScreen.GetVSCaption: string;
  165. begin
  166. result := inherited Caption;
  167. end;
  168. function TCustomBGRAVirtualScreen.GetBitmapScale: double;
  169. begin
  170. {$if laz_fullversion >= 2000000}
  171. if not FBitmapAutoScale then
  172. result := GetCanvasScaleFactor
  173. else
  174. result := 1;
  175. {$else}
  176. result := 1;
  177. {$endif}
  178. end;
  179. function TCustomBGRAVirtualScreen.GetBitmapHeight: integer;
  180. begin
  181. result := round(ClientHeight * BitmapScale);
  182. end;
  183. function TCustomBGRAVirtualScreen.GetBitmapWidth: integer;
  184. begin
  185. result := round(ClientWidth * BitmapScale);
  186. end;
  187. procedure TCustomBGRAVirtualScreen.SetBevelInner(const AValue: TPanelBevel);
  188. begin
  189. if FBevelInner = AValue then
  190. exit;
  191. FBevelInner := AValue;
  192. DiscardBitmap;
  193. end;
  194. procedure TCustomBGRAVirtualScreen.SetBevelOuter(const AValue: TPanelBevel);
  195. begin
  196. if FBevelOuter = AValue then
  197. exit;
  198. FBevelOuter := AValue;
  199. DiscardBitmap;
  200. end;
  201. procedure TCustomBGRAVirtualScreen.SetBevelWidth(const AValue: TBevelWidth);
  202. begin
  203. if FBevelWidth = AValue then
  204. exit;
  205. FBevelWidth := AValue;
  206. DiscardBitmap;
  207. end;
  208. procedure TCustomBGRAVirtualScreen.SetBitmapAutoScale(AValue: boolean);
  209. begin
  210. if FBitmapAutoScale=AValue then Exit;
  211. DiscardBitmap; //before to get correct invalidate bounds
  212. FBitmapAutoScale:=AValue;
  213. end;
  214. procedure TCustomBGRAVirtualScreen.SetBorderWidth(const AValue: TBorderWidth);
  215. begin
  216. if FBorderWidth = AValue then
  217. exit;
  218. FBorderWidth := AValue;
  219. DiscardBitmap;
  220. end;
  221. procedure TCustomBGRAVirtualScreen.SetVSCaption(AValue: string);
  222. begin
  223. inherited Caption := AValue;
  224. DiscardBitmap;
  225. end;
  226. procedure TCustomBGRAVirtualScreen.Paint;
  227. begin
  228. {$IFDEF WINDOWS}
  229. // to avoid flickering in Windows running without themes (classic style)
  230. DoubleBuffered := ControlCount <> 0;
  231. {$ENDIF}
  232. BGRASetSize(BitmapWidth, BitmapHeight);
  233. if FBGRA <> nil then
  234. begin
  235. if not FDiscardedRect.IsEmpty then
  236. begin
  237. FBGRA.ClipRect := FDiscardedRect;
  238. FDiscardedRect := EmptyRect;
  239. RedrawBitmapContent;
  240. FBGRA.NoClip;
  241. end;
  242. FBGRA.Draw(Canvas, rect(0, 0, ClientWidth, ClientHeight));
  243. end;
  244. end;
  245. procedure TCustomBGRAVirtualScreen.Resize;
  246. begin
  247. inherited Resize;
  248. if (FBGRA <> nil) and ((ClientWidth <> FBGRA.Width) or (ClientHeight <> FBGRA.Height)) then
  249. DiscardBitmap;
  250. end;
  251. procedure TCustomBGRAVirtualScreen.BGRASetSize(AWidth, AHeight: integer);
  252. begin
  253. if (FBGRA <> nil) and ((AWidth <> FBGRA.Width) or (AHeight <> FBGRA.Height)) then
  254. begin
  255. FBGRA.SetSize(AWidth, AHeight);
  256. RedrawBitmapContent;
  257. FDiscardedRect := EmptyRect;
  258. end;
  259. end;
  260. procedure TCustomBGRAVirtualScreen.RedrawBitmapContent;
  261. var
  262. ARect: TRect;
  263. TS: TTextStyle;
  264. scale: Double;
  265. begin
  266. if (FBGRA <> nil) and (FBGRA.NbPixels <> 0) then
  267. begin
  268. FBGRA.FillRect(FBGRA.ClipRect, ColorToRGB(Color));
  269. scale := BitmapScale;
  270. ARect := GetClientRect;
  271. ARect.Left := round(ARect.Left*scale);
  272. ARect.Top := round(ARect.Top*scale);
  273. ARect.Right := round(ARect.Right*scale);
  274. ARect.Bottom := round(ARect.Bottom*scale);
  275. // if BevelOuter is set then draw a frame with BevelWidth
  276. if BevelOuter <> bvNone then
  277. FBGRA.CanvasBGRA.Frame3d(ARect, round(BevelWidth*scale), BevelOuter,
  278. BGRA(255, 255, 255, 200), BGRA(0, 0, 0, 160)); // Note: Frame3D inflates ARect
  279. InflateRect(ARect, -round(BorderWidth*scale), -round(BorderWidth*scale));
  280. // if BevelInner is set then skip the BorderWidth and draw a frame with BevelWidth
  281. if BevelInner <> bvNone then
  282. FBGRA.CanvasBGRA.Frame3d(ARect, round(BevelWidth*scale), BevelInner,
  283. BGRA(255, 255, 255, 160), BGRA(0, 0, 0, 160)); // Note: Frame3D inflates ARect
  284. if Caption <> '' then
  285. begin
  286. FBGRA.CanvasBGRA.Font.Assign(Canvas.Font);
  287. FBGRA.CanvasBGRA.Font.Height:= round(FBGRA.CanvasBGRA.Font.Height*scale);
  288. {$IFDEF FPC}//#
  289. TS := Canvas.TextStyle;
  290. {$ENDIF}
  291. TS.Alignment := Alignment;
  292. TS.Layout := tlTop;
  293. TS.Opaque := False;
  294. TS.Clipping := False;
  295. {$IFDEF FPC}//#
  296. TS.SystemFont := Canvas.Font.IsDefault;
  297. {$ENDIF}
  298. FBGRA.CanvasBGRA.Font.Color := Color xor $FFFFFF;
  299. if not Enabled then
  300. FBGRA.CanvasBGRA.Font.Style := [fsStrikeOut]
  301. else
  302. FBGRA.CanvasBGRA.Font.Style := [];
  303. FBGRA.CanvasBGRA.TextRect(ARect, ARect.Left, ARect.Top, Caption, TS);
  304. end;
  305. if Assigned(FOnRedraw) then
  306. FOnRedraw(self, FBGRA);
  307. end;
  308. end;
  309. procedure TCustomBGRAVirtualScreen.SetColor(Value: TColor);
  310. begin
  311. if Value <> Color then
  312. DiscardBitmap;
  313. {$IFDEF FPC}
  314. inherited SetColor(Value);
  315. {$ENDIF}
  316. end;
  317. {$hints off}
  318. procedure TCustomBGRAVirtualScreen.WMEraseBkgnd(var Message: {$IFDEF FPC}TLMEraseBkgnd{$ELSE}TWMEraseBkgnd{$ENDIF});
  319. begin
  320. //do nothing
  321. end;
  322. {$hints on}
  323. procedure TCustomBGRAVirtualScreen.SetEnabled(Value: boolean);
  324. begin
  325. if Value <> Enabled then
  326. DiscardBitmap;
  327. inherited SetEnabled(Value);
  328. end;
  329. constructor TCustomBGRAVirtualScreen.Create(TheOwner: TComponent);
  330. begin
  331. inherited Create(TheOwner);
  332. inherited BevelOuter := bvNone;
  333. FBGRA := TBGRABitmap.Create;
  334. FBitmapAutoScale := true;
  335. FBevelWidth := 1;
  336. FAlignment := taLeftJustify;
  337. FDiscardedRect := EmptyRect;
  338. Color := clWhite;
  339. end;
  340. function TCustomBGRAVirtualScreen.BitmapRectToClient(ARect: TRect): TRect;
  341. var
  342. scale: Double;
  343. begin
  344. scale := BitmapScale;
  345. result := rect(floor(ARect.Left/scale), floor(ARect.Top/scale),
  346. ceil(ARect.Right/scale), ceil(ARect.Bottom/scale));
  347. end;
  348. procedure TCustomBGRAVirtualScreen.RedrawBitmap;
  349. begin
  350. RedrawBitmapContent;
  351. FDiscardedRect := EmptyRect;
  352. Repaint;
  353. end;
  354. procedure TCustomBGRAVirtualScreen.RedrawBitmap(ARect: TRect);
  355. var
  356. All, displayRect: TRect;
  357. begin
  358. if Assigned(FBGRA) then
  359. begin
  360. All := Rect(0,0,FBGRA.Width,FBGRA.Height);
  361. ARect.Intersect(All);
  362. if not FDiscardedRect.IsEmpty then
  363. begin
  364. if ARect.IsEmpty then
  365. ARect := FDiscardedRect
  366. else
  367. ARect.Union(FDiscardedRect);
  368. FDiscardedRect := EmptyRect;
  369. end;
  370. if ARect.IsEmpty then exit;
  371. if ARect.Contains(All) then
  372. begin
  373. RedrawBitmap;
  374. end
  375. else
  376. begin
  377. FBGRA.ClipRect := ARect;
  378. RedrawBitmapContent;
  379. FBGRA.NoClip;
  380. displayRect := BitmapRectToClient(ARect);
  381. {$IFDEF LINUX}
  382. FBGRA.DrawPart(ARect, Canvas, displayRect, True);
  383. {$ELSE}
  384. InvalidateRect(Handle, @displayRect, False);
  385. Update;
  386. {$ENDIF}
  387. end;
  388. end;
  389. end;
  390. procedure TCustomBGRAVirtualScreen.RedrawBitmap(ARectArray: array of TRect);
  391. const cellShift = 6;
  392. cellSize = 1 shl cellShift;
  393. var
  394. grid: array of array of boolean;
  395. gAll: TRect;
  396. procedure IncludeRect(ARect: TRect);
  397. var
  398. gR: TRect;
  399. y,x: LongInt;
  400. begin
  401. with ARect do
  402. gR := rect(max(Left,0) shr cellShift, max(Top,0) shr cellShift,
  403. (max(Right,0)+cellSize-1) shr cellShift,
  404. (max(Bottom,0)+cellSize-1) shr cellShift);
  405. gR.Intersect(gAll);
  406. if gR.IsEmpty then exit;
  407. for y := gR.Top to gR.Bottom-1 do
  408. for x := gR.Left to gR.Right-1 do
  409. grid[y,x] := true;
  410. end;
  411. var
  412. gW,gH, i,gCount: integer;
  413. gR: TRect;
  414. y,x: LongInt;
  415. expand: boolean;
  416. begin
  417. if not Assigned(FBGRA) then exit;
  418. gW := (Bitmap.Width+cellSize-1) shr cellShift;
  419. gH := (Bitmap.Height+cellSize-1) shr cellShift;
  420. gAll := rect(0,0,gW,gH);
  421. //determine which cells of the grid to redraw
  422. setlength(grid,gH,gW);
  423. for i := 0 to high(ARectArray) do
  424. IncludeRect(ARectArray[i]);
  425. if not FDiscardedRect.IsEmpty then
  426. begin
  427. IncludeRect(FDiscardedRect);
  428. FDiscardedRect := EmptyRect;
  429. end;
  430. gCount := 0;
  431. for y := 0 to gH-1 do
  432. for x := 0 to gW-1 do
  433. if grid[y,x] then inc(gCount);
  434. if gCount >= gH*gW div 5 then
  435. begin
  436. RedrawBitmap(rect(0,0,Width,Height));
  437. end else
  438. for y := 0 to gH-1 do
  439. begin
  440. x := 0;
  441. while x < gW do
  442. begin
  443. if grid[y,x] then
  444. begin
  445. gR.Left := x;
  446. grid[y,x] := false;
  447. inc(x);
  448. while (x < gW) and grid[y,x] do
  449. begin
  450. grid[y,x] := false;
  451. inc(x);
  452. end;
  453. gR.Right := x;
  454. gR.Top := y;
  455. gR.Bottom := y+1;
  456. expand := true;
  457. while expand and (gR.Bottom < gH) do
  458. begin
  459. expand := true;
  460. for x := gR.Left to gR.Right-1 do
  461. if not grid[gR.Bottom, x] then
  462. begin
  463. expand := false;
  464. break;
  465. end;
  466. if expand then
  467. begin
  468. for x := gR.Left to gR.Right-1 do
  469. grid[gR.Bottom,x] := false;
  470. inc(gR.Bottom);
  471. end;
  472. end;
  473. RedrawBitmap(rect(gR.Left shl cellShift,gR.Top shl cellShift,gr.Right shl cellShift,gr.Bottom shl cellShift));
  474. end else
  475. inc(x);
  476. end;
  477. end;
  478. end;
  479. procedure TCustomBGRAVirtualScreen.DiscardBitmap;
  480. begin
  481. if FBGRA <> nil then
  482. DiscardBitmap(rect(0,0,FBGRA.Width,FBGRA.Height));
  483. end;
  484. procedure TCustomBGRAVirtualScreen.DiscardBitmap(ARect: TRect);
  485. var
  486. displayRect: TRect;
  487. begin
  488. ARect.Intersect(rect(0,0,FBGRA.Width,FBGRA.Height));
  489. if ARect.IsEmpty then exit;
  490. if FBGRA <> nil then
  491. begin
  492. if FDiscardedRect.IsEmpty then
  493. FDiscardedRect := ARect
  494. else
  495. FDiscardedRect.Union(ARect);
  496. displayRect := BitmapRectToClient(ARect);
  497. InvalidateRect(self.Handle, @displayRect, false);
  498. end;
  499. end;
  500. procedure TCustomBGRAVirtualScreen.InvalidateBitmap(ARect: TRect);
  501. var
  502. displayRect: TRect;
  503. begin
  504. displayRect := BitmapRectToClient(ARect);
  505. InvalidateRect(self.Handle, @displayRect, false);
  506. end;
  507. destructor TCustomBGRAVirtualScreen.Destroy;
  508. begin
  509. FBGRA.Free;
  510. inherited Destroy;
  511. end;
  512. end.