Skip to content

Commit e5993a4

Browse files
committed
feat(gui): refactor AutoDevVariableListComponent to use JBList and add support for variable selection popup #51
The AutoDevVariableListComponent has been refactored to use a JBList instead of a custom component. This change improves the user experience by providing a standard list component with a cell renderer that can be easily customized. Additionally, a new popup has been added to allow for the selection of variables. The popup is created using the JBPopupFactory and is displayed above the input component. The popup's size is dynamically adjusted to fit the available space.
1 parent 8b54522 commit e5993a4

File tree

3 files changed

+105
-18
lines changed

3 files changed

+105
-18
lines changed

src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevInputSection.kt

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,33 @@ import com.intellij.openapi.ui.ComponentValidator
2323
import com.intellij.openapi.ui.ValidationInfo
2424
import com.intellij.openapi.ui.popup.JBPopup
2525
import com.intellij.openapi.ui.popup.JBPopupFactory
26+
import com.intellij.openapi.ui.popup.JBPopupListener
27+
import com.intellij.openapi.ui.popup.LightweightWindowEvent
2628
import com.intellij.openapi.wm.IdeFocusManager
2729
import com.intellij.openapi.wm.impl.InternalDecorator
2830
import com.intellij.temporary.gui.block.AutoDevCoolBorder
2931
import com.intellij.ui.JBColor
3032
import com.intellij.ui.MutableCollectionComboBoxModel
3133
import com.intellij.ui.SimpleListCellRenderer
34+
import com.intellij.ui.awt.RelativePoint
3235
import com.intellij.ui.components.JBLabel
3336
import com.intellij.ui.content.ContentManager
3437
import com.intellij.util.EventDispatcher
3538
import com.intellij.util.ui.JBEmptyBorder
3639
import com.intellij.util.ui.JBUI
3740
import com.intellij.util.ui.UIUtil
3841
import com.intellij.util.ui.components.BorderLayoutPanel
39-
import com.intellij.vcsUtil.showAbove
4042
import kotlinx.serialization.decodeFromString
4143
import kotlinx.serialization.json.Json
4244
import java.awt.Color
4345
import java.awt.Component
4446
import java.awt.Dimension
47+
import java.awt.Point
4548
import java.awt.event.MouseAdapter
4649
import java.awt.event.MouseEvent
4750
import java.util.function.Supplier
4851
import javax.swing.Box
4952
import javax.swing.JComponent
50-
import javax.swing.JTextField
5153
import kotlin.math.max
5254
import kotlin.math.min
5355

@@ -106,11 +108,15 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
106108

107109
// check new input == $
108110
if (event.newFragment.contentEquals("$") || event.newFragment.contentEquals("¥")) {
111+
if (popup?.isVisible == true) {
112+
popup?.cancel()
113+
}
114+
109115
if (popup?.isDisposed == true) {
110116
popup = createPopup()
111-
popup?.showAbove(input)
117+
showPopupAbove(popup!!, this@AutoDevInputSection)
112118
} else {
113-
popup?.showAbove(input)
119+
showPopupAbove(popup!!, this@AutoDevInputSection)
114120
}
115121
}
116122
}
@@ -169,10 +175,13 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
169175
tokenizer = TokenizerImpl.INSTANCE
170176
}
171177

172-
private fun createPopup() = JBPopupFactory.getInstance().createComponentPopupBuilder(AutoDevVariableListComponent(), null)
178+
private fun createPopup() = JBPopupFactory.getInstance()
179+
.createComponentPopupBuilder(AutoDevVariableList(listOf(
180+
AutoDevVariableListComponent(),
181+
) ,null), null )
173182
.setRequestFocus(false)
174183
.setMinSize(
175-
Dimension(200, 200)
184+
Dimension(this@AutoDevInputSection.width, 0)
176185
).createPopup()
177186

178187

@@ -266,4 +275,19 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
266275
}
267276

268277
val focusableComponent: JComponent get() = input
269-
}
278+
}
279+
280+
fun showPopupAbove(popup: JBPopup, component: Component) {
281+
val northWest = RelativePoint(component, Point())
282+
283+
popup.addListener(object : JBPopupListener {
284+
override fun beforeShown(event: LightweightWindowEvent) {
285+
val location = Point(popup.locationOnScreen).apply { y = northWest.screenPoint.y - popup.size.height }
286+
287+
popup.setLocation(location)
288+
popup.removeListener(this)
289+
}
290+
})
291+
292+
popup.show(northWest)
293+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package cc.unitmesh.devti.gui.chat
2+
3+
import com.intellij.ui.Gray
4+
import com.intellij.ui.JBColor
5+
import com.intellij.ui.components.JBList
6+
import java.awt.Component
7+
import java.awt.event.MouseEvent
8+
import java.awt.event.MouseListener
9+
import javax.swing.*
10+
import javax.swing.border.Border
11+
import javax.swing.event.MouseInputAdapter
12+
13+
class AutoDevVariableList(
14+
val list: List<AutoDevVariableListComponent>,
15+
val callback: ((AutoDevVariableListComponent) -> Unit?)?,
16+
) : JBList<AutoDevVariableListComponent>() {
17+
init {
18+
border = BorderFactory.createEmptyBorder(0, 5, 0, 5)
19+
setCellRenderer(VariableListCellRenderer())
20+
addMouseListener(object : MouseInputAdapter() {
21+
override fun mouseClicked(event: MouseEvent?) {
22+
val item = selectedValue ?: return
23+
callback?.invoke(item)
24+
}
25+
} as MouseListener)
26+
}
27+
}
28+
29+
class VariableListCellRenderer : ListCellRenderer<AutoDevVariableListComponent> {
30+
private var emptyBorder: Border = BorderFactory.createEmptyBorder(1, 1, 1, 1)
31+
32+
override fun getListCellRendererComponent(
33+
jList: JList<out AutoDevVariableListComponent>,
34+
value: AutoDevVariableListComponent?,
35+
index: Int,
36+
isSelected: Boolean,
37+
cellHasFocus: Boolean,
38+
): Component {
39+
if (isSelected) {
40+
value!!.background = jList.selectionBackground
41+
value.foreground = jList.selectionForeground
42+
} else {
43+
value!!.background = jList.getBackground()
44+
value.foreground = jList.getForeground()
45+
}
46+
value.isEnabled = jList.isEnabled
47+
value.font = jList.font
48+
49+
var border: Border? = null
50+
if (cellHasFocus) {
51+
if (isSelected) {
52+
border = UIManager.getBorder("List.focusSelectedCellHighlightBorder")
53+
}
54+
if (border == null) {
55+
border = UIManager.getBorder("List.focusCellHighlightBorder")
56+
}
57+
} else {
58+
border = this.emptyBorder
59+
}
60+
61+
value.border = border
62+
return value
63+
}
64+
65+
}
66+
67+
class AutoDevVariableListComponent : JPanel() {
68+
init {
69+
val label = JLabel("doing something")
70+
label.border = BorderFactory.createEmptyBorder(0, 8, 0, 0)
71+
label.foreground = JBColor.namedColor("Component.infoForeground", JBColor(Gray.x99, Gray.x78))
72+
add(label, "East")
73+
}
74+
}

src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevVariableListComponent.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)