UniTextSelectable
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 UniTextWorld — RequireComponent validates the dependency but cannot auto-add the abstract base, so add the text component first.
Remarks
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 and magnifier are owner-aware serialized entities that choose their presentation mechanism. The context menu is the platform's edit menu or a TextContextMenu prefab, as AndroidMenu, IOSMenu and ContextMenuPrefab choose with the project's settings; the prefab is instantiated once under the shared touch overlay. 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; null 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 — by default the platform's own loupe (NativeMagnifier), which Android and iOS present and other platforms do not. The implementation owns how it is presented; null shows no magnifier. It appears while a selection handle is dragged, and a sibling UniTextEditable additionally raises it for long-press caret placement.
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.
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 SelectionChangingArgs.Cancel to abort, or assign SelectionChangingArgs.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 TextMenuOverride AndroidMenu{ get; set }Context menu the field presents on Android: the project's choice (UniTextSettings.AndroidMenu), the system's floating toolbar, or the Unity-UI menu. A device without the system menu, before Android 6.0, presents the Unity-UI menu.
public TextMenuOverride IOSMenu{ get; set }Context menu the field presents on iOS: the project's choice (UniTextSettings.IOSMenu), the system's edit menu, or the Unity-UI menu. A device without the system menu, before iOS 13, presents the Unity-UI menu.
public TextContextMenu ContextMenuPrefab{ get; set }Unity-UI menu the field presents wherever it presents no system menu; empty presents the project's (UniTextSettings.ContextMenuPrefab).
public void HandleScroll(PointerEventData eventData)Scrolls the enclosing scrolling adapter, or the text viewport when no adapter is present.
public bool SetCaret(int codepointIndex, CaretAffinity affinity = CaretAffinity.Downstream, string userEvent = SelectionChangeReason.Programmatic)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(int anchor, int focus, CaretAffinity affinity = CaretAffinity.Downstream, string userEvent = SelectionChangeReason.Programmatic)Sets both endpoints simultaneously. Out-of-range indices are clamped to [0, codepointCount].
public bool ExtendSelection(int newFocus, CaretAffinity affinity = CaretAffinity.Downstream, string userEvent = SelectionChangeReason.Extend)Moves the focus while keeping the anchor fixed. Used for shift-click and drag extension.
public bool DragSelectionHandle(bool draggingAnchor, int codepointIndex, CaretAffinity affinity = CaretAffinity.Downstream)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.
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 void HandlePrimaryClick(TextHitResult hit, Vector2 screenPosition, PointerModifiers modifiers = PointerModifiers.None)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; PointerModifiers.Shift extends. Affinity defaults downstream — the bounding-box TextHitResult carries none.
Drives selection from a touch-side double tap (word selection) and arms IsWordDragMode.
public void BeginDrag(int codepointIndex, bool extendOnly = false, CaretAffinity affinity = CaretAffinity.Downstream)Begins a drag-to-select operation at codepointIndex. When extendOnly is true, the existing selection's anchor is preserved (used by long-press → drag flow).
public void UpdateDrag(int codepointIndex, CaretAffinity affinity = CaretAffinity.Downstream)Updates a drag-in-progress to codepointIndex. In word-drag mode, extends by whole-word boundaries; otherwise extends by single codepoints.
public void RequestContextMenu(Vector2 screenPosition)Raises the context menu with the field's commands. During a touch session it opens as touch opens it: clear of the selection, following it until a gesture, the selection, a command or an edit of the text takes it down. Otherwise it opens as a mouse or pen opens it, at screenPosition; the Unity-UI menu then holds the field's keys until it closes, and Escape closes it.
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(out Rect screenRect)Gets the screen rect enclosing the current selection, clipped to the visible text viewport.
public bool TryGetCaretScreenPoint(int codepointIndex, out Vector2 screenPoint)Gets the screen point at the bottom of the caret at codepointIndex in document space.
public bool TryGetCaretScreenRect(int codepointIndex, out Rect screenRect)Gets the screen rect of the caret at codepointIndex in document space — its position and its line height — clipped to the visible text viewport.
public bool TryGetContextMenuScreenRect(out Rect screenRect)Gets the screen rect a context menu is raised over and keeps clear of: the selection box, or the caret's box for a collapsed selection, 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> SelectionChangedPost-change notification with previous and current state plus a hierarchical UserEvent string. See SelectionChangedArgs for category strings.
public Action<TextPointerEvent> SelectionDragStartedOccurs when a pointer drag has been routed to the field (mouse / pen always; touch as the drag policy keeps it in the field). A touch swipe that turns out to scroll an enclosing container is handed to it, and SelectionDragEnded marks the hand-off. The event is anchored at the press position, not the position where the drag threshold was crossed. The instance is reused across emissions and TextPointerEvent.Hit is not computed — hit-test from TextPointerEvent.ScreenPosition.
public Action<TextPointerEvent> SelectionDragUpdatedOccurs when a pointer drag has been routed to the field (mouse / pen always; touch as the drag policy keeps it in the field). A touch swipe that turns out to scroll an enclosing container is handed to it, and SelectionDragEnded marks the hand-off. The event is anchored at the press position, not the position where the drag threshold was crossed. The instance is reused across emissions and TextPointerEvent.Hit is not computed — hit-test from TextPointerEvent.ScreenPosition.
public Action<TextPointerEvent> SelectionDragEndedOccurs when a pointer drag has been routed to the field (mouse / pen always; touch as the drag policy keeps it in the field). A touch swipe that turns out to scroll an enclosing container is handed to it, and SelectionDragEnded marks the hand-off. The event is anchored at the press position, not the position where the drag threshold was crossed. The instance is reused across emissions and TextPointerEvent.Hit is not computed — hit-test from TextPointerEvent.ScreenPosition.
