close Warning: Can't synchronize with repository "(default)" (No changeset 184 in the repository). Look in the Trac log for more information.

source: trunk/Packages/Common/UScaleDPI.pas

Last change on this file was 145, checked in by chronos, 7 years ago
  • Modified: Do not create settings form on application start but just if form is opened.
  • Fixed: Removed various compilation warnings.
File size: 10.9 KB
Line 
1unit UScaleDPI;
2
3{ See: http://wiki.lazarus.freepascal.org/High_DPI }
4
5{$mode delphi}{$H+}
6
7interface
8
9uses
10 Classes, Forms, Graphics, Controls, ComCtrls, LCLType, SysUtils, StdCtrls,
11 Contnrs;
12
13type
14
15 { TControlDimension }
16
17 TControlDimension = class
18 BoundsRect: TRect;
19 FontHeight: Integer;
20 Controls: TObjectList; // TList<TControlDimension>
21 // Class specifics
22 ButtonSize: TPoint; // TToolBar
23 CoolBandWidth: Integer;
24 ConstraintsMin: TPoint; // TForm
25 ConstraintsMax: TPoint; // TForm
26 constructor Create;
27 destructor Destroy; override;
28 end;
29
30 { TScaleDPI }
31
32 TScaleDPI = class(TComponent)
33 private
34 FAutoDetect: Boolean;
35 FDesignDPI: TPoint;
36 FDPI: TPoint;
37 procedure SetAutoDetect(AValue: Boolean);
38 procedure SetDesignDPI(AValue: TPoint);
39 procedure SetDPI(AValue: TPoint);
40 public
41 procedure StoreDimensions(Control: TControl; Dimensions: TControlDimension);
42 procedure RestoreDimensions(Control: TControl; Dimensions: TControlDimension);
43 procedure ScaleDimensions(Control: TControl; Dimensions: TControlDimension);
44 procedure ApplyToAll(FromDPI: TPoint);
45 procedure ScaleControl(Control: TControl; FromDPI: TPoint);
46 procedure ScaleImageList(ImgList: TImageList; FromDPI: TPoint);
47 function ScalePoint(APoint: TPoint; FromDPI: TPoint): TPoint;
48 function ScaleRect(ARect: TRect; FromDPI: TPoint): TRect;
49 function ScaleX(Size: Integer; FromDPI: Integer): Integer;
50 function ScaleY(Size: Integer; FromDPI: Integer): Integer;
51 constructor Create(AOwner: TComponent); override;
52 property DesignDPI: TPoint read FDesignDPI write SetDesignDPI;
53 property DPI: TPoint read FDPI write SetDPI;
54 published
55 property AutoDetect: Boolean read FAutoDetect write SetAutoDetect;
56 end;
57
58procedure Register;
59
60
61implementation
62
63resourcestring
64 SWrongDPI = 'Wrong DPI [%d,%d]';
65
66procedure Register;
67begin
68 RegisterComponents('Common', [TScaleDPI]);
69end;
70
71{ TControlDimension }
72
73constructor TControlDimension.Create;
74begin
75 Controls := TObjectList.Create;
76end;
77
78destructor TControlDimension.Destroy;
79begin
80 FreeAndNil(Controls);
81 inherited Destroy;
82end;
83
84procedure TScaleDPI.SetAutoDetect(AValue: Boolean);
85begin
86 if FAutoDetect = AValue then Exit;
87 FAutoDetect := AValue;
88 if AValue then begin
89 DPI := Point(ScreenInfo.PixelsPerInchX, ScreenInfo.PixelsPerInchY);
90 end;
91end;
92
93procedure TScaleDPI.SetDesignDPI(AValue: TPoint);
94begin
95 if (FDesignDPI.X = AValue.X) and (FDesignDPI.Y = AValue.Y) then Exit;
96 if (AValue.X <= 0) or (AValue.Y <= 0) then
97 raise Exception.Create(Format(SWrongDPI, [AValue.X, AValue.Y]));
98 FDesignDPI := AValue;
99end;
100
101procedure TScaleDPI.SetDPI(AValue: TPoint);
102begin
103 if (FDPI.X = AValue.X) and (FDPI.Y = AValue.Y) then Exit;
104 if (AValue.X <= 0) or (AValue.Y <= 0) then
105 raise Exception.Create(Format(SWrongDPI, [AValue.X, AValue.Y]));
106 FDPI := AValue;
107end;
108
109procedure TScaleDPI.StoreDimensions(Control: TControl;
110 Dimensions: TControlDimension);
111var
112 NewControl: TControlDimension;
113 I: Integer;
114begin
115 Dimensions.BoundsRect := Control.BoundsRect;
116 Dimensions.FontHeight := Control.Font.GetTextHeight('Hg');
117 Dimensions.Controls.Clear;
118 if Control is TToolBar then
119 Dimensions.ButtonSize := Point(TToolBar(Control).ButtonWidth, TToolBar(Control).ButtonHeight);
120 if Control is TForm then begin
121 Dimensions.ConstraintsMin := Point(TForm(Control).Constraints.MinWidth,
122 TForm(Control).Constraints.MinHeight);
123 Dimensions.ConstraintsMax := Point(TForm(Control).Constraints.MaxWidth,
124 TForm(Control).Constraints.MaxHeight);
125 end;
126 if Control is TWinControl then
127 for I := 0 to TWinControl(Control).ControlCount - 1 do begin
128 if TWinControl(Control).Controls[I] is TControl then
129 // Do not scale docked forms twice
130 if not (TWinControl(Control).Controls[I] is TForm) then begin
131 NewControl := TControlDimension.Create;
132 Dimensions.Controls.Add(NewControl);
133 StoreDimensions(TWinControl(Control).Controls[I], NewControl);
134 end;
135 end;
136end;
137
138procedure TScaleDPI.RestoreDimensions(Control: TControl;
139 Dimensions: TControlDimension);
140var
141 I: Integer;
142begin
143 Control.BoundsRect := Dimensions.BoundsRect;
144 Control.Font.Height := Dimensions.FontHeight;
145 if Control is TToolBar then begin
146 TToolBar(Control).ButtonWidth := Dimensions.ButtonSize.X;
147 TToolBar(Control).ButtonHeight := Dimensions.ButtonSize.Y;
148 end;
149 if Control is TForm then begin
150 TForm(Control).Constraints.MinWidth := Dimensions.ConstraintsMin.X;
151 TForm(Control).Constraints.MinHeight := Dimensions.ConstraintsMin.Y;
152 TForm(Control).Constraints.MaxWidth := Dimensions.ConstraintsMax.X;
153 TForm(Control).Constraints.MaxHeight := Dimensions.ConstraintsMax.Y;
154 end;
155 if Control is TWinControl then
156 for I := 0 to TWinControl(Control).ControlCount - 1 do begin
157 if TWinControl(Control).Controls[I] is TControl then
158 // Do not scale docked forms twice
159 if not (TWinControl(Control).Controls[I] is TForm) then begin
160 RestoreDimensions(TWinControl(Control).Controls[I], TControlDimension(Dimensions.Controls[I]));
161 end;
162 end;
163end;
164
165procedure TScaleDPI.ScaleDimensions(Control: TControl;
166 Dimensions: TControlDimension);
167var
168 I: Integer;
169begin
170 Control.BoundsRect := ScaleRect(Dimensions.BoundsRect, DesignDPI);
171 Control.Font.Height := ScaleY(Dimensions.FontHeight, DesignDPI.Y);
172 if Control is TToolBar then begin
173 TToolBar(Control).ButtonWidth := ScaleX(Dimensions.ButtonSize.X, DesignDPI.X);
174 TToolBar(Control).ButtonHeight := ScaleY(Dimensions.ButtonSize.Y, DesignDPI.Y);
175 end;
176 if Control is TCoolBar then begin
177 with TCoolBar(Control) do
178 for I := 0 to Bands.Count - 1 do
179 with TCoolBand(Bands[I]) do begin
180 MinWidth := ScaleX(Dimensions.ButtonSize.X, DesignDPI.X);
181 MinHeight := ScaleY(Dimensions.ButtonSize.Y, DesignDPI.Y);
182 //Width := ScaleX(Dimensions.BoundsRect.Left -
183 end;
184 end;
185 if Control is TForm then begin
186 TForm(Control).Constraints.MinWidth := ScaleX(Dimensions.ConstraintsMin.X, DesignDPI.X);
187 TForm(Control).Constraints.MaxWidth := ScaleX(Dimensions.ConstraintsMax.X, DesignDPI.X);
188 TForm(Control).Constraints.MinHeight := ScaleY(Dimensions.ConstraintsMin.Y, DesignDPI.Y);
189 TForm(Control).Constraints.MaxHeight := ScaleY(Dimensions.ConstraintsMax.Y, DesignDPI.Y);
190 end;
191 if Control is TWinControl then
192 for I := 0 to TWinControl(Control).ControlCount - 1 do begin
193 if TWinControl(Control).Controls[I] is TControl then
194 // Do not scale docked forms twice
195 if not (TWinControl(Control).Controls[I] is TForm) then begin
196 ScaleDimensions(TWinControl(Control).Controls[I], TControlDimension(Dimensions.Controls[I]));
197 end;
198 end;
199end;
200
201procedure TScaleDPI.ApplyToAll(FromDPI: TPoint);
202var
203 I: Integer;
204begin
205 for I := 0 to Screen.FormCount - 1 do begin
206 ScaleControl(Screen.Forms[I], FromDPI);
207 end;
208end;
209
210procedure TScaleDPI.ScaleImageList(ImgList: TImageList; FromDPI: TPoint);
211var
212 TempBmp: TBitmap;
213 Temp: array of TBitmap;
214 NewWidth, NewHeight: integer;
215 I: Integer;
216begin
217 NewWidth := ScaleX(ImgList.Width, FromDPI.X);
218 NewHeight := ScaleY(ImgList.Height, FromDPI.Y);
219
220 SetLength(Temp, ImgList.Count);
221 for I := 0 to ImgList.Count - 1 do
222 begin
223 TempBmp := TBitmap.Create;
224 TempBmp.PixelFormat := pf32bit;
225 ImgList.GetBitmap(I, TempBmp);
226 Temp[I] := TBitmap.Create;
227 Temp[I].SetSize(NewWidth, NewHeight);
228 {$ifdef linux}
229 Temp[I].PixelFormat := pf24bit;
230 {$else}
231 Temp[I].PixelFormat := pf32bit;
232 {$endif}
233 Temp[I].TransparentColor := TempBmp.TransparentColor;
234 //Temp[I].TransparentMode := TempBmp.TransparentMode;
235 Temp[I].Transparent := True;
236 Temp[I].Canvas.Brush.Style := bsSolid;
237 Temp[I].Canvas.Brush.Color := Temp[I].TransparentColor;
238 Temp[I].Canvas.FillRect(0, 0, Temp[I].Width, Temp[I].Height);
239
240 if (Temp[I].Width = 0) or (Temp[I].Height = 0) then Continue;
241 Temp[I].Canvas.StretchDraw(Rect(0, 0, Temp[I].Width, Temp[I].Height), TempBmp);
242 TempBmp.Free;
243 end;
244
245 ImgList.Clear;
246 ImgList.Width := NewWidth;
247 ImgList.Height := NewHeight;
248
249 for I := 0 to High(Temp) do
250 begin
251 ImgList.Add(Temp[I], nil);
252 Temp[i].Free;
253 end;
254end;
255
256function TScaleDPI.ScaleX(Size: Integer; FromDPI: Integer): Integer;
257begin
258 Result := MulDiv(Size, DPI.X, FromDPI);
259end;
260
261function TScaleDPI.ScaleY(Size: Integer; FromDPI: Integer): Integer;
262begin
263 Result := MulDiv(Size, DPI.Y, FromDPI);
264end;
265
266function TScaleDPI.ScalePoint(APoint: TPoint; FromDPI: TPoint): TPoint;
267begin
268 Result.X := ScaleX(APoint.X, FromDPI.X);
269 Result.Y := ScaleY(APoint.Y, FromDPI.Y);
270end;
271
272function TScaleDPI.ScaleRect(ARect: TRect; FromDPI: TPoint): TRect;
273begin
274 Result.TopLeft := ScalePoint(ARect.TopLeft, FromDPI);
275 Result.BottomRight := ScalePoint(ARect.BottomRight, FromDPI);
276end;
277
278constructor TScaleDPI.Create(AOwner: TComponent);
279begin
280 inherited;
281 DPI := Point(96, 96);
282 DesignDPI := Point(96, 96);
283end;
284
285procedure TScaleDPI.ScaleControl(Control: TControl; FromDPI: TPoint);
286var
287 I: Integer;
288 WinControl: TWinControl;
289 ToolBarControl: TToolBar;
290 OldAnchors: TAnchors;
291 OldAutoSize: Boolean;
292begin
293 //if Control is TMemo then Exit;
294 //if Control is TForm then
295 // Control.DisableAutoSizing;
296 with Control do begin
297 //OldAutoSize := AutoSize;
298 //AutoSize := False;
299 //Anchors := [];
300 Left := ScaleX(Left, FromDPI.X);
301 Top := ScaleY(Top, FromDPI.Y);
302 //if not (akRight in Anchors) then
303 Width := ScaleX(Width, FromDPI.X);
304 //if not (akBottom in Anchors) then
305 Height := ScaleY(Height, FromDPI.Y);
306 {$IFDEF LCL Qt}
307 Font.Size := 0;
308 {$ELSE}
309 Font.Height := ScaleY(Font.GetTextHeight('Hg'), FromDPI.Y);
310 {$ENDIF}
311 //Anchors := OldAnchors;
312 //AutoSize := OldAutoSize;
313 end;
314
315 if Control is TCoolBar then
316 with TCoolBar(Control) do begin
317 BeginUpdate;
318 for I := 0 to Bands.Count - 1 do
319 with Bands[I] do begin
320 MinWidth := ScaleX(MinWidth, FromDPI.X);
321 MinHeight := ScaleY(MinHeight, FromDPI.Y);
322 Width := ScaleX(Width, FromDPI.X);
323 //Control.Invalidate;
324 end;
325 EndUpdate;
326 end;
327
328 if Control is TToolBar then begin
329 ToolBarControl := TToolBar(Control);
330 with ToolBarControl do begin
331 ButtonWidth := ScaleX(ButtonWidth, FromDPI.X);
332 ButtonHeight := ScaleY(ButtonHeight, FromDPI.Y);
333 end;
334 end;
335
336 //if not (Control is TCustomPage) then
337 if Control is TWinControl then begin
338 WinControl := TWinControl(Control);
339 if WinControl.ControlCount > 0 then begin
340 for I := 0 to WinControl.ControlCount - 1 do begin
341 if WinControl.Controls[I] is TControl then begin
342 ScaleControl(WinControl.Controls[I], FromDPI);
343 end;
344 end;
345 end;
346 end;
347 //if Control is TForm then
348 // Control.EnableAutoSizing;
349end;
350
351end.
Note: See TracBrowser for help on using the repository browser.