Implemented dual list selection widgets for choosing modules.
This commit is contained in:
159
src/client/views/widgets/dualListSelection.nim
Normal file
159
src/client/views/widgets/dualListSelection.nim
Normal file
@@ -0,0 +1,159 @@
|
||||
import strutils
|
||||
import imguin/[cimgui, glfw_opengl, simple]
|
||||
import ../../utils/[appImGui, colors]
|
||||
import ../../../common/[types, utils]
|
||||
|
||||
type
|
||||
Direction = enum
|
||||
Right = 0
|
||||
Left = 1
|
||||
|
||||
DualListSelectionComponent* = ref object of RootObj
|
||||
items: array[2, seq[string]]
|
||||
selection: array[2, ptr ImGuiSelectionBasicStorage]
|
||||
|
||||
proc DualListSelection*(items: seq[string]): DualListSelectionComponent =
|
||||
result = new DualListSelectionComponent
|
||||
result.items[0] = items
|
||||
result.items[1] = @[]
|
||||
result.selection[0] = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||
result.selection[1] = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||
|
||||
proc moveAll(component: DualListSelectionComponent, direction: Direction) =
|
||||
|
||||
if direction == Right:
|
||||
for m in component.items[0]:
|
||||
component.items[1].add(m)
|
||||
component.items[0].setLen(0)
|
||||
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[0], component.selection[1])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[0])
|
||||
|
||||
else:
|
||||
for m in component.items[1]:
|
||||
component.items[0].add(m)
|
||||
component.items[1].setLen(0)
|
||||
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[1], component.selection[0])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[1])
|
||||
|
||||
proc moveSelection(component: DualListSelectionComponent, direction: Direction) =
|
||||
|
||||
if direction == Right:
|
||||
var
|
||||
keep: seq[string]
|
||||
|
||||
for i in 0 ..< component.items[0].len():
|
||||
let item = component.items[0][i]
|
||||
if not component.selection[0].ImGuiSelectionBasicStorage_Contains(cast[ImGuiID](i)):
|
||||
keep.add(item)
|
||||
continue
|
||||
component.items[1].add(item)
|
||||
component.items[0] = keep
|
||||
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[0], component.selection[1])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[0])
|
||||
|
||||
else:
|
||||
var
|
||||
keep: seq[string]
|
||||
|
||||
for i in 0 ..< component.items[1].len():
|
||||
let item = component.items[1][i]
|
||||
if not component.selection[1].ImGuiSelectionBasicStorage_Contains(cast[ImGuiID](i)):
|
||||
keep.add(item)
|
||||
continue
|
||||
component.items[0].add(item)
|
||||
component.items[1] = keep
|
||||
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[1], component.selection[0])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[1])
|
||||
|
||||
proc draw*(component: DualListSelectionComponent) =
|
||||
|
||||
if igBeginTable("split", 3, ImGuiTableFlags_None.int32, vec2(0.0f, 0.0f), 0.0f):
|
||||
|
||||
igTableSetupColumn("", ImGuiTableColumnFlags_WidthStretch.int32, 0.0f, 0) # Left
|
||||
igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed.int32, 0.0f, 0) # Buttons
|
||||
igTableSetupColumn("", ImGuiTableColumnFlags_WidthStretch.int32, 0.0f, 0) # Right
|
||||
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
|
||||
|
||||
var containerHeight: float
|
||||
|
||||
# Left selection container
|
||||
igTableSetColumnIndex(0)
|
||||
|
||||
var modules = component.items[0]
|
||||
var selection = component.selection[0]
|
||||
|
||||
# Header
|
||||
var text = "Available"
|
||||
var textSize: ImVec2
|
||||
igCalcTextSize(addr textSize, text, nil, false, 0.0f)
|
||||
igSetCursorPosX(igGetCursorPosX() + (igGetColumnWidth(0) - textSize.x) * 0.5f)
|
||||
igTextColored(GRAY, text)
|
||||
|
||||
# Set the size of selection box to fit all modules
|
||||
igSetNextWindowContentSize(vec2(0.0f, float(modules.len()) * igGetTextLineHeightWithSpacing()))
|
||||
igSetNextWindowSizeConstraints(vec2(0.0f, igGetTextLineHeightWithSpacing() * 10.0f), vec2(igGET_FLT_MAX(), igGET_FLT_MAX()), nil, nil) # Set minimum container size
|
||||
if igBeginChild_Str("0", vec2(0.0f, -1.0f), ImGuiChildFlags_FrameStyle.int32 or ImGuiChildFlags_ResizeY.int32, ImGuiWindowFlags_None.int32):
|
||||
containerHeight = igGetWindowHeight()
|
||||
|
||||
var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_None.int32, selection[].Size, int32(modules.len()))
|
||||
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
|
||||
|
||||
for row in 0 ..< modules.len().int32:
|
||||
var isSelected = ImGuiSelectionBasicStorage_Contains(selection, cast[ImGuiID](row))
|
||||
igSetNextItemSelectionUserData(row)
|
||||
discard igSelectable_Bool(modules[row], isSelected, ImGuiSelectableFlags_AllowDoubleClick.int32, vec2(0.0f, 0.0f))
|
||||
|
||||
multiSelectIO = igEndMultiSelect()
|
||||
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
|
||||
|
||||
igEndChild()
|
||||
|
||||
# Buttons column
|
||||
igTableSetColumnIndex(1)
|
||||
igNewLine()
|
||||
|
||||
let buttonSize = vec2(igGetFrameHeight(), igGetFrameHeight())
|
||||
if igButton(">>", buttonSize):
|
||||
component.moveAll(Right)
|
||||
if igButton(">", buttonSize):
|
||||
component.moveSelection(Right)
|
||||
if igButton("<", buttonSize):
|
||||
component.moveSelection(Left)
|
||||
if igButton("<<", buttonSize):
|
||||
component.moveAll(Left)
|
||||
|
||||
# Right selection container
|
||||
igTableSetColumnIndex(2)
|
||||
|
||||
modules = component.items[1]
|
||||
selection = component.selection[1]
|
||||
|
||||
# Header
|
||||
text = "Selected"
|
||||
igCalcTextSize(addr textSize, text, nil, false, 0.0f)
|
||||
igSetCursorPosX(igGetCursorPosX() + (igGetColumnWidth(2) - textSize.x) * 0.5f)
|
||||
igTextColored(GRAY, text)
|
||||
|
||||
# Set the size of selection box to fit all modules
|
||||
igSetNextWindowContentSize(vec2(0.0f, float(modules.len()) * igGetTextLineHeightWithSpacing()))
|
||||
if igBeginChild_Str("1", vec2(0.0f, containerHeight), ImGuiChildFlags_FrameStyle.int32, ImGuiWindowFlags_None.int32):
|
||||
|
||||
var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_None.int32, selection[].Size, int32(modules.len()))
|
||||
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
|
||||
|
||||
for row in 0 ..< modules.len().int32:
|
||||
var isSelected = ImGuiSelectionBasicStorage_Contains(selection, cast[ImGuiID](row))
|
||||
igSetNextItemSelectionUserData(row)
|
||||
discard igSelectable_Bool(modules[row], isSelected, ImGuiSelectableFlags_AllowDoubleClick.int32, vec2(0.0f, 0.0f))
|
||||
|
||||
multiSelectIO = igEndMultiSelect()
|
||||
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
|
||||
|
||||
igEndChild()
|
||||
|
||||
|
||||
igEndTable()
|
||||
Reference in New Issue
Block a user