Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2016-06

Zooming a form

6 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Grajcar

I should zoom a form, so that all its controls (and their fonts) get bigger by X%. The recursion is trivial and it mostly works, but ...

I'm doing it in a moment when not everything is visible (and can't see how to postpone it). Despite that, it works fine for all controls with Anchors = [akLeft, akTop]. For controls with other anchors, nothing works: Even a trivial change like increasing left or width by one makes the control lose its anchoring (and behave like left-top-anchored) and move to a strange position.

The problem seems to lie in TControl.UpdateBaseBounds when the FBaseParentClientSize gets stored, which happens to be (0, 0) at this point. If I hack it to keep the previously stored value, it somehow works.

The zero-client-size parent is a TPage, but I can't claim it guilty as I couldn't reproduce my problem in a small example.

So I wonder:

   - Is it forbidden to change position and/or size of a component when
   it's not shown?
   - If not, how can I deal with right-aligned controls? Simply setting
   c.Left := c.Left * Factor doesn't seem to work (though it should as in this
   step all positions and all sizes simply get scaled up; anchoring is used
   when the parent resizes and not the component itself, right?).

But actually any help is appreciated.

I'm stuck with Lazarus 1.4.2, but the trunk code seems to do the same. -------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20160621/38bd8594/attachment.html>

Reply by email

Mattias Gaertner
to Martin Grajcar
Show quoted text 5 lines
[...]Despite that, it works fine for all controls with Anchors = [akLeft, akTop]. For controls with other anchors, nothing works[...] The problem seems to lie in TControl.UpdateBaseBounds when the FBaseParentClientSize gets stored, which happens to be (0, 0) at this point. If I hack it to keep the previously stored value, it somehow works.

BoundsRect (Left,Top,Width,Height) is the current position/size.

When a form's width is changed the LCL has to adapt the right anchored controls - aka changing the Left so that the distance of the right side is restored. The right distance is computed from BaseBounds and BaseParentClientSize.

BaseBounds/BaseParentClientSize is set when you call SetBounds (e.g. when setting Left, Top, Width, Height). When the LCL computes the autosized values it calls SetBoundsKeepBase, so it changes BoundsRect and keeps BaseBounds/BaseParentClientSize.

The zero-client-size parent is a TPage, but I can't claim it guilty as I couldn't reproduce my problem in a small example.

Do you mean it does work in a small example, but it does not in your complex application?

So I wonder: - Is it forbidden to change position and/or size of a component when it's not shown?

It is allowed and a pretty normal thing.

- If not, how can I deal with right-aligned controls? Simply setting c.Left := c.Left * Factor doesn't seem to work (though it should as in this step all positions and all sizes simply get scaled up; anchoring is used when the parent resizes and not the component itself, right?).

Maybe you forget to disable the autosize updates during the changes?

Simple example:

MainControl.DisableAlign;
try
  MainControl.SetBounds(Width*f,Height*f);
  for aControl in List do
    aControl.SetBounds(aControl.Left*f,aControl.Top*f,aControl.Width*f,aControl.Height*f);
finally
  MainControl.EnableAlign;
end;

Note: This algorithm has rounding errors, so multiple zooms will destroy your layout.

Mattias

Reply by email

Luca Olivetti
to Mattias Gaertner

El 21/06/16 a les 13:45, Mattias Gaertner ha escrit:

Show quoted text 12 lines
Simple example: MainControl.DisableAlign; try MainControl.SetBounds(Width*f,Height*f); for aControl in List do aControl.SetBounds(aControl.Left*f,aControl.Top*f,aControl.Width*f,aControl.Height*f); finally MainControl.EnableAlign; end;

I just use ScaleBy, it recursively scales all components. I do in in the FormShow method, I don't remember the details but I think it didn't work well when the form was still hidden. Another problem is that it also moves the Top,Left of the form, but I just restore it after the ScaleBy

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Martin Grajcar
to Mattias Gaertner: On Tue, 21 Jun 2016 04:05:04 +0200 BoundsRect (Left,Top,Width,Height) is the current…

