View Issue Details

IDProjectCategoryView StatusLast Update
0036493LazarusLCLpublic2021-06-11 07:27
ReporterChris Rorden Assigned ToJuha Manninen  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformMacBook 2012 Retina 13"OSDarwin 
Product Version2.1 (SVN) 
Summary0036493: Form with autosize := true does not consider width of TPageControl TTabSheet
DescriptionThis seems to be a general problem when a Form has AutoSize of true where the labels for the tabbed page control are wider than the window contents. The form is sized for the contents ignoring the requirements of the tabs.
Steps To ReproduceSet a Form to AutoSize = true, add a PageControl, Add several pages and set each tab sheet to have a long name. Run the program.
TagsNo tags attached.
Fixed in Revisionr65218
LazTarget-
Widgetset
Attached Files

Relationships

related to 0035858 closedJuha Manninen GTK2: Form AutoSize does not take menu size into account with bsSingle 

Activities

Chris Rorden

2019-12-29 12:51

reporter  

autoSize.zip (119,380 bytes)

Chris Rorden

2019-12-29 12:52

reporter   ~0120131

Example project on different widget sets, so seems to be general LCL problem, not specific to one widget set.
gtk2.png (15,897 bytes)   
gtk2.png (15,897 bytes)   
gtk3.png (11,579 bytes)   
gtk3.png (11,579 bytes)   
qt5.png (14,790 bytes)   
qt5.png (14,790 bytes)   
cocoa.png (49,471 bytes)   
cocoa.png (49,471 bytes)   

Dmitry Boyarintsev

2020-01-04 19:29

developer   ~0120223

here's a proposed patch
tabwidth.diff (1,707 bytes)   
Index: lcl/comctrls.pp
===================================================================
--- lcl/comctrls.pp	(revision 62492)
+++ lcl/comctrls.pp	(working copy)
@@ -587,6 +587,9 @@
     procedure DoRemoveDockClient(Client: TControl); override;
     function DoUndockClientMsg(NewTarget, Client: TControl):boolean; override;
     function ChildClassAllowed(ChildClass: TClass): boolean; override;
+    procedure GetPreferredSize(var PreferredWidth, PreferredHeight: integer;
+                               Raw: boolean = false;
+                               WithThemeSpace: boolean = true); override;
   public
     function FindNextPage(CurPage: TTabSheet;
                           GoForward, CheckTabVisible: Boolean): TTabSheet;
Index: lcl/include/pagecontrol.inc
===================================================================
--- lcl/include/pagecontrol.inc	(revision 62492)
+++ lcl/include/pagecontrol.inc	(working copy)
@@ -116,6 +116,23 @@
   if Widgetset.GetLCLCapability(lcAllowChildControlsInNativeControls) = LCL_CAPABILITY_YES then Result := True;
 end;
 
+procedure TPageControl.GetPreferredSize(var PreferredWidth,
+  PreferredHeight: integer; Raw: boolean; WithThemeSpace: boolean);
+var
+  i : integer;
+  r : TRect;
+begin
+  inherited GetPreferredSize(PreferredWidth, PreferredHeight, Raw,
+    WithThemeSpace);
+  for i:=0 to PageCount-1 do begin
+    if Pages[i].TabVisible then begin
+      r:=TabRect(i);
+      //PreferredWidth:=Max(Min(Width, r.Right), PreferredWidth);
+      PreferredWidth:=Max(r.Right, PreferredWidth);
+    end;
+  end;
+end;
+
 function TPageControl.FindNextPage(CurPage: TTabSheet; GoForward,
   CheckTabVisible: Boolean): TTabSheet;
 var
tabwidth.diff (1,707 bytes)   

Chris Rorden

2020-01-05 12:18

reporter   ~0120229

Dmitry, thanks for the patch. It improves things on GTK2. However, the preferred size seems to be based on the active page used when the form is first displayed. In my example, set the "ActivePage" of From2/PageControl1 to "TabSheet2" - this is a smaller tab sheet. Now when you run the program the program initially appears with the correct (small) form size, but clicking to the larger "TabSheet1" does not change the form size, so content is not visible.

Joeny Ang

2021-06-01 05:27

reporter   ~0131110

Hi, try this patch. Tweaking Dmitry's patch, this will use the largest page
width and height to compute for the pagecontrol's size. Published AutoSize
for both TPageControl and TTabSheet. Its AutoSize behaviour is now similar
to other container controls.
tpagecontrol-autosize.patch (2,033 bytes)   
--- lcl/comctrls.pp
+++ lcl/comctrls.pp
@@ -527,6 +527,7 @@
     property PageControl: TPageControl read GetPageControl write SetPageControl;
     property TabIndex: Integer read GetTabIndex;
   published
