Docsv3.10.0
Back to API Reference
Class

UniTextSelectable

sealed
Inherits:MonoBehaviour
Implements:IPointerMoveHandlerIPointerExitHandlerISelectHandlerIDeselectHandlerIInitializePotentialDragHandlerIBeginDragHandlerIDragHandlerIEndDragHandlerIScrollHandler

Selection capability for UniTextBase: caret + range state with explicit affinity, gesture interpretation (multi-click promotion, drag-to-select, word-by-word drag, context-menu coordination), and highlight rendering. Sits on the same GameObject as UniTextBase; requires an existing UniText or UniTextWorldRequireComponent validates the dependency but cannot auto-add the abstract base, so add the text component first.

Remarks

First-class component, not a modifier. The misuse pattern (selection-as-Style, empty OnApply) is gone — selection is a component-level capability with its own lifecycle, distinct from text-range markup. Add this component for read-only selectable text; combine with UniTextEditable for editable input. See Component Composition Model in the roadmap (D-008, D-011). This component owns the pointer surface for text — presses, drags and the touch gesture recogniser — for editable and read-only fields alike, so one pipeline produces one behaviour. A sibling UniTextEditable plugs into it through ITextEditingLayer and adds no gestures of its own. Drag policy: mouse / pen drags select; touch drags forward to the enclosing scroll container (the iOS / Android convention — selection on touch starts from a long-press or a double-tap, never from a plain drag) unless a selection gesture armed word-drag mode or the field itself has content to scroll. Handles, magnifier, and context menu are owner-aware serialized entities. Their implementations choose the presentation mechanism; the component never instantiates UI itself. Multi-click thresholds default to desktop conventions (MultiClickMaxInterval, MultiClickMaxDistance). Single = caret, double = word, triple = paragraph. Touch-side multi-tap thresholds (different from desktop) are fed in via DispatchTap / DispatchDoubleTap / DispatchTripleTap by the gesture recogniser, which applies its own timing.
public HighlightPresentation SelectionHighlight{ get; set }

Selection highlight presentation emitted through the text component's shared range-decoration host. It uses the same paint, mapping and geometry contract as HighlightModifier.

public ITouchHandles SelectionHandles{ get; set }

Touch handle entity. It may implement ISelectionHandles, IInsertionHandle, or both; shows no handles. This component drives the selection handles for touch-selected text; a sibling UniTextEditable, when present, takes over and drives the caret handle too.

public IMagnifier Magnifier{ get; set }

Touch magnifier entity. The implementation owns how it is presented; shows no magnifier. It appears while a selection handle is dragged, and a sibling UniTextEditable additionally raises it for long-press caret placement.

public static float MultiClickMaxInterval{ get; set }

Maximum interval between consecutive primary clicks for multi-click detection (seconds). Defaults to 0.5 s — the Windows (GetDoubleClickTime) and macOS default. Assign to match a user-configured OS value.

public static float MultiClickMaxDistance{ get; set }

Maximum distance between consecutive primary clicks for multi-click detection, in density-independent pixels (Android dp, 160 dpi baseline) — the comparison scales by the display density at use so the physical slop stays constant on high-density displays. Defaults to 8.

public UniTextBase TextComponent{ get }

Gets the display component on the same GameObject, resolving it on first access.

public TextSelection Selection{ get }

Current selection state (anchor / focus / affinity). Immutable.

public bool IsWordDragMode{ get }

True while word-by-word drag is active (started by a double-click on text). Drag extension snaps to whole-word boundaries instead of individual codepoints. Read by the touch gesture pipeline to decide whether to start a fresh caret-drag or continue extending the word selection.

public OrderedValueEvent<SelectionChangingArgs> SelectionChanging{ get }

Occurs when Selection is about to change through any of the public mutators (SetCaret / SetSelection / ExtendSelection / Select* / Click+drag dispatchers). Subscribers may set Cancel to abort, or assign Proposed to clamp into a permitted range (P2.A atomic-token boundary, integrator-defined read-only ranges). Side-effect movements driven by text mutation (insert / delete / IME commit / undo) bypass this event by design — they go through an internal non-vetoable path. See SelectionChangingArgs. Callbacks run by ascending order and equal orders retain subscription order.

public ITextContextMenu ContextMenu{ get; set }

Menu entity presented on a context-menu request. It owns its presentation and may use Unity UI, native platform UI, or another mechanism. leaves presentation to ContextMenuRequested subscribers.

public bool IsDragging{ get }

Whether a pointer is currently dragging a selection endpoint, a handle or the caret.

public bool IsContextMenuVisible{ get }

Whether this component is presenting its context menu.

public void HandleScroll()

Scrolls the enclosing scrolling adapter, or the text viewport when no adapter is present.

public bool SetCaret()

