From e16bb0cfa43affe0e0bc2b9f6bf6d2572d4ad62d Mon Sep 17 00:00:00 2001 From: mattias Date: Sat, 3 Apr 2010 13:28:35 +0000 Subject: [PATCH] LCL: autosize: turn childs visible before parent autosize without visible handle: clear requests TWinControl.UpdateControlState: call AdjustSize to delay showing after bound computation TWinControl.WMSize: ignore if no bounds were sent to intf TToolBar.CreateWnd: delay autosize TControl.DoAllAutoSize: do not autosize invisible controls git-svn-id: trunk@24377 - --- lcl/comctrls.pp | 3 +- lcl/controls.pp | 22 +++++ lcl/include/control.inc | 2 + lcl/include/toolbar.inc | 30 ++++--- lcl/include/wincontrol.inc | 154 ++++++++++++++++++++++++--------- lcl/interfaces/gtk/gtkproc.inc | 1 + 6 files changed, 157 insertions(+), 55 deletions(-) diff --git a/lcl/comctrls.pp b/lcl/comctrls.pp index cec11be4a2..a5313cb712 100644 --- a/lcl/comctrls.pp +++ b/lcl/comctrls.pp @@ -1706,7 +1706,6 @@ type PreferredHeight: integer; WithThemeSpace: Boolean); override; function CheckMenuDropdown(Button: TToolButton): Boolean; virtual; procedure ClickButton(Button: TToolButton); virtual; - procedure CreateParams(var Params: TCreateParams); override; procedure CreateWnd; override; procedure ControlsAligned; override; function FindButtonFromAccel(Accel: Word): TToolButton; @@ -1716,7 +1715,7 @@ type procedure RepositionButton(Index: Integer); procedure RepositionButtons(Index: Integer); function WrapButtons(UseWidth: integer; - var NewWidth, NewHeight: Integer; + out NewWidth, NewHeight: Integer; Simulate: boolean): Boolean; public constructor Create(TheOwner: TComponent); override; diff --git a/lcl/controls.pp b/lcl/controls.pp index d021655f09..68aa3a7049 100644 --- a/lcl/controls.pp +++ b/lcl/controls.pp @@ -1615,6 +1615,7 @@ type wcfInitializing, // Set while initializing during handle creation wcfCreatingChildHandles, // Set while constructing the handles of the childs wcfRealizingBounds, + wcfBoundsRealized, // bounds were sent to the interface wcfUpdateShowing, wcfHandleVisible ); @@ -2397,6 +2398,8 @@ function DbgS(a: TAnchorKind): string; overload; function DbgS(Anchors: TAnchors): string; overload; function DbgS(a: TAlign): string; overload; function DbgS(a: TAnchorKind; Side: TAnchorSideReference): string; overload; +function DbgS(p: TControlAutoSizePhase): string; overload; +function DbgS(Phases: TControlAutoSizePhases): string; overload; operator := (AVariant: Variant): TCaption; @@ -2569,6 +2572,25 @@ begin end; end; +function DbgS(p: TControlAutoSizePhase): string; overload; +begin + Result:=AutoSizePhaseNames[p]; +end; + +function DbgS(Phases: TControlAutoSizePhases): string; overload; +var + p: TControlAutoSizePhase; +begin + Result:=''; + for p:=Low(TControlAutoSizePhase) to High(TControlAutoSizePhase) do begin + if p in Phases then begin + if Result<>'' then Result:=Result+','; + Result:=Result+AutoSizePhaseNames[p]; + end; + end; + Result:='['+Result+']'; +end; + {------------------------------------------------------------------------------ RecreateWnd This function was originally member of TWincontrol. From a VCL point of view diff --git a/lcl/include/control.inc b/lcl/include/control.inc index ee2d34ca20..70f9e790ae 100644 --- a/lcl/include/control.inc +++ b/lcl/include/control.inc @@ -2421,6 +2421,8 @@ procedure TControl.DoAllAutoSize; //DebugLn(['TControl.DoAllAutoSize.AutoSizeControl ',DbgSName(AControl),' AutoSize=',AControl.AutoSize]); Exclude(AControl.FControlFlags,cfAutoSizeNeeded); + if not IsControlVisible then exit; + if AControl.AutoSize then AControl.DoAutoSize; if AControl is TWinControl then begin diff --git a/lcl/include/toolbar.inc b/lcl/include/toolbar.inc index 8ea4161d8a..fc3df7218d 100644 --- a/lcl/include/toolbar.inc +++ b/lcl/include/toolbar.inc @@ -103,17 +103,20 @@ begin // no flipping end; -procedure TToolBar.CreateParams(var Params: TCreateParams); -begin - inherited CreateParams(Params); -end; - procedure TToolBar.CreateWnd; begin BeginUpdate; - inherited CreateWnd; - UpdateVisibleBar; - EndUpdate; + try + DisableAutoSizing; + try + inherited CreateWnd; + UpdateVisibleBar; + finally + EnableAutoSizing; + end; + finally + EndUpdate; + end; end; procedure TToolBar.ControlsAligned; @@ -450,16 +453,17 @@ begin end; procedure TToolBar.DoAutoSize; +{$IFDEF OldAutoSize} var - ModifyWidth, ModifyHeight : Boolean; NewWidth: Integer; NewHeight: Integer; + ModifyWidth, ModifyHeight : Boolean; +{$ENDIF} begin {$IFDEF OldAutoSize} if AutoSizing then Exit; // we shouldn't come here in the first place BeginAutoSizing; try - {$ENDIF} NewWidth:=Width; NewHeight:=Height; GetPreferredSize(NewWidth,NewHeight); @@ -472,10 +476,11 @@ begin //DebugLn(['TToolBar.DoAutoSize ',DbgSName(Self),' ',Width,',',Height,' ',NewWidth,',',NewHeight]); if (NewWidth <> Width) or (NewHeight <> Height) then SetBounds(Left, Top, NewWidth, NewHeight); - {$IFDEF OldAutoSize} finally EndAutoSizing; end; + {$ELSE} + // childs are moved in ControlsAligned independent of AutoSize=true {$ENDIF} end; @@ -535,6 +540,7 @@ begin PreferredHeight := NewHeight; end; {$ENDIF} + //DebugLn(['TToolBar.CalculatePreferredSize ',DbgSName(Self),' ',PreferredWidth,'x',PreferredHeight,' Count=',ControlCount]); end; {------------------------------------------------------------------------------ @@ -548,7 +554,7 @@ end; Wrap=true. ------------------------------------------------------------------------------} function TToolBar.WrapButtons(UseWidth: integer; - var NewWidth, NewHeight: Integer; Simulate: boolean): Boolean; + out NewWidth, NewHeight: Integer; Simulate: boolean): Boolean; var ARect: TRect; x: Integer; diff --git a/lcl/include/wincontrol.inc b/lcl/include/wincontrol.inc index 720557dcdc..e376a447a2 100644 --- a/lcl/include/wincontrol.inc +++ b/lcl/include/wincontrol.inc @@ -33,7 +33,7 @@ {off $DEFINE CHECK_POSITION} {$IFDEF CHECK_POSITION} const CheckPostionClassName = 'xxTPage'; -const CheckPostionName = 'PropertyStoredIdentPostfixLabel'; +const CheckPostionName = 'tbViewDebug'; const CheckPostionParentName = 'xxxEnvVarsPage'; function CheckPosition(AControl: TControl): boolean; @@ -3440,22 +3440,29 @@ end; {$IFNDEF OldAutoSize} procedure TWinControl.DoAllAutoSize; + procedure ClearRequests(AControl: TControl); + var + i: Integer; + begin + Exclude(AControl.FControlFlags,cfAutoSizeNeeded); + if AControl is TWinControl then + for i:=0 to TWinControl(AControl).ControlCount-1 do + ClearRequests(TWinControl(AControl).Controls[i]); + end; + procedure UpdateShowingRecursive(AWinControl: TWinControl); var i: Integer; begin - Include(FWinControlFlags,wcfUpdateShowing); - try - if AWinControl.HandleObjectShouldBeVisible - and (not AWinControl.Showing) then - AWinControl.UpdateShowing; - if AWinControl.FControls<>nil then - for i:=0 to AWinControl.FControls.Count-1 do - if TObject(AWinControl.FControls[i]) is TWinControl then - UpdateShowingRecursive(TWinControl(AWinControl.FControls[i])); - finally - Exclude(FWinControlFlags,wcfUpdateShowing); - end; + // first make the childs visible + if AWinControl.FControls<>nil then + for i:=0 to AWinControl.FControls.Count-1 do + if TObject(AWinControl.FControls[i]) is TWinControl then + UpdateShowingRecursive(TWinControl(AWinControl.FControls[i])); + // then make the control visible + if AWinControl.HandleObjectShouldBeVisible + and (not AWinControl.Showing) then + AWinControl.UpdateShowing; end; begin @@ -3466,15 +3473,21 @@ begin DebugLn(['TWinControl.DoAllAutoSize START ',DbgSName(Self),' ',dbgs(BoundsRect)]); {$ENDIF} // create needed handles - if HandleObjectShouldBeVisible and (not HandleAllocated) then begin - {$IFDEF VerboseAllAutoSize} - DebugLn(['TWinControl.DoAllAutoSize CREATE HANDLE ',DbgSName(Self)]); - {$ENDIF} - HandleNeeded; - // creating the handle called DisableAutoSizing/EnableAutoSizing - // so after handle creation the autosizing was done - // => exit - exit; + if not HandleAllocated then begin + if HandleObjectShouldBeVisible then begin + {$IFDEF VerboseAllAutoSize} + DebugLn(['TWinControl.DoAllAutoSize CREATE HANDLE ',DbgSName(Self)]); + {$ENDIF} + HandleNeeded; + // creating the handle called DisableAutoSizing/EnableAutoSizing + // so after handle creation the autosizing was done + // => exit + exit; + end else begin + // no autosize possible => remove needed flags + ClearRequests(Self); + exit; + end; end; Include(FWinControlFlags,wcfAllAutoSizing); @@ -3496,7 +3509,12 @@ begin {$IFDEF VerboseAllAutoSize} DebugLn(['TWinControl.DoAllAutoSize UPDATESHOWING ',DbgSName(Self),' lclbounds=',dbgs(BoundsRect)]); {$ENDIF} - UpdateShowingRecursive(Self); + Include(FWinControlFlags,wcfUpdateShowing); + try + UpdateShowingRecursive(Self); + finally + Exclude(FWinControlFlags,wcfUpdateShowing); + end; // check if another turn is needed if not (cfAutoSizeNeeded in FControlFlags) then break; // complete end; @@ -5981,11 +5999,18 @@ end; {------------------------------------------------------------------------------ TWinControl UpdateControlState + + Called by: RecreateWnd, TCustomNotebook.ShowCurrentPage, + TWinControl.SetParentWindow, TWinControl.InsertControl, + TWinControl.CMVisibleChanged ------------------------------------------------------------------------------} procedure TWinControl.UpdateControlState; +{$IFDEF OldAutoSize} var AWinControl: TWinControl; +{$ENDIF} begin + {$IFDEF OldAutoSize} AWinControl:= Self; { If any of the parent is not visible, exit } while AWinControl.Parent <> nil do @@ -5997,16 +6022,14 @@ begin if ((AWinControl is TCustomForm) and (AWinControl.Parent=nil)) or (AWinControl.FParentWindow <> 0) then begin - {$IFDEF OldAutoSize} UpdateShowing; - {$ELSE} - //DebugLn(['TWinControl.UpdateControlState ',DbgSName(Self),' wcfAllAutoSizing=',wcfAllAutoSizing in FWinControlFlags,' AutoSizeDelayed=',AutoSizeDelayed,' HandleObjectShouldBeVisible=',HandleObjectShouldBeVisible]); - if HandleObjectShouldBeVisible then - AdjustSize // this will trigger DoAllAutoSize, which calls UpdateShowing - else - UpdateShowing; - {$ENDIF} end; + {$ELSE} + if HandleObjectShouldBeVisible then + AdjustSize // this will trigger DoAllAutoSize, which calls UpdateShowing + else + UpdateShowing; + {$ENDIF} end; {------------------------------------------------------------------------------ @@ -6704,11 +6727,12 @@ begin NewBoundsRealized := Bounds(NewLeft, NewTop, Message.Width, Message.Height); if CompareRect(@NewBoundsRealized, @FBoundsRealized) and (not (wcfClientRectNeedsUpdate in FWinControlFlags)) then exit; - FBoundsRealized := NewBoundsRealized; - InvalidatePreferredSize; {$IFNDEF OldAutoSize} - if AutoSizingAll then begin + //DebugLn(['TWinControl.WMSize ',DbgSName(Self),' phases=',dbgs(AutoSizePhases)]); + if ([caspCreatingHandles,caspComputingBounds]*AutoSizePhases<>[]) + or (not (wcfBoundsRealized in FWinControlFlags)) + then begin // while the LCL is creating handles the widgetset may send default bounds // we have not yet told the widgetset the final bounds // => the InvalidatePreferredSize and the InvalidateClientRectCache @@ -6716,9 +6740,13 @@ begin // size algorithm to take care of the new bounds // => do not call SetBounds, as this will set the Bounds to the widgetset // default values. + //DebugLn(['TWinControl.WMSize from intf ignored, because phases=',dbgs(AutoSizePhases),' boundsrealized=',wcfBoundsRealized in FWinControlFlags]); exit; end; {$ENDIF} + + FBoundsRealized := NewBoundsRealized; + InvalidatePreferredSize; end; {$IFDEF OldAutoSize} @@ -7063,6 +7091,9 @@ begin //RaiseGDBException(''); end; + FBoundsRealized:=Rect(0,0,0,0); + Exclude(FWinControlFlags,wcfBoundsRealized); + {$IFDEF OldAutoSize} // obsolete DisableAlign; @@ -7094,11 +7125,11 @@ begin end; end; - //DebugLn(['TWinControl.CreateWnd ',DbgSName(WidgetSetClass),' ',DbgSName(Self)]); + //DebugLn(['TWinControl.CreateWnd Creating handle ... ',DbgSName(WidgetSetClass),' ',DbgSName(Self)]); FHandle := TWSWinControlClass(WidgetSetClass).CreateHandle(Self, Params); if not HandleAllocated then RaiseGDBException('Handle creation failed creating '+DbgSName(Self)); - //debugln('TWinControl.CreateWnd ',DbgSName(Self)); + //debugln('TWinControl.CreateWnd update constraints ... ',DbgSName(Self)); Constraints.UpdateInterfaceConstraints; InvalidateClientRectCache(False); TWSWinControlClass(WidgetSetClass).ConstraintsChange(Self); @@ -7112,6 +7143,7 @@ begin //WriteClientRect('B'); Include(FWinControlFlags, wcfInitializing); + //DebugLn(['TWinControl.CreateWnd initializing window ...']); InitializeWnd; finally @@ -7129,6 +7161,7 @@ begin for i := 0 to FControls.Count - 1 do begin AWinControl := TWinControl(FControls.Items[i]); + //DebugLn(['TWinControl.CreateWnd create child handles self=',DbgSName(Self),' Child=',DbgSName(AWinControl)]); if (AWinControl is TWinControl) and AWinControl.IsControlVisible then AWinControl.HandleNeeded; end; @@ -7156,7 +7189,7 @@ begin AdjustSize; {$ENDIF} finally - //DebugLn(['TWinControl.CreateWnd ',DbgSName(Self)]); + //DebugLn(['TWinControl.CreateWnd created ',DbgSName(Self),' enable autosizing ...']); EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TWinControl.CreateWnd'){$ENDIF}; {$IFDEF OldAutoSize} // obsolete @@ -7437,6 +7470,7 @@ begin TWSWinControlClass(WidgetSetClass).DestroyHandle(Self); Handle := 0; + Exclude(FWinControlFlags,wcfBoundsRealized); // Maybe handle is not needed at moment but later it will be created once // again. To propely initialize control after we need to restore color // and font. Request update. @@ -7965,10 +7999,29 @@ begin ' -> NewBounds=',dbgs(NewBounds)); {$ENDIF} FBoundsRealized:=NewBounds; + Include(FWinControlFlags,wcfBoundsRealized); // Note: set before calling widgetset, because used in WMSize + // this can trigger WMSize messages TWSWinControlClass(WidgetSetClass).SetBounds(Self, Left, Top, Width, Height); end; procedure TWinControl.RealizeBounds; + + procedure Check; + var + c: TWinControl; + begin + c:=Self; + while c<>nil do begin + DebugLn(['Check ',DbgSName(c),' ',c.HandleAllocated, + ' wcfCreatingHandle=',wcfCreatingHandle in FWinControlFlags, + ' wcfInitializing=',wcfInitializing in FWinControlFlags, + ' wcfCreatingChildHandles=',wcfCreatingChildHandles in FWinControlFlags, + '']); + c:=c.Parent; + end; + RaiseGDBException(''); + end; + var NewBounds: TRect; begin @@ -7977,8 +8030,10 @@ begin and ([csLoading,csDestroying]*ComponentState=[]) and (not (csDestroyingHandle in ControlState)) and (not CompareRect(@NewBounds,@FBoundsRealized)) - and (not IsAParentAligning) then - begin + {$IFDEF OldAutoSize} + and (not IsAParentAligning) + {$ENDIF} + then begin // the new bounds were not yet sent to the InterfaceObject -> send them {$IFDEF CHECK_POSITION} //if csDesigning in ComponentState then @@ -7993,6 +8048,19 @@ begin finally EndUpdateBounds; end; + end else begin + {$IFDEF CHECK_POSITION} + //if CheckPosition(Self) then + DbgOut('[TWinControl.RealizeBounds] NOT REALIZING ',DbgSName(Self), + ' OldRelBounds=',dbgs(FBoundsRealized), + ' -> NewBounds=',dbgs(NewBounds), + ', because '); + if not HandleAllocated then debugln('not HandleAllocated'); + if (csLoading in ComponentState) then debugln('csLoading'); + if (csDestroying in ComponentState) then debugln('csDestroying'); + if (CompareRect(@NewBounds,@FBoundsRealized)) then debugln('bounds not changed'); + {$ENDIF} + if not HandleAllocated then Check; end; end; @@ -8000,14 +8068,18 @@ procedure TWinControl.RealizeBoundsRecursive; var i: Integer; OldRealizing: boolean; + AWinControl: TWinControl; begin + if not HandleAllocated then exit; OldRealizing:=wcfRealizingBounds in FWinControlFlags; Include(FWinControlFlags,wcfRealizingBounds); try if FControls<>nil then begin - for i:=0 to FControls.Count-1 do - if TObject(FControls[i]) is TWinControl then + for i:=0 to FControls.Count-1 do begin + AWinControl:=TWinControl(FControls[i]); + if (AWinControl is TWinControl) then TWinControl(FControls[i]).RealizeBoundsRecursive; + end; end; RealizeBounds; finally diff --git a/lcl/interfaces/gtk/gtkproc.inc b/lcl/interfaces/gtk/gtkproc.inc index a7fe8b1c21..925c2dc9f6 100644 --- a/lcl/interfaces/gtk/gtkproc.inc +++ b/lcl/interfaces/gtk/gtkproc.inc @@ -7100,6 +7100,7 @@ begin allocation := PGtkWidget(Window)^.allocation; allocation.width := Width; allocation.height := Height; + //DebugLn(['SetWindowSizeAndPosition ',DbgSName(AWinControl),' ',dbgs(allocation)]); gtk_widget_size_allocate(PGtkWidget(Window), @allocation);// Beware: this triggers callbacks if (PGtkWidget(Window)^.Window <> nil) then