Class TextSelection

java.lang.Object
swingtree.style.TextSelection

@Immutable public final class TextSelection extends Object
An immutable value describing which characters of a styled text are selected. Bind a property holding one to the styled text of a component through UIForAnySwing.withTextSelection(swingtree.UI.Layer, String, sprouts.Var):

  Var<TextSelection> selection = Var.of(TextSelection.caretAt(0));
  UI.box()
  .withStyle( it -> it
      .text("body", t -> t.content("Hello world"))
  )
  .withTextSelection("body", selection);
  
A selection holds two positions in the text. A position is a gap between two characters: position 0 is the gap in front of the first character, position 1 is the gap behind the first character, and the position equal to the length of the text is the gap behind its last character. In "Hello world", TextSelection.between(6, 11) selects "world".

The anchor is the position where the selection began, for example where your user pressed the mouse button. The caret is the position which moves, for example where your user drags the mouse to. A click with the shift key held down keeps the anchor and moves the caret. Which of the two positions comes first in the text does not change which characters are selected: start() is always the smaller and end() always the larger of the two.

The two positions, isCaretAtLineEnd() and isEnabled() are the only parts of a selection which your code chooses. Everything else is read only, and SwingTree fills it in: after SwingTree has painted the text, it writes a selection into the property which holds the selected characters in selectedText(), the pixel rectangles of the anchor and the caret in anchorBounds() and caretBounds(), and which converts a pixel coordinate into a position in positionAt(Position). SwingTree also moves a position which lies behind the end of the text to the end of the text, and sets isCaretAtLineEnd() to false where the caret is not the end of a painted line. A selection which your code creates with caretAt(int) or between(int, int) has none of this until SwingTree has written it into the property.

