[Text Selection] Cross-widget Selection.
Bug: 134533989
Test: ./gradlew test
Change-Id: I133c6f3f264937c259a761429b60ac76d4fe4b60
diff --git a/ui/framework/api/1.0.0-alpha01.txt b/ui/framework/api/1.0.0-alpha01.txt
index 104650a..eb13089 100644
--- a/ui/framework/api/1.0.0-alpha01.txt
+++ b/ui/framework/api/1.0.0-alpha01.txt
@@ -264,13 +264,22 @@
public final class SelectionContainerKt {
ctor public SelectionContainerKt();
- method public static void SelectionContainer(androidx.ui.core.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.ui.core.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method public static void SelectionContainer(androidx.ui.core.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.ui.core.selection.Selection,kotlin.Unit> onSelectionChange, androidx.ui.core.selection.SelectionMode mode = SelectionMode.Vertical, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ }
+
+ public final class SelectionKt {
+ ctor public SelectionKt();
}
public final class SelectionManagerKt {
ctor public SelectionManagerKt();
}
+ public enum SelectionMode {
+ enum_constant public static final androidx.ui.core.selection.SelectionMode Horizontal;
+ enum_constant public static final androidx.ui.core.selection.SelectionMode Vertical;
+ }
+
}
package androidx.ui.core.vectorgraphics {
diff --git a/ui/framework/api/current.txt b/ui/framework/api/current.txt
index 104650a..eb13089 100644
--- a/ui/framework/api/current.txt
+++ b/ui/framework/api/current.txt
@@ -264,13 +264,22 @@
public final class SelectionContainerKt {
ctor public SelectionContainerKt();
- method public static void SelectionContainer(androidx.ui.core.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.ui.core.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method public static void SelectionContainer(androidx.ui.core.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.ui.core.selection.Selection,kotlin.Unit> onSelectionChange, androidx.ui.core.selection.SelectionMode mode = SelectionMode.Vertical, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ }
+
+ public final class SelectionKt {
+ ctor public SelectionKt();
}
public final class SelectionManagerKt {
ctor public SelectionManagerKt();
}
+ public enum SelectionMode {
+ enum_constant public static final androidx.ui.core.selection.SelectionMode Horizontal;
+ enum_constant public static final androidx.ui.core.selection.SelectionMode Vertical;
+ }
+
}
package androidx.ui.core.vectorgraphics {
diff --git a/ui/framework/src/main/java/androidx/ui/core/Text.kt b/ui/framework/src/main/java/androidx/ui/core/Text.kt
index b039494..e1f7fc1 100644
--- a/ui/framework/src/main/java/androidx/ui/core/Text.kt
+++ b/ui/framework/src/main/java/androidx/ui/core/Text.kt
@@ -19,7 +19,6 @@
import androidx.ui.engine.geometry.Offset
import androidx.ui.engine.text.TextAlign
import androidx.ui.engine.text.TextDirection
-import androidx.ui.engine.text.TextPosition
import androidx.ui.graphics.Color
import androidx.ui.painting.TextSpan
import androidx.ui.painting.TextStyle
@@ -37,10 +36,8 @@
import androidx.compose.memo
import androidx.compose.onDispose
import androidx.compose.unaryPlus
-import androidx.ui.core.selection.Selection
import androidx.ui.core.selection.SelectionRegistrarAmbient
-import androidx.ui.core.selection.TextSelectionHandler
-import androidx.ui.engine.text.TextAffinity
+import androidx.ui.core.selection.TextSelectionHandlerImpl
import androidx.ui.painting.TextPainter
private val DefaultTextAlign: TextAlign = TextAlign.Start
@@ -206,54 +203,12 @@
})
+onCommit(textPainter) {
- val id = registrar.subscribe(object : TextSelectionHandler {
- // Get selection for the start and end coordinates pair.
- override fun getSelection(
- selectionCoordinates: Pair<PxPosition, PxPosition>,
- containerLayoutCoordinates: LayoutCoordinates
- ): Selection? {
- val relativePosition = containerLayoutCoordinates.childToLocal(
- layoutCoordinates.value!!, PxPosition.Origin
- )
- val startPx = selectionCoordinates.first - relativePosition
- val endPx = selectionCoordinates.second - relativePosition
-
- val startOffset = Offset(startPx.x.value, startPx.y.value)
- val endOffset = Offset(endPx.x.value, endPx.y.value)
-
- var selectionStart = textPainter.getPositionForOffset(startOffset)
- var selectionEnd = textPainter.getPositionForOffset(endOffset)
-
- if (selectionStart.offset == selectionEnd.offset) {
- val wordBoundary = textPainter.getWordBoundary(selectionStart)
- selectionStart =
- TextPosition(wordBoundary.start, selectionStart.affinity)
- selectionEnd = TextPosition(wordBoundary.end, selectionEnd.affinity)
- } else {
- // Currently on Android, selection end is the offset after last character.
- // But when dragging happens, current Crane Text Selection end is the offset
- // of the last character. Thus before calling drawing selection background,
- // make the selection end matches Android behaviour.
- selectionEnd = TextPosition(selectionEnd.offset + 1, TextAffinity.upstream)
- }
-
- internalSelection.value =
- TextSelection(selectionStart.offset, selectionEnd.offset)
-
- // In Crane Text Selection, the selection end should be the last character, thus
- // make the selection end matches Crane behaviour.
- selectionEnd = TextPosition(selectionEnd.offset - 1, TextAffinity.upstream)
-
- return Selection(
- startOffset =
- textPainter.getBoundingBoxForTextPosition(selectionStart),
- endOffset =
- textPainter.getBoundingBoxForTextPosition(selectionEnd),
- startLayoutCoordinates = layoutCoordinates.value!!,
- endLayoutCoordinates = layoutCoordinates.value!!
- )
- }
- })
+ val id = registrar.subscribe(
+ TextSelectionHandlerImpl(
+ textPainter = textPainter,
+ layoutCoordinates = layoutCoordinates.value,
+ internalSelection.value = it })
+ )
onDispose {
registrar.unsubscribe(id)
}
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/Selection.kt b/ui/framework/src/main/java/androidx/ui/core/selection/Selection.kt
index fd376e0..786a3d6 100644
--- a/ui/framework/src/main/java/androidx/ui/core/selection/Selection.kt
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/Selection.kt
@@ -45,4 +45,28 @@
* does not contain the end of the selection, this should be null.
*/
val endLayoutCoordinates: LayoutCoordinates?
-)
\ No newline at end of file
+) {
+ internal fun merge(other: Selection): Selection {
+ // TODO: combine two selections' contents with styles together.
+ var currentSelection = this.copy()
+ if (other.startLayoutCoordinates != null) {
+ currentSelection = currentSelection.copy(
+ startOffset = other.startOffset,
+ startLayoutCoordinates = other.startLayoutCoordinates
+ )
+ }
+ if (other.endLayoutCoordinates != null) {
+ currentSelection = currentSelection.copy(
+ endOffset = other.endOffset,
+ endLayoutCoordinates = other.endLayoutCoordinates
+ )
+ }
+ return currentSelection
+ }
+}
+
+internal operator fun Selection?.plus(rhs: Selection?): Selection? {
+ if (this == null) return rhs
+ if (rhs == null) return this
+ return merge(rhs)
+}
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
index 84d9793..3b6ab5a 100644
--- a/ui/framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
@@ -51,6 +51,8 @@
selection: Selection?,
/** A function containing customized behaviour when selection changes. */
onSelectionChange: (Selection?) -> Unit,
+ /** Selection mode. The default mode is Vertical. */
+ mode: SelectionMode = SelectionMode.Vertical,
@Children children: @Composable() () -> Unit
) {
val manager = +memo { SelectionManager() }
@@ -60,6 +62,7 @@
// +memo(onSelectionChange) { manager. }
manager.selection = selection
manager.>
+ manager.mode = mode
SelectionRegistrarAmbient.Provider(value = manager) {
val content = @Composable {
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
index 64727fd..53c9ef5 100644
--- a/ui/framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
@@ -23,29 +23,6 @@
import androidx.ui.core.px
import androidx.ui.engine.geometry.Rect
-/**
- * An interface handling selection. Get selection from a widget by passing in the start and end of
- * selection in a selection container as a pair, and the layout coordinates of the selection
- * container.
- */
-internal interface TextSelectionHandler {
- fun getSelection(
- selectionCoordinates: Pair<PxPosition, PxPosition>,
- containerLayoutCoordinates: LayoutCoordinates
- ): Selection?
-}
-
-/**
- * An interface allowing a Text composable to "register" and "unregister" itself with the class
- * implementing the interface.
- */
-internal interface SelectionRegistrar {
- // TODO(qqd): Replace Any with a type in future.
- fun subscribe(handler: TextSelectionHandler): Any
-
- fun unsubscribe(key: Any)
-}
-
internal class SelectionManager : SelectionRegistrar {
/**
* The current selection.
@@ -60,6 +37,11 @@
var onSelectionChange: (Selection?) -> Unit = {}
/**
+ * The selection mode. The default value is Vertical.
+ */
+ var mode: SelectionMode = SelectionMode.Vertical
+
+ /**
* Layout Coordinates of the selection container.
*/
lateinit var containerLayoutCoordinates: LayoutCoordinates
@@ -100,7 +82,10 @@
fun onPress(position: PxPosition) {
var result: Selection? = null
for (handler in handlers) {
- result = handler.getSelection(Pair(position, position), containerLayoutCoordinates)
+ result += handler.getSelection(
+ Pair(position, position),
+ containerLayoutCoordinates,
+ mode)
}
onSelectionChange(result)
}
@@ -170,9 +155,10 @@
}
for (handler in handlers) {
- result = handler.getSelection(
+ result += handler.getSelection(
Pair(currentStart, currentEnd),
- containerLayoutCoordinates)
+ containerLayoutCoordinates,
+ mode)
}
onSelectionChange(result)
return dragDistance
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/SelectionMode.kt b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionMode.kt
new file mode 100644
index 0000000..0240940b
--- /dev/null
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionMode.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.core.selection
+
+import androidx.ui.core.PxPosition
+import androidx.ui.core.px
+import androidx.ui.engine.geometry.Rect
+
+/**
+ * The enum class allows user to decide the selection mode.
+ */
+enum class SelectionMode {
+ /**
+ * When selection handles are dragged across widgets, selection extends by row, for example,
+ * when the end selection handle is dragged down, upper rows will be selected first, and the
+ * lower rows.
+ */
+ Vertical {
+ override fun isSelected(
+ box: Rect,
+ start: PxPosition,
+ end: PxPosition
+ ): Boolean {
+ // When the end of the selection is above the top of the widget, the widget is outside
+ // of the selection range.
+ if (end.y < box.top.px) return false
+
+ // When the end of the selection is on the left of the widget, and not below the bottom
+ // of widget, the widget is outside of the selection range.
+ if (end.x < box.left.px && end.y <= box.bottom.px) return false
+
+ // When the start of the selection is below the bottom of the widget, the widget is
+ // outside of the selection range.
+ if (start.y > box.bottom.px) return false
+
+ // When the start of the selection is on the right of the widget, and not above the top
+ // of the widget, the widget is outside of the selection range.
+ if (start.x > box.right.px && start.y >= box.top.px) return false
+
+ return true
+ }
+ },
+
+ /**
+ * When selection handles are dragged across widgets, selection extends by column, for example,
+ * when the end selection handle is dragged to the right, left columns will be selected first,
+ * and the right rows.
+ */
+ Horizontal {
+ override fun isSelected(
+ box: Rect,
+ start: PxPosition,
+ end: PxPosition
+ ): Boolean {
+ // When the end of the selection is on the left of the widget, the widget is outside of
+ // the selection range.
+ if (end.x < box.left.px) return false
+
+ // When the end of the selection is on the top of the widget, and the not on the right
+ // of the widget, the widget is outside of the selection range.
+ if (end.y < box.top.px && end.x <= box.right.px) return false
+
+ // When the start of the selection is on the right of the widget, the widget is outside
+ // of the selection range.
+ if (start.x > box.right.px) return false
+
+ // When the start of the selection is below the widget, and not on the left of the
+ // widget, the widget is outside of the selection range.
+ if (start.y > box.bottom.px && start.x >= box.left.px) return false
+
+ return true
+ }
+ };
+
+ internal abstract fun isSelected(
+ box: Rect,
+ start: PxPosition,
+ end: PxPosition
+ ): Boolean
+}
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/SelectionRegistrar.kt b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionRegistrar.kt
new file mode 100644
index 0000000..598dea6
--- /dev/null
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/SelectionRegistrar.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.core.selection
+
+/**
+ * An interface allowing a Text composable to "register" and "unregister" itself with the class
+ * implementing the interface.
+ */
+internal interface SelectionRegistrar {
+ // TODO(qqd): Replace Any with a type in future.
+ fun subscribe(handler: TextSelectionHandler): Any
+
+ fun unsubscribe(key: Any)
+}
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/TextSelectionHandler.kt b/ui/framework/src/main/java/androidx/ui/core/selection/TextSelectionHandler.kt
new file mode 100644
index 0000000..d58caf5
--- /dev/null
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/TextSelectionHandler.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.core.selection
+
+import androidx.ui.core.LayoutCoordinates
+import androidx.ui.core.PxPosition
+
+/**
+ * An interface handling selection. Get selection from a widget by passing in the start and end of
+ * selection in a selection container as a pair, and the layout coordinates of the selection
+ * container.
+ */
+internal interface TextSelectionHandler {
+ fun getSelection(
+ selectionCoordinates: Pair<PxPosition, PxPosition>,
+ containerLayoutCoordinates: LayoutCoordinates,
+ mode: SelectionMode
+ ): Selection?
+}
diff --git a/ui/framework/src/main/java/androidx/ui/core/selection/TextSelectionHandlerImpl.kt b/ui/framework/src/main/java/androidx/ui/core/selection/TextSelectionHandlerImpl.kt
new file mode 100644
index 0000000..0a70040
--- /dev/null
+++ b/ui/framework/src/main/java/androidx/ui/core/selection/TextSelectionHandlerImpl.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.core.selection
+
+import androidx.ui.core.LayoutCoordinates
+import androidx.ui.core.PxPosition
+import androidx.ui.core.px
+import androidx.ui.engine.geometry.Offset
+import androidx.ui.engine.geometry.Rect
+import androidx.ui.engine.text.TextAffinity
+import androidx.ui.engine.text.TextPosition
+import androidx.ui.painting.TextPainter
+import androidx.ui.services.text_editing.TextSelection
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * A class contains all the logic for text selection.
+ */
+internal class TextSelectionHandlerImpl(
+ val textPainter: TextPainter,
+ val layoutCoordinates: LayoutCoordinates?,
+ var onSelectionChange: (TextSelection?) -> Unit = {}
+) : TextSelectionHandler {
+
+ /** Last TextPosition of the text in text widget. */
+ private val lastTextPosition: Int
+ /** Bounding box of the text widget. */
+ private val box: Rect
+
+ init {
+ lastTextPosition = textPainter.text?.let { it.toPlainText().length - 1 } ?: 0
+ box = Rect(
+ top = 0f,
+ bottom = textPainter.height,
+ left = 0f,
+ right = textPainter.width
+ )
+ }
+
+ // Get selection for the start and end coordinates pair.
+ override fun getSelection(
+ selectionCoordinates: Pair<PxPosition, PxPosition>,
+ containerLayoutCoordinates: LayoutCoordinates,
+ mode: SelectionMode
+ ): Selection? {
+ val relativePosition = containerLayoutCoordinates.childToLocal(
+ layoutCoordinates!!, PxPosition.Origin
+ )
+ val startPx = selectionCoordinates.first - relativePosition
+ val endPx = selectionCoordinates.second - relativePosition
+
+ if (!mode.isSelected(box, start = startPx, end = endPx)) {
+ onSelectionChange(null)
+ return null
+ }
+
+ var textSelectionStart = getSelectionBorder(startPx, true).first
+ var startLayoutCoordinates = getSelectionBorder(startPx, true).second
+
+ var textSelectionEnd = getSelectionBorder(endPx, false).first
+ var endLayoutCoordinates = getSelectionBorder(endPx, false).second
+
+ if (textSelectionStart.offset == textSelectionEnd.offset) {
+ val wordBoundary = textPainter.getWordBoundary(textSelectionStart)
+ textSelectionStart =
+ TextPosition(wordBoundary.start, textSelectionStart.affinity)
+ textSelectionEnd = TextPosition(wordBoundary.end, textSelectionEnd.affinity)
+ } else {
+ // Currently on Android, selection end is the offset after last character.
+ // But when dragging happens, current Crane Text Selection end is the offset
+ // of the last character. Thus before calling drawing selection background,
+ // make the selection end matches Android behaviour.
+ textSelectionEnd =
+ TextPosition(textSelectionEnd.offset + 1, TextAffinity.upstream)
+ }
+
+ onSelectionChange(TextSelection(textSelectionStart.offset, textSelectionEnd.offset))
+
+ // In Crane Text Selection, the selection end should be the last character, thus
+ // make the selection end matches Crane behaviour.
+ textSelectionEnd =
+ TextPosition(textSelectionEnd.offset - 1, TextAffinity.upstream)
+
+ return Selection(
+ startOffset =
+ textPainter.getBoundingBoxForTextPosition(textSelectionStart),
+ endOffset =
+ textPainter.getBoundingBoxForTextPosition(textSelectionEnd),
+ startLayoutCoordinates = startLayoutCoordinates,
+ endLayoutCoordinates = endLayoutCoordinates
+ )
+ }
+
+ /**
+ * This function gets the border of the text selection. Border means either start or end of the
+ * selection.
+ */
+ private fun getSelectionBorder(
+ position: PxPosition,
+ isStart: Boolean
+ ): Pair<TextPosition, LayoutCoordinates?> {
+ // The text position of the border of selection. The default value is set to the beginning
+ // of the text widget for the start border, and the very last position of the text widget
+ // for the end border. If the widget contains the whole selection's border, this value will
+ // be reset.
+ var selectionBorder = TextPosition(
+ offset = if (isStart) 0 else lastTextPosition,
+ affinity = TextAffinity.upstream
+ )
+ // This LayoutCoordinates is for the widget which contains the whole selection's border. If
+ // the current widget does not contain the whole selection's border, this default null value
+ // will be returned.
+ var selectionBorderLayoutCoordinates: LayoutCoordinates? = null
+
+ // If the current text widget contains the whole selection's border, then find the exact
+ // text position of the border, and the LayoutCoordinates of the current widget will be
+ // returned.
+ if (position.x >= box.left.px &&
+ position.x <= box.right.px &&
+ position.y >= box.top.px &&
+ position.y <= box.bottom.px
+ ) {
+ val offset = Offset(position.x.value, position.y.value)
+ // Constrain the position of the selection border to be within the text range of the
+ // current widget.
+ val constrainedSelectionBorderPosition =
+ min(max(textPainter.getPositionForOffset(offset).offset, 0), lastTextPosition)
+ selectionBorder = TextPosition(
+ offset = constrainedSelectionBorderPosition,
+ affinity = TextAffinity.upstream
+ )
+ selectionBorderLayoutCoordinates = layoutCoordinates
+ }
+ return Pair(selectionBorder, selectionBorderLayoutCoordinates)
+ }
+}
diff --git a/ui/text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt b/ui/text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt
index 99f8585..be6506e 100644
--- a/ui/text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt
+++ b/ui/text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt
@@ -24,6 +24,7 @@
import androidx.ui.core.px
import androidx.ui.core.selection.Selection
import androidx.ui.core.selection.SelectionContainer
+import androidx.ui.core.selection.SelectionMode
import androidx.ui.engine.geometry.Offset
import androidx.ui.engine.text.BaselineShift
import androidx.ui.engine.text.FontStyle
@@ -97,6 +98,10 @@
EditLine()
TagLine(tag = "selection")
TextDemoSelection()
+ TagLine(tag = "selection in 2D Array Vertical")
+ TextDemoSelection2DArrayVertical()
+ TagLine(tag = "selection in 2D Array Horizontal")
+ TextDemoSelection2DArrayHorizontal()
TagLine(tag = "composable textspan")
TextDemoComposableTextSpan()
TagLine(tag = "fontSizeScale")
@@ -581,6 +586,93 @@
}
@Composable
+fun TextDemoSelection2DArrayVertical() {
+ var text = ""
+ for (i in 1..3) {
+ text = "$text$displayText" + "\n"
+ }
+
+ val colorList = listOf(
+ Color(0xFFFF0000.toInt()),
+ Color(0xFF00FF00.toInt()),
+ Color(0xFF0000FF.toInt()),
+ Color(0xFF00FFFF.toInt()),
+ Color(0xFFFF00FF.toInt()),
+ Color(0xFFFFFF00.toInt()),
+ Color(0xFF0000FF.toInt()),
+ Color(0xFF00FF00.toInt()),
+ Color(0xFFFF0000.toInt())
+ )
+
+ val selection = +state<Selection?> { null }
+ SelectionContainer(
+ selection = selection.value,
+ selection.value = it }) {
+ Column {
+ for (i in 0..2) {
+ Row {
+ for (j in 0..2) {
+ Text {
+ Span(
+ text = text,
+ style = TextStyle(
+ color = colorList[i * 3 + j],
+ fontSize = fontSize6
+ )
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun TextDemoSelection2DArrayHorizontal() {
+ var text = ""
+ for (i in 1..3) {
+ text = "$text$displayText" + "\n"
+ }
+
+ val colorList = listOf(
+ Color(0xFFFF0000.toInt()),
+ Color(0xFF00FF00.toInt()),
+ Color(0xFF0000FF.toInt()),
+ Color(0xFF00FFFF.toInt()),
+ Color(0xFFFF00FF.toInt()),
+ Color(0xFFFFFF00.toInt()),
+ Color(0xFF0000FF.toInt()),
+ Color(0xFF00FF00.toInt()),
+ Color(0xFFFF0000.toInt())
+ )
+
+ val selection = +state<Selection?> { null }
+ SelectionContainer(
+ selection = selection.value,
+ selection.value = it },
+ mode = SelectionMode.Horizontal) {
+ Column {
+ for (i in 0..2) {
+ Row {
+ for (j in 0..2) {
+ Text {
+ Span(
+ text = text,
+ style = TextStyle(
+ color = colorList[i * 3 + j],
+ fontSize = fontSize6
+ )
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
fun TextDemoComposableTextSpan() {
Text {
Span(text = "This is a ", style = TextStyle(fontSize = fontSize8)) {