Difference between revisions of "LCL Internals - Resizing, Moving"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(7 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 +
{{LCL Internals - Resizing, Moving}}
 +
 
== Overview ==
 
== Overview ==
  
Line 6: Line 8:
  
 
In TWinControl.DoSendBoundsToInterface the widget function SetBounds is called
 
In TWinControl.DoSendBoundsToInterface the widget function SetBounds is called
  TWSWinControlClass(WidgetSetClass).SetBounds(Self, Left, Top, Width, Height);
+
<syntaxhighlight lang=pascal>TWSWinControlClass(WidgetSetClass).SetBounds(Self, Left, Top, Width, Height);</syntaxhighlight>
  
 
== How the Interface tells the LCL to resize/move a handle ==
 
== How the Interface tells the LCL to resize/move a handle ==
Line 64: Line 66:
  
 
The LCL asks the interface for constraints (min, max for width and height) with the function
 
The LCL asks the interface for constraints (min, max for width and height) with the function
  GetControlConstraints
+
<syntaxhighlight lang=pascal>GetControlConstraints</syntaxhighlight>
  
 
For example: Under gtk a horizontal scrollbar has a fixed height.
 
For example: Under gtk a horizontal scrollbar has a fixed height.
Line 72: Line 74:
 
To autosize a control (e.g. a TButton or a TLabel) the LCL asks the interface about the minimum size to render a control nicely:
 
To autosize a control (e.g. a TButton or a TLabel) the LCL asks the interface about the minimum size to render a control nicely:
  
  TWSWinControlClass(WidgetSetClass).GetPreferredSize(Self, PreferredWidth, PreferredHeight, WithThemeSpace);
+
<syntaxhighlight lang=pascal>TWSWinControlClass(WidgetSetClass).GetPreferredSize(Self, PreferredWidth, PreferredHeight, WithThemeSpace);</syntaxhighlight>
  
 
== Scrolling ==
 
== Scrolling ==
 +
 +
The LCL scrolls child controls only virtually. That means, their Left,Top properties do not change. To scroll it uses the LCL interface function
 +
<syntaxhighlight lang=pascal>TWSScrollingWinControlClass(WidgetSetClass).ScrollBy(Self, DeltaX, DeltaY);</syntaxhighlight>
 +
 +
==Rectangles==
 +
 +
* BoundsRect - the rectangle containing coordinates of the control within parents coordinates
 +
: for TForm (not embedded into another control) coordinates are given in Screen position. The form non-client area (aka header, aka title) section is also NOT PART of the BoundsRect.
 +
* ClientsRect - the rectangle containing coordinates of the client area.
  
 
== Miscellaneous ==
 
== Miscellaneous ==
Line 81: Line 92:
  
 
Returns the unscrolled client rectangle relative to the top, left of the Handle. In other words it is equivalent to:
 
Returns the unscrolled client rectangle relative to the top, left of the Handle. In other words it is equivalent to:
  CurClientBounds := GetClientRect(Handle)
+
 
  OffsetRect(CurClientBounds,FrameBorderLeft,FrameBorderTop);
+
<syntaxhighlight lang=pascal>
 +
CurClientBounds := GetClientRect(Handle)
 +
OffsetRect(CurClientBounds,FrameBorderLeft,FrameBorderTop);
 +
</syntaxhighlight>

Latest revision as of 01:04, 19 February 2020

English (en) français (fr)

Overview

The LCL has a lot of resizing properties (Left, Width, Anchors, Align, AnchorSide, AutoSize, Constraints, ChildSizing, ...) and hooks where applications can alter the behavior (OnResize, OnChangeBounds, ...). All these things can not be calculated in one step, so controls can move quite a lot before the final coordinates come out. To reduce flickering the LCL does not send every move/resize to the LCL interface. For example during Begin/EndAlign and csLoading no move/resize is sent to the interface. The widgetset will try to follow the advices of the LCL, but there are some cases, where it does not follow. For example forms (top level windows) are limited by the window manager policies. And TPage completely depends on the size and theme of the TNotebook.

How the LCL tells the interface to resize/move a handle

In TWinControl.DoSendBoundsToInterface the widget function SetBounds is called

TWSWinControlClass(WidgetSetClass).SetBounds(Self, Left, Top, Width, Height);

How the Interface tells the LCL to resize/move a handle

When the client area of a Handle was resized

Note: If the theme changes the frame of a TGroupBox can change. This leaves the Size and Position of the TGroupBox unchanged, but the client area can change. The interface calls

 LCLControl.InvalidateClientRectCache(false);

and sends a LM_SIZE message as below.

When a Handle of a TWinControl was resized/moved

First the LCL interface send a LM_WINDOWPOSCHANGED message

  • x := Left (relative to 0,0 of client area of parent)
  • y := Top
  • cx := Width
  • cy := Height

Then a LM_SIZE message is sent

  • Width
  • Height
  • SizeType is a bit flag containing Size_SourceIsInterface plus one of the values SIZENORMAL, SIZEICONIC, SIZEFULLSCREEN.

Then a LM_MOVE message is sent

  • MoveType := Move_SourceIsInterface;
  • XPos := Left (relative to 0,0 of client area of parent)
  • YPos := Top

When a form is maximized, minimized or restored the interface sends a LM_SIZE message

  • Width
  • Height
  • SizeType is a bit flag containing Size_SourceIsInterface plus one of the values SIZENORMAL, SIZEICONIC, SIZEFULLSCREEN.

How the LCL gets the current size / position of a LCL interface handle

LCLIntf.GetWindowSize(Handle, InterfaceWidth, InterfaceHeight)

Returns the current width and height of a Handle.

LCLIntf.GetClientRect(Handle, Result)

Returns the current width and height (left and top are always 0) of the client area of a Handle (= inner area inside the border/frame of a control).

TWSWinControlClass(WidgetSetClass).GetDefaultClientRect(Self, Left, Top, Width, Height, Result)

This function is called first by the LCL to get the ClientRect. If it returns false, the LCL will use GetClientRect if it has already created a handle, otherwise the values loaded from the .lfm. If all this fails, the default is Rect(0,0,Width,Height). GetDefaultClientRect can be used by the LCL interface to reduce flickering by providing good values before the handle is created.

GetWindowRelativePosition(Handle,NewLeft,NewTop)

Returns the current Left, Top of a Handle relative to the client area (0,0) of its parent.

Constraints

The LCL asks the interface for constraints (min, max for width and height) with the function

GetControlConstraints

For example: Under gtk a horizontal scrollbar has a fixed height.

Preferred Size

To autosize a control (e.g. a TButton or a TLabel) the LCL asks the interface about the minimum size to render a control nicely:

TWSWinControlClass(WidgetSetClass).GetPreferredSize(Self, PreferredWidth, PreferredHeight, WithThemeSpace);

Scrolling

The LCL scrolls child controls only virtually. That means, their Left,Top properties do not change. To scroll it uses the LCL interface function

TWSScrollingWinControlClass(WidgetSetClass).ScrollBy(Self, DeltaX, DeltaY);

Rectangles

  • BoundsRect - the rectangle containing coordinates of the control within parents coordinates
for TForm (not embedded into another control) coordinates are given in Screen position. The form non-client area (aka header, aka title) section is also NOT PART of the BoundsRect.
  • ClientsRect - the rectangle containing coordinates of the client area.

Miscellaneous

LCLIntf.GetClientBounds(Handle,Result);

Returns the unscrolled client rectangle relative to the top, left of the Handle. In other words it is equivalent to:

CurClientBounds := GetClientRect(Handle)
OffsetRect(CurClientBounds,FrameBorderLeft,FrameBorderTop);