All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.peanuuutz.fork.ui.foundation.text.TextSelectionHelper.kt Maven / Gradle / Ivy

The newest version!
package net.peanuuutz.fork.ui.foundation.text

import androidx.compose.runtime.Stable
import net.peanuuutz.fork.ui.foundation.text.MeasuredParagraph.Companion.NullIndex
import net.peanuuutz.fork.ui.foundation.text.field.CursorAnchor
import net.peanuuutz.fork.ui.foundation.text.field.getCursorAnchorFromOffsetApproximately
import net.peanuuutz.fork.ui.ui.unit.FloatOffset
import net.peanuuutz.fork.util.common.fastIndexOfFirst

@Stable
fun MeasuredParagraph.getLineIndexFromSelectionIndex(selectionIndex: Int): Int {
    if (isEmpty()) {
        return NullIndex
    }
    if (selectionIndex == displayPlainText.length) {
        return lines.lastIndex
    }
    return lines.fastIndexOfFirst { line ->
        selectionIndex in line.range.start..line.range.endExclusive
    }
}

@Stable
fun MeasuredParagraph.getSectionPositionFromSelectionIndex(selectionIndex: Int): SectionPosition {
    if (isEmpty()) {
        return SectionPosition.Null
    }
    if (selectionIndex == displayPlainText.length) {
        return lastPosition
    }
    val lineIndex = getLineIndexFromSelectionIndex(selectionIndex)
    if (lineIndex == NullIndex) {
        return SectionPosition.Null
    }
    val line = this[lineIndex]
    val sectionIndex = line.sections.fastIndexOfFirst { section ->
        selectionIndex in section.range
    }
    return if (sectionIndex != -1) {
        SectionPosition(lineIndex, sectionIndex)
    } else {
        SectionPosition(lineIndex, line.sections.lastIndex)
    }
}

@Stable
fun MeasuredParagraph.getSelectionIndexFromOffset(offset: FloatOffset): Int {
    if (isEmpty()) {
        return NullIndex
    }
    val cursorAnchor = getCursorAnchorFromOffsetApproximately(offset)
    return convertCursorAnchorToSelectionIndex(cursorAnchor)
}

@Stable
fun MeasuredParagraph.convertCursorAnchorToSelectionIndex(cursorAnchor: CursorAnchor): Int {
    if (isEmpty()) {
        return NullIndex
    }
    val section = this[cursorAnchor.lineIndex][cursorAnchor.sectionIndex]
    return section.range.start + cursorAnchor.localOffset
}

@Stable
fun MeasuredParagraph.convertSelectionIndexToCursorAnchor(selectionIndex: Int): CursorAnchor {
    if (isEmpty()) {
        return CursorAnchor.Null
    }
    val sectionPosition = getSectionPositionFromSelectionIndex(selectionIndex)
    if (sectionPosition.isNull()) {
        return CursorAnchor.Null
    }
    val localOffset = selectionIndex - this[sectionPosition].range.start
    return CursorAnchor(sectionPosition.lineIndex, sectionPosition.sectionIndex, localOffset)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy