2 std/logging, std/sequtils, std/strutils,
6 imgui/base, imgui/backend_sdl2, imgui/backend_gl2
12 imguiCtx*: ptr ImGuiContext = nil
14 proc init*(window: WindowPtr): bool =
15 var context = igCreateContext()
17 if not igSDL2Init(window):
18 error("Could not init SDL2 backend for ImGui: ", sdl2.getError())
19 context.igDestroyContext()
22 error("Could not init GL2 backend for ImGui")
23 context.igDestroyContext()
32 imguiCtx.igDestroyContext()
43 igGL2RenderDrawData(igGetDrawData())
45 proc event*(event: var Event): bool =
46 result = igSDL2ProcessEvent(nil, event)
50 proc `+`*(a, b: ImVec2): ImVec2 = ImVec2(x: a.x + b.x, y: a.y + b.y)
51 proc `-`*(a, b: ImVec2): ImVec2 = ImVec2(x: a.x - b.x, y: a.y - b.y)
52 proc `*`*(a: ImVec2, b: float32): ImVec2 = ImVec2(x: a.x * b, y: a.y * b)
53 proc `/`*(a: ImVec2, b: float32): ImVec2 = ImVec2(x: a.x / b, y: a.y / b)
57 proc `or`*(a, b: ImGuiWindowFlags): ImGuiWindowFlags = ImGuiWindowFlags(a.int32 or b.int32)
58 proc `or`*(a, b: ImGuiItemFlags): ImGuiItemFlags = ImGuiItemFlags(a.int32 or b.int32)
60 # extra helper functions
62 proc rgba*(r, g, b, a: float32): ImVec4 =
63 ImVec4(x: r, y: g, z: b, w: a)
65 proc pushInactive*() =
66 igPushItemFlag(ImGuiItemFlags.Disabled, true)
67 igPushStyleVar(ImGuiStyleVar.Alpha, igGetStyle().alpha * 0.5f)
73 # control wrappers; need these mostly because of a weird fucking header error and also for type checking convenience
75 proc showStackToolWindow*() =
76 igShowStackToolWindow()
78 proc beginWindow*(label: string, pOpen: ptr bool = nil, flags: ImGuiWindowFlags = ImGuiWindowFlags.None): bool =
79 igBegin(label.cstring, pOpen, flags)
84 proc openPopup*(label: string, flags: ImGuiPopupFlags = ImGuiPopupFlags.None) =
85 igOpenPopup(label.cstring, flags)
87 proc beginPopup*(label: string, flags: ImGuiWindowFlags = ImGuiWindowFlags.None): bool =
88 igBeginPopup(label.cstring, flags)
93 proc closeCurrentPopup*() =
96 proc beginPopupModal*(label: string, pOpen: ptr bool = nil, flags: ImGuiWindowFlags = ImGuiWindowFlags.None): bool =
97 igBeginPopupModal(label.cstring, pOpen, flags)
99 proc beginMenu*(label: string, enabled: bool = true): bool =
100 igBeginMenu(label.cstring, enabled)
105 proc beginMenuBar*(): bool =
111 proc beginMainMenuBar*(): bool =
114 proc endMainMenuBar*() =
117 proc beginTable*(tableId: string, columns: int, flags: ImGuiTableFlags = ImGuiTableFlags.None, outerSz: ImVec2 = ImVec2(x: 0.0f, y: 0.0f), innerW: float32 = 0.0f): bool =
118 igBeginTable(tableId.cstring, columns.int32, flags, outerSz, innerW)
123 proc beginListBox*(label: string, size: ImVec2 = ImVec2(x: 0, y: 0)): bool =
124 igBeginListBox(label.cstring, size)
129 proc beginCombo*(label: string, preview: string, flags: ImGuiComboFlags = ImGuiComboFlags.None): bool =
130 igBeginCombo(label.cstring, preview.cstring, flags)
135 proc beginChild*(label: string, size: ImVec2 = ImVec2(x: 0, y: 0), border: bool = false, flags: ImGuiWindowFlags = ImGuiWindowFlags.None): bool {.discardable.} =
136 igBeginChild(label.cstring, size, border, flags)
141 proc treeNode*(label: string): bool =
142 igTreeNode(label.cstring)
150 proc sameLine*(offsetX: float32 = 0f, spacing: float32 = -1f) =
151 igSameLine(offsetX, spacing)
153 proc dummy*(size: ImVec2) =
156 proc text*(args: varargs[string, `$`]) =
157 var argStr = args.join()
158 igText("%s", argStr.cstring)
160 proc image*(id: uint32, size: ImVec2, borderCol: ImVec4 = ImVec4(x: 0, y: 0, z: 0, w: 0)) =
161 igImage(cast[ImTextureId](id), size, border_col = borderCol)
163 proc textWrapped*(args: varargs[string, `$`]) =
164 var argStr = args.join()
165 igTextWrapped("%s", argStr.cstring)
167 proc button*(label: string, size: ImVec2 = ImVec2(x: 0, y: 0)): bool =
168 igButton(label.cstring, size)
170 proc arrowButton*(label: string, dir: ImGuiDir): bool =
171 igArrowButton(label.cstring, dir)
173 proc arrowButtonEx*(label: string, dir: ImGuiDir, size: ImVec2, flags: ImGuiButtonFlags = ImGuiButtonFlags.None): bool =
174 igArrowButtonEx(label.cstring, dir, size, flags)
176 proc checkbox*(label: string, v: var bool): bool {.discardable.} =
177 igCheckbox(label.cstring, v.addr)
179 proc selectable*(label: string, selected: bool = false, flags: ImGuiSelectableFlags = ImGuiSelectableFlags.None, size: ImVec2 = ImVec2(x: 0, y: 0)): bool {.discardable.} =
180 igSelectable(label.cstring, selected, flags, size)
182 proc combo*(label: string, index: var int, choices: openArray[string]): bool =
183 var choicesPtrs = newSeq[cstring](choices.len())
184 var curChoice = index.int32
185 for i, x in choices: choicesPtrs[i] = x.cstring
186 result = igCombo(label.cstring, curChoice.addr, choicesPtrs[0].addr, choices.len().int32)
187 index = curChoice.int
189 proc menuItem*(label: string, shortcut: string = "", selected: bool = false, enabled: bool = true): bool {.discardable.} =
190 igMenuItem(label.cstring, (if shortcut == "": nil else: shortcut.cstring), selected, enabled)
192 proc menuItem*(label: string, shortcut: string = "", pSelected: ptr bool, enabled: bool = true): bool {.discardable.} =
193 igMenuItem(label.cstring, (if shortcut == "": nil else: shortcut.cstring), pSelected, enabled)
195 proc inputText*(label: string, outStr: var string, outMaxLen: int = 0, flags: ImGuiInputTextFlags = ImGuiInputTextFlags.None, callback: ImGuiInputTextCallback = nil, userData: pointer = nil): bool =
196 var strMax = (if outMaxLen == 0: outStr.len() else: outMaxLen)
197 if strMax == 0: strMax = 1 # for the \0
198 var tmp = outStr.items().toSeq()
200 if igInputText(label.cstring, tmp[0].addr.cstring, tmp.len().uint, flags, callback, userData):
201 outStr = $(tmp[0].addr.cstring)
206 proc inputInt*(label: string, x: var int32, step: int32 = 1, stepFast: int32 = 100, flags: ImGuiInputTextFlags = ImGuiInputTextFlags.None): bool =
207 igInputInt(label.cstring, x.addr, step, stepFast, flags)
209 proc inputInt2*(label: string, x: var array[2, int32], flags: ImGuiInputTextFlags = ImGuiInputTextFlags.None): bool =
210 igInputInt2(label.cstring, x[0].addr, flags)
212 proc inputInt4*(label: string, x: var array[4, int32], flags: ImGuiInputTextFlags = ImGuiInputTextFlags.None): bool =
213 igInputInt4(label.cstring, x[0].addr, flags)
215 proc columns*(count: int = 1, border: bool = true) =
216 igColumns(count.int32, nil, border)
221 proc setColumnWidth*(idx: int, w: float32) =
222 igSetColumnWidth(idx.int32, w)
224 proc alignTextToFramePadding*() =
225 igAlignTextToFramePadding()
227 proc setItemDefaultFocus*() =
228 igSetItemDefaultFocus()
230 proc setNextItemWidth*(w: float32) =
231 igSetNextItemWidth(w)
233 proc setNextWindowPos*(pos: ImVec2, cond: ImGuiCond = ImGuiCond.None, pivot: ImVec2 = ImVec2(x: 0, y: 0)) =
234 igSetNextWindowPos(pos, cond, pivot)
236 proc setNextWindowSize*(size: ImVec2, cond: ImGuiCond = ImGuiCond.None) =
237 igSetNextWindowSize(size, cond)
239 proc setNextWindowContentSize*(size: ImVec2) =
240 igSetNextWindowContentSize(size)
242 proc setNextWindowSizeConstraints*(minSize, maxSize: ImVec2) =
243 igSetNextWindowSizeConstraints(minSize, maxSize)
245 proc setCursorPosX*(x: float32) =
248 proc setScrollFromPosX*(x: float32, ratio: float32 = 0.5f) =
249 igSetScrollFromPosX(x, ratio)
251 proc setScrollFromPosY*(y: float32, ratio: float32 = 0.5f) =
252 igSetScrollFromPosY(y, ratio)
254 proc setScrollHereX*(ratio: float32 = 0.5f) =
255 igSetScrollHereX(ratio)
257 proc setScrollHereY*(ratio: float32 = 0.5f) =
258 igSetScrollHereY(ratio)
260 proc setScrollX*(ratio: float32) =
263 proc setScrollY*(ratio: float32) =
266 proc getScrollX*(): float32 =
269 proc getScrollY*(): float32 =
272 proc getScrollMaxX*(): float32 =
275 proc getScrollMaxY*(): float32 =
278 proc getItemSize*(): ImVec2 =
279 igGetItemRectSizeNonUDT(result.addr)
281 proc getWindowSize*(): ImVec2 =
282 igGetWindowSizeNonUDT(result.addr)
284 proc getWindowContentRegionSize*(): ImVec2 =
285 igGetWindowContentRegionMaxNonUDT(result.addr)
287 igGetWindowContentRegionMinNonUDT(mins.addr)
288 result = result - mins
290 proc getIO*(): ptr ImGuiIO =
293 proc getStyle*(): ptr ImGuiStyle =
296 proc getFrameHeight*(): float32 =
299 proc getFrameHeightWithSpacing*(): float32 =
300 igGetFrameHeightWithSpacing()
302 proc getCursorPosX*(): float32 =
305 proc getCursorPosY*(): float32 =
308 proc getCursorPos*(): ImVec2 =
309 ImVec2(x: igGetCursorPosX(), y: igGetCursorPosY())
311 proc getMousePos*(): ImVec2 =
312 igGetMousePosNonUDT(result.addr)
314 proc calcTextSize*(text: string): ImVec2 =
315 igCalcTextSizeNonUDT(result.addr, text.cstring)
317 proc pushStyleColor*(what: ImGuiCol, col: ImVec4) =
318 igPushStyleColor(what, col)
320 proc popStyleColor*(count: int = 1) =
321 igPopStyleColor(count.int32)
323 proc pushItemWidth*(w: float32) =
326 proc popItemWidth*() =
329 proc isItemFocused*(): bool =
332 proc isItemActive*(): bool =
335 proc isPopupOpen*(id: string): bool =
336 igIsPopupOpen(id.cstring)
338 proc isMouseDoubleClicked*(button: ImGuiMouseButton): bool =
339 igIsMouseDoubleClicked(button)
341 proc isMouseDown*(button: ImGuiMouseButton): bool =
342 igIsMouseDown(button)
344 proc isMouseClicked*(button: ImGuiMouseButton): bool =
345 igIsMouseClicked(button)
347 proc isKeyPressed*(key: ImGuiKey, repeat: bool = true): bool =
348 igIsKeyPressedMap(key, repeat)
350 proc isAnyModalPopupOpen*(): bool =
351 (igGetTopMostPopupModal() != nil)
353 # `with`-style templates for all kinds of controls
355 template doWindow*(label: string, actions: untyped): untyped =
356 if imgui.beginWindow(label):
360 template doPopup*(label: string, actions: untyped): untyped =
361 if imgui.beginPopup(label):
365 template doPopupModal*(label: string, actions: untyped): untyped =
366 if imgui.beginPopupModal(label):
370 template doMenu*(label: string, actions: untyped): untyped =
371 if imgui.beginMenu(label):
375 template doMenuBar*(actions: untyped): untyped =
376 if imgui.beginMenuBar():
380 template doMainMenuBar*(actions: untyped): untyped =
381 if imgui.beginMainMenuBar():
383 imgui.endMainMenuBar()
385 template doTreeNode*(label: string, actions: untyped): untyped =
386 if imgui.treeNode(label):
390 template doTable*(label: string, colums: int, actions: untyped): untyped =
391 if imgui.beginTable(label, columns):
395 template doCombo*(label: string, initVal: string, actions: untyped): untyped =
396 if imgui.beginCombo(label, initVal):
400 template doListBox*(label: string, actions: untyped): untyped =
401 if imgui.beginListBox(label):
405 template doChild*(label: string, actions: untyped): untyped =
406 if imgui.beginChild(label):
410 template doInactive*(actions: untyped): untyped =
415 template doColumns*(numCols: int, border: bool, actions: untyped): untyped =
416 imgui.columns(numCols, border)