Class TabbedPane
TabbedPane.TabAlignment.LEFT, TabbedPane.TabAlignment.CENTER or
TabbedPane.TabAlignment.RIGHT. Headers select on click; only the selected
content is laid out and painted. All visuals come from the Theme.
This or a SegmentedControl? Ask who owns the content. A tabbed pane
owns it (addTab(java.lang.String, limn.scene.Widget) hands it the pages and it decides which is laid out), which
is why it carries chevrons, a popup and a scrollable strip. A segmented control owns
nothing and hands back an index, so it fits wherever the caller keeps the content and
switches it itself.
Keyboard: the strip is a single tab stop (roving focus): only the selected header is focusable, so Tab/Shift+Tab land on it; Left/Right arrows move between tabs (Home/End jump to the ends) and Enter/Space dive into the panel. Focus follows a programmatic selection while the strip holds it.
Overflow: when the headers don't fit, the strip becomes a clipped,
scrollable viewport (alignment is moot then): chevron buttons appear at the
edges (the dead side disabled, not hidden; hiding would resize the viewport
and oscillate at the ends), the mouse wheel scrolls the strip, and a list
button opens a PopupMenu of all tabs (check on the current one) to
jump directly. Selecting a tab (by click, keyboard or
setSelectedIndex(int)) always scrolls it into view. The three square controls
shrink with the pane rather than being dropped, each capped at a sixth of its width, so
the viewport never falls below half the pane, never reaches zero, and never changes
non-monotonically as the pane is resized.
Sizes follow the ControlSize resolved on this pane: type,
tab paddings, icon and reveal margin come from the SizeTokens row, while the
strip separator, the selected-tab indicator, the focus ring and the chevron pen are
weights and stay identical at every step. The strip height composes the independent
type and padding ramps, so it is deliberately fractional, which is why the whole
layout must derive from one resolve per pass.
Reading right to left the strip is still one run of tabs in reading order, and the run reflects with the interface: the first tab lands on the edge reading starts from and the run advances away from it, the three overflow controls swap ends keeping the order they had, and the two scroll chevrons turn around. Left and Right select the tab that is visually to the left and to the right, so the keyboard and the pointer agree; Home and End name the ends of the tab order and stay first and last in both directions.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumWhere the strip sits when the headers are narrower than the pane, named for where it lands in an interface that reads left to right. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionaddTab(String title, Icon icon, Icon.Mirroring mirroring, Widget content) Appends a tab with a leading icon and says whether the glyph inside it turns around when the interface does.Appends a tab with a leading icon, tinted to the tab's text colour and drawn as authored whichever way the pane reads.Appends a tab.addTab(I18nString title, Icon icon, Icon.Mirroring mirroring, Widget content) The icon-mirroring form for a caption that follows the UI language.addTab(I18nString title, Icon icon, Widget content) Appends a tab with an icon and a caption that follows the UI language.addTab(I18nString title, Widget content) A tab whose caption follows the UI language; seeI18nString.The strip's horizontal alignment.protected booleanKeeps a panel inside the pane.protected voidonLayout()Containers position children here (measure +Widget.layoutBox(float, float, float, float)per child).protected SizeonMeasure(Constraints constraints) Reports the size this widget wants withinconstraints.protected voidWidget's own background/content, in local coordinates.Called with the new index whenever the selection changes, by click, keyboard or code.protected voidpaintChildren(Canvas canvas) Children pass; override to clip (e.g.intIndex of the selected tab, or-1when there are none.setAlignment(TabbedPane.TabAlignment newAlignment) Where the strip sits when the headers are narrower than the pane.setSelectedIndex(int index) Selects a tab, scrolls it into view and firesonSelect(java.util.function.Consumer<java.lang.Integer>); code and a click take the same path, so a listener sees every change either way.inttabCount()How many tabs the pane holds; and, read before anaddTab, the index that call will land on.Methods inherited from class limn.scene.Widget
acceptsTextInput, add, baselineOffset, baselineOffsetOf, caretRect, children, clipboard, controlSize, cursor, declaredControlSize, declaredLayoutDirection, declaredLocale, focusArrivedByTraversal, height, hitTest, imageCursor, invalidate, invalidate, isEnabled, isFocusable, isFocused, isShowing, isVisible, layoutBox, layoutDirection, locale, localToSceneX, localToSceneY, markNeedsContainedLayout, markNeedsLayout, measure, moveChild, neutralBase, onAttached, onCharTyped, onDetached, onFileDrop, onFocusGained, onFocusLost, onKeyEvent, onMouseEvent, onPaintOverlay, onPreedit, overlayPassesPointer, paintOutset, paintWidget, parent, remove, requestFocus, revealInView, scene, sceneToLocalX, sceneToLocalY, setControlSize, setCursor, setEnabled, setFocusable, setImageCursor, setInheritanceHost, setLayoutDirection, setLocale, setTooltip, setTooltip, setVisible, shapeText, textRuler, tooltip, width, x, y
-
Constructor Details
-
TabbedPane
public TabbedPane()An empty pane; add pages withaddTab(java.lang.String, limn.scene.Widget).
-
-
Method Details
-
addTab
Appends a tab. The first one added is selected. UI thread only. -
addTab
A tab whose caption follows the UI language; seeI18nString. -
addTab
Appends a tab with a leading icon, tinted to the tab's text colour and drawn as authored whichever way the pane reads. Leading is the side reading starts on: the left of the caption left to right, its right in a right-to-left pane. -
addTab
Appends a tab with an icon and a caption that follows the UI language. -
addTab
Appends a tab with a leading icon and says whether the glyph inside it turns around when the interface does. The icon's position is leading either way and is this pane's decision; whether the drawing is a back arrow (which turns around) or a logo, a download arrow or a photograph (which must not) is knowable only at the call that placed it.- Parameters:
mirroring-Icon.Mirroring.NEVERunless this glyph is directional; a wrongNEVERis one arrow pointing the wrong way, and a wrongIN_RTLis a flipped brand mark
-
addTab
The icon-mirroring form for a caption that follows the UI language. -
setAlignment
Where the strip sits when the headers are narrower than the pane. Ignored while overflowing. -
alignment
The strip's horizontal alignment. -
selectedIndex
public int selectedIndex()Index of the selected tab, or-1when there are none. A pane that holds tabs always has one selected, so there is no clearing operation and no way back to-1. -
tabCount
public int tabCount()How many tabs the pane holds; and, read before anaddTab, the index that call will land on.That is what it is for.
addTabreturns the pane so a builder can chain, which leaves a caller that needs to select a tab later with a hand-written index, and a hand-written index is wrong the moment a tab is inserted above it, silently, because every index below merely shifts to another real tab. -
setSelectedIndex
Selects a tab, scrolls it into view and firesonSelect(java.util.function.Consumer<java.lang.Integer>); code and a click take the same path, so a listener sees every change either way. Re-selecting the current tab still scrolls it back into view (a caller asking for a tab is asking to be shown it) but changes nothing and fires nothing; that early return is what keeps two controls bound to each other from recursing, so do not remove it. UI thread only.- Parameters:
index- a tab in[0, tabCount)- Throws:
IndexOutOfBoundsException- ifindexis not a tab; an empty pane has none, so every index throws there. Arrowing past an end is not this: keyboard traversal stops at the end rather than raising.
-
onSelect
Called with the new index whenever the selection changes, by click, keyboard or code. -
onMeasure
Description copied from class:WidgetReports the size this widget wants withinconstraints. 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
ControlSizeand theLayoutDirectiononce each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, andI18n.locale()answers it wherever text is resolved. -
onLayout
protected void onLayout()Description copied from class:WidgetContainers position children here (measure +Widget.layoutBox(float, float, float, float)per child). -
onPaint
Description copied from class:WidgetWidget's own background/content, in local coordinates. -
clipsChildren
protected boolean clipsChildren()Keeps a panel inside the pane.onLayout()hands the selected panel a box, and a box is all it is: nothing stops a child from measuring taller than it and painting past the bottom edge. A panel that does (anything not wrapped in aScrollView, which is most content once a window is made short enough) then draws over whatever the pane is sitting on, and it looks like the container has no bounds at all rather than like the content is too big.Clipping is the honest answer, and it is not a substitute for scrolling: it makes overflow read as content that continues past an edge, which is what it is. Content that should be reachable still needs a scroll view around it, and the demo's panels have one.
- Overrides:
clipsChildrenin classWidget
-
paintChildren
Description copied from class:WidgetChildren pass; override to clip (e.g. scroll views).- Overrides:
paintChildrenin classWidget
-