Browse Source

Detach List scrollbar value change of focused item change

Margers 7 months ago
parent
commit
aebc7458e1
1 changed files with 65 additions and 28 deletions
  1. 65 28
      packages/fv/src/views.inc

+ 65 - 28
packages/fv/src/views.inc

@@ -650,6 +650,8 @@ TYPE
       PROCEDURE HandleEvent (Var Event: TEvent); Virtual;
       PROCEDURE ChangeBounds (Var Bounds: TRect); Virtual;
       PROCEDURE FocusItemNum (Item: Sw_Integer); Virtual;
+      private
+        LastY : Sw_integer;                           { to track last Size.Y }
    END;
    PListViewer = ^TListViewer;
 
@@ -3561,22 +3563,12 @@ CONST TvListViewerName = 'LISTBOX';                   { Native name }
 {---------------------------------------------------------------------------}
 CONSTRUCTOR TListViewer.Init (Var Bounds: TRect; ANumCols: Sw_Word; AHScrollBar,
   AVScrollBar: PScrollBar);
-VAR ArStep, PgStep: Sw_Integer;
 BEGIN
    Inherited Init(Bounds);                            { Call ancestor }
    Options := Options OR (ofFirstClick+ofSelectable); { Set options }
    EventMask := EventMask OR evBroadcast;             { Set event mask }
    NumCols := ANumCols;                               { Hold column number }
-   If (AVScrollBar <> Nil) Then Begin                 { Chk vert scrollbar }
-     If (NumCols = 1) Then Begin                      { Only one column }
-       PgStep := Size.Y -1;                           { Set page size }
-       ArStep := 1;                                   { Set step size }
-     End Else Begin                                   { Multiple columns }
-       PgStep := Size.Y * NumCols;                    { Set page size }
-       ArStep := Size.Y;                              { Set step size }
-     End;
-     AVScrollBar^.SetStep(PgStep, ArStep);            { Set scroll values }
-   End;
+   LastY:=0;
    If (AHScrollBar <> Nil) Then
      AHScrollBar^.SetStep(Size.X DIV NumCols, 1);     { Set step size }
    HScrollBar := AHScrollBar;                         { Horz scrollbar held }
@@ -3687,41 +3679,79 @@ END;
 
 
 {--TListViewer--------------------------------------------------------------}
-{  FocusItem -> Platforms DOS/DPMI/WIN/NT/OS2 - Updated 26Jul99 LdB         }
+{  FocusItem -> Platforms DOS/DPMI/WIN/NT/OS2 - Updated 03Jan2025 M         }
 {---------------------------------------------------------------------------}
 PROCEDURE TListViewer.FocusItem (Item: Sw_Integer);
+VAR NewTopItem : Sw_Integer;
 BEGIN
    Focused := Item;                                   { Set focus to item }
-   If (VScrollBar <> Nil) Then
-     VScrollBar^.SetValue(Item);                      { Scrollbar to value }
+   NewTopItem:=TopItem;
    If (Item < TopItem) Then                           { Item above top item }
-     If (NumCols = 1) Then TopItem := Item            { Set top item }
-       Else TopItem := Item - Item MOD Size.Y         { Set top item }
+     If (NumCols = 1) Then NewTopItem := Item         { New top item }
+       Else NewTopItem := Item - Item MOD Size.Y      { New top item }
    Else If (Item >= TopItem + (Size.Y*NumCols)) Then  { Item below bottom }
-     If (NumCols = 1) Then TopItem := Item-Size.Y+1   { Set new top item }
-     Else TopItem := Item - Item MOD Size.Y -
-       (Size.Y*(NumCols-1));                          { Set new top item }
+     If (NumCols = 1) Then NewTopItem := Item-Size.Y+1 { New top item }
+     Else NewTopItem := Item - Item MOD Size.Y -
+       (Size.Y*(NumCols-1));
+   if TopItem <> NewTopItem then SetTopItem(NewTopItem); { Set new top item }
+   DrawView;                                           { Redraw focus box }
 END;
 
 {--TListViewer--------------------------------------------------------------}
-{  SetTopItem -> Platforms DOS/DPMI/WIN/NT/OS2 - Updated 06Aug99 LdB        }
+{  SetTopItem -> Platforms DOS/DPMI/WIN/NT/OS2 - Updated 07Jan2025 M        }
 {---------------------------------------------------------------------------}
 PROCEDURE TListViewer.SetTopItem (Item: Sw_Integer);
 BEGIN