On Tue, Jun 21, 2016 at 1:45 PM, Mattias Gaertner <

Show quoted text 19 lines
wrote: On Tue, 21 Jun 2016 04:05:04 +0200 Martin Grajcar wrote: >[...]Despite that, it works fine for all controls with Anchors > = [akLeft, akTop]. For controls with other anchors, nothing works[...] > The problem seems to lie in TControl.UpdateBaseBounds when > the FBaseParentClientSize gets stored, which happens to be (0, 0) at this > point. If I hack it to keep the previously stored value, it somehow works. BoundsRect (Left,Top,Width,Height) is the current position/size. When a form's width is changed the LCL has to adapt the right anchored controls - aka changing the Left so that the distance of the right side is restored. The right distance is computed from BaseBounds and BaseParentClientSize.

Thank you a lot for all the explanations.

That's what I'm doing now manually:

bb := AControl.BaseBounds;
bpcs := AControl.BaseParentClientSize;
OldLeft := bb.Left;
OldWidth := bb.Right - bb.Left;
// right = distance of the right edge from the *right* parent's edge
OldRight := bpcs.cx - OldLeft - OldWidth;
NewRight := OldRight; // keep it
NewWidth := OldWidth * Zoom; // scale it
NewLeft := bpcs.cx - OldRight - OldWidth;

I'm rather sure that the computation is right (the above code mayn't be, but the real one is). The problem is that not only BaseBounds gets stored, but also BaseParentClientSize, which gets taken from the actual parent, which has zero size at the moment.

What I'm doing would be right if the BaseParentClientSize were preserved. I hacked lcl/include/control.inc and got what I wanted:

 procedure TControl.UpdateAnchorRules;
 begin
-  UpdateBaseBounds(true,true,false);
+  UpdateBaseBounds(true,false,true);
 end;

This doesn't sound right... I guess, Lazarus counts on me computing the bounds relatively to the zero-size parent??? Maybe replacing the second occurrence of bpcs.cx by 0 (more exactly: the actual Parent.ClientWidth) would do? This would imply negative Left, but what...

BaseBounds/BaseParentClientSize is set when you call SetBounds (e.g.

when setting Left, Top, Width, Height).

My debugger agrees with you. I don't ask why so complicated. ;)

When the LCL computes the autosized values it calls SetBoundsKeepBase, so it changes BoundsRect and keeps BaseBounds/BaseParentClientSize.

Makes sense.

Show quoted text 7 lines
> The zero-client-size parent is a TPage, but I can't claim it guilty as I > couldn't reproduce my problem in a small example. Do you mean it does work in a small example, but it does not in your complex application?

Exactly. I thought that there might be a bug in TNotebook/TPage leading to zero client area, but this isn't the case.

Show quoted text 28 lines
So I wonder: > > - Is it forbidden to change position and/or size of a component when > it's not shown? It is allowed and a pretty normal thing. > - If not, how can I deal with right-aligned controls? Simply setting > c.Left := c.Left * Factor doesn't seem to work (though it should as in this > step all positions and all sizes simply get scaled up; anchoring is used > when the parent resizes and not the component itself, right?). Maybe you forget to disable the autosize updates during the changes? Simple example: MainControl.DisableAlign; try MainControl.SetBounds(Width*f,Height*f); for aControl in List do aControl.SetBounds(aControl.Left*f,aControl.Top*f,aControl.Width*f,aControl.Height*f); finally MainControl.EnableAlign; end;

I sort of intentionally did not use it: I use no align and no autosize (just anchors), so I though I won't need it. Now, I included it, but I still need to hack TControl.UpdateAnchorRules as above.

Note: This algorithm has rounding errors, so multiple zooms will

destroy your layout.

I know. Currently, I don't care about a pixel or two... my layout has orders of magnitude bigger problems.

However, for the future, I'm curious if there's a simple way of storing additional information for a control without subclassing it. Let's say, I need to store the *original* font size of *every* control. And I don't want to run to any problems when the control gets freed.

