1 unit ADLayoutViewer;
2
3 {$mode objfpc}{$H+}
4
5 interface
6
7 uses
8 Classes, SysUtils, types, math, Controls, Graphics, ComCtrls, LCLType,
9 LMessages, LCLIntf, AnchorDockStorage, LazLoggerBase;
10
11 type
12 TADLTVMonitor = class
13 public
14 Monitor: integer;
15 WorkArea: TRect;
16 Bounds: TRect; // hull of all windows on this monitor
17 X, Y: integer;
18 end;
19
20 { TADCustomLayoutTreeView }
21
22 TADCustomLayoutTreeView = class(TCustomControl)
23 private
24 FLayout: TAnchorDockLayoutTree;
25 FScaleMax: double;
26 FScaleMin: double;
27 FScale: double;
28 FBounds: TRect;
29 FScaledBounds: TRect;
30 FScaledScroll: TPoint;
31 FMonitors: array of TADLTVMonitor;
32 FZoomTrackbar: TCustomTrackBar;
33 FOldZoombarOnChange: TNotifyEvent;
34 FIgnoreZoomTrackbarChange: boolean;
GetLayoutMaxXnull35 function GetLayoutMaxX: integer;
GetLayoutMaxYnull36 function GetLayoutMaxY: integer;
GetLayoutMinXnull37 function GetLayoutMinX: integer;
GetLayoutMinYnull38 function GetLayoutMinY: integer;
GetMonitorsnull39 function GetMonitors(Index: integer): TADLTVMonitor;
GetScaledMaxXnull40 function GetScaledMaxX: integer;
GetScaledMaxYnull41 function GetScaledMaxY: integer;
GetScaledMinXnull42 function GetScaledMinX: integer;
GetScaledMinYnull43 function GetScaledMinY: integer;
GetScaledOffsetXnull44 function GetScaledOffsetX: integer;
GetScaledOffsetYnull45 function GetScaledOffsetY: integer;
46 procedure SetScaleMax(AValue: double);
47 procedure SetScaleMin(AValue: double);
48 procedure SetScale(AValue: double);
49 procedure SetScaledOffsetX(AValue: integer);
50 procedure SetScaledOffsetY(AValue: integer);
51 procedure ComputeLayout;
52 procedure ClearMonitors;
FindMonitornull53 function FindMonitor(Monitor: integer): TADLTVMonitor;
54 procedure SetZoomTrackbar(AValue: TCustomTrackBar);
55 procedure UpdateZoomTrackBar;
56 procedure ZoomTrackbarChange(Sender: TObject);
57 procedure WMVScroll(var Msg: TLMScroll); message LM_VSCROLL;
58 procedure WMHScroll(var Msg: TLMScroll); message LM_HSCROLL;
59 procedure WMMouseWheel(var Message: TLMMouseEvent); message LM_MOUSEWHEEL;
60 procedure UpdateScrollBar;
61 protected
62 procedure Notification(AComponent: TComponent; Operation: TOperation);
63 override;
64 procedure CreateWnd; override;
65 procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
66 public
67 constructor Create(AOwner: TComponent); override;
68 destructor Destroy; override;
69 procedure Paint; override;
ScaleRectnull70 function ScaleRect(const r: TRect): TRect;
71 procedure LayoutChanged; virtual;
72 property Layout: TAnchorDockLayoutTree read FLayout;
73 property Scale: double read FScale write SetScale;
74 property ScaledOffsetX: integer read GetScaledOffsetX write SetScaledOffsetX;
75 property ScaledOffsetY: integer read GetScaledOffsetY write SetScaledOffsetY;
ScaledOffsetYMaxnull76 function ScaledOffsetYMax: integer;
ScaledOffsetXMaxnull77 function ScaledOffsetXMax: integer;
78 property LayoutMinX: integer read GetLayoutMinX;
79 property LayoutMinY: integer read GetLayoutMinY;
80 property LayoutMaxX: integer read GetLayoutMaxX;
81 property LayoutMaxY: integer read GetLayoutMaxY;
82 property ScaledMinX: integer read GetScaledMinX;
83 property ScaledMinY: integer read GetScaledMinY;
84 property ScaledMaxX: integer read GetScaledMaxX;
85 property ScaledMaxY: integer read GetScaledMaxY;
MonitorCountnull86 function MonitorCount: integer;
87 property Monitors[Index: integer]: TADLTVMonitor read GetMonitors;
88 property ZoomTrackbar: TCustomTrackBar read FZoomTrackbar write SetZoomTrackbar;
ScaleToZoomTrackBarPosnull89 function ScaleToZoomTrackBarPos(aScale: double): integer;
ZoomTrackBarPosToScalenull90 function ZoomTrackBarPosToScale(p: integer): double;
91 property ScaleMin: double read FScaleMin write SetScaleMin;
92 property ScaleMax: double read FScaleMax write SetScaleMax;
93 end;
94
95 TADLayoutTreeView = class(TADCustomLayoutTreeView)
96 published
97 property Scale: double read FScale write SetScale;
98 property ScaledOffsetX: integer read GetScaledOffsetX write SetScaledOffsetX;
99 property ScaledOffsetY: integer read GetScaledOffsetY write SetScaledOffsetY;
100 property ZoomTrackbar: TCustomTrackBar read FZoomTrackbar write SetZoomTrackbar;
101 property ScaleMin: double read FScaleMin write SetScaleMin;
102 property ScaleMax: double read FScaleMax write SetScaleMax;
103 end;
104
105 implementation
106
107 { TADCustomLayoutTreeView }
108
109 procedure TADCustomLayoutTreeView.SetScale(AValue: double);
110 begin
111 AValue:=Min(ScaleMax,Max(AValue,ScaleMin));
112 if FScale=AValue then Exit;
113 FScale:=AValue;
114 FScaledBounds:=ScaleRect(FBounds);
115 FScaledScroll.X:=Min(FScaledScroll.X,ScaledMaxX);
116 FScaledScroll.Y:=Min(FScaledScroll.Y,ScaledMaxY);
117 UpdateScrollBar;
118 UpdateZoomTrackBar;
119 Invalidate;
120 end;
121
122 procedure TADCustomLayoutTreeView.ZoomTrackbarChange(Sender: TObject);
123 begin
124 if not FIgnoreZoomTrackbarChange then
125 Scale:=ZoomTrackBarPosToScale(ZoomTrackbar.Position);
126 if Assigned(FOldZoombarOnChange) then
127 FOldZoombarOnChange(Sender);
128 end;
129
130 procedure TADCustomLayoutTreeView.WMVScroll(var Msg: TLMScroll);
131 begin
132 case Msg.ScrollCode of
133 // Scrolls to start / end of the text
134 SB_TOP: ScaledOffsetY := 0;
135 SB_BOTTOM: ScaledOffsetY := ScaledOffsetYMax;
136 // Scrolls one line up / down
137 SB_LINEDOWN: ScaledOffsetY := ScaledOffsetY + 10 div 2;
138 SB_LINEUP: ScaledOffsetY := ScaledOffsetY - 10 div 2;
139 // Scrolls one page of lines up / down
140 SB_PAGEDOWN: ScaledOffsetY := ScaledOffsetY + ClientHeight - 10;
141 SB_PAGEUP: ScaledOffsetY := ScaledOffsetY - ClientHeight + 10;
142 // Scrolls to the current scroll bar position
143 SB_THUMBPOSITION,
144 SB_THUMBTRACK: ScaledOffsetY := Msg.Pos;
145 // Ends scrolling
146 SB_ENDSCROLL: SetCaptureControl(nil); // release scrollbar capture
147 end;
148 end;
149
150 procedure TADCustomLayoutTreeView.WMHScroll(var Msg: TLMScroll);
151 begin
152 case Msg.ScrollCode of
153 // Scrolls to start / end of the text
154 SB_TOP: ScaledOffsetX := 0;
155 SB_BOTTOM: ScaledOffsetX := ScaledOffsetXMax;
156 // Scrolls one line up / down
157 SB_LINEDOWN: ScaledOffsetX := ScaledOffsetX + 10 div 2;
158 SB_LINEUP: ScaledOffsetX := ScaledOffsetX - 10 div 2;
159 // Scrolls one page of lines up / down
160 SB_PAGEDOWN: ScaledOffsetX := ScaledOffsetX + ClientWidth - 10;
161 SB_PAGEUP: ScaledOffsetX := ScaledOffsetX - ClientWidth + 10;
162 // Scrolls to the current scroll bar position
163 SB_THUMBPOSITION,
164 SB_THUMBTRACK: ScaledOffsetX := Msg.Pos;
165 // Ends scrolling
166 SB_ENDSCROLL: SetCaptureControl(nil); // release scrollbar capture
167 end;
168 end;
169
170 procedure TADCustomLayoutTreeView.WMMouseWheel(var Message: TLMMouseEvent);
171 begin
172 if Mouse.WheelScrollLines=-1 then
173 begin
174 // -1 : scroll by page
175 ScaledOffsetY := ScaledOffsetY -
176 (Message.WheelDelta * (ClientHeight - 10)) div 120;
177 end else begin
178 // scrolling one line -> scroll half an item, see SB_LINEDOWN and SB_LINEUP
179 // handler in WMVScroll
180 ScaledOffsetY := ScaledOffsetY -
181 (Message.WheelDelta * Mouse.WheelScrollLines*10) div 240;
182 end;
183 Message.Result := 1;
184 end;
185
186 procedure TADCustomLayoutTreeView.UpdateScrollBar;
187 var
188 ScrollInfo: TScrollInfo;
189 begin
190 if HandleAllocated then begin
191 ScrollInfo.cbSize := SizeOf(ScrollInfo);
192 ScrollInfo.fMask := SIF_ALL or SIF_DISABLENOSCROLL;
193 ScrollInfo.nMin := 0;
194 ScrollInfo.nTrackPos := 0;
195 ScrollInfo.nMax := Max(1,ScaledMaxY-1);
196 ScrollInfo.nPage := Max(1,ClientHeight-10);
197 ScrollInfo.nPos := ScaledOffsetY;
198 ShowScrollBar(Handle, SB_Vert, True);
199 SetScrollInfo(Handle, SB_Vert, ScrollInfo, True);
200
201 ScrollInfo.cbSize := SizeOf(ScrollInfo);
202 ScrollInfo.fMask := SIF_ALL or SIF_DISABLENOSCROLL;
203 ScrollInfo.nMin := 0;
204 ScrollInfo.nTrackPos := 0;
205 ScrollInfo.nMax := Max(1,ScaledMaxX-1);
206 ScrollInfo.nPage := Max(1,ClientWidth-10);
207 ScrollInfo.nPos := ScaledOffsetX;
208 ShowScrollBar(Handle, SB_Horz, True);
209 SetScrollInfo(Handle, SB_Horz, ScrollInfo, True);
210 end;
211 end;
212
TADCustomLayoutTreeView.GetLayoutMaxXnull213 function TADCustomLayoutTreeView.GetLayoutMaxX: integer;
214 begin
215 Result:=FBounds.Right;
216 end;
217
GetLayoutMaxYnull218 function TADCustomLayoutTreeView.GetLayoutMaxY: integer;
219 begin
220 Result:=FBounds.Bottom;
221 end;
222
TADCustomLayoutTreeView.GetLayoutMinXnull223 function TADCustomLayoutTreeView.GetLayoutMinX: integer;
224 begin
225 Result:=FBounds.Left;
226 end;
227
GetLayoutMinYnull228 function TADCustomLayoutTreeView.GetLayoutMinY: integer;
229 begin
230 Result:=FBounds.Top;
231 end;
232
TADCustomLayoutTreeView.GetMonitorsnull233 function TADCustomLayoutTreeView.GetMonitors(Index: integer): TADLTVMonitor;
234 begin
235 Result:=FMonitors[Index];
236 end;
237
GetScaledMaxXnull238 function TADCustomLayoutTreeView.GetScaledMaxX: integer;
239 begin
240 Result:=FScaledBounds.Right;
241 end;
242
TADCustomLayoutTreeView.GetScaledMaxYnull243 function TADCustomLayoutTreeView.GetScaledMaxY: integer;
244 begin
245 Result:=FScaledBounds.Bottom;
246 end;
247
GetScaledMinXnull248 function TADCustomLayoutTreeView.GetScaledMinX: integer;
249 begin
250 Result:=FScaledBounds.Left;
251 end;
252
TADCustomLayoutTreeView.GetScaledMinYnull253 function TADCustomLayoutTreeView.GetScaledMinY: integer;
254 begin
255 Result:=FScaledBounds.Top;
256 end;
257
TADCustomLayoutTreeView.GetScaledOffsetXnull258 function TADCustomLayoutTreeView.GetScaledOffsetX: integer;
259 begin
260 Result:=FScaledScroll.X;
261 end;
262
TADCustomLayoutTreeView.GetScaledOffsetYnull263 function TADCustomLayoutTreeView.GetScaledOffsetY: integer;
264 begin
265 Result:=FScaledScroll.Y;
266 end;
267
268 procedure TADCustomLayoutTreeView.SetScaleMax(AValue: double);
269 // must be >=1.0
270 begin
271 AValue:=Max(AValue,1.0);
272 if FScaleMax=AValue then Exit;
273 FScaleMax:=AValue;
274 Scale:=Min(ScaleMax,Max(Scale,ScaleMin));
275 UpdateZoomTrackBar;
276 end;
277
278 procedure TADCustomLayoutTreeView.SetScaleMin(AValue: double);
279 // must be between 0.00001 and 1.0
280 begin
281 AValue:=Min(1.0,Max(AValue,0.00001));
282 if FScaleMin=AValue then Exit;
283 FScaleMin:=AValue;
284 Scale:=Min(ScaleMax,Max(Scale,ScaleMin));
285 UpdateZoomTrackBar;
286 end;
287
288 procedure TADCustomLayoutTreeView.SetScaledOffsetX(AValue: integer);
289 begin
290 AValue:=Max(0,Min(ScaledMaxX,AValue));
291 if FScaledScroll.X=AValue then Exit;
292 FScaledScroll.X:=AValue;
293 UpdateScrollBar;
294 Invalidate;
295 end;
296
297 procedure TADCustomLayoutTreeView.SetScaledOffsetY(AValue: integer);
298 begin
299 AValue:=Max(0,Min(ScaledMaxY,AValue));
300 if FScaledScroll.Y=AValue then Exit;
301 FScaledScroll.Y:=AValue;
302 UpdateScrollBar;
303 Invalidate;
304 end;
305
306 procedure TADCustomLayoutTreeView.ComputeLayout;
307
308 procedure ComputeMonitors(Node: TAnchorDockLayoutTreeNode);
309 var
310 i: Integer;
311 Monitor: TADLTVMonitor;
312 r: TRect;
313 begin
314 if Node=nil then exit;
315 if Node.NodeType in [adltnLayout,adltnCustomSite] then begin
316 // top level window
317 Monitor:=FindMonitor(Node.Monitor);
318 if Monitor=nil then begin
319 // first window on this monitor
320 Monitor:=TADLTVMonitor.Create;
321 Monitor.Monitor:=Node.Monitor;
322 Monitor.WorkArea:=Node.WorkAreaRect;
323 Monitor.Bounds:=Node.BoundsRect;
324 SetLength(FMonitors,length(FMonitors)+1);
325 FMonitors[length(FMonitors)-1]:=Monitor;
326 end else begin
327 // another window on this monitor
328 r:=Rect(0,0,0,0);
329 UnionRect(r,Monitor.Bounds,Node.BoundsRect);
330 Monitor.Bounds:=r;
331 end;
332 end else begin
333 for i:=0 to Node.Count-1 do
334 ComputeMonitors(Node[i]);
335 end;
336 end;
337
338 var
339 i: Integer;
340 Monitor: TADLTVMonitor;
341 TileSize: TPoint;
342 TileCols: Integer;
343 LeftMost: Integer;
344 TopMost: Integer;
345 TileCol: Integer;
346 TileRow: Integer;
347 TileLeft: Integer;
348 TileTop: Integer;
349 r: TRect;
350 begin
351 if FLayout=nil then exit;
352 // clear computed values
353 FBounds:=Rect(0,0,0,0);
354 FScaledBounds:=Rect(0,0,0,0);
355 ClearMonitors;
356 // collect all monitor bounds
357 ComputeMonitors(FLayout.Root);
358 if length(FMonitors)=0 then exit;
359 // get biggest monitor
360 TileSize:=Point(0,0);
361 for i:=0 to length(FMonitors)-1 do begin
362 Monitor:=FMonitors[i];
363 Monitor.Bounds.Right:=Max(Monitor.Bounds.Left,Monitor.Bounds.Right);
364 Monitor.Bounds.Bottom:=Max(Monitor.Bounds.Top,Monitor.Bounds.Bottom);
365 TileSize.X:=Max(TileSize.X,Monitor.Bounds.Right-Monitor.Bounds.Left);
366 TileSize.X:=Max(TileSize.X,Monitor.WorkArea.Right-Monitor.WorkArea.Left);
367 TileSize.Y:=Max(TileSize.Y,Monitor.Bounds.Bottom-Monitor.Bounds.Top);
368 TileSize.Y:=Max(TileSize.Y,Monitor.WorkArea.Bottom-Monitor.WorkArea.Top);
369 end;
370 // put monitors into tiles of same size in a quadratic layout
371 TileCols:=ceil(SQRT(length(FMonitors)));
372 for i:=0 to length(FMonitors)-1 do begin
373 Monitor:=FMonitors[i];
374 LeftMost:=Min(Monitor.WorkArea.Left,Monitor.Bounds.Left);
375 TopMost:=Min(Monitor.WorkArea.Top,Monitor.Bounds.Top);
376 TileCol:=i mod TileCols;
377 TileRow:=i div TileCols;
378 TileLeft:=TileCol*TileSize.X;
379 TileTop:=TileRow*TileSize.Y;
380 // move left/topmost to left,top of tile
381 Monitor.X:=TileLeft-LeftMost;
382 Monitor.Y:=TileTop-TopMost;
383 // compute total bounds
384 r.Left:=Monitor.X+Min(Monitor.WorkArea.Left,Monitor.Bounds.Left);
385 r.Top:=Monitor.Y+Min(Monitor.WorkArea.Top,Monitor.Bounds.Top);
386 r.Right:=Monitor.X+Min(Monitor.WorkArea.Right,Monitor.Bounds.Right);
387 r.Bottom:=Monitor.Y+Min(Monitor.WorkArea.Bottom,Monitor.Bounds.Bottom);
388 if i=0 then
389 FBounds:=r
390 else begin
391 FBounds.Left:=Min(FBounds.Left,r.Left);
392 FBounds.Right:=Max(FBounds.Right,r.Right);
393 FBounds.Top:=Min(FBounds.Top,r.Top);
394 FBounds.Bottom:=Max(FBounds.Bottom,r.Bottom);
395 end;
396 DebugLn(['TADLayoutTreeView.ComputeLayout ',i,'/',length(FMonitors),' WorkArea=',dbgs(Monitor.WorkArea),' Bounds=',dbgs(Monitor.Bounds),' X=',Monitor.X,' Y=',Monitor.Y]);
397 end;
398 FScaledBounds:=ScaleRect(FBounds);
399 UpdateScrollBar;
400 end;
401
402 procedure TADCustomLayoutTreeView.ClearMonitors;
403 var
404 i: Integer;
405 begin
406 for i:=0 to length(FMonitors)-1 do FreeAndNil(FMonitors[i]);
407 SetLength(FMonitors,0);
408 end;
409
TADCustomLayoutTreeView.FindMonitornull410 function TADCustomLayoutTreeView.FindMonitor(Monitor: integer): TADLTVMonitor;
411 var
412 i: Integer;
413 begin
414 for i:=0 to length(FMonitors)-1 do begin
415 Result:=FMonitors[i];
416 if Result.Monitor=Monitor then exit;
417 end;
418 Result:=nil;
419 end;
420
421 procedure TADCustomLayoutTreeView.SetZoomTrackbar(AValue: TCustomTrackBar);
422 begin
423 if FZoomTrackbar=AValue then Exit;
424 if ZoomTrackbar<>nil then begin
425 ZoomTrackbar.OnChange:=FOldZoombarOnChange;
426 end;
427 FZoomTrackbar:=AValue;
428 if ZoomTrackbar<>nil then begin
429 FreeNotification(ZoomTrackbar);
430 fOldZoombarOnChange:=ZoomTrackbar.OnChange;
431 ZoomTrackbar.OnChange:=@ZoomTrackbarChange;
432 UpdateZoomTrackBar;
433 end;
434 end;
435
436 procedure TADCustomLayoutTreeView.UpdateZoomTrackBar;
437 var
438 OldChange: Boolean;
439 begin
440 OldChange:=FIgnoreZoomTrackbarChange;
441 try
442 FIgnoreZoomTrackbarChange:=true;
443 //debugln(['TADCustomLayoutTreeView.UpdateZoomTrackBar Scale=',Scale,' Zoom=',ScaleToZoomTrackBarPos(Scale)]);
444 ZoomTrackbar.Position:=ScaleToZoomTrackBarPos(Scale);
445 finally
446 FIgnoreZoomTrackbarChange:=OldChange;
447 end;
448 ZoomTrackbar.Caption:='';
449 end;
450
451 procedure TADCustomLayoutTreeView.Notification(AComponent: TComponent;
452 Operation: TOperation);
453 begin
454 inherited Notification(AComponent, Operation);
455 if Operation=opRemove then begin
456 if AComponent=ZoomTrackbar then
457 ZoomTrackbar:=nil;
458 end;
459 end;
460
461 procedure TADCustomLayoutTreeView.CreateWnd;
462 begin
463 inherited CreateWnd;
464 UpdateScrollBar;
465 end;
466
467 procedure TADCustomLayoutTreeView.DoSetBounds(ALeft, ATop, AWidth,
468 AHeight: integer);
469 begin
470 inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
471 UpdateScrollBar;
472 end;
473
474 constructor TADCustomLayoutTreeView.Create(AOwner: TComponent);
475 begin
476 inherited Create(AOwner);
477 FLayout:=TAnchorDockLayoutTree.Create;
478 FScale:=0.25;
479 FScaleMin:=1/20;
480 FScaleMax:=5;
481 end;
482
483 destructor TADCustomLayoutTreeView.Destroy;
484 begin
485 FreeAndNil(FLayout);
486 ClearMonitors;
487 inherited Destroy;
488 end;
489
490 procedure TADCustomLayoutTreeView.Paint;
491
492 procedure DrawContent(Node: TAnchorDockLayoutTreeNode;
493 OriginX, OriginY: integer);
494 var
495 r: TRect;
496 i: Integer;
497 begin
498 r:=Node.BoundsRect;
499 OffsetRect(r,OriginX,OriginY);
500 case Node.NodeType of
501 adltnLayout,adltnCustomSite:
502 begin
503 Canvas.Brush.Color:=clWhite;
504 Canvas.Pen.Color:=clBlue;
505 end;
506 adltnControl:
507 begin
508 Canvas.Brush.Color:=clGray;
509 Canvas.Pen.Color:=clBlack;
510 end;
511 adltnSplitterHorizontal:
512 begin
513 Canvas.Brush.Color:=clGreen;
514 Canvas.Pen.Color:=clGreen;
515 end;
516 adltnSplitterVertical:
517 begin
518 Canvas.Brush.Color:=clLime;
519 Canvas.Pen.Color:=clLime;
520 end;
521 adltnPages:
522 begin
523 Canvas.Brush.Color:=clYellow;
524 Canvas.Pen.Color:=clYellow;
525 end;
526 else
527 exit;
528 end;
529 Canvas.Rectangle(ScaleRect(r));
530 if Node.NodeType in [adltnLayout] then begin
531 for i:=0 to Node.Count-1 do
532 DrawContent(Node[i],r.Left,r.Top);
533 end;
534 end;
535
536 procedure DrawWindows(Node: TAnchorDockLayoutTreeNode);
537 var
538 i: Integer;
539 Monitor: TADLTVMonitor;
540 r: TRect;
541 begin
542 if Node.NodeType in [adltnCustomSite,adltnLayout] then begin
543 // top level window
544 Monitor:=FindMonitor(Node.Monitor);
545 if Monitor=nil then exit;
546 r:=Node.BoundsRect;
547 OffsetRect(r,Monitor.X,Monitor.Y);
548 Canvas.Brush.Color:=clWhite;
549 Canvas.Pen.Color:=clRed;
550 Canvas.Rectangle(ScaleRect(r));
551 for i:=0 to Node.Count-1 do
552 DrawContent(Node[i],r.Left,r.Top);
553 end else begin
554 for i:=0 to Node.Count-1 do
555 DrawWindows(Node[i]);
556 end;
557 end;
558
559 var
560 i: Integer;
561 Monitor: TADLTVMonitor;
562 r: TRect;
563 begin
564 Canvas.Brush.Color:=clGray;
565 Canvas.FillRect(0,0,ClientWidth,ClientHeight);
566
567 // draw monitor workareas
568 Canvas.Pen.Color:=clBlue;
569 Canvas.Brush.Color:=RGBToColor(128,128,255);
570 for i:=0 to MonitorCount-1 do begin
571 Monitor:=fMonitors[i];
572 r:=ScaleRect(Monitor.WorkArea);
573 Canvas.Rectangle(r);
574 end;
575
576 DrawWindows(Layout.Root);
577
578 // call event
579 inherited Paint;
580 end;
581
TADCustomLayoutTreeView.ScaleRectnull582 function TADCustomLayoutTreeView.ScaleRect(const r: TRect): TRect;
583 begin
584 Result.Left:=floor(r.Left*Scale)-FScaledScroll.X;
585 Result.Top:=floor(r.Top*Scale)-FScaledScroll.Y;
586 Result.Right:=ceil(r.Right*Scale)-FScaledScroll.X;
587 Result.Bottom:=ceil(r.Bottom*Scale)-FScaledScroll.Y;
588 end;
589
590 procedure TADCustomLayoutTreeView.LayoutChanged;
591 begin
592 ComputeLayout;
593 end;
594
ScaledOffsetYMaxnull595 function TADCustomLayoutTreeView.ScaledOffsetYMax: integer;
596 begin
597 Result:=ScaledMaxY-ClientHeight;
598 end;
599
ScaledOffsetXMaxnull600 function TADCustomLayoutTreeView.ScaledOffsetXMax: integer;
601 begin
602 Result:=ScaledMaxY-ClientWidth;
603 end;
604
MonitorCountnull605 function TADCustomLayoutTreeView.MonitorCount: integer;
606 begin
607 Result:=length(FMonitors);
608 end;
609
TADCustomLayoutTreeView.ScaleToZoomTrackBarPosnull610 function TADCustomLayoutTreeView.ScaleToZoomTrackBarPos(aScale: double
611 ): integer;
612 var
613 lnMinPos, lnMaxPos, lnPos, Percent: Double;
614 begin
615 // ZoomTrackbar.Min corresponds to ln(ScaleMin)
616 // ZoomTrackbar.Max corresponds to ln(ScaleMax)
617 lnMinPos:=ln(ScaleMin);
618 lnMaxPos:=ln(ScaleMax);
619 lnPos:=ln(aScale);
620 Percent:=(lnPos-lnMinPos)/(lnMaxPos-lnMinPos);
621 Result:=ZoomTrackbar.Min+round(Percent*(ZoomTrackbar.Max-ZoomTrackbar.Min));
622 //debugln(['TADCustomLayoutTreeView.ScaleToZoomTrackBarPos ScaleMin=',ScaleMin,' ScaleMax=',ScaleMax,' lnMinPos=',lnMinPos,' lnMaxPos=',lnMaxPos,' lnPos=',lnPos,' Percent=',Percent,' TrackBar=Min=',ZoomTrackbar.Min,',Max=',ZoomTrackbar.Max,' Result=',Result]);
623 // avoid out of bounds due to rounding errors
624 Result:=Min(ZoomTrackbar.Max,Max(ZoomTrackbar.Min,Result));
625 end;
626
TADCustomLayoutTreeView.ZoomTrackBarPosToScalenull627 function TADCustomLayoutTreeView.ZoomTrackBarPosToScale(p: integer): double;
628 var
629 lnMinPos, lnMaxPos, lnPos, Percent: Double;
630 begin
631 // ZoomTrackbar.Min corresponds to ln(ScaleMin)
632 // ZoomTrackbar.Max corresponds to ln(ScaleMax)
633 lnMinPos:=ln(ScaleMin);
634 lnMaxPos:=ln(ScaleMax);
635 Percent:=(p-ZoomTrackbar.Min)/(ZoomTrackbar.Max-ZoomTrackbar.Min);
636 lnPos:=lnMinPos+Percent*(lnMaxPos-lnMinPos);
637 Result:=exp(lnPos);
638 //debugln(['TADCustomLayoutTreeView.ZoomTrackBarPosToScale ScaleMin=',ScaleMin,' ScaleMax=',ScaleMax,' lnMinPos=',lnMinPos,' lnMaxPos=',lnMaxPos,' TrackBar=Min=',ZoomTrackbar.Min,',Max=',ZoomTrackbar.Max,',Position=',ZoomTrackbar.Position,' Percent=',Percent,' lnPos=',lnPos,' Result=',Result]);
639 // avoid out of bounds due to rounding errors
640 Result:=Max(ScaleMin,Min(ScaleMax,Result));
641 end;
642
643 end.
644
645