mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 01:38:03 +02:00
279 lines
6.5 KiB
ObjectPascal
279 lines
6.5 KiB
ObjectPascal
{
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2000 by B'rczi, Gÿbor
|
|
member of the Free Pascal development team
|
|
|
|
Support objects for the install program
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
unit Scroll;
|
|
|
|
interface
|
|
|
|
uses Objects,
|
|
FVConsts,
|
|
Drivers,Views,App;
|
|
|
|
const
|
|
CScrollBoxBackground = #6;
|
|
|
|
type
|
|
PScrollBoxBackground = ^TScrollBoxBackground;
|
|
TScrollBoxBackground = object(TBackground)
|
|
function GetPalette: PPalette; virtual;
|
|
end;
|
|
|
|
PScrollBox = ^TScrollBox;
|
|
TScrollBox = object(TGroup)
|
|
Delta,Limit: TPoint;
|
|
HScrollBar,VScrollBar: PScrollBar;
|
|
Background: PScrollBoxBackground;
|
|
constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
|
|
procedure InitBackground; virtual;
|
|
procedure HandleEvent(var Event: TEvent); virtual;
|
|
procedure ChangeBounds(var Bounds: TRect); virtual;
|
|
procedure ScrollDraw; virtual;
|
|
procedure ScrollTo(X, Y: Sw_Integer);
|
|
procedure SetLimit(X, Y: Sw_Integer);
|
|
procedure SetState(AState: Word; Enable: Boolean); virtual;
|
|
procedure TrackCursor;
|
|
procedure Draw; virtual;
|
|
function ClipChilds: boolean; virtual;
|
|
procedure BeforeInsert(P: PView); virtual;
|
|
procedure AfterInsert(P: PView); virtual;
|
|
procedure AfterDelete(P: PView); virtual;
|
|
private
|
|
DrawLock: Byte;
|
|
DrawFlag: Boolean;
|
|
ScrollFlag : boolean;
|
|
procedure CheckDraw;
|
|
procedure UpdateLimits;
|
|
procedure ShiftViews(DX,DY: sw_integer);
|
|
end;
|
|
|
|
implementation
|
|
|
|
function TScrollBoxBackground.GetPalette: PPalette;
|
|
const P: string[length(CScrollBoxBackground)] = CScrollBoxBackground;
|
|
begin
|
|
GetPalette:=@P;
|
|
end;
|
|
|
|
constructor TScrollBox.Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
|
|
begin
|
|
inherited Init(Bounds);
|
|
EventMask:=EventMask or evBroadcast;
|
|
HScrollBar:=AHScrollBar; VScrollBar:=AVScrollBar;
|
|
InitBackground;
|
|
if Assigned(Background) then Insert(Background);
|
|
ReDraw;
|
|
end;
|
|
|
|
procedure TScrollBox.InitBackground;
|
|
var R: TRect;
|
|
begin
|
|
GetExtent(R);
|
|
New(Background, Init(R,' '));
|
|
end;
|
|
|
|
procedure TScrollBox.HandleEvent(var Event: TEvent);
|
|
begin
|
|
if (Event.What=evBroadcast) and (Event.Command=cmCursorChanged) then
|
|
TrackCursor;
|
|
If (Event.What = evBroadcast) AND
|
|
(Event.Command = cmScrollBarChanged) AND { Scroll bar change }
|
|
Not ScrollFlag AND
|
|
((Event.InfoPtr = HScrollBar) OR { Our scrollbar? }
|
|
(Event.InfoPtr = VScrollBar)) Then ScrollDraw; { Redraw scroller }
|
|
inherited HandleEvent(Event);
|
|
end;
|
|
|
|
procedure TScrollBox.ChangeBounds(var Bounds: TRect);
|
|
begin
|
|
SetBounds(Bounds);
|
|
Inc(DrawLock);
|
|
SetLimit(Limit.X, Limit.Y);
|
|
Dec(DrawLock);
|
|
DrawFlag := False;
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TScrollBox.CheckDraw;
|
|
begin
|
|
if (DrawLock = 0) and DrawFlag then
|
|
begin
|
|
DrawFlag := False;
|
|
ReDraw; DrawView;
|
|
end;
|
|
end;
|
|
|
|
procedure TScrollBox.ScrollDraw;
|
|
var
|
|
D: TPoint;
|
|
begin
|
|
if HScrollBar <> nil then
|
|
D.X := HScrollBar^.Value
|
|
else
|
|
D.X := 0;
|
|
if VScrollBar <> nil then
|
|
D.Y := VScrollBar^.Value
|
|
else
|
|
D.Y := 0;
|
|
if (D.X <> Delta.X) or (D.Y <> Delta.Y) then
|
|
begin
|
|
SetCursor(Cursor.X + Delta.X - D.X, Cursor.Y + Delta.Y - D.Y);
|
|
ScrollTo(D.X,D.Y);
|
|
if DrawLock <> 0 then
|
|
DrawFlag := True
|
|
else
|
|
DrawView;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TScrollBox.ScrollTo(X, Y: Sw_Integer);
|
|
var DX,DY: sw_integer;
|
|
PrevScrollFlag : boolean;
|
|
begin
|
|
Inc(DrawLock);
|
|
DX:=Delta.X-X;
|
|
DY:=Delta.Y-Y;
|
|
PrevScrollFlag:=ScrollFlag;
|
|
ScrollFlag:=true;
|
|
|
|
if HScrollBar <> nil then
|
|
HScrollBar^.SetValue(X);
|
|
if VScrollBar <> nil then
|
|
VScrollBar^.SetValue(Y);
|
|
ScrollFlag:=PrevScrollFlag;
|
|
ShiftViews(DX,DY);
|
|
Dec(DrawLock);
|
|
CheckDraw;
|
|
end;
|
|
|
|
procedure TScrollBox.ShiftViews(DX,DY: sw_integer);
|
|
procedure DoShift(P: PView);
|
|
begin
|
|
P^.MoveTo(P^.Origin.X+DX,P^.Origin.Y+DY);
|
|
end;
|
|
begin
|
|
ForEach(@DoShift);
|
|
Delta.X:=Delta.X-DX;
|
|
Delta.Y:=Delta.Y-DY;
|
|
end;
|
|
|
|
procedure TScrollBox.SetLimit(X, Y: Sw_Integer);
|
|
begin
|
|
Limit.X := X;
|
|
Limit.Y := Y;
|
|
Inc(DrawLock);
|
|
if HScrollBar <> nil then
|
|
HScrollBar^.SetParams(HScrollBar^.Value, HScrollBar^.Min, HScrollBar^.Max, HScrollBar^.PgStep, HScrollBar^.ArStep);
|
|
if VScrollBar <> nil then
|
|
VScrollBar^.SetParams(VScrollBar^.Value, VScrollBar^.Min, VScrollBar^.Max, VScrollBar^.PgStep, VScrollBar^.ArStep);
|
|
Dec(DrawLock);
|
|
CheckDraw;
|
|
end;
|
|
|
|
procedure TScrollBox.SetState(AState: Word; Enable: Boolean);
|
|
procedure ShowSBar(SBar: PScrollBar);
|
|
begin
|
|
if (SBar <> nil) then
|
|
if GetState(sfActive + sfSelected) then
|
|
SBar^.Show
|
|
else
|
|
SBar^.Hide;
|
|
end;
|
|
var OState: word;
|
|
begin
|
|
OState:=State;
|
|
inherited SetState(AState, Enable);
|
|
if AState and (sfActive + sfSelected) <> 0 then
|
|
begin
|
|
ShowSBar(HScrollBar);
|
|
ShowSBar(VScrollBar);
|
|
end;
|
|
if ((OState xor State) and (sfFocused))<>0 then
|
|
TrackCursor;
|
|
end;
|
|
|
|
procedure TScrollBox.TrackCursor;
|
|
var V: PView;
|
|
P,ND: TPoint;
|
|
begin
|
|
V:=Current;
|
|
if (not Assigned(V)) then Exit;
|
|
P.X:=V^.Origin.X+V^.Cursor.X;
|
|
P.Y:=V^.Origin.Y+V^.Cursor.Y;
|
|
ND:=Delta;
|
|
if (P.X<0) then
|
|
Dec(ND.X,-P.X)
|
|
else
|
|
if (P.X>=Size.X) then
|
|
Inc(ND.X,P.X-(Size.X-1));
|
|
if (P.Y<0) then
|
|
Dec(ND.Y,-P.Y)
|
|
else
|
|
if (P.Y>=Size.Y) then
|
|
Inc(ND.Y,P.Y-(Size.Y-1));
|
|
if (ND.X<>Delta.X) or (ND.Y<>Delta.Y) then
|
|
ScrollTo(ND.X,ND.Y);
|
|
end;
|
|
|
|
function TScrollBox.ClipChilds: boolean;
|
|
begin
|
|
ClipChilds:=false;
|
|
end;
|
|
|
|
procedure TScrollBox.BeforeInsert(P: PView);
|
|
begin
|
|
if Assigned(P) then
|
|
P^.MoveTo(P^.Origin.X-Delta.X,P^.Origin.Y-Delta.Y);
|
|
end;
|
|
|
|
procedure TScrollBox.AfterInsert(P: PView);
|
|
begin
|
|
UpdateLimits;
|
|
end;
|
|
|
|
procedure TScrollBox.AfterDelete(P: PView);
|
|
begin
|
|
{ UpdateLimits;
|
|
removed because it creates GPF PM }
|
|
end;
|
|
|
|
procedure TScrollBox.Draw;
|
|
begin
|
|
inherited Draw;
|
|
end;
|
|
|
|
procedure TScrollBox.UpdateLimits;
|
|
var Max: TPoint;
|
|
|
|
procedure Check(P: PView);
|
|
var O: TPoint;
|
|
begin
|
|
O.X:=P^.Origin.X+P^.Size.X+Delta.X;
|
|
O.Y:=P^.Origin.Y+P^.Size.Y+Delta.Y;
|
|
if O.X>Max.X then
|
|
Max.X:=O.X;
|
|
if O.Y>Max.Y then
|
|
Max.Y:=O.Y;
|
|
end;
|
|
|
|
begin
|
|
Max.X:=0; Max.Y:=0;
|
|
ForEach(@Check);
|
|
if (Max.X<>Limit.X) or (Max.Y<>Limit.Y) then
|
|
SetLimit(Max.X,Max.Y);
|
|
end;
|
|
|
|
END.
|