Skip to content
This is the documentation for xc 0.65. The current documentation describes the newest version.

UXScrollView

UXScrollView is the generic vertical scroller: a clipped viewport over a taller document view, with an optional pinned header strip and a scrollbar (track, arrow boxes, a draggable thumb). UXTableView and UXOutlineView are built on it. Put a tall view in the document and set its height, and the wheel, arrows, paging and thumb-drag all work.

The document is moved, not re-laid-out. Scrolling sets the document view’s y to -scrollOffset and the clip cuts it to the viewport. Your content keeps fixed coordinates, and the ordinary hit test finds it where it is drawn.

On backends that scroll natively (Win32, AppKit) a native container overlays this whole subtree and the custom bar never draws. On GEM (and headless) this bar is the scrollbar.

#use <UXKit>
UXScrollView* sv = new UXScrollView();
content.addSubview(sv, UXGeom.make(8, 8, 300, 200));
BigCanvas* big = new BigCanvas();
sv.document().addSubview(big, UXGeom.make(0, 0, 300, 900));
sv.setDocumentHeight(900);
sv.setLineHeight(18); // the arrow/wheel step

The document · document · setDocumentHeight · setHeaderView · setLineHeight Motion · scrollTo · scrollByLines Appearance · setCornerRadius · setBorderRGB · clearBorder Geometry · contentPx · viewportPx · scrollPx · maxScroll · needsBar

UXView* document(void)

The view your content goes in. Add subviews at their natural, fixed coordinates. Scrolling moves the document, not them.

void setDocumentHeight(i32 h)

The height of the content. All the scroll geometry derives from this number. Update it whenever the content grows.

void setHeaderView(UXView* hv, i16 h)

A strip pinned above the viewport, such as a table’s column header. It does not scroll with the document.

void setLineHeight(i16 h)

The arrow-click and wheel-notch step. A table sets its row height here so an arrow click moves one row.

void scrollTo(i16 off)

Scrolls to an absolute offset, clamped to [0, maxScroll]. This is the only place a scroll is announced; every other motion goes through it.

void scrollByLines(i32 lines)

Relative motion in line-height steps, used by arrows, wheel notches and the keyboard.

void setCornerRadius(i32 r)

A rounded panel: the scroll view clips its content and its scroller to a rounded rectangle of radius r, as a browser panel with border-radius and overflow: auto does, and the scroller runs between the corners rather than into them. 0 is square. It is read when the tree next realises, so display in the same turn.

Every backend rounds it except GEM, whose clip is a rectangle. On AppKit the native scroll view is clipped by its layer, and on Win32 the native scroll container is clipped by a window region. GTK, the web, iOS and Android draw the scroll view themselves, so they clip the subtree to the rounded shape.

void setBorderRGB(i32 r, i32 g, i32 b)
void clearBorder(void)

A 1-pixel edge in this colour that follows the rounding, or none. Where the toolkit draws the scroll view, the edge sits just inside the frame and the content is inset by a pixel to clear it. With neither a radius nor an edge, AppKit and Win32 draw their usual border. On Win32 a radius with no edge colour draws the edge in the system’s window-frame colour.

i32 contentPx(void)

The document height, as set.

i32 viewportPx(void)

The visible height (the clip’s, minus any header).

i32 scrollPx(void)

The current scroll offset. On a native backend the container holds the real value, because the user can drag its scroller without the toolkit being told. This method asks the driver rather than reporting the last value the toolkit set.

i32 maxScroll(void)

The largest valid offset (zero when the document fits).

bool needsBar(void)

Whether the content overflows the viewport. The bar hides when it does not.

UXScrollView on Web

The toolkit’s scrollbar: track, arrows, and the proportional thumb over the clipped document.

Reveal a row from code. This works because scrollTo is the single path for every scroll:

void revealRow(i32 row) {
i32 y = row * rowH;
if (y < sv.scrollPx()) { sv.scrollTo((i16)y); }
else if (y + rowH > sv.scrollPx() + sv.viewportPx()) {
sv.scrollTo((i16)(y + rowH - sv.viewportPx()));
}
}