Class ScrollBar

java.lang.Object
limn.scene.Widget
limn.components.ScrollBar

public class ScrollBar extends Widget
The one scrollbar shared by every scrollable component (ListView, TextArea, ScrollView, …), so they look and behave identically. It is an overlay widget the host lays out along an edge; it reads/writes scroll through a ScrollBar.Model and handles its own thumb drag and track paging.
  • Themed: the thumb is drawn in Theme.textMuted, so it is visible on both light and dark surfaces.
  • Draggable: drag the thumb, or click the track to page.
  • Policy (setPolicy(limn.components.ScrollBar.Policy)): ScrollBar.Policy.HIDDEN, ScrollBar.Policy.ALWAYS, ScrollBar.Policy.ON_SCROLL (fades in on scroll) or ScrollBar.Policy.AUTO (also while the pointer is active over the host).
  • Thin idle / wide on approach: a slim bar that widens when the pointer is over it or dragging, ready to grab.
  • Mirrored: a horizontal bar reads with its subtree, so right to left the thumb rests at the right end of the track and walks left as the offset grows. A vertical bar's travel is a y and never mirrors; only the side its thumb hugs does, following the side the host puts the strip on.
The host calls onScrolled() when it scrolls and onHostActivity() on pointer movement (for AUTO).

The hold is a timer, not an animation. A reveal lasts HOLD_SECONDS past the last scroll or pointer movement and then fades; the fade in and out are transitions, which tick only while a value moves. The hold itself used to be a real-time ticker that returned "still holding" every frame for a second after every pointer move, and a scene keeps its frame pump running while any ticker is alive: moving the pointer over a form inside a scroll view rendered at the display's rate with nothing on screen changing, and resting it over the bar rendered forever. The hold is now a timestamp compared on demand and one delayed task armed for the moment it expires, so a bar that is showing and still asks for no frame at all.

  • Constructor Details

  • Method Details

    • setPolicy

      public ScrollBar setPolicy(ScrollBar.Policy newPolicy)
      When the bar is shown: always, never, or only while the content overflows.
    • policy

      public ScrollBar.Policy policy()
      The current visibility policy.
    • thickness

      public static float thickness()
      The strip thickness the host reserves/lays the bar out with.
    • onScrolled

      public void onScrolled()
      The host scrolled: reveal the bar (ON_SCROLL / AUTO).
    • onHostActivity

      public void onHostActivity()
      The pointer is active over the host: reveal the bar (AUTO). Called for every pointer move over the host, so it must cost nothing while the bar is already showing: a stamp and two comparisons, no invalidation and no frame.
    • refresh

      public void refresh()
      Re-evaluate visibility after the content/overflow changed.

      Content that has just become scrollable reveals the bar for one hold-and-fade, the way an overlay scroller flashes when a pane first has something to scroll. Under ScrollBar.Policy.AUTO (the default, and what a Dialog body uses) the bar is otherwise invisible until the pointer moves over the host or the wheel turns, so a card that was capped opens with nothing at all saying that anything was cut off. The gutter inset says the card is capped; only the bar says it can be scrolled.

    • onMeasure

      protected Size onMeasure(Constraints constraints)
      Description copied from class: Widget
      Reports the size this widget wants within constraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.

      Resolve the ControlSize and the LayoutDirection once each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, and I18n.locale() answers it wherever text is resolved.

      Specified by:
      onMeasure in class Widget
    • onPaint

      protected void onPaint(Canvas canvas)
      Description copied from class: Widget
      Widget's own background/content, in local coordinates.
      Overrides:
      onPaint in class Widget
    • hitTest

      public Widget hitTest(float localX, float localY)
      Transparent to events while effectively invisible, so it never blocks the content.
      Overrides:
      hitTest in class Widget
    • onMouseEvent

      protected void onMouseEvent(MouseEvent event)
      Description copied from class: Widget
      Mouse events (bubbling); call event.consume() when handled.
      Overrides:
      onMouseEvent in class Widget