mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-12 18:39:52 +02:00
LCL: fixed TScrollingWinControl.AutoScroll endless loop when one scrollbars needs to be shown because of the other
git-svn-id: trunk@45082 -
This commit is contained in:
parent
1631dd22e2
commit
59516fe2c8
@ -80,12 +80,12 @@ type
|
|||||||
|
|
||||||
TControlScrollBar = class(TPersistent)
|
TControlScrollBar = class(TPersistent)
|
||||||
private
|
private
|
||||||
FAutoRange: Longint; // = FRange - ClientSize, >=0
|
FAutoRange: Longint; // = Max(0, FRange - ClientSize)
|
||||||
FIncrement: TScrollBarInc;
|
FIncrement: TScrollBarInc;
|
||||||
FKind: TScrollBarKind;
|
FKind: TScrollBarKind;
|
||||||
FPage: TScrollBarInc;
|
FPage: TScrollBarInc;
|
||||||
FPosition: Integer;
|
FPosition: Integer;
|
||||||
FRange: Integer;
|
FRange: Integer; // if AutoScroll=true this is the needed size of the child controls
|
||||||
FSmooth: Boolean;
|
FSmooth: Boolean;
|
||||||
FTracking: Boolean;
|
FTracking: Boolean;
|
||||||
FVisible: Boolean;
|
FVisible: Boolean;
|
||||||
@ -103,7 +103,6 @@ type
|
|||||||
function GetSmooth: Boolean; virtual;
|
function GetSmooth: Boolean; virtual;
|
||||||
function HandleAllocated: boolean; virtual;
|
function HandleAllocated: boolean; virtual;
|
||||||
function IsRangeStored: boolean; virtual;
|
function IsRangeStored: boolean; virtual;
|
||||||
procedure AutoCalcRange; virtual;
|
|
||||||
procedure ControlUpdateScrollBars; virtual;
|
procedure ControlUpdateScrollBars; virtual;
|
||||||
procedure InternalSetRange(const AValue: Integer); virtual;
|
procedure InternalSetRange(const AValue: Integer); virtual;
|
||||||
procedure ScrollHandler(var Message: TLMScroll);
|
procedure ScrollHandler(var Message: TLMScroll);
|
||||||
@ -158,6 +157,7 @@ type
|
|||||||
class procedure WSRegisterClass; override;
|
class procedure WSRegisterClass; override;
|
||||||
procedure AlignControls(AControl: TControl; var ARect: TRect); override;
|
procedure AlignControls(AControl: TControl; var ARect: TRect); override;
|
||||||
function AutoScrollEnabled: Boolean; virtual;
|
function AutoScrollEnabled: Boolean; virtual;
|
||||||
|
procedure CalculateAutoRanges; virtual;
|
||||||
procedure CreateWnd; override;
|
procedure CreateWnd; override;
|
||||||
function GetClientScrollOffset: TPoint; override;
|
function GetClientScrollOffset: TPoint; override;
|
||||||
function GetLogicalClientRect: TRect; override;// logical size of client area
|
function GetLogicalClientRect: TRect; override;// logical size of client area
|
||||||
@ -165,7 +165,7 @@ type
|
|||||||
procedure WMSize(var Message: TLMSize); message LM_Size;
|
procedure WMSize(var Message: TLMSize); message LM_Size;
|
||||||
procedure WMHScroll(var Message : TLMHScroll); message LM_HScroll;
|
procedure WMHScroll(var Message : TLMHScroll); message LM_HScroll;
|
||||||
procedure WMVScroll(var Message : TLMVScroll); message LM_VScroll;
|
procedure WMVScroll(var Message : TLMVScroll); message LM_VScroll;
|
||||||
function ComputeScrollbars: Boolean; virtual;
|
procedure ComputeScrollbars; virtual;
|
||||||
procedure ScrollbarHandler(ScrollKind: TScrollBarKind;
|
procedure ScrollbarHandler(ScrollKind: TScrollBarKind;
|
||||||
OldPosition: Integer); virtual;
|
OldPosition: Integer); virtual;
|
||||||
procedure SetAutoScroll(Value: Boolean); virtual;
|
procedure SetAutoScroll(Value: Boolean); virtual;
|
||||||
|
@ -41,9 +41,6 @@ begin
|
|||||||
|
|
||||||
if GetAutoScroll then
|
if GetAutoScroll then
|
||||||
begin
|
begin
|
||||||
if FAutoRange < 0 then
|
|
||||||
AutoCalcRange;
|
|
||||||
|
|
||||||
if Value > FAutoRange then
|
if Value > FAutoRange then
|
||||||
begin
|
begin
|
||||||
{$IFDEF VerboseScrollingWinControl}
|
{$IFDEF VerboseScrollingWinControl}
|
||||||
@ -210,64 +207,6 @@ begin
|
|||||||
FSmooth := AValue;
|
FSmooth := AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TControlScrollBar.AutoCalcRange;
|
|
||||||
|
|
||||||
function IsNonAligned(Control: TControl): boolean;
|
|
||||||
begin
|
|
||||||
Result:=(Control.Align in [alNone,alCustom])
|
|
||||||
and (Control.Anchors=[akLeft,akTop])
|
|
||||||
and (Control.AnchorSide[akLeft].Control=nil)
|
|
||||||
and (Control.AnchorSide[akTop].Control=nil);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure GetPreferredClientRect(out PreferredWidth, PreferredHeight: integer);
|
|
||||||
var
|
|
||||||
CurClientRect: TRect;
|
|
||||||
begin
|
|
||||||
PreferredWidth:=0;
|
|
||||||
PreferredHeight:=0;
|
|
||||||
FControl.GetPreferredSize(PreferredWidth,PreferredHeight,true,false);
|
|
||||||
//DebugLn(['GetPreferredClientRect ',DbgSName(FControl),' PrefSize=',PreferredWidth,'x',PreferredHeight]);
|
|
||||||
CurClientRect := FControl.ClientRect;
|
|
||||||
if PreferredWidth>0 then
|
|
||||||
PreferredWidth:=Max(0,PreferredWidth-(FControl.Width-CurClientRect.Right));
|
|
||||||
if PreferredHeight>0 then
|
|
||||||
PreferredHeight:=Max(0,PreferredHeight-(FControl.Height-CurClientRect.Bottom));
|
|
||||||
//DebugLn(['GetPreferredClientRect ',DbgSName(FControl),' PrefClient=',PreferredWidth,'x',PreferredHeight,' Client=',dbgs(CurClientRect),' Size=',dbgs(FControl.BoundsRect)]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure AutoCalcVRange;
|
|
||||||
var
|
|
||||||
PreferredWidth: Integer;
|
|
||||||
PreferredHeight: Integer;
|
|
||||||
begin
|
|
||||||
GetPreferredClientRect(PreferredWidth,PreferredHeight);
|
|
||||||
//DebugLn(['AutoCalcVRange ',DbgSName(FControl),' AutoSize=',FControl.AutoSize,' Bounds=',dbgs(FControl.BoundsRect),' Client=',dbgs(FControl.ClientRect),' ' pref=',PreferredWidth,'x',PreferredHeight]);
|
|
||||||
InternalSetRange(PreferredHeight);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure AutoCalcHRange;
|
|
||||||
var
|
|
||||||
PreferredWidth: Integer;
|
|
||||||
PreferredHeight: Integer;
|
|
||||||
begin
|
|
||||||
GetPreferredClientRect(PreferredWidth,PreferredHeight);
|
|
||||||
//if FControl.ClassName='TEditorCodetoolsOptionsFrame' then
|
|
||||||
//DebugLn(['AutoCalcHRange ',DbgSName(FControl),' AutoSize=',FControl.AutoSize,' Bounds=',dbgs(FControl.BoundsRect),' Client=',dbgs(FControl.ClientRect),' pref=',PreferredWidth,'x',PreferredHeight]);
|
|
||||||
InternalSetRange(PreferredWidth);
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
|
||||||
if GetAutoScroll then
|
|
||||||
begin
|
|
||||||
FVisible := True;
|
|
||||||
if Kind = sbVertical then
|
|
||||||
AutoCalcVRange
|
|
||||||
else
|
|
||||||
AutoCalcHRange;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TControlScrollBar.UpdateScrollBar;
|
procedure TControlScrollBar.UpdateScrollBar;
|
||||||
var
|
var
|
||||||
ScrollInfo: TScrollInfo;
|
ScrollInfo: TScrollInfo;
|
||||||
@ -296,8 +235,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
ShowScrollBar(FControl.Handle, IntfBarKind[Kind], NewVisible);
|
ShowScrollBar(FControl.Handle, IntfBarKind[Kind], NewVisible);
|
||||||
{$IFDEF VerboseScrollingWinControl}
|
{$IFDEF VerboseScrollingWinControl}
|
||||||
if DebugCondition then
|
//if DebugCondition then
|
||||||
DebugLn(['TControlScrollBar.UpdateScrollBar ',DbgSName(FControl),' ',DbgSName(Self),' FVisible=',FVisible,' Range=',FRange,' FPosition=',FPosition,' FPage=',FPage,' FAutoRange=',FAutoRange,' ShouldVisible=',NewVisible]);
|
DebugLn(['TControlScrollBar.UpdateScrollBar ',DbgSName(FControl),' ',DbgSName(Self),' ',dbgs(Kind),' FVisible=',FVisible,' Range=',FRange,' FPosition=',FPosition,' FPage=',FPage,' FAutoRange=',FAutoRange,' ShouldVisible=',NewVisible]);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -498,14 +437,14 @@ function TControlScrollBar.ClientSizeWithBar: integer;
|
|||||||
begin
|
begin
|
||||||
Result := ClientSize;
|
Result := ClientSize;
|
||||||
if not IsScrollBarVisible then
|
if not IsScrollBarVisible then
|
||||||
dec(Result, GetSize);
|
dec(Result, GetSize+3);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TControlScrollBar.ClientSizeWithoutBar: integer;
|
function TControlScrollBar.ClientSizeWithoutBar: integer;
|
||||||
begin
|
begin
|
||||||
Result:=ClientSize;
|
Result:=ClientSize;
|
||||||
if IsScrollBarVisible then
|
if IsScrollBarVisible then
|
||||||
inc(Result, GetSize);
|
inc(Result, GetSize+3);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TControlScrollBar.GetHorzScrollBar: TControlScrollBar;
|
function TControlScrollBar.GetHorzScrollBar: TControlScrollBar;
|
||||||
|
@ -13,11 +13,6 @@ procedure TScrollingWinControl.SetAutoScroll(Value: Boolean);
|
|||||||
begin
|
begin
|
||||||
if FAutoScroll = Value then Exit;
|
if FAutoScroll = Value then Exit;
|
||||||
FAutoScroll := Value;
|
FAutoScroll := Value;
|
||||||
if Value then
|
|
||||||
begin
|
|
||||||
HorzScrollBar.AutoCalcRange;
|
|
||||||
VertScrollBar.AutoCalcRange;
|
|
||||||
end;
|
|
||||||
UpdateScrollBars;
|
UpdateScrollBars;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -26,11 +21,6 @@ begin
|
|||||||
DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TScrollingWinControl.CreateWnd'){$ENDIF};
|
DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TScrollingWinControl.CreateWnd'){$ENDIF};
|
||||||
try
|
try
|
||||||
inherited CreateWnd;
|
inherited CreateWnd;
|
||||||
if AutoScroll then
|
|
||||||
begin
|
|
||||||
HorzScrollBar.AutoCalcRange;
|
|
||||||
VertScrollBar.AutoCalcRange;
|
|
||||||
end;
|
|
||||||
UpdateScrollBars;
|
UpdateScrollBars;
|
||||||
finally
|
finally
|
||||||
EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TScrollingWinControl.CreateWnd'){$ENDIF};
|
EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TScrollingWinControl.CreateWnd'){$ENDIF};
|
||||||
@ -71,8 +61,6 @@ begin
|
|||||||
if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
|
if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
|
||||||
inherited AlignControls(AControl, ARect);
|
inherited AlignControls(AControl, ARect);
|
||||||
|
|
||||||
HorzScrollBar.AutoCalcRange;
|
|
||||||
VertScrollBar.AutoCalcRange;
|
|
||||||
UpdateScrollBars;
|
UpdateScrollBars;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -84,6 +72,34 @@ begin
|
|||||||
Result := not (AutoSize or (DockSite and UseDockManager));
|
Result := not (AutoSize or (DockSite and UseDockManager));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TScrollingWinControl.CalculateAutoRanges;
|
||||||
|
|
||||||
|
procedure GetPreferredClientRect(out PreferredWidth, PreferredHeight: integer);
|
||||||
|
var
|
||||||
|
CurClientRect: TRect;
|
||||||
|
begin
|
||||||
|
PreferredWidth:=0;
|
||||||
|
PreferredHeight:=0;
|
||||||
|
GetPreferredSize(PreferredWidth,PreferredHeight,true,false);
|
||||||
|
//DebugLn(['GetPreferredClientRect ',DbgSName(FControl),' PrefSize=',PreferredWidth,'x',PreferredHeight]);
|
||||||
|
CurClientRect := ClientRect;
|
||||||
|
if PreferredWidth>0 then
|
||||||
|
PreferredWidth:=Max(0,PreferredWidth-(Width-CurClientRect.Right));
|
||||||
|
if PreferredHeight>0 then
|
||||||
|
PreferredHeight:=Max(0,PreferredHeight-(Height-CurClientRect.Bottom));
|
||||||
|
//DebugLn(['GetPreferredClientRect ',DbgSName(FControl),' PrefClient=',PreferredWidth,'x',PreferredHeight,' Client=',dbgs(CurClientRect),' Size=',dbgs(FControl.BoundsRect)]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
PreferredWidth: Integer;
|
||||||
|
PreferredHeight: Integer;
|
||||||
|
begin
|
||||||
|
GetPreferredClientRect(PreferredWidth,PreferredHeight);
|
||||||
|
//DebugLn(['TScrollingWinControl.CalculateAutoRanges ',DbgSName(Self),' AutoSize=',AutoSize,' Bounds=',dbgs(BoundsRect),' Client=',dbgs(ClientRect),' pref=',PreferredWidth,'x',PreferredHeight]);
|
||||||
|
HorzScrollBar.InternalSetRange(PreferredWidth);
|
||||||
|
VertScrollBar.InternalSetRange(PreferredHeight);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TScrollingWinControl.DoOnResize;
|
procedure TScrollingWinControl.DoOnResize;
|
||||||
begin
|
begin
|
||||||
inherited DoOnResize;
|
inherited DoOnResize;
|
||||||
@ -91,7 +107,8 @@ begin
|
|||||||
if AutoScroll then
|
if AutoScroll then
|
||||||
begin
|
begin
|
||||||
if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
|
if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
|
||||||
if HorzScrollBar.Visible or VertScrollBar.Visible then UpdateScrollBars;
|
if HorzScrollBar.Visible or VertScrollBar.Visible then
|
||||||
|
UpdateScrollBars;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -136,54 +153,47 @@ begin
|
|||||||
//
|
//
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScrollingWinControl.ComputeScrollbars: Boolean;
|
procedure TScrollingWinControl.ComputeScrollbars;
|
||||||
// true if something changed
|
// true if something has changed
|
||||||
// update Page, AutoRange, IsScrollBarVisible
|
// update Page, AutoRange
|
||||||
|
|
||||||
function UpdateRange(p_Bar: TControlScrollBar): Boolean;
|
procedure UpdateBar(aBar: TControlScrollBar; aClientSize: integer);
|
||||||
var
|
|
||||||
SBSize: Longint;
|
|
||||||
OtherScrollbar: TControlScrollBar;
|
|
||||||
OldAutoRange: LongInt;
|
|
||||||
begin
|
begin
|
||||||
Result := False;
|
// page (must be smaller than Range but at least 1)
|
||||||
OldAutoRange := p_Bar.FAutoRange;
|
aBar.FPage := Max(1,Min(Min(aBar.Range,aClientSize), High(HorzScrollbar.FPage)));
|
||||||
p_Bar.FAutoRange := 0;
|
aBar.FAutoRange := Max(0, aBar.Range - aClientSize);
|
||||||
OtherScrollbar := p_Bar.GetOtherScrollBar;
|
|
||||||
SBSize := OtherScrollbar.ClientSize;
|
|
||||||
if (p_Bar.FRange > SBSize) and (SBSize > 0) then
|
|
||||||
p_Bar.FAutoRange := (p_Bar.FRange - SBSize)
|
|
||||||
else
|
|
||||||
p_Bar.FAutoRange := 0;
|
|
||||||
{$IFDEF VerboseScrollingWinControl}
|
{$IFDEF VerboseScrollingWinControl}
|
||||||
if p_Bar.DebugCondition then
|
debugln(['TScrollingWinControl.ComputeScrollbars ',DbgSName(Self),' ',dbgs(aBar.Kind),' Page=',aBar.Page,' Range=',aBar.Range,' ClientSize=',aClientSize]);
|
||||||
DebugLn(['UpdateRange p_Bar.fRange=',p_Bar.FRange,' SBSize=',SBSize,' ClientWidth=',ClientWidth,' FAutoRange=',p_Bar.FAutoRange]);
|
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if OldAutoRange <> p_Bar.FAutoRange then
|
|
||||||
Result := True;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
NewPage: Integer;
|
ClientW: Integer;
|
||||||
|
ClientH: Integer;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
CalculateAutoRanges;
|
||||||
|
|
||||||
// page (must be smaller than Range but at least 1)
|
ClientW:=VertScrollBar.ClientSizeWithoutBar;
|
||||||
NewPage := Max(1,Min(VertScrollbar.ClientSize, High(HorzScrollbar.FPage)));
|
ClientH:=HorzScrollBar.ClientSizeWithoutBar;
|
||||||
if NewPage <> HorzScrollbar.FPage then
|
if VertScrollBar.Range > ClientH then
|
||||||
begin
|
begin
|
||||||
HorzScrollbar.FPage := NewPage;
|
// vertical does not fit -> vertical scrollbar will be shown
|
||||||
Result := True;
|
ClientW:=VertScrollBar.ClientSizeWithBar;
|
||||||
end;
|
end;
|
||||||
NewPage := Max(1,Min(HorzScrollbar.ClientSize, High(VertScrollbar.FPage)));
|
if HorzScrollBar.Range > ClientW then
|
||||||
if NewPage <> VertScrollbar.FPage then
|
|
||||||
begin
|
begin
|
||||||
VertScrollbar.FPage := NewPage;
|
// horizontal does not fit -> horizontal scrollbar will be shown
|
||||||
Result := True;
|
ClientH:=HorzScrollBar.ClientSizeWithBar;
|
||||||
|
if VertScrollBar.Range > ClientH then
|
||||||
|
begin
|
||||||
|
// vertical does not fit, because of the other scrollbar
|
||||||
|
// -> vertical scrollbar will be shown too
|
||||||
|
ClientW:=VertScrollBar.ClientSizeWithBar;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
// range
|
|
||||||
if UpdateRange(HorzScrollbar) then Result:=true;
|
UpdateBar(HorzScrollBar,ClientW);
|
||||||
if UpdateRange(VertScrollbar) then Result:=true;
|
UpdateBar(VertScrollBar,ClientH);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TScrollingWinControl.UpdateScrollbars;
|
procedure TScrollingWinControl.UpdateScrollbars;
|
||||||
|
Loading…
Reference in New Issue
Block a user