From 2327a7228630621a6f980ad6537c158c8759f746 Mon Sep 17 00:00:00 2001 From: Ivan Morgillo Date: Wed, 16 Oct 2024 11:01:13 +0200 Subject: [PATCH] restore basic onHover behavior for ListComboBox Signed-off-by: Ivan Morgillo --- .../ideplugin/SwingComparisonTabPanel.kt | 3 -- .../standalone/view/component/Dropdowns.kt | 18 ++++-------- .../src/test/kotlin/ListComboBoxUiTest.kt | 3 +- .../jewel/ui/component/ListComboBox.kt | 22 +++++++++++++- .../jewel/ui/component/SimpleListItem.kt | 29 +++++++++---------- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/SwingComparisonTabPanel.kt b/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/SwingComparisonTabPanel.kt index 004b2ecb8..dd8d7fb3b 100644 --- a/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/SwingComparisonTabPanel.kt +++ b/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/SwingComparisonTabPanel.kt @@ -261,7 +261,6 @@ internal class SwingComparisonTabPanel : BorderLayoutPanel() { text = item, isSelected = isSelected, isHovered = isItemHovered, - isListHovered = isListHovered, style = JewelTheme.comboBoxStyle.itemStyle, contentDescription = item, ) @@ -283,7 +282,6 @@ internal class SwingComparisonTabPanel : BorderLayoutPanel() { text = item, isSelected = isSelected, isHovered = isItemHovered, - isListHovered = isListHovered, style = JewelTheme.comboBoxStyle.itemStyle, contentDescription = item, ) @@ -304,7 +302,6 @@ internal class SwingComparisonTabPanel : BorderLayoutPanel() { text = item, isSelected = isSelected, isHovered = isItemHovered, - isListHovered = isListHovered, style = JewelTheme.comboBoxStyle.itemStyle, contentDescription = item, ) diff --git a/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/component/Dropdowns.kt b/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/component/Dropdowns.kt index 458280634..0d6543f79 100644 --- a/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/component/Dropdowns.kt +++ b/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/component/Dropdowns.kt @@ -17,6 +17,7 @@ import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.ui.Outline import org.jetbrains.jewel.ui.component.Dropdown import org.jetbrains.jewel.ui.component.ListComboBox +import org.jetbrains.jewel.ui.component.ListItemState import org.jetbrains.jewel.ui.component.SimpleListItem import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.Typography @@ -180,8 +181,6 @@ fun Dropdowns() { var selectedComboBox2: String? by remember { mutableStateOf(comboBoxItems.first()) } var selectedComboBox3: String? by remember { mutableStateOf(comboBoxItems.first()) } - var isListHovered1 by remember { mutableStateOf(false) } - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Text(text = "ComboBoxes", style = Typography.h1TextStyle()) Text(text = "Selected item: $selectedComboBox1") @@ -195,15 +194,12 @@ fun Dropdowns() { modifier = Modifier.width(200.dp), maxPopupHeight = 150.dp, onSelectedItemChange = { selectedComboBox1 = it }, - onListHoverChange = { isListHovered1 = it }, listItemContent = { item, isSelected, isFocused, isItemHovered, isListHovered -> SimpleListItem( text = item, - isSelected = isSelected && !isListHovered1, - isHovered = isItemHovered, - isListHovered = isListHovered, - style = JewelTheme.comboBoxStyle.itemStyle, modifier = Modifier, + state = ListItemState(isSelected, isListHovered, isItemHovered), + style = JewelTheme.comboBoxStyle.itemStyle, contentDescription = item, ) }, @@ -223,9 +219,7 @@ fun Dropdowns() { listItemContent = { item, isSelected, isFocused, isItemHovered, isListHovered -> SimpleListItem( text = item, - isSelected = isSelected, - isHovered = isItemHovered, - isListHovered = isListHovered, + state = ListItemState(isSelected, isListHovered, isItemHovered), style = JewelTheme.comboBoxStyle.itemStyle, contentDescription = item, ) @@ -244,9 +238,7 @@ fun Dropdowns() { listItemContent = { item, isSelected, isFocused, isItemHovered, isListHovered -> SimpleListItem( text = item, - isSelected = isSelected, - isHovered = isItemHovered, - isListHovered = isListHovered, + state = ListItemState(isSelected, isListHovered, isItemHovered), style = JewelTheme.comboBoxStyle.itemStyle, contentDescription = item, ) diff --git a/ui-tests/src/test/kotlin/ListComboBoxUiTest.kt b/ui-tests/src/test/kotlin/ListComboBoxUiTest.kt index b5ca85b0c..235c92c79 100644 --- a/ui-tests/src/test/kotlin/ListComboBoxUiTest.kt +++ b/ui-tests/src/test/kotlin/ListComboBoxUiTest.kt @@ -469,11 +469,10 @@ class ListComboBoxUiTest { listItemContent = { item, isSelected, isFocused, isItemHovered, isListHovered -> SimpleListItem( text = item, + modifier = Modifier.testTag(item), isSelected = isSelected, isHovered = isItemHovered, - isListHovered = isListHovered, style = JewelTheme.comboBoxStyle.itemStyle, - modifier = Modifier.testTag(item), contentDescription = item, ) }, diff --git a/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/ListComboBox.kt b/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/ListComboBox.kt index 962b140a5..929cb6d43 100644 --- a/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/ListComboBox.kt +++ b/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/ListComboBox.kt @@ -44,6 +44,8 @@ public fun ListComboBox( val scrollState = rememberSelectableLazyListState() var selectedItem by remember { mutableIntStateOf(0) } var isListHovered by remember { mutableStateOf(false) } + var hoverItemIndex by remember { mutableStateOf(-1) } + var softSelection by remember { mutableStateOf(isListHovered) } val scope = rememberCoroutineScope() LaunchedEffect(selectedItem) { scrollState.selectedKeys = setOf(items[selectedItem]) } @@ -56,10 +58,18 @@ public fun ListComboBox( } val onArrowDownPress: () -> Unit = { + if (hoverItemIndex != -1) { + selectedItem = hoverItemIndex + hoverItemIndex = -1 + } selectedItem = selectedItem.plus(1).coerceAtMost(items.lastIndex) scope.launch { scrollState.lazyListState.scrollToIndex(selectedItem) } } val onArrowUpPress: () -> Unit = { + if (hoverItemIndex != -1) { + selectedItem = hoverItemIndex + hoverItemIndex = -1 + } selectedItem = selectedItem.minus(1).coerceAtLeast(0) scope.launch { scrollState.lazyListState.scrollToIndex(selectedItem) } } @@ -88,6 +98,7 @@ public fun ListComboBox( modifier = Modifier.heightIn(max = popupMaxHeight).onHover { isListHovered = it + if (!isListHovered) hoverItemIndex = -1 onListHoverChange(it) }, ) { @@ -113,11 +124,18 @@ public fun ListComboBox( Modifier.onHover { isItemHovered = it if (isItemHovered) { + hoverItemIndex = items.indexOf(item) onHoverItemChange(item) } } ) { - listItemContent(item, isSelected, isActive, isItemHovered, isListHovered) + listItemContent( + item, + isSelected, + isActive, + isItemHovered && hoverItemIndex != -1, + isListHovered, + ) } }, ) @@ -143,6 +161,7 @@ public fun ListComboBox( modifier = Modifier.heightIn(max = popupMaxHeight).onHover { isListHovered = it + if (!isListHovered) hoverItemIndex = -1 onListHoverChange(it) }, ) { @@ -168,6 +187,7 @@ public fun ListComboBox( Modifier.onHover { isHovered = it if (isHovered) { + hoverItemIndex = items.indexOf(item) onHoverItemChange(item) } } diff --git a/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/SimpleListItem.kt b/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/SimpleListItem.kt index eb5689827..4466cdd2f 100644 --- a/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/SimpleListItem.kt +++ b/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/SimpleListItem.kt @@ -16,39 +16,29 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import org.jetbrains.jewel.foundation.GenerateDataFunctions import org.jetbrains.jewel.foundation.theme.JewelTheme -import org.jetbrains.jewel.foundation.util.JewelLogger import org.jetbrains.jewel.ui.component.styling.SimpleListItemStyle import org.jetbrains.jewel.ui.icon.IconKey +import org.jetbrains.jewel.ui.theme.comboBoxStyle @Composable public fun SimpleListItem( text: String, - isSelected: Boolean, - isHovered: Boolean, - isListHovered: Boolean, - style: SimpleListItemStyle, modifier: Modifier = Modifier, + state: ListItemState, + style: SimpleListItemStyle = JewelTheme.comboBoxStyle.itemStyle, height: Dp = JewelTheme.globalMetrics.rowHeight, icon: IconKey? = null, contentDescription: String? = null, ) { - - JewelLogger.getInstance("Jewel.SimpleListItem") - .debug("$text isSelected: $isSelected, isHovered: $isHovered, islistHovered: $isListHovered") - - val color = - when { - isSelected -> style.colors.backgroundSelectedFocused - isHovered -> style.colors.backgroundSelectedFocused - else -> Color.Transparent - } + val color = if (state.isHovered) style.colors.backgroundSelectedFocused else Color.Transparent Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier - .semantics { selected = isSelected } + .semantics { selected = state.isSelected } .fillMaxWidth() .height(height) .padding(style.metrics.outerPadding) @@ -61,3 +51,10 @@ public fun SimpleListItem( Text(text = text, maxLines = 1, overflow = TextOverflow.Ellipsis, style = JewelTheme.defaultTextStyle) } } + +@GenerateDataFunctions +public class ListItemState( + public val isSelected: Boolean, + public val isSoftSelected: Boolean, + public val isHovered: Boolean, +)