mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
fix(jetbrains): align picker popup selection
This commit is contained in:
+34
@@ -0,0 +1,34 @@
|
||||
package ai.kilocode.client.session.ui
|
||||
|
||||
import com.intellij.openapi.ui.popup.util.PopupUtil
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.popup.list.SelectablePanel
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import java.awt.BorderLayout
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JList
|
||||
|
||||
internal class PickerRow : SelectablePanel() {
|
||||
init {
|
||||
layout = BorderLayout()
|
||||
isOpaque = true
|
||||
}
|
||||
|
||||
fun setContent(component: JComponent) {
|
||||
accessibleContextProvider = component
|
||||
add(component, BorderLayout.CENTER)
|
||||
}
|
||||
|
||||
fun update(list: JList<*>, selected: Boolean, focused: Boolean) {
|
||||
background = list.background
|
||||
selectionColor = if (selected) UIUtil.getListBackground(true, focused) else null
|
||||
if (ExperimentalUI.isNewUI()) {
|
||||
PopupUtil.configListRendererFlexibleHeight(this)
|
||||
return
|
||||
}
|
||||
border = JBUI.Borders.empty()
|
||||
selectionArc = 0
|
||||
selectionInsets = JBUI.emptyInsets()
|
||||
}
|
||||
}
|
||||
+1
@@ -79,6 +79,7 @@ class ModePicker : JBLabel() {
|
||||
.setCancelKeyEnabled(true)
|
||||
.setResizable(false)
|
||||
.setMovable(false)
|
||||
.setAutoselectOnMouseMove(true)
|
||||
.setItemChosenCallback { value ->
|
||||
selected = value
|
||||
refresh()
|
||||
|
||||
+7
-5
@@ -1,6 +1,7 @@
|
||||
package ai.kilocode.client.session.ui.mode
|
||||
|
||||
import ai.kilocode.client.plugin.KiloBundle
|
||||
import ai.kilocode.client.session.ui.PickerRow
|
||||
import ai.kilocode.client.ui.UiStyle
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ui.RoundedLineBorder
|
||||
@@ -51,10 +52,11 @@ internal class ModePickerRenderer(
|
||||
UiStyle.Components.transparent(this)
|
||||
}
|
||||
private val row = JPanel(BorderLayout())
|
||||
private val wrap = PickerRow()
|
||||
|
||||
init {
|
||||
isOpaque = true
|
||||
row.isOpaque = true
|
||||
UiStyle.Components.transparent(this)
|
||||
UiStyle.Components.transparent(row)
|
||||
(row.layout as BorderLayout).hgap = UiStyle.Gap.inline()
|
||||
row.border = JBUI.Borders.empty(
|
||||
UiStyle.Space.MD,
|
||||
@@ -66,7 +68,8 @@ internal class ModePickerRenderer(
|
||||
body.add(desc, BorderLayout.CENTER)
|
||||
row.add(icon, BorderLayout.WEST)
|
||||
row.add(body, BorderLayout.CENTER)
|
||||
add(row, BorderLayout.CENTER)
|
||||
wrap.setContent(row)
|
||||
add(wrap, BorderLayout.CENTER)
|
||||
}
|
||||
|
||||
override fun getListCellRendererComponent(
|
||||
@@ -78,12 +81,11 @@ internal class ModePickerRenderer(
|
||||
): JPanel {
|
||||
val focus = selected || list.hasFocus() || focused
|
||||
val fg = UIUtil.getListForeground(selected, focus)
|
||||
val bg = if (selected) UIUtil.getListBackground(true, focus) else list.background
|
||||
val weak = if (selected) fg else UiStyle.Colors.weak()
|
||||
val warn = if (selected) fg else UiStyle.Colors.warning()
|
||||
|
||||
background = list.background
|
||||
row.background = bg
|
||||
wrap.update(list, selected, focus)
|
||||
title.clear()
|
||||
title.append(value.display, SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, fg))
|
||||
desc.clear()
|
||||
|
||||
+1
@@ -119,6 +119,7 @@ class ModelPicker : JBLabel() {
|
||||
emptyText.text = KiloBundle.message("model.picker.no.matches")
|
||||
background = popupBackground
|
||||
border = JBUI.Borders.empty(PopupUtil.getListInsets(false, false))
|
||||
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
|
||||
}
|
||||
list.cellRenderer = ModelPickerRenderer(
|
||||
model = model,
|
||||
|
||||
+21
-9
@@ -1,9 +1,11 @@
|
||||
package ai.kilocode.client.session.ui.model
|
||||
|
||||
import ai.kilocode.client.plugin.KiloBundle
|
||||
import ai.kilocode.client.session.ui.PickerRow
|
||||
import ai.kilocode.client.ui.UiStyle
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ui.CollectionListModel
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.GroupHeaderSeparator
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.SimpleColoredComponent
|
||||
@@ -41,11 +43,20 @@ internal class ModelPickerRenderer(
|
||||
|
||||
fun isFavoriteClick(list: JList<*>, bounds: Rectangle, point: Point): Boolean {
|
||||
val width = JBUI.scale(FAVORITE_CLICK_AREA_WIDTH)
|
||||
return if (list.componentOrientation.isLeftToRight) {
|
||||
point.x >= bounds.x + bounds.width - width
|
||||
} else {
|
||||
point.x <= bounds.x + width
|
||||
val inset = favoriteInset(list)
|
||||
if (list.componentOrientation.isLeftToRight) {
|
||||
val right = bounds.x + bounds.width - inset
|
||||
return point.x in (right - width)..right
|
||||
}
|
||||
val left = bounds.x + inset
|
||||
return point.x in left..(left + width)
|
||||
}
|
||||
|
||||
private fun favoriteInset(list: JList<*>): Int {
|
||||
if (!ExperimentalUI.isNewUI()) return 0
|
||||
val inner = JBUI.CurrentTheme.Popup.Selection.innerInsets()
|
||||
val edge = JBUI.CurrentTheme.Popup.Selection.LEFT_RIGHT_INSET.get()
|
||||
return edge + if (list.componentOrientation.isLeftToRight) inner.right else inner.left
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,11 +88,12 @@ internal class ModelPickerRenderer(
|
||||
add(head, BorderLayout.CENTER)
|
||||
add(star, BorderLayout.EAST)
|
||||
}
|
||||
private val wrap = PickerRow()
|
||||
|
||||
init {
|
||||
isOpaque = true
|
||||
top.isOpaque = true
|
||||
row.isOpaque = true
|
||||
UiStyle.Components.transparent(row)
|
||||
UiStyle.Components.transparent(check)
|
||||
UiStyle.Components.transparent(title)
|
||||
UiStyle.Components.transparent(head)
|
||||
@@ -93,8 +105,9 @@ internal class ModelPickerRenderer(
|
||||
UiStyle.Space.MD,
|
||||
UiStyle.Space.LG + UiStyle.Space.SM,
|
||||
)
|
||||
wrap.setContent(row)
|
||||
add(top, BorderLayout.NORTH)
|
||||
add(row, BorderLayout.CENTER)
|
||||
add(wrap, BorderLayout.CENTER)
|
||||
}
|
||||
|
||||
override fun getListCellRendererComponent(
|
||||
@@ -103,17 +116,16 @@ internal class ModelPickerRenderer(
|
||||
index: Int,
|
||||
selected: Boolean,
|
||||
focused: Boolean,
|
||||
): Component {
|
||||
): JPanel {
|
||||
val focus = selected || list.hasFocus() || focused
|
||||
val fg = UIUtil.getListForeground(selected, focus)
|
||||
val bg = if (selected) UIUtil.getListBackground(true, focus) else list.background
|
||||
val weak = if (selected) fg else UiStyle.Colors.weak()
|
||||
val current = model.items.getOrNull(index)
|
||||
val section = if (current === value) modelPickerSectionTitle(model.items, index) else null
|
||||
|
||||
background = list.background
|
||||
top.background = list.background
|
||||
row.background = bg
|
||||
wrap.update(list, selected, focus)
|
||||
sep.caption = section
|
||||
sep.setHideLine(index == 0)
|
||||
top.isVisible = section != null
|
||||
|
||||
+1
@@ -105,4 +105,5 @@ class ModePickerTest : BasePlatformTestCase() {
|
||||
cell.getListCellRendererComponent(list, code, 1, false, false)
|
||||
assertFalse(renderer.badgeVisible())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
-2
@@ -3,9 +3,11 @@ package ai.kilocode.client.session.ui.model
|
||||
import ai.kilocode.rpc.dto.ModelSelectionDto
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ui.CollectionListModel
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.components.JBList
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import com.intellij.util.ui.EmptyIcon
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.ComponentOrientation
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
@@ -228,15 +230,28 @@ class ModelPickerTest : BasePlatformTestCase() {
|
||||
fun `test favorite click area uses trailing edge in both orientations`() {
|
||||
val list = JBList(listOf<ModelPickerRow>())
|
||||
val bounds = Rectangle(10, 0, 100, 20)
|
||||
val inset = favoriteInset(list)
|
||||
|
||||
assertTrue(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(100, 10)))
|
||||
assertTrue(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(100 - inset, 10)))
|
||||
assertFalse(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(20, 10)))
|
||||
|
||||
list.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT
|
||||
assertTrue(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(20, 10)))
|
||||
val rtl = favoriteInset(list)
|
||||
assertTrue(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(20 + rtl, 10)))
|
||||
assertFalse(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(100, 10)))
|
||||
}
|
||||
|
||||
fun `test favorite click area ignores popup selection inset outside row content`() {
|
||||
val list = JBList(listOf<ModelPickerRow>())
|
||||
val bounds = Rectangle(10, 0, 100, 20)
|
||||
val inset = favoriteInset(list)
|
||||
|
||||
if (inset <= 0) return
|
||||
|
||||
assertFalse(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(bounds.x + bounds.width - 1, 10)))
|
||||
assertTrue(ModelPickerRenderer.isFavoriteClick(list, bounds, Point(bounds.x + bounds.width - inset, 10)))
|
||||
}
|
||||
|
||||
fun `test renderer shows free badge for free model`() {
|
||||
val row = ModelPickerRow(ModelPicker.Item("auto", "Auto", "kilo", "Kilo", free = true), "Kilo", false)
|
||||
val model = CollectionListModel(listOf(row))
|
||||
@@ -256,4 +271,11 @@ class ModelPickerTest : BasePlatformTestCase() {
|
||||
index: Double? = null,
|
||||
free: Boolean = false,
|
||||
) = ModelPicker.Item(id, display, provider, name, index, free = free)
|
||||
|
||||
private fun favoriteInset(list: JBList<*>): Int {
|
||||
if (!ExperimentalUI.isNewUI()) return 0
|
||||
val inner = JBUI.CurrentTheme.Popup.Selection.innerInsets()
|
||||
val edge = JBUI.CurrentTheme.Popup.Selection.LEFT_RIGHT_INSET.get()
|
||||
return edge + if (list.componentOrientation.isLeftToRight) inner.right else inner.left
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user