mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 16:59:45 +01: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.
 |