@@ -26,8 +26,9 @@ import com.lambda.config.SettingEditorDsl
2626import com.lambda.config.SettingGroupEditor
2727import com.lambda.context.SafeContext
2828import com.lambda.gui.dsl.ImGuiBuilder
29- import com.lambda.util.StringUtils.levenshteinDistance
29+ import com.lambda.threading.runSafe
3030import imgui.ImGuiListClipper
31+ import imgui.callback.ImListClipperCallback
3132import imgui.flag.ImGuiChildFlags
3233import imgui.flag.ImGuiSelectableFlags.DontClosePopups
3334import java.lang.reflect.Type
@@ -58,41 +59,50 @@ open class CollectionSetting<R : Any>(
5859 val deselectListeners = mutableListOf<SafeContext .(R ) - > Unit > ()
5960
6061 context(setting: Setting <* , MutableCollection <R >>)
61- override fun ImGuiBuilder.buildLayout () {
62- val text = if (value.size == 1 ) " item" else " items"
63-
64- combo(" ##${setting.name} " , " ${setting.name} : ${value.size} $text " ) {
65- inputText(" ##${setting.name} -SearchBox" , ::searchFilter)
66-
67- child(
68- strId = " ##${setting.name} -ComboOptionsChild" ,
69- childFlags = ImGuiChildFlags .AutoResizeY or ImGuiChildFlags .AlwaysAutoResize ,
70- ) {
71- val list = immutableCollection
72- .filter { searchFilter == " " || searchFilter.levenshteinDistance(it.toString()) < 3 }
73-
74- ImGuiListClipper .forEach { // not actually iterating
75- it.begin(list.size)
76-
77- while (it.step()) {
78- for (i in it.displayStart.. it.displayEnd) {
79- val v = list.getOrNull(i) ? : continue
80- val selected = value.contains(v)
81-
82- selectable(
83- label = v.toString(),
84- selected = selected,
85- flags = DontClosePopups
86- ) {
87- if (selected) value.remove(v)
88- else value.add(v)
89- }
90- }
91- }
92- }
93- }
94- }
95- }
62+ override fun ImGuiBuilder.buildLayout () = buildComboBox(" item" )
63+
64+ context(setting: Setting <* , MutableCollection <R >>)
65+ fun ImGuiBuilder.buildComboBox (itemName : String ) {
66+ val text = if (value.size == 1 ) itemName else " ${itemName} s"
67+
68+ combo(" ##${setting.name} " , " ${setting.name} : ${value.size} $text " ) {
69+ inputText(" ##${setting.name} -SearchBox" , ::searchFilter)
70+
71+ child(
72+ strId = " ##${setting.name} -ComboOptionsChild" ,
73+ childFlags = ImGuiChildFlags .AutoResizeY or ImGuiChildFlags .AlwaysAutoResize ,
74+ ) {
75+ val list = immutableCollection
76+ .filter { item ->
77+ val q = searchFilter.trim()
78+ if (q.isEmpty()) true
79+ else item.toString().startsWith(q, ignoreCase = true )
80+ }
81+
82+ val listClipperCallback = object : ImListClipperCallback () {
83+ override fun accept (index : Int ) {
84+ val v = list.getOrNull(index) ? : return
85+ val selected = value.contains(v)
86+
87+ selectable(
88+ label = v.toString(),
89+ selected = selected,
90+ flags = DontClosePopups
91+ ) {
92+ if (selected) {
93+ value.remove(v)
94+ runSafe { deselectListeners.forEach { listener -> listener(v) } }
95+ } else {
96+ value.add(v)
97+ runSafe { selectListeners.forEach { listener -> listener(v) } }
98+ }
99+ }
100+ }
101+ }
102+ ImGuiListClipper .forEach(list.size, listClipperCallback)
103+ }
104+ }
105+ }
96106
97107 context(setting: Setting <* , MutableCollection <R >>)
98108 override fun toJson (): JsonElement =
0 commit comments