+   if Size.Y<> LastY then SetRange(Range);{ Reset range to ajdust to Size.Y}
+   If (VScrollBar <> Nil) and (Item> VScrollBar^.Max) Then
+       Item:=VScrollBar^.Max;           { Don't let overrun scrollbar limit }
+   if Item>=Range then Item:=Range-1;             { Item has to be in range }
+   if Item<0 then Item:=0;                      { Don't allow negative item }
    TopItem := Item;                                   { Set the top item }
+   If (VScrollBar <> Nil) and (VScrollBar^.Value<>TopItem) Then
+       VScrollBar^.SetValue(TopItem);               { Scrollbar to value }
 END;
 
 {--TListViewer--------------------------------------------------------------}
-{  SetRange -> Platforms DOS/DPMI/WIN/NT/OS2 - Updated 26Jul99 LdB          }
+{  SetRange -> Platforms DOS/DPMI/WIN/NT/OS2 - Updated 07Jan2025 M          }
 {---------------------------------------------------------------------------}
 PROCEDURE TListViewer.SetRange (ARange: Sw_Integer);
+
+procedure NewScrollbarStep;
+var ArStep, PgStep: Sw_Integer;
+begin
+   If (VScrollBar <> Nil) Then Begin                 { Chk vert scrollbar }
+     If (NumCols = 1) Then Begin                      { Only one column }
+       PgStep := Size.Y -1;                           { Set page size }
+       ArStep := 1;                                   { Set step size }
+     End Else Begin                                   { Multiple columns }
+       PgStep := Size.Y * NumCols;                    { Set page size }
+       ArStep := Size.Y;                              { Set step size }
+     End;
+     VScrollBar^.SetStep(PgStep, ArStep);            { Set scroll values }
+   End;
+end;
+
+var MaxRange : sw_integer;
 BEGIN
    Range := ARange;                                   { Set new range }
+   if LastY <> Size.Y then NewScrollbarStep;
+   LastY := Size.Y;                                   { Save last seen Size.Y }
+   If (Focused >= ARange) Then Focused := 0;          { Clear focused }
    If (VScrollBar <> Nil) Then Begin                  { Vertical scrollbar }
-     If (Focused > ARange) Then Focused := 0;         { Clear focused }
-     VScrollBar^.SetParams(Focused, 0, ARange - 1,
+     MaxRange:=Min(ARange-Size.Y,ARange - 1);         { Glue last item at bottom }
+     if (Size.Y > 0) and (NumCols>1) then             { More than one column ? }
+     begin
+       MaxRange:=(ARange div Size.Y) * Size.Y;   { Last column stay in view }
+       if MaxRange=ARange then MaxRange:=MaxRange-Size.Y;
+       MaxRange:=MaxRange-((NumCols-1)*Size.Y);  { Last NumCols stay in view }
+     end;
+     if MaxRange < 0 then MaxRange:=0;           { Negative isn't acceptable }
+     If (TopItem > MaxRange) Then TopItem:=MaxRange;  { Adjust top item }
+     VScrollBar^.SetParams(TopItem, 0, MaxRange,
        VScrollBar^.PgStep, VScrollBar^.ArStep);       { Set parameters }
-   End;
+   End else
+   If (TopItem >= ARange) Then TopItem := ARange-1;   { Adjust top item }
 END;
 
 {--TListViewer--------------------------------------------------------------}
@@ -3780,7 +3810,12 @@ VAR Oi, Ni: Sw_Integer; Ct, Cw: Word; Mouse: TPoint;
    PROCEDURE MoveFocus (Req: Sw_Integer);
    BEGIN
      FocusItemNum(Req);                               { Focus req item }
-     DrawView;                                      { Redraw focus box }
+   END;
+
+   PROCEDURE ScrollTo (Req: Sw_Integer);
+   BEGIN
+     SetTopItem(Req);
+     DrawView;                                        { Redraw focus box }
    END;
 
 BEGIN
@@ -3818,7 +3853,7 @@ BEGIN
          Else If (Event.Command = cmScrollBarChanged) { Scrollbar changed }
          Then Begin
            If (VScrollBar = Event.InfoPtr) Then Begin
-             MoveFocus(VScrollBar^.Value);            { Focus us to item }
+             ScrollTo(VScrollBar^.Value);            { Focus us to item }
            End Else If (HScrollBar = Event.InfoPtr)
              Then DrawView;                           { Redraw the view }
          End;
@@ -3826,11 +3861,13 @@ BEGIN
      evMouseDown: Begin                               { Mouse down event }
        if (Event.Buttons=mbScrollUp) then             { mouse scroll up}
          begin
-           if Event.Double then MoveFocus(Focused+1) else MoveFocus(Focused+1);
+           if NumCols>1 then ScrollTo(TopItem+Size.Y)
+           else if Event.Double then ScrollTo(TopItem+4) else ScrollTo(TopItem+1);
          end else
        if (Event.Buttons=mbScrollDown) then           { mouse scroll down }
          begin
-           if Event.Double then MoveFocus(Focused-1) else MoveFocus(Focused-1);
+           if NumCols>1 then ScrollTo(TopItem-Size.Y)
+           else if Event.Double then ScrollTo(TopItem-4) else ScrollTo(TopItem-1);
          end else
        begin
        Cw := Size.X DIV NumCols + 1;                  { Column width }