Regards, Martin.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20160623/36a97234/attachment-0001.html>

Reply by email

Mattias Gaertner
to Martin Grajcar
[...]also BaseParentClientSize, which gets taken from the actual parent, which has zero size at the moment.

...which is a show stopper for right anchoring.

Show quoted text 5 lines
[...] BaseBounds/BaseParentClientSize is set when you call SetBounds (e.g. > when setting Left, Top, Width, Height). My debugger agrees with you. I don't ask why so complicated. ;)

One part Delphi compatibility, one part flexibility for custom controls.

Show quoted text 10 lines
[...] > > The zero-client-size parent is a TPage, but I can't claim it guilty as I > > couldn't reproduce my problem in a small example. > > Do you mean it does work in a small example, but it does not in your > complex application? > Exactly. I thought that there might be a bug in TNotebook/TPage leading to zero client area, but this isn't the case.

Let's see if I can follow you:
Do you mean, when you set the bounds and anchors of the control the BaseParentClientSize is 0,0 and Parent.ClientRect has non 0 values?

[...] I sort of intentionally did not use it: I use no align and no autosize (just anchors), so I though I won't need it.

Without Disable/EnableAlign the AutoSize algorithm kicks in after each property change. And because anchoring is context sensitive, it is better to make sure. Also it avoids some overhead, which can load a form much faster.

Show quoted text 5 lines
[...] However, for the future, I'm curious if there's a simple way of storing additional information for a control without subclassing it. Let's say, I need to store the *original* font size of *every* control. And I don't want to run to any problems when the control gets freed.

There is no LCL-built-in user storage space. You need to use subclassing or some other objects to store your settings.

Mattias

Reply by email

Martin Grajcar
to Mattias Gaertner

On Thu, Jun 23, 2016 at 10:00 AM, Mattias Gaertner <

Show quoted text 10 lines
wrote: On Thu, 23 Jun 2016 09:35:15 +0200 Martin Grajcar wrote: >[...]also BaseParentClientSize, which gets taken from the actual parent, > which has zero size at the moment. ...which is a show stopper for right anchoring.

Yet it works well with my hack saying "don't store parent size".

Show quoted text 26 lines
>[...] > BaseBounds/BaseParentClientSize is set when you call SetBounds (e.g. > > when setting Left, Top, Width, Height). > > My debugger agrees with you. I don't ask why so complicated. ;) One part Delphi compatibility, one part flexibility for custom controls. >[...] > > > The zero-client-size parent is a TPage, but I can't claim it guilty as I > > > couldn't reproduce my problem in a small example. > > > > Do you mean it does work in a small example, but it does not in your > > complex application? > > > > Exactly. I thought that there might be a bug in TNotebook/TPage leading to > zero client area, but this isn't the case. Let's see if I can follow you: Do you mean, when you set the bounds and anchors of the control the BaseParentClientSize is 0,0 and Parent.ClientRect has non 0 values?

No, exactly the opposite:
BaseParentClientSize.cx = 850
Parent.Width = ParentClientRect.Right = ParentClientRect.Left = 0

So not storing the parent size seems to make sense.

Show quoted text 9 lines
[...] > I sort of intentionally did not use it: I use no align and no autosize > (just anchors), so I though I won't need it. Without Disable/EnableAlign the AutoSize algorithm kicks in after each property change. And because anchoring is context sensitive, it is better to make sure. Also it avoids some overhead, which can load a form much faster.

OK, I keep using DisableAlign.

Show quoted text 9 lines
[...] > However, for the future, I'm curious if there's a simple way of storing > additional information for a control without subclassing it. Let's say, I > need to store the *original* font size of *every* control. And I don't want > to run to any problems when the control gets freed. There is no LCL-built-in user storage space. You need to use subclassing or some other objects to store your settings.

OK, let's forget it for now.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20160623/1c174a07/attachment-0002.html>

Reply by email