diff --git a/foundation/api/foundation.api b/foundation/api/foundation.api index 6fbe2262c..4481fe5e1 100644 --- a/foundation/api/foundation.api +++ b/foundation/api/foundation.api @@ -306,13 +306,13 @@ public final class org/jetbrains/jewel/foundation/lazy/SelectableLazyListState : public final fun getLastActiveItemIndex ()Ljava/lang/Integer; public final fun getLayoutInfo ()Landroidx/compose/foundation/lazy/LazyListLayoutInfo; public final fun getLazyListState ()Landroidx/compose/foundation/lazy/LazyListState; - public fun getSelectedKeys ()Ljava/util/List; + public fun getSelectedKeys ()Ljava/util/Set; public fun isScrollInProgress ()Z public fun scroll (Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun scrollToItem (IZILkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun scrollToItem$default (Lorg/jetbrains/jewel/foundation/lazy/SelectableLazyListState;IZILkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public final fun setLastActiveItemIndex (Ljava/lang/Integer;)V - public fun setSelectedKeys (Ljava/util/List;)V + public fun setSelectedKeys (Ljava/util/Set;)V } public final class org/jetbrains/jewel/foundation/lazy/SelectableLazyListStateKt { @@ -322,8 +322,8 @@ public final class org/jetbrains/jewel/foundation/lazy/SelectableLazyListStateKt } public abstract interface class org/jetbrains/jewel/foundation/lazy/SelectableScope { - public abstract fun getSelectedKeys ()Ljava/util/List; - public abstract fun setSelectedKeys (Ljava/util/List;)V + public abstract fun getSelectedKeys ()Ljava/util/Set; + public abstract fun setSelectedKeys (Ljava/util/Set;)V } public final class org/jetbrains/jewel/foundation/lazy/SelectionMode : java/lang/Enum { @@ -638,12 +638,12 @@ public final class org/jetbrains/jewel/foundation/lazy/tree/TreeState : androidx public fun getCanScrollBackward ()Z public fun getCanScrollForward ()Z public final fun getOpenNodes ()Ljava/util/Set; - public fun getSelectedKeys ()Ljava/util/List; + public fun getSelectedKeys ()Ljava/util/Set; public fun isScrollInProgress ()Z public final fun openNodes (Ljava/util/List;)V public fun scroll (Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun setOpenNodes (Ljava/util/Set;)V - public fun setSelectedKeys (Ljava/util/List;)V + public fun setSelectedKeys (Ljava/util/Set;)V public final fun toggleNode (Ljava/lang/Object;)V } diff --git a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt index b70a32c39..4d1c8ce5d 100644 --- a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt +++ b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt @@ -18,7 +18,7 @@ public interface SelectableColumnOnKeyEvent { for (index in allKeys.indices) { val key = allKeys[index] if (key is Selectable) { - state.selectedKeys = listOf(key.key) + state.selectedKeys = setOf(key.key) state.lastActiveItemIndex = index return } @@ -34,7 +34,7 @@ public interface SelectableColumnOnKeyEvent { state: SelectableLazyListState, ) { val initialIndex = state.lastActiveItemIndex ?: return - val newSelection = ArrayList(max(initialIndex, state.selectedKeys.size)).apply { + val newSelection = HashSet(max(initialIndex, state.selectedKeys.size)).apply { addAll(state.selectedKeys) } var lastActiveItemIndex = initialIndex @@ -59,7 +59,7 @@ public interface SelectableColumnOnKeyEvent { for (index in keys.lastIndex downTo 0) { val key = keys[index] if (key is Selectable) { - state.selectedKeys = listOf(key.key) + state.selectedKeys = setOf(key.key) state.lastActiveItemIndex = index return } @@ -75,7 +75,7 @@ public interface SelectableColumnOnKeyEvent { state: SelectableLazyListState, ) { val initialIndex = state.lastActiveItemIndex ?: return - val newSelection = ArrayList(max(keys.size - initialIndex, state.selectedKeys.size)).apply { + val newSelection = HashSet(max(keys.size - initialIndex, state.selectedKeys.size)).apply { addAll(state.selectedKeys) } var lastActiveItemIndex = initialIndex @@ -101,7 +101,7 @@ public interface SelectableColumnOnKeyEvent { for (index in initialIndex - 1 downTo 0) { val key = keys[index] if (key is Selectable) { - state.selectedKeys = listOf(key.key) + state.selectedKeys = setOf(key.key) state.lastActiveItemIndex = index return } @@ -138,7 +138,7 @@ public interface SelectableColumnOnKeyEvent { for (index in initialIndex + 1..keys.lastIndex) { val key = keys[index] if (key is Selectable) { - state.selectedKeys = listOf(key.key) + state.selectedKeys = setOf(key.key) state.lastActiveItemIndex = index return } @@ -173,7 +173,7 @@ public interface SelectableColumnOnKeyEvent { ) { val visibleSize = state.layoutInfo.visibleItemsInfo.size val targetIndex = max((state.lastActiveItemIndex ?: 0) - visibleSize, 0) - state.selectedKeys = listOf(keys[targetIndex].key) + state.selectedKeys = setOf(keys[targetIndex].key) state.lastActiveItemIndex = targetIndex } @@ -206,7 +206,7 @@ public interface SelectableColumnOnKeyEvent { ) { val visibleSize = state.layoutInfo.visibleItemsInfo.size val targetIndex = min((state.lastActiveItemIndex ?: 0) + visibleSize, keys.lastIndex) - state.selectedKeys = listOf(keys[targetIndex].key) + state.selectedKeys = setOf(keys[targetIndex].key) state.lastActiveItemIndex = targetIndex } @@ -240,7 +240,7 @@ public interface SelectableColumnOnKeyEvent { * Select All. */ public fun onSelectAll(keys: List, state: SelectableLazyListState) { - state.selectedKeys = keys.filterIsInstance().map { it.key } + state.selectedKeys = keys.filterIsInstance().map { it.key }.toSet() } } diff --git a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt index 7fb803578..82ad8398c 100644 --- a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt +++ b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt @@ -21,7 +21,7 @@ public val SelectableLazyListState.visibleItemsRange: IntRange public interface SelectableScope { - public var selectedKeys: List + public var selectedKeys: Set } /** @@ -36,7 +36,7 @@ public class SelectableLazyListState( internal var lastKeyEventUsedMouse: Boolean = false - override var selectedKeys: List by mutableStateOf(emptyList()) + override var selectedKeys: Set by mutableStateOf(emptySet()) public var lastActiveItemIndex: Int? = null diff --git a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/BasicLazyTree.kt b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/BasicLazyTree.kt index de11c75b3..932641286 100644 --- a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/BasicLazyTree.kt +++ b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/BasicLazyTree.kt @@ -15,8 +15,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment @@ -149,8 +149,21 @@ public fun BasicLazyTree( ?: false, ) - val backgroundShape by remember { - mutableStateOf(RoundedCornerShape(elementBackgroundCornerSize)) + val backgroundShape by derivedStateOf { + val hasRoundedTopCorners = flattenedTree.getOrNull(index - 1)?.id?.let { + it !in treeState.delegate.selectedKeys + } ?: false + val hasRoundedBottomCorners = flattenedTree.getOrNull(index + 1)?.id?.let { + it !in treeState.delegate.selectedKeys + } ?: false + val topCornerSize = computerCornerSize(hasRoundedTopCorners, elementBackgroundCornerSize) + val bottomCornerSize = computerCornerSize(hasRoundedBottomCorners, elementBackgroundCornerSize) + RoundedCornerShape( + topStart = topCornerSize, + topEnd = topCornerSize, + bottomEnd = bottomCornerSize, + bottomStart = bottomCornerSize, + ) } Row( verticalAlignment = Alignment.CenterVertically, @@ -201,6 +214,11 @@ public fun BasicLazyTree( } } +private fun computerCornerSize( + isRounded: Boolean, + cornerSize: CornerSize, +) = if (isRounded) cornerSize else CornerSize(0.dp) + private fun Modifier.elementBackground( state: TreeElementState, selectedFocused: Color, diff --git a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/DefaultTreeViewOnKeyEvent.kt b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/DefaultTreeViewOnKeyEvent.kt index 33bfd4d86..614489d33 100644 --- a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/DefaultTreeViewOnKeyEvent.kt +++ b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/DefaultTreeViewOnKeyEvent.kt @@ -41,7 +41,7 @@ public open class DefaultTreeViewOnKeyEvent( ?.let { state.lastActiveItemIndex = keys.indexOfFirst { selectableKey -> selectableKey.key == parentNodeKey } - state.selectedKeys = listOf(parentNodeKey) + state.selectedKeys = setOf(parentNodeKey) } } } @@ -59,7 +59,7 @@ public open class DefaultTreeViewOnKeyEvent( if (keys[i].key in keyNodeList) { if (keys[i] is SelectableLazyListKey.Selectable) { state.lastActiveItemIndex = i - state.selectedKeys = listOf(keys[i].key) + state.selectedKeys = setOf(keys[i].key) } break } diff --git a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/KeyActions.kt b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/KeyActions.kt index 4072bc6f1..a1b0842f5 100644 --- a/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/KeyActions.kt +++ b/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/tree/KeyActions.kt @@ -82,7 +82,7 @@ public open class DefaultSelectableLazyColumnEventAction : PointerEventActions { } else -> { - selectableLazyListState.selectedKeys = listOf(key) + selectableLazyListState.selectedKeys = setOf(key) selectableLazyListState.lastActiveItemIndex = allKeys.indexOfFirst { it.key == key } } } @@ -94,12 +94,10 @@ public open class DefaultSelectableLazyColumnEventAction : PointerEventActions { allKeys: List, selectableLazyListState: SelectableLazyListState, ) { - if (selectableLazyListState.selectedKeys.contains(key)) { - selectableLazyListState.selectedKeys = - selectableLazyListState.selectedKeys.toMutableList().also { it.remove(key) } + selectableLazyListState.selectedKeys = if (selectableLazyListState.selectedKeys.contains(key)) { + selectableLazyListState.selectedKeys - key } else { - selectableLazyListState.selectedKeys = - selectableLazyListState.selectedKeys.toMutableList().also { it.add(key) } + selectableLazyListState.selectedKeys + key } selectableLazyListState.lastActiveItemIndex = allKeys.indexOfFirst { it == key } } @@ -112,7 +110,7 @@ public open class DefaultSelectableLazyColumnEventAction : PointerEventActions { ) { if (selectionMode == SelectionMode.None) return if (selectionMode == SelectionMode.Single) { - state.selectedKeys = listOf(key) + state.selectedKeys = setOf(key) } else { val currentIndex = allKeys.indexOfFirst { it.key == key }.coerceAtLeast(0) val lastFocussed = state.lastActiveItemIndex ?: currentIndex @@ -133,7 +131,7 @@ public open class DefaultSelectableLazyColumnEventAction : PointerEventActions { } } } - state.selectedKeys = state.selectedKeys.toMutableList().also { it.addAll(keys) } + state.selectedKeys += keys state.lastActiveItemIndex = allKeys.indexOfFirst { it.key == key } } } @@ -165,9 +163,8 @@ public class DefaultTreeViewPointerEventAction( selectableLazyListState.lastKeyEventUsedMouse = false super.toggleKeySelection(key, allKeys, selectableLazyListState) } - else -> { - selectableLazyListState.selectedKeys = listOf(key) + selectableLazyListState.selectedKeys = setOf(key) } } }