+    property AutoSize;
     property BorderWidth;
     property BiDiMode;
     property Caption;
@@ -587,6 +588,9 @@
     procedure DoRemoveDockClient(Client: TControl); override;
     function DoUndockClientMsg(NewTarget, Client: TControl):boolean; override;
     function ChildClassAllowed(ChildClass: TClass): boolean; override;
+    procedure GetPreferredSize(var PreferredWidth, PreferredHeight: integer;
+                               Raw: boolean = false;
+                               WithThemeSpace: boolean = true); override;
   public
     function FindNextPage(CurPage: TTabSheet;
                           GoForward, CheckTabVisible: Boolean): TTabSheet;
@@ -606,6 +610,7 @@
     
     property Align;
     property Anchors;
+    property AutoSize;
     property BorderSpacing;
     property BiDiMode;
     property Constraints;
--- lcl/include/pagecontrol.inc
+++ lcl/include/pagecontrol.inc
@@ -116,6 +116,26 @@
   if Widgetset.GetLCLCapability(lcAllowChildControlsInNativeControls) = LCL_CAPABILITY_YES then Result := True;
 end;
 
+procedure TPageControl.GetPreferredSize(var PreferredWidth,
+  PreferredHeight: integer; Raw: boolean; WithThemeSpace: boolean);
+var
+  i, w, h, fw, fh: integer;
+begin
+  PreferredWidth := 0;
+  PreferredHeight := 0;
+  for i := 0 to PageCount - 1 do
+    if Pages[i].TabVisible then begin
+      if Pages[i].AutoSize then
+        Pages[i].DoAutoSize;
+      Pages[i].GetPreferredSize(w, h, Raw, WithThemeSpace);
+      PreferredWidth := Max(PreferredWidth, w);
+      PreferredHeight := Max(PreferredHeight, h);
+    end;
+  GetPreferredSizeClientFrame(fw, fh);
+  PreferredWidth := PreferredWidth + fw;
+  PreferredHeight := PreferredHeight + fh;
+end;
+
 function TPageControl.FindNextPage(CurPage: TTabSheet; GoForward,
   CheckTabVisible: Boolean): TTabSheet;
 var

tpagecontrol-autosize.patch (2,033 bytes)   
test01.zip (109,644 bytes)

Joeny Ang

2021-06-08 08:27

reporter   ~0131195

Hi, patch updated. Fixed non-active pages' sizes not properly calculated.
tpagecontrol-autosize-v2.patch (2,547 bytes)   
--- lcl/comctrls.pp
+++ lcl/comctrls.pp
@@ -527,6 +527,7 @@
     property PageControl: TPageControl read GetPageControl write SetPageControl;
     property TabIndex: Integer read GetTabIndex;
   published
+    property AutoSize;
     property BorderWidth;
     property BiDiMode;
     property Caption;
@@ -587,6 +588,9 @@
     procedure DoRemoveDockClient(Client: TControl); override;
     function DoUndockClientMsg(NewTarget, Client: TControl):boolean; override;
     function ChildClassAllowed(ChildClass: TClass): boolean; override;
+    procedure GetPreferredSize(var PreferredWidth, PreferredHeight: integer;
+                               Raw: boolean = false;
+                               WithThemeSpace: boolean = true); override;
   public
     function FindNextPage(CurPage: TTabSheet;
                           GoForward, CheckTabVisible: Boolean): TTabSheet;
@@ -606,6 +610,7 @@
     
     property Align;
     property Anchors;
+    property AutoSize;
     property BorderSpacing;
     property BiDiMode;
     property Constraints;
--- lcl/include/pagecontrol.inc
+++ lcl/include/pagecontrol.inc
@@ -116,6 +116,26 @@
   if Widgetset.GetLCLCapability(lcAllowChildControlsInNativeControls) = LCL_CAPABILITY_YES then Result := True;
 end;
 
+procedure TPageControl.GetPreferredSize(var PreferredWidth,
+  PreferredHeight: integer; Raw: boolean; WithThemeSpace: boolean);
+var
+  i, w, h, fw, fh: integer;
+begin
+  PreferredWidth := 0;
+  PreferredHeight := 0;
+  for i := 0 to PageCount - 1 do
+    if Pages[i].TabVisible then begin
+      if Pages[i].AutoSize then
+        Pages[i].DoAutoSize;
+      Pages[i].GetPreferredSize(w, h, Raw, WithThemeSpace);
+      PreferredWidth := Max(PreferredWidth, w);
+      PreferredHeight := Max(PreferredHeight, h);
+    end;
+  GetPreferredSizeClientFrame(fw, fh);
+  PreferredWidth := PreferredWidth + fw;
+  PreferredHeight := PreferredHeight + fh;
+end;
+
 function TPageControl.FindNextPage(CurPage: TTabSheet; GoForward,
   CheckTabVisible: Boolean): TTabSheet;
 var