Two selections are equal when their positions, their isCaretAtLineEnd() and isEnabled() flags and everything that SwingTree filled in are equal. So the property receives a new selection whenever the painted text moves, for example when the component gets a new size.

  • Method Summary

    Modifier and Type
    Method
    Description
    int
    Returns the position where the selection began, which a shift-click keeps.
    Returns the pixel rectangle of the anchor on the component, measured in the same way as caretBounds(): when this selection is not empty and the anchor is its end(), which is the case for a selection made backwards, the rectangle lies at the end of the line which holds the last selected character, and otherwise in front of the character behind the anchor.
    between(int anchor, int caret)
    Creates an enabled selection of the characters between the two given positions.
    int
    Returns the position which moves while your user drags the mouse, and which a shift-click replaces.
    caretAt(int position)
    Creates an enabled selection of no characters, whose anchor and caret are both at the given position.
    Returns the pixel rectangle of the caret on the component, which is where SwingTree paints the caret when showCaret(true) is set in the style of the selection.
    int
    end()
    Returns the larger of the anchor and the caret, which is the gap behind the last selected character.
    boolean
    equals(Object other)
     
    int
     
    boolean
    Tells where the caret lies when its position is both the end of one painted line and the start of the next one.
    boolean
    Tells whether no character is selected, because the anchor and the caret are the same position.
    boolean
    Tells whether your users can select characters of the text.
    Returns the position nearest to the given pixel coordinate, by the rule which SwingTree uses for the mouse: the line nearest to the coordinate, and in that line the gap between two characters nearest to it.
    Returns the selected characters.
    int
    Returns the smaller of the anchor and the caret, which is the gap in front of the first selected character.
     
    Returns a selection with the same caret and the anchor at the position nearest to the given pixel coordinate, see positionAt(Position).
    withCaret(int caret)
    Returns a selection with the same anchor and the given caret, which is what a click with the shift key held down makes of this selection.
    Returns a selection with the same anchor and the caret at the position nearest to the given pixel coordinate, see positionAt(Position).
    withCaretAtLineEnd(boolean atLineEnd)
    Returns a selection with the same positions whose caret lies at the end of the upper line, or at the start of the next line, where its position is both, see isCaretAtLineEnd().
    withEnabled(boolean enabled)
    Returns a selection with the same positions which your users can or cannot change, see isEnabled().

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Method Details

    • caretAt

      public static TextSelection caretAt(int position)
      Creates an enabled selection of no characters, whose anchor and caret are both at the given position. Where a line wraps, the caret lies at the start of the next line, see isCaretAtLineEnd().
      Parameters:
      position - The gap between two characters at which both the anchor and the caret are, counted from 0 for the gap in front of the first character.
      Returns:
      A selection for which isEmpty() is true.
      Throws:
      IllegalArgumentException - If the position is negative.
    • between

      public static TextSelection between(int anchor, int caret)
      Creates an enabled selection of the characters between the two given positions. The anchor may lie behind the caret, which is what a selection made by dragging the mouse backwards looks like. When the caret lies behind the anchor, so that the caret is the end of the selected characters, isCaretAtLineEnd() is true, otherwise false.
      Parameters:
      anchor - The position where the selection began, which a shift-click keeps.
      caret - The position which moves, which a shift-click replaces.
      Returns:
      A selection with the given anchor and caret.
      Throws:
      IllegalArgumentException - If one of the positions is negative.
    • anchor

      public int anchor()
      Returns the position where the selection began, which a shift-click keeps.
      Returns:
      The anchor of this selection.
    • caret

      public int caret()
      Returns the position which moves while your user drags the mouse, and which a shift-click replaces.
      Returns:
      The caret of this selection.
    • start

      public int start()
      Returns the smaller of the anchor and the caret, which is the gap in front of the first selected character.
      Returns:
      The position where the selected characters start.
    • end

      public int end()
      Returns the larger of the anchor and the caret, which is the gap behind the last selected character.
      Returns:
      The position where the selected characters end.
    • isEmpty

      public boolean isEmpty()
      Tells whether no character is selected, because the anchor and the caret are the same position.
      Returns:
      true if the anchor and the caret are the same position.
    • isEnabled

      public boolean isEnabled()
      Tells whether your users can select characters of the text. When this is false, SwingTree paints no selection colour, no selection border and no caret, the mouse and the keyboard select and copy nothing, and the mouse cursor stays the default cursor. SwingTree still fills in selectedText() and the rectangles of the anchor and the caret.
      Returns:
      true if your users can select characters, which is the default.
    • withEnabled

      public TextSelection withEnabled(boolean enabled)
      Returns a selection with the same positions which your users can or cannot change, see isEnabled().
      Parameters:
      enabled - true to let your users select characters, false to ignore the mouse and the keyboard.
      Returns:
      A selection with the given flag.
    • withCaret

      public TextSelection withCaret(int caret)
      Returns a selection with the same anchor and the given caret, which is what a click with the shift key held down makes of this selection. When the new caret lies behind the anchor, so that it is the end of the selected characters, isCaretAtLineEnd() of the new selection is true, otherwise false. If the caret already is at the given position, this method returns this selection.
      Parameters:
      caret - The new position of the caret.
      Returns:
      A selection from the anchor of this selection to the given caret.
      Throws:
      IllegalArgumentException - If the caret is negative.
    • isCaretAtLineEnd

      public boolean isCaretAtLineEnd()
      Tells where the caret lies when its position is both the end of one painted line and the start of the next one. That happens where SwingTree wraps a long line, and on the two sides of an obstacle which the text flows around. With true, the caret lies at the end of the upper line, right next to the character in front of it. With false, it lies at the start of the next line, in front of the character behind it. At every other position there is only one place, and this flag changes nothing. Text editors know this as the affinity of the caret.

      SwingTree sets the flag wherever your users put the caret: a click right of the end of a line, the End key and the arrow keys up and down landing on the end of a line put the caret at the end of that line, and a click in front of the first character of a line and the Home key put it at the start of the line. When SwingTree writes a selection into the property, it keeps this flag only where the caret really is the end of a painted line, and sets it to false everywhere else, so two carets in the same place are equal. A selection which your code creates holds the value which your code chose until SwingTree has written it into the property. caretBounds() returns the place which this flag chooses:

      
        // "HHHH HHHH" wraps behind the space, so position 5 ends the first line and starts the second:
        TextSelection atStartOfSecondLine = TextSelection.caretAt(5);
        TextSelection atEndOfFirstLine    = TextSelection.caretAt(5).withCaretAtLineEnd(true);
        
      Returns:
      true if the caret lies at the end of the upper line where a position has two places.
    • withCaretAtLineEnd

      public TextSelection withCaretAtLineEnd(boolean atLineEnd)
      Returns a selection with the same positions whose caret lies at the end of the upper line, or at the start of the next line, where its position is both, see isCaretAtLineEnd().
      Parameters:
      atLineEnd - true for the end of the upper line, false for the start of the next line.
      Returns:
      A selection with the given flag.
    • selectedText

      public String selectedText()
      Returns the selected characters. SwingTree fills them in after it has painted the text, so this is an empty string for a selection which your code created and which SwingTree has not written into the property yet.
      Returns:
      The characters between start() and end(), up to the end of the text.
    • caretBounds

      public Optional<Bounds> caretBounds()
      Returns the pixel rectangle of the caret on the component, which is where SwingTree paints the caret when showCaret(true) is set in the style of the selection. The rectangle uses the same coordinates as the mouse events of the component: pixels, counted from the top left corner of the component, with the UI scale already applied. It reaches from the top to the bottom of the line of the caret, and its left edge is the gap between the two characters, whatever the shape of the caret is. For a UI.CaretShape.BAR, which is the default, it is as wide as the caretWidth of the style of the selection, and at least one pixel. For a UI.CaretShape.BLOCK and an UI.CaretShape.UNDERLINE, it is as wide as the character behind the gap, and SwingTree paints an underline into the bottom of it, as thick as the caretWidth.

      The position where a line wraps is both the end of that line and the start of the next line. There, isCaretAtLineEnd() decides where the rectangle lies: at the end of the upper line when it is true, and in front of the character behind the caret when it is false. For example, when your users select up to the place where a line wraps, the rectangle of the caret lies at the right end of the upper line, next to the last selected character, and not in front of the first character of the next line. A caret made by caretAt(int) at that place lies at the start of the next line.

      Two line breaks in a row make an empty paragraph, which SwingTree paints as an empty line. The rectangle of a caret in it lies at the start of that empty line and is as tall as the font size.

      It is empty for a selection which SwingTree has not written into the property yet, and for a caret on a line which is not painted because the component is too small to show it.

      Returns:
      The rectangle of the caret, or an empty Optional.
    • anchorBounds

      public Optional<Bounds> anchorBounds()
      Returns the pixel rectangle of the anchor on the component, measured in the same way as caretBounds(): when this selection is not empty and the anchor is its end(), which is the case for a selection made backwards, the rectangle lies at the end of the line which holds the last selected character, and otherwise in front of the character behind the anchor.
      Returns:
      The rectangle of the anchor, or an empty Optional.
    • positionAt

      public Optional<Integer> positionAt(Position point)
      Returns the position nearest to the given pixel coordinate, by the rule which SwingTree uses for the mouse: the line nearest to the coordinate, and in that line the gap between two characters nearest to it. A coordinate left of the first or right of the last character of a line gives the first or the last position of that line. The coordinate uses the same coordinates as the mouse events of the component, see caretBounds().
      Parameters:
      point - A pixel coordinate on the component.
      Returns:
      The position nearest to the coordinate, or an empty Optional for a selection which SwingTree has not written into the property yet.
    • withCaretAt

      public TextSelection withCaretAt(Position point)
      Returns a selection with the same anchor and the caret at the position nearest to the given pixel coordinate, see positionAt(Position). This is what dragging the mouse to the coordinate does. Where a line wraps, the caret lies on the line of the coordinate: isCaretAtLineEnd() is true for a coordinate at the end of the upper line and false for a coordinate at the start of the next line. So a handle which your code paints at caretBounds() stays under the finger of your users while they drag it across that place.
      Parameters:
      point - A pixel coordinate on the component.
      Returns:
      A selection with the moved caret, or this selection if SwingTree has not written it into the property yet.
    • withAnchorAt

      public TextSelection withAnchorAt(Position point)
      Returns a selection with the same caret and the anchor at the position nearest to the given pixel coordinate, see positionAt(Position).
      Parameters:
      point - A pixel coordinate on the component.
      Returns:
      A selection with the moved anchor, or this selection if SwingTree has not written it into the property yet.
    • equals

      public boolean equals(Object other)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object