Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions richtextfx/src/main/java/org/fxmisc/richtext/CharacterHit.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,44 @@
import java.util.OptionalInt;

/**
* Object that stores information relating to the position in an area's content that corresponds to a given position
* in some visible entity (e.g. the area, a paragraph in the area, a line on a paragraph).
* <p>Object that stores information relating to the position in an area's content that corresponds to a given position
* in some visible entity (e.g. the area, a paragraph in the area, a line on a paragraph).</p>
* <p>A character hit can either be before a given character (leading) or after a given character (trailing).</p>
* <p>A special case is planned when the character hit happens outside the boundaries of some visible entity. In this case
* there is an insertion index but there isn't any actual character position in the content.</p>
*/
public class CharacterHit {

/**
* Returns a {@link CharacterHit} for cases where the insertion occurs outside the bounds of some visible entity
* @return a {@link CharacterHit} for cases where the insertion occurs outside the bounds of some visible entity
* (e.g. the area, the paragraph in an area, the line in a paragraph)
*/
public static CharacterHit insertionAt(int insertionIndex) {
return new CharacterHit(OptionalInt.empty(), insertionIndex);
}

/**
* Returns a {@link CharacterHit} for cases where the hit occurs inside the bounds of some visible entity
* <p>Represents a hit happening before a character at a given position (meaning the character is located forward).</p>
* <p>Example: If you have a hit on {@code ALPHA} at position 1, it means before the character {@code L}. The character
* index would be 1 and the insertion would be at 1.</p>
* @return a {@link CharacterHit} for cases where the hit occurs inside the bounds of some visible entity
* (e.g. the area, the paragraph in an area, the line in a paragraph) and the character is leading.
*/
public static CharacterHit leadingHalfOf(int charIdx) {
return new CharacterHit(OptionalInt.of(charIdx), charIdx);
}

/**
* Returns a {@link CharacterHit} for cases where the hit occurs inside the bounds of some visible entity
* <p>A hit that happens after the character at the given position (meaning the character is before).</p>
* <p>Example: If you have a hit on {@code ALPHA} at position 1, it means after the character {@code L}. The character
* index would be 1 but the insertion would be at 2.</p>
* @return a {@link CharacterHit} for cases where the hit occurs inside the bounds of some visible entity
* (e.g. the area, the paragraph in an area, the line in a paragraph) and the character is trailing.
*/
public static CharacterHit trailingHalfOf(int charIdx) {
return new CharacterHit(OptionalInt.of(charIdx), charIdx + 1);
}


private final OptionalInt charIdx;
private final int insertionIndex;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/**
* Default implementation of {@link TwoDimensional} that makes it trivial to calculate a position within a
* two dimensional object.
* two-dimensional object.
*/
public class TwoLevelNavigator implements TwoDimensional {

Expand Down
40 changes: 40 additions & 0 deletions richtextfx/src/test/java/org/fxmisc/richtext/CharacterHitTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.fxmisc.richtext;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class CharacterHitTest {
private void checkHitAndNoCharIndex(CharacterHit hit, int insertion) {
assertEquals(insertion, hit.getInsertionIndex());
assertTrue(hit.getCharacterIndex().isEmpty());
}

private void checkHit(CharacterHit hit, int insertion, int charIdx) {
assertEquals(insertion, hit.getInsertionIndex());
assertEquals(charIdx, hit.getCharacterIndex().orElseThrow());
}

@Test
@DisplayName("Character hit insertion at a given position")
void insertionAt() {
checkHitAndNoCharIndex(CharacterHit.insertionAt(2), 2);
checkHitAndNoCharIndex(CharacterHit.insertionAt(2).offset(12), 14);
}

@Test
@DisplayName("Character hit leading half at a given position")
void leadingHalfOf() {
checkHit(CharacterHit.leadingHalfOf(2), 2, 2);
checkHit(CharacterHit.leadingHalfOf(2).offset(12), 14, 14);
}

@Test
@DisplayName("Character hit trailing half at a given position")
void trailingHalfOf() {
checkHit(CharacterHit.trailingHalfOf(2), 3, 2);
checkHit(CharacterHit.trailingHalfOf(2).offset(12), 15, 14);
}
}