Table of Contents

rip_scrollbar.js

rip_scrollbar.js is a loadable JavaScript file that provides a class, RIPScrollbar, which is a reusable scrollbar widget for RIP terminals on Synchronet. It renders a graphical scrollbar with arrow buttons, a proportional track, and a draggable thumb, all using RIPScrip vector drawing primitives.

RIPScrollbar supports both vertical and horizontal orientations. By default the scrollbar is vertical (with up/down arrow buttons and a thumb that moves vertically). Setting the horizontal property to true before calling computeLayout() switches to horizontal mode, where the arrow buttons become left/right arrows and the thumb moves horizontally.

RIPScrollbar is a pure rendering/layout component — it does not handle user input directly. Instead, the consumer (such as RIPLightbarMenu or a custom dialog) is responsible for reading keyboard and mouse input and calling the appropriate methods to update the scroll position and redraw the thumb.

To create a new RIPScrollbar object:

var sb = new RIPScrollbar(x, y, width, height);

The x, y, width, and height parameters are in RIP pixel coordinates (the RIP graphics viewport is 640×350 pixels).

Dependencies

rip_scrollbar.js requires the following loadable module:

Orientation

The scrollbar defaults to vertical mode. To create a horizontal scrollbar, set the horizontal property to true before calling computeLayout():

var sb = new RIPScrollbar(50, 330, 400, 14);
sb.horizontal = true;
sb.computeLayout();

In horizontal mode:

The consumer handles the mouse input the same way regardless of orientation — the character codes are identical. The only difference is which coordinate (X or Y) follows the thumbDrag character.

How it works

The typical usage pattern is:

  1. Create a RIPScrollbar with the desired position and size.
  2. Optionally set horizontal to true for a horizontal scrollbar.
  3. Set the scroll state: totalItems, visibleCount, and topIndex.
  4. Call computeLayout() to calculate the internal geometry.
  5. Call buildFullRIP() to get the RIP command string for the complete scrollbar, and send it to the terminal.
  6. Call buildMouseRegionsRIP() to get the RIP mouse region commands, and send those as well. This registers clickable areas for the arrow buttons, track areas, and the thumb.
  7. When the user scrolls (via keyboard or mouse clicks), update topIndex, then call buildThumbRIP() and buildMouseRegionsRIP() to efficiently redraw just the thumb and update the mouse regions.

The scrollbar's mouse regions send high-byte character codes when clicked (configurable via the mouseChars property). The consumer reads these codes from console input and maps them to scroll actions:

RIPScrollbar methods

Name Returns Usage Description
computeLayout void RIPScrollbar.computeLayout() Computes the internal geometry (arrow button bounds, track bounds) from the current pos, size, arrowHeight, and orientation. Must be called before any build methods, and again if the scrollbar's position, size, or orientation changes.
setScrollState void RIPScrollbar.setScrollState(totalItems, visibleCount, topIndex) Sets the scroll state (total number of items, number of visible items, and the index of the first visible item). Call this before building RIP commands so the thumb size and position are correct.
buildFullRIP string RIPScrollbar.buildFullRIP() Returns a RIP command string that draws the complete scrollbar: both arrow buttons (with beveled 3D appearance), the track background, and the thumb. Does NOT include mouse regions — call buildMouseRegionsRIP() separately.
buildThumbRIP string RIPScrollbar.buildThumbRIP() Returns a RIP command string that redraws just the track and thumb. Used for efficient updates when only the scroll position has changed (no need to redraw the arrow buttons).
buildMouseRegionsRIP string RIPScrollbar.buildMouseRegionsRIP() Returns a RIP command string that defines mouse regions for the scrollbar's clickable areas. In vertical mode: up/down arrows, track above/below thumb, and thumb (with $Y$). In horizontal mode: left/right arrows, track left/right of thumb, and thumb (with $X$). Note: this does NOT call RIPKillMouseFields() — the consumer must kill existing fields before registering new ones if needed.
getThumbGeometry object RIPScrollbar.getThumbGeometry() Returns an object describing the current thumb position and size. In vertical mode: { y, h } (top pixel and height). In horizontal mode: { x, w } (left pixel and width).

RIPScrollbar properties

Name Type Description
pos object An object with x and y properties for the upper-left corner of the scrollbar, in RIP pixel coordinates.
size object An object with width and height properties for the scrollbar dimensions, in RIP pixels.
horizontal boolean Orientation of the scrollbar. false (default) for vertical, true for horizontal. Must be set before calling computeLayout().
colors object An object containing RIP color numbers (0-15, as defined in rip_lib.js) for the scrollbar's visual components. Properties: track (track background), thumb (thumb body), arrowBg (arrow button background), arrowFg (arrow triangle foreground), bevelBright (bright edge of 3D bevel), bevelDark (dark edge of 3D bevel).
arrowHeight number Size of each arrow button along the scrollbar's primary axis (pixels). For vertical mode this is the height of each up/down button; for horizontal mode this is the width of each left/right button. Defaults to 14.
totalItems number Total number of items being scrolled through. Set by the consumer.
visibleCount number Number of items visible at once. Set by the consumer.
topIndex number Index of the first visible item (scroll position). Set by the consumer and updated on scroll.
mouseChars object Object containing the character codes sent when mouse regions are clicked. Properties: scrollUp (default 0xFE), scrollDn (default 0xFD), trackPgUp (default 0xFC), trackPgDn (default 0xFB), thumbDrag (default 0xFA). In horizontal mode, scrollUp/scrollDn correspond to left/right, and trackPgUp/trackPgDn correspond to page-left/page-right. These can be changed to avoid conflicts when multiple scrollbars or other mouse-aware widgets are on screen simultaneously.

