Recent

Author Topic: Faking a different DesignTimePPI to artificially zoom a form  (Read 1012 times)

prof7bit

  • Full Member
  • ***
  • Posts: 144
Faking a different DesignTimePPI to artificially zoom a form
« on: September 08, 2021, 09:54:43 am »
I tried to zoom a form at runtime to twice its sice by entering a smaller value into DesignTimePPI than that of my development machine but Lazarus will not allow any manual change here and always replace it with the true dpi of my system.

Is there any way at runtime to force or fake a different design time ppi to achieve the desired effect?

CCRDude

  • Hero Member
  • *****
  • Posts: 529
Re: Faking a different DesignTimePPI to artificially zoom a form
« Reply #1 on: September 08, 2021, 10:00:41 am »
Probably overkill, but something I used to spoof a different OS language to an app recently:

Check how DesigntimePPI is set, hook a function behind it, return adjusted value.

See https://github.com/MahdiSafsafi/DDetours

Warning: there are probably easier, and better, ways to reach your goal.


wp

  • Hero Member
  • *****
  • Posts: 9025
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

prof7bit

  • Full Member
  • ***
  • Posts: 144
Re: Faking a different DesignTimePPI to artificially zoom a form
« Reply #3 on: September 08, 2021, 11:09:04 am »
https://forum.lazarus.freepascal.org/index.php/topic,54112.msg401763.html#msg401763

I was really thinking that since the LCL has already implemented in all the hard stuff to scale it to whatever DPI is needed there would be an easy way to make use of this magic with a one-liner and let it do its scaling magic with a different DPI value.

So far I have found only two methods to achieve what I want:

  • write a function that iterates over all child components of a form to scale all their positions, sizes, borders and fonts, handling a bunch of ugly special cases with anchoring, making my own descendant of THintWindow that respects the scaling and having failed so far to also apply my scale to popumenus
  • use Qt widgetset, make sure it is installed on a machine with Qt 5.12+ and then inject the environment variable QT_SCALE_FACTOR before the widgetset is initialized, this gives exceptionally pleasing results, even the scrollbars will be scaled, but it is highly platform dependent and I don't know whether it will break again in the next Qt version (it is broken for Lazarus apps in older Qt versions, although it works for other Qt apps in the same old Qt version). Since I don't know why this Qt mechanism is broken for LCL in some versions I am still using method 1 at the moment.

It would be nice if this DPI scaling mechanisms could be exposed in such a way that it can be used to intentionally scale forms to "wrong" dpi values.
« Last Edit: September 08, 2021, 11:30:15 am by prof7bit »

paweld

  • Sr. Member
  • ****
  • Posts: 312
Re: Faking a different DesignTimePPI to artificially zoom a form
« Reply #4 on: September 08, 2021, 11:56:34 am »
Code: Pascal  [Select][+][-]
  1. Form1.ScaleBy(ToPPI, FromPPI);
Best regards
paweld

avra

  • Hero Member
  • *****
  • Posts: 2262
    • Additional info
Re: Faking a different DesignTimePPI to artificially zoom a form
« Reply #5 on: September 09, 2021, 01:30:11 am »
I tried to zoom a form at runtime to twice its sice by entering a smaller value into DesignTimePPI
As an alternative you might want to take a look at old school methods: https://forum.lazarus.freepascal.org/index.php/topic,40155.msg277088.html#msg277088
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

prof7bit

  • Full Member
  • ***
  • Posts: 144
Re: Faking a different DesignTimePPI to artificially zoom a form
« Reply #6 on: September 20, 2021, 11:04:19 am »
Code: Pascal  [Select][+][-]
  1. Form1.ScaleBy(ToPPI, FromPPI);

This is almost a replacement for my previous scaling method but unfortunately ScaleBy() will not scale the anchor borders, so the spacing between controls will become much too small :-(

This is how I am currently doing it:
Code: Pascal  [Select][+][-]
  1. procedure ScaleByEx(const Control: TControl; Multiplier, Divider: Integer);
  2. var
  3.   n: Integer;
  4.   WinControl: TWinControl;
  5.  
  6. begin
  7.   with Control do begin
  8.     DisableAutoSizing; // prevent property changes influencing each other
  9.  
  10.     Height := Height * Multiplier div Divider;
  11.     Width := Width * Multiplier div Divider;
  12.  
  13.     if Assigned(Parent) then begin
  14.       Left := Left * Multiplier div Divider;
  15.       Top := Top * Multiplier div Divider;
  16.     end;
  17.  
  18.     if not IsParentFont then begin
  19.       Font.Size := GetFontData(Font.Handle).Height * 72 * Multiplier
  20.         div (Font.PixelsPerInch * Divider);
  21.     end;
  22.  
  23.     with BorderSpacing do begin
  24.       Left := Left * Multiplier div Divider;
  25.       Top := Top * Multiplier div Divider;
  26.       Right := Right * Multiplier div Divider;
  27.       Bottom := Bottom * Multiplier div Divider;
  28.       Around := Around * Multiplier div Divider;
  29.       InnerBorder := InnerBorder * Multiplier div Divider;
  30.     end;
  31.   end;
  32.  
  33.   if Control is TWinControl then begin
  34.     WinControl:=TWinControl(Control);
  35.     if WinControl.ControlCount > 0 then begin
  36.       for n:=0 to WinControl.ControlCount-1 do begin
  37.         if WinControl.Controls[n] is TControl then begin
  38.           ScaleByEx(WinControl.Controls[n], Multiplier, Divider);
  39.         end;
  40.       end;
  41.     end;
  42.   end;
  43.   Control.EnableAutoSizing;
  44. end;
  45.  
« Last Edit: September 20, 2021, 01:44:08 pm by prof7bit »

 

TinyPortal © 2005-2018