1{%MainUnit ../forms.pp}
2
3{
4 *****************************************************************************
5  This file is part of the Lazarus Component Library (LCL)
6
7  See the file COPYING.modifiedLGPL.txt, included in this distribution,
8  for details about the license.
9 *****************************************************************************
10}
11
12procedure TScrollingWinControl.SetAutoScroll(Value: Boolean);
13begin
14  if FAutoScroll = Value then Exit;
15  FAutoScroll := Value;
16  UpdateScrollBars;
17end;
18
19procedure TScrollingWinControl.CreateWnd;
20begin
21  DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TScrollingWinControl.CreateWnd'){$ENDIF};
22  try
23    inherited CreateWnd;
24    UpdateScrollBars;
25  finally
26    EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TScrollingWinControl.CreateWnd'){$ENDIF};
27  end;
28end;
29
30function TScrollingWinControl.GetClientScrollOffset: TPoint;
31begin
32  if (HorzScrollBar <> nil) and (VertScrollBar <> nil) then
33  begin
34    Result.X := HorzScrollBar.Position;
35    Result.Y := VertScrollBar.Position;
36  end else
37  begin
38    Result.X := 0;
39    Result.Y := 0;
40  end;
41end;
42
43function TScrollingWinControl.GetLogicalClientRect: TRect;
44begin
45  Result := ClientRect;
46  {if (FHorzScrollBar.Range>Result.Right)
47  or (FVertScrollBar.Range>Result.Bottom) then
48    DebugLn(['TScrollingWinControl.GetLogicalClientRect Client=',ClientWidth,'x',ClientHeight,' Ranges=',FHorzScrollBar.Range,'x',FVertScrollBar.Range]);}
49  if Assigned(FHorzScrollBar) and FHorzScrollBar.Visible
50  and (FHorzScrollBar.Range > Result.Right) then
51    Result.Right := FHorzScrollBar.Range;
52  if Assigned(FVertScrollBar) and FVertScrollBar.Visible
53  and (FVertScrollBar.Range > Result.Bottom) then
54    Result.Bottom := FVertScrollBar.Range;
55end;
56
57procedure TScrollingWinControl.DoOnResize;
58begin
59  inherited DoOnResize;
60
61  if AutoScroll then
62  begin
63    if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
64    if HorzScrollBar.Visible or VertScrollBar.Visible then
65      UpdateScrollBars;
66  end;
67  //debugln(['TScrollingWinControl.DoOnResize ',DbgSName(Self),' ',dbgs(BoundsRect),' ',dbgs(ClientRect),' ',dbgs(GetLogicalClientRect)]);
68end;
69
70procedure TScrollingWinControl.GetPreferredSizeClientFrame(out aWidth,
71  aHeight: integer);
72// return frame width independent of scrollbars (i.e. as if scrollbars not shown)
73begin
74  if AutoScroll and (VertScrollBar<>nil) then
75    aWidth:=Width-VertScrollBar.ClientSizeWithoutBar
76  else
77    aWidth:=Width-ClientWidth;
78  if AutoScroll and (HorzScrollBar<>nil) then
79    aHeight:=Height-HorzScrollBar.ClientSizeWithoutBar
80  else
81    aHeight:=Height-ClientHeight;
82end;
83
84procedure TScrollingWinControl.AlignControls(AControl: TControl; var ARect: TRect);
85begin
86  if AutoScroll then
87  begin
88    if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
89    inherited AlignControls(AControl, ARect);
90
91    UpdateScrollBars;
92  end
93  else
94    inherited AlignControls(AControl, ARect);
95end;
96
97function TScrollingWinControl.AutoScrollEnabled: Boolean;
98begin
99  Result := not (AutoSize or (DockSite and UseDockManager));
100end;
101
102procedure TScrollingWinControl.CalculateAutoRanges;
103var
104  NeededClientW: Integer;
105  NeededClientH: Integer;
106  FrameWidth: integer;
107  FrameHeight: integer;
108begin
109  NeededClientW:=0;
110  NeededClientH:=0;
111  GetPreferredSize(NeededClientW,NeededClientH,true,false);
112  GetPreferredSizeClientFrame(FrameWidth,FrameHeight);
113  if NeededClientW>0 then
114    NeededClientW-=FrameWidth;
115  if NeededClientH>0 then
116    NeededClientH-=FrameHeight;
117
118  if HorzScrollBar.Visible then
119    HorzScrollBar.InternalSetRange(NeededClientW)
120  else
121    HorzScrollBar.InternalSetRange(0);
122
123  if VertScrollBar.Visible then
124    VertScrollBar.InternalSetRange(NeededClientH)
125  else
126    VertScrollBar.InternalSetRange(0);
127end;
128
129class function TScrollingWinControl.GetControlClassDefaultSize: TSize;
130begin
131  Result.CX := 150;
132  Result.CY := 150;
133end;
134
135procedure TScrollingWinControl.SetHorzScrollBar(Value: TControlScrollBar);
136begin
137  FHorzScrollbar.Assign(Value);
138end;
139
140procedure TScrollingWinControl.SetVertScrollBar(Value: TControlScrollBar);
141begin
142  FVertScrollbar.Assign(Value);
143end;
144
145procedure TScrollingWinControl.WMSize(var Message: TLMSize);
146var
147  NewState: TWindowState;
148begin
149  inherited;
150  if (Message.SizeType and SIZE_SourceIsInterface) <> 0 then
151  begin
152    NewState := wsNormal;
153    case (Message.SizeType xor SIZE_SourceIsInterface) of
154      SIZE_MINIMIZED:
155        NewState := wsMinimized;
156      SIZE_MAXIMIZED:
157        NewState := wsMaximized;
158      SIZE_FULLSCREEN:
159        NewState := wsFullScreen;
160    end;
161    Resizing(NewState);
162  end;
163end;
164
165procedure TScrollingWinControl.Resizing(State: TWindowState);
166begin
167  //
168end;
169
170procedure TScrollingWinControl.ComputeScrollbars;
171  procedure UpdateBar(aBar: TControlScrollBar; aClientSize: integer);
172  begin
173    // page (must be smaller than Range but at least 1)
174    aBar.FPage := Max(1,Min(Min(aBar.Range,aClientSize), High(HorzScrollbar.FPage)));
175    aBar.FAutoRange := Max(0, aBar.Range - aClientSize);
176    {$IFDEF VerboseScrollingWinControl}
177    debugln(['TScrollingWinControl.ComputeScrollbars ',DbgSName(Self),' ',dbgs(aBar.Kind),' Page=',aBar.Page,' Range=',aBar.Range,' ClientSize=',aClientSize]);
178    {$ENDIF}
179  end;
180
181var
182  ClientW: Integer;
183  ClientH: Integer;
184begin
185  CalculateAutoRanges;
186
187  ClientW:=VertScrollBar.ClientSizeWithoutBar;
188  ClientH:=HorzScrollBar.ClientSizeWithoutBar;
189  {$IFDEF VerboseScrollingWinControl}
190  debugln(['TScrollingWinControl.ComputeScrollbars ',DbgSName(Self),' Bounds=',dbgs(BoundsRect),' ClientRect=',dbgs(ClientRect),' ClientRectNoScrollBars=',ClientW,'x',ClientH]);
191  {$ENDIF}
192
193  if VertScrollBar.Range > ClientH then
194  begin
195    // vertical does not fit -> vertical scrollbar will be shown
196    ClientW:=VertScrollBar.ClientSizeWithBar;
197  end;
198  if HorzScrollBar.Range > ClientW then
199  begin
200    // horizontal does not fit -> horizontal scrollbar will be shown
201    ClientH:=HorzScrollBar.ClientSizeWithBar;
202    if VertScrollBar.Range > ClientH then
203    begin
204      // vertical does not fit, because of the other scrollbar
205      // -> vertical scrollbar will be shown too
206      ClientW:=VertScrollBar.ClientSizeWithBar;
207    end;
208  end;
209
210  UpdateBar(HorzScrollBar,ClientW);
211  UpdateBar(VertScrollBar,ClientH);
212end;
213
214procedure TScrollingWinControl.UpdateScrollbars;
215begin
216  if ([csLoading, csDestroying] * ComponentState <> []) then Exit;
217  if not HandleAllocated then Exit;
218  if (HorzScrollBar = nil) or (VertScrollBar = nil) then Exit;
219
220  if FIsUpdating then Exit;
221
222  FIsUpdating := True;
223  try
224    if AutoScroll then
225      ComputeScrollbars; // page, autorange, IsScrollBarVisible
226    FVertScrollbar.UpdateScrollbar;
227    FHorzScrollbar.UpdateScrollbar;
228  finally
229    FIsUpdating := False;
230  end;
231end;
232
233class procedure TScrollingWinControl.WSRegisterClass;
234begin
235  inherited WSRegisterClass;
236  RegisterScrollingWinControl;
237end;
238
239procedure TScrollingWinControl.ScrollBy(DeltaX, DeltaY: Integer);
240begin
241  ScrollBy_WS(DeltaX, DeltaY);
242end;
243
244procedure TScrollingWinControl.ScrollInView(AControl: TControl);
245var
246  xRect: TRect;
247begin
248  if AControl=nil then
249    Exit;
250  xRect := AControl.BoundsRect;
251  OffsetRect(xRect, -HorzScrollBar.Position, -VertScrollBar.Position);
252  if xRect.Left < 0 then
253    HorzScrollBar.Position := HorzScrollBar.Position + xRect.Left
254  else if xRect.Right > ClientWidth then
255  begin
256    if xRect.Right - xRect.Left > ClientWidth then
257      xRect.Right := xRect.Left + ClientWidth;
258    HorzScrollBar.Position := HorzScrollBar.Position + xRect.Right - ClientWidth;
259  end;
260  if xRect.Top < 0 then
261    VertScrollBar.Position := VertScrollBar.Position + xRect.Top
262  else if xRect.Bottom > ClientHeight then
263  begin
264    if xRect.Bottom - xRect.Top > ClientHeight then
265      xRect.Bottom := xRect.Top + ClientHeight;
266    VertScrollBar.Position := VertScrollBar.Position + xRect.Bottom - ClientHeight;
267  end;
268end;
269
270procedure TScrollingWinControl.Loaded;
271begin
272  inherited Loaded;
273  UpdateScrollbars;
274end;
275
276procedure TScrollingWinControl.SetAutoSize(Value: Boolean);
277begin
278  if AutoSize=Value then exit;
279  if Value then
280    ControlStyle:=ControlStyle-[csAutoSizeKeepChildLeft,csAutoSizeKeepChildTop]
281  else
282    ControlStyle:=ControlStyle+[csAutoSizeKeepChildLeft,csAutoSizeKeepChildTop];
283  inherited SetAutoSize(Value);
284end;
285
286procedure TScrollingWinControl.WMVScroll(var Message : TLMVScroll);
287begin
288  VertScrollbar.ScrollHandler(Message);
289end;
290
291procedure TScrollingWinControl.WMHScroll(var Message : TLMHScroll);
292begin
293  //DebugLn(['TScrollingWinControl.WMHScroll ',dbgsName(Self)]);
294  HorzScrollbar.ScrollHandler(Message);
295end;
296
297constructor TScrollingWinControl.Create(TheOwner : TComponent);
298begin
299  Inherited Create(TheOwner);
300
301  FAutoScroll := False;
302  FVertScrollbar := TControlScrollBar.Create(Self, sbVertical);
303  FHorzScrollbar := TControlScrollBar.Create(Self, sbHorizontal);
304
305  ControlStyle := [csAcceptsControls, csClickEvents, csDoubleClicks,
306                   csAutoSizeKeepChildLeft, csAutoSizeKeepChildTop];
307
308  with GetControlClassDefaultSize do
309    SetInitialBounds(0, 0, CX, CY);
310end;
311
312destructor TScrollingWinControl.Destroy;
313begin
314  FreeThenNil(FHorzScrollBar);
315  FreeThenNil(FVertScrollBar);
316  inherited Destroy;
317end;
318
319function TScrollingWinControl.ScreenToClient(const APoint: TPoint): TPoint;
320var
321  P: TPoint;
322begin
323  P := GetClientScrollOffset;
324  Result := inherited;
325  Result.x := Result.x - P.x;
326  Result.y := Result.y - P.y;
327end;
328
329function TScrollingWinControl.ClientToScreen(const APoint: TPoint): TPoint;
330var
331  P: TPoint;
332begin
333  P := GetClientScrollOffset;
334  Result := inherited;
335  Result.x := Result.x + P.x;
336  Result.y := Result.y + P.y;
337end;
338
339// included by forms.pp
340