--- lcl/include/custompage.inc
+++ lcl/include/custompage.inc
@@ -221,6 +221,13 @@
 
 function TCustomPage.IsControlVisible: Boolean;
 begin
+  // when autosizing, need this to return True so that the sizes of non-active
+  // pages will be considered in parent's GetPreferredSize()
+  if AutoSizingAll then
+  begin
+    Result := True;
+    Exit;
+  end;
   Result := inherited IsControlVisible;
   if Result and (Parent is TCustomTabControl) then
     Result := PageIndex = TCustomTabControl(Parent).PageIndex;

tpagecontrol-autosize-v2.patch (2,547 bytes)   

Anton Kavalenka

2021-06-08 11:12

reporter   ~0131199

4 times the getter (Pages.GetItem) returning the same called
+ if Pages[i].TabVisible then begin
+ if Pages[i].AutoSize then
+ Pages[i].DoAutoSize;
+ Pages[i].GetPreferredSize(w, h, Raw, WithThemeSpace);

Joeny Ang

2021-06-09 04:02

reporter   ~0131210

Hi Anton, yes, my bad. Thanks :)

It turns out, GetPreferredSize() need not be overriden anymore. The parent
method properly does the calculation. We only need to make the hidden pages
"visible" when doing autosize.
tpagecontrol-autosize-v3.patch (992 bytes)   
--- lcl/comctrls.pp
+++ lcl/comctrls.pp
@@ -527,6 +527,7 @@
     property PageControl: TPageControl read GetPageControl write SetPageControl;
     property TabIndex: Integer read GetTabIndex;
   published
+    property AutoSize;
     property BorderWidth;
     property BiDiMode;
     property Caption;
@@ -606,6 +607,7 @@
     
     property Align;
     property Anchors;
+    property AutoSize;
     property BorderSpacing;
     property BiDiMode;
     property Constraints;
--- lcl/include/custompage.inc
+++ lcl/include/custompage.inc
@@ -221,6 +221,13 @@
 
 function TCustomPage.IsControlVisible: Boolean;
 begin
+  // when autosizing, need this to return True so that the sizes of non-active
+  // pages will be considered in parent's GetPreferredSize()
+  if AutoSizingAll then
+  begin
+    Result := True;
+    Exit;
+  end;
   Result := inherited IsControlVisible;
   if Result and (Parent is TCustomTabControl) then
     Result := PageIndex = TCustomTabControl(Parent).PageIndex;

Juha Manninen

2021-06-11 07:27

developer   ~0131247

I applied the last patch. Thanks.
I used a shorter "Exit(True)".

Issue History

Date Modified Username Field Change
2019-12-29 12:51 Chris Rorden New Issue
2019-12-29 12:51 Chris Rorden File Added: autoSize.zip
2019-12-29 12:52 Chris Rorden File Added: gtk2.png
2019-12-29 12:52 Chris Rorden File Added: gtk3.png
2019-12-29 12:52 Chris Rorden File Added: qt5.png
2019-12-29 12:52 Chris Rorden File Added: cocoa.png
2019-12-29 12:52 Chris Rorden Note Added: 0120131
2020-01-01 22:43 Juha Manninen Relationship added related to 0035858
2020-01-04 19:29 Dmitry Boyarintsev File Added: tabwidth.diff
2020-01-04 19:29 Dmitry Boyarintsev Note Added: 0120223
2020-01-05 12:18 Chris Rorden Note Added: 0120229
2021-06-01 05:27 Joeny Ang Note Added: 0131110
2021-06-01 05:27 Joeny Ang File Added: 0036493-tpagecontrol-autosize.patch
2021-06-01 05:27 Joeny Ang File Added: 0036493-test01.zip
2021-06-08 08:27 Joeny Ang Note Added: 0131195
2021-06-08 08:27 Joeny Ang File Added: 0036493-tpagecontrol-autosize-v2.patch
2021-06-08 11:12 Anton Kavalenka Note Added: 0131199
2021-06-09 04:02 Joeny Ang Note Added: 0131210
2021-06-09 04:02 Joeny Ang File Added: 0036493-tpagecontrol-autosize-v3.patch
2021-06-11 07:21 Juha Manninen Assigned To => Juha Manninen
2021-06-11 07:21 Juha Manninen Status new => assigned
2021-06-11 07:27 Juha Manninen Status assigned => resolved
2021-06-11 07:27 Juha Manninen Resolution open => fixed
2021-06-11 07:27 Juha Manninen Fixed in Revision => r65218
2021-06-11 07:27 Juha Manninen LazTarget => -
2021-06-11 07:27 Juha Manninen Note Added: 0131247