Collapses the selection to a single caret at codepointIndex with the given affinity. Out-of-range indices are clamped to [0, codepointCount].

public bool SetSelection()

Sets both endpoints simultaneously. Out-of-range indices are clamped to [0, codepointCount].

public bool ExtendSelection()

Moves the focus while keeping the anchor fixed. Used for shift-click and drag extension.

public bool DragSelectionHandle()

Moves one selection endpoint to codepointIndex with the touch selection-handle contract (iOS / Android): the selection never collapses — when the dragged endpoint lands on the fixed one it is clamped one grapheme cluster away — and dragging past the fixed endpoint is allowed, inverting the anchor / focus orientation (the handles swap roles). draggingAnchor selects which endpoint moves; the other stays fixed.

public bool SelectWord()

Selects the word containing codepointIndex.

public bool SelectLine()

Selects the visual (soft-wrapped) line containing codepointIndex. Gesture pipelines use SelectParagraph for triple-click / triple-tap; this stays for consumers that genuinely want the visual row.

public bool SelectParagraph()

Selects the paragraph (between hard line breaks) containing codepointIndex.

public bool SelectAll()

Selects the entire text.

public bool ClearSelection()

Collapses the selection at the current focus.

public string GetSelectedText()

Returns the selected text, including content outside the rendered window; returns an empty string for a collapsed selection. An editing host supplies its authoritative document text.

public void ResetGestureState()

Resets all transient gesture state. Call on focus loss so a stale click count or drag mode does not bleed into the next focus session.

public void HandlePrimaryClick()

Programmatic primary-click driver — runs the same press gesture the pointer pipeline uses (HandlePressGesture): single places the caret, double selects the word, triple the paragraph; Shift extends. Affinity defaults downstream — the bounding-box TextHitResult carries none.

public void DispatchTap()

Drives selection from a touch-side single tap (caret placement). Bypasses the desktop multi-click counter so the touch gesture recogniser can apply its own thresholds.

public void DispatchDoubleTap()

Drives selection from a touch-side double tap (word selection) and arms IsWordDragMode.

public void DispatchTripleTap()

Drives selection from a touch-side triple tap (paragraph / line).

public void BeginDrag()

Begins a drag-to-select operation at codepointIndex. When extendOnly is, the existing selection's anchor is preserved (used by long-press → drag flow).

public void UpdateDrag()

Updates a drag-in-progress to codepointIndex. In word-drag mode, extends by whole-word boundaries; otherwise extends by single codepoints.

public void EndDrag()

Ends an active drag-to-select operation.

public void RequestContextMenu(Vector2 screenPosition)

Raises the assigned ContextMenu (if any) over the current selection, then raises ContextMenuRequested. The menu stays up until the selection, a gesture or a command takes it down.

public void DismissContextMenu()

Hides the assigned ContextMenu (if any) and releases it, so it does not return when the current gesture ends; then raises ContextMenuDismissRequested.

public void RefreshHighlight()

Repaints the highlight rects backing the selection. Called automatically after each selection change and after the host commits a relayout; expose for consumers that reposition the text out-of-band (manual scroll offsets) without changing Selection.

public bool TryGetSelectionScreenRect(Rect screenRect)

Gets the screen rect enclosing the current selection, clipped to the visible text viewport.

public bool TryGetSelectionHandlePoints(Vector2 anchorPoint, Vector2 focusPoint)

Gets the screen points the two touch selection handles hang from: the bottom of the line box at each selection endpoint, on the physical side that endpoint lies on.

public bool TryGetCaretScreenPoint(int codepointIndex, Vector2 screenPoint)

Gets the screen point at the bottom of the caret at codepointIndex in document space.

public bool TryGetLineScreenRect(Vector2 screenPosition, Rect screenRect)

Gets the screen rect of the text line under screenPosition, clipped to the visible text viewport.

public Rect GetViewportScreenRect()

Gets the screen rect of the visible text viewport in Unity screen pixels.

public Action<SelectionChangedArgs> SelectionChanged

Post-change notification with previous and current state plus a hierarchical UserEvent string. See SelectionChangedArgs for category strings.

public Action<TextPointerEvent> SelectionDragStarted

Occurs when a pointer drag has been routed to selection (mouse / pen always; touch only in an armed selection gesture — see the class drag policy). The event is anchored at the press position, not the position where the drag threshold was crossed. The instance is reused across emissions and Hit is not computed — hit-test from ScreenPosition.

public Action<TextPointerEvent> SelectionDragUpdated
public Action<TextPointerEvent> SelectionDragEnded
public Action<Vector2> ContextMenuRequested

Occurs when the user has requested a context menu (right-click, long-press) at a screen position — after the assigned ContextMenu (if any) is shown. Subscribe to present a custom menu.

public Action ContextMenuDismissRequested

Occurs when an open context menu should hide (drag, scroll, edit, focus loss).