source: trunk/Packages/Common/UScaleDPI.pas

Last change on this file was 19, checked in by chronos, 7 years ago
  • Fixed: Build under Lazarus 1.8.0.
  • Modified: Updated Common package.
File size: 10.8 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 Temp[I].PixelFormat := pf32bit;
229 Temp[I].TransparentColor := TempBmp.TransparentColor;
230 //Temp[I].TransparentMode := TempBmp.TransparentMode;
231 Temp[I].Transparent := True;
232 Temp[I].Canvas.Brush.Style := bsSolid;
233 Temp[I].Canvas.Brush.Color := Temp[I].TransparentColor;
234 Temp[I].Canvas.FillRect(0, 0, Temp[I].Width, Temp[I].Height);
235
236 if (Temp[I].Width = 0) or (Temp[I].Height = 0) then Continue;
237 Temp[I].Canvas.StretchDraw(Rect(0, 0, Temp[I].Width, Temp[I].Height), TempBmp);
238 TempBmp.Free;
239 end;
240
241 ImgList.Clear;
242 ImgList.Width := NewWidth;
243 ImgList.Height := NewHeight;
244
245 for I := 0 to High(Temp) do
246 begin
247 ImgList.Add(Temp[I], nil);
248 Temp[i].Free;
249 end;
250end;
251
252function TScaleDPI.ScaleX(Size: Integer; FromDPI: Integer): Integer;
253begin
254 Result := MulDiv(Size, DPI.X, FromDPI);
255end;
256
257function TScaleDPI.ScaleY(Size: Integer; FromDPI: Integer): Integer;
258begin
259 Result := MulDiv(Size, DPI.Y, FromDPI);
260end;
261
262function TScaleDPI.ScalePoint(APoint: TPoint; FromDPI: TPoint): TPoint;
263begin
264 Result.X := ScaleX(APoint.X, FromDPI.X);
265 Result.Y := ScaleY(APoint.Y, FromDPI.Y);
266end;
267
268function TScaleDPI.ScaleRect(ARect: TRect; FromDPI: TPoint): TRect;
269begin
270 Result.TopLeft := ScalePoint(ARect.TopLeft, FromDPI);
271 Result.BottomRight := ScalePoint(ARect.BottomRight, FromDPI);
272end;
273
274constructor TScaleDPI.Create(AOwner: TComponent);
275begin
276 inherited;
277 DPI := Point(96, 96);
278 DesignDPI := Point(96, 96);
279end;
280
281procedure TScaleDPI.ScaleControl(Control: TControl; FromDPI: TPoint);
282var
283 I: Integer;
284 WinControl: TWinControl;
285 ToolBarControl: TToolBar;
286 OldAnchors: TAnchors;
287 OldAutoSize: Boolean;
288begin
289 //if Control is TMemo then Exit;
290 //if Control is TForm then
291 // Control.DisableAutoSizing;
292 with Control do begin
293 //OldAutoSize := AutoSize;
294 //AutoSize := False;
295 //Anchors := [];
296 Left := ScaleX(Left, FromDPI.X);
297 Top := ScaleY(Top, FromDPI.Y);
298 //if not (akRight in Anchors) then
299 Width := ScaleX(Width, FromDPI.X);
300 //if not (akBottom in Anchors) then
301 Height := ScaleY(Height, FromDPI.Y);
302 {$IFDEF LCL Qt}
303 Font.Size := 0;
304 {$ELSE}
305 Font.Height := ScaleY(Font.GetTextHeight('Hg'), FromDPI.Y);
306 {$ENDIF}
307 //Anchors := OldAnchors;
308 //AutoSize := OldAutoSize;
309 end;
310
311 if Control is TCoolBar then
312 with TCoolBar(Control) do begin
313 BeginUpdate;
314 for I := 0 to Bands.Count - 1 do
315 with Bands[I] do begin
316 MinWidth := ScaleX(MinWidth, FromDPI.X);
317 MinHeight := ScaleY(MinHeight, FromDPI.Y);
318 Width := ScaleX(Width, FromDPI.X);
319 //Control.Invalidate;
320 end;
321 EndUpdate;
322 end;
323
324 if Control is TToolBar then begin
325 ToolBarControl := TToolBar(Control);
326 with ToolBarControl do begin
327 ButtonWidth := ScaleX(ButtonWidth, FromDPI.X);
328 ButtonHeight := ScaleY(ButtonHeight, FromDPI.Y);
329 end;
330 end;
331
332 //if not (Control is TCustomPage) then
333 if Control is TWinControl then begin
334 WinControl := TWinControl(Control);
335 if WinControl.ControlCount > 0 then begin
336 for I := 0 to WinControl.ControlCount - 1 do begin
337 if WinControl.Controls[I] is TControl then begin
338 ScaleControl(WinControl.Controls[I], FromDPI);
339 end;
340 end;
341 end;
342 end;
343 //if Control is TForm then
344 // Control.EnableAutoSizing;
345end;
346
347end.
Note: See TracBrowser for help on using the repository browser.