To change the scrollbar colors:

sb.colors.track = RIP_COLOR_BLACK;
sb.colors.thumb = RIP_COLOR_LT_CYAN;
sb.colors.arrowBg = RIP_COLOR_LT_GRAY;
sb.colors.arrowFg = RIP_COLOR_BLACK;
sb.colors.bevelBright = RIP_COLOR_WHITE;
sb.colors.bevelDark = RIP_COLOR_DK_GRAY;

Example usage (vertical)

load("rip_scrollbar.js");
load("rip_lib.js");
// Helper to send a batch of RIP commands
function sendRIP(cmds) {
  console.write("\r!" + cmds + RIPGotoXYNumeric(0, 0) + "\r\n");
}
// Create a vertical scrollbar at pixel position (600, 70), 14 pixels wide, 260 pixels tall
var sb = new RIPScrollbar(600, 70, 14, 260);
sb.setScrollState(100, 20, 0);  // 100 total items, 20 visible, starting at item 0
sb.computeLayout();
// Draw the scrollbar and register mouse regions
sendRIP(sb.buildFullRIP() + sb.buildMouseRegionsRIP());
// In your input loop, when the user scrolls:
sb.topIndex = 5;  // User scrolled down to show items 5-24
sendRIP(sb.buildThumbRIP() + sb.buildMouseRegionsRIP());

Example usage (horizontal)

load("rip_scrollbar.js");
load("rip_lib.js");
function sendRIP(cmds) {
  console.write("\r!" + cmds + RIPGotoXYNumeric(0, 0) + "\r\n");
}
// Create a horizontal scrollbar at pixel position (50, 330), 500 pixels wide, 14 pixels tall
var sb = new RIPScrollbar(50, 330, 500, 14);
sb.horizontal = true;  // Switch to horizontal mode
sb.setScrollState(200, 50, 0);  // 200 total items, 50 visible, starting at item 0
sb.computeLayout();
// Draw and register mouse regions (same API as vertical)
sendRIP(sb.buildFullRIP() + sb.buildMouseRegionsRIP());

Handling mouse input

When the user clicks on the scrollbar's mouse regions, SyncTerm sends the corresponding character code. Here is an example of handling the mouse input in a getkey() loop. The handling code is the same for vertical and horizontal scrollbars — only the coordinate variable (Y vs X) differs for the thumb drag:

var key = console.getkey(K_NOCRLF | K_NOECHO | K_NOSPIN);
var ch = key.charCodeAt(0);
if (ch === sb.mouseChars.scrollUp) {
  if (topIndex > 0) --topIndex;
}
else if (ch === sb.mouseChars.scrollDn) {
  if (topIndex < maxTopIndex) ++topIndex;
}
else if (ch === sb.mouseChars.trackPgUp) {
  topIndex = Math.max(0, topIndex - visibleCount);
}
else if (ch === sb.mouseChars.trackPgDn) {
  topIndex = Math.min(maxTopIndex, topIndex + visibleCount);
}
else if (ch === sb.mouseChars.thumbDrag) {
  // Read the coordinate digits that follow.  For vertical scrollbars this is
  // the $Y$ value; for horizontal scrollbars this is the $X$ value.
  var coordStr = "";
  for (var d = 0; d < 4; ++d) {
    var dc = console.inkey(0, 500);
    if (dc === "") break;
    coordStr += dc;
  }
  var mouseCoord = parseInt(coordStr, 10);
  if (!isNaN(mouseCoord)) {
    var sbL = sb._layout;
    if (sb.horizontal) {
      // Horizontal: map X coordinate to scroll position
      var thumb = sb.getThumbGeometry();
      var thumbRange = sbL.trackWidth - thumb.w;
      if (thumbRange > 0) {
        var clampedX = Math.max(sbL.trackLeft, Math.min(sbL.trackRight, mouseCoord));
        var relX = clampedX - sbL.trackLeft;
        topIndex = Math.round(relX * maxTopIndex / thumbRange);
        topIndex = Math.max(0, Math.min(maxTopIndex, topIndex));
      }
    }
    else {
      // Vertical: map Y coordinate to scroll position
      var thumb = sb.getThumbGeometry();
      var thumbRange = sbL.trackHeight - thumb.h;
      if (thumbRange > 0) {
        var clampedY = Math.max(sbL.trackTop, Math.min(sbL.trackBot, mouseCoord));
        var relY = clampedY - sbL.trackTop;
        topIndex = Math.round(relY * maxTopIndex / thumbRange);
        topIndex = Math.max(0, Math.min(maxTopIndex, topIndex));
      }
    }
  }
}
// After updating topIndex, redraw the thumb and mouse regions
sb.topIndex = topIndex;
sendRIP(sb.buildThumbRIP() + sb.buildMouseRegionsRIP());

Example code

For real-world examples where RIPScrollbar is used, see:

See Also