├── screen.png ├── README.md ├── NimbleImGui.nimble ├── src ├── globals.nim ├── imgui.ini ├── NimbleImGui.nim ├── cmd.nim └── ui.nim └── LICENSE.md /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qb-0/NimbleImGui/HEAD/screen.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `nimble install NimbleImGui` 2 | 3 | ![alt text](https://raw.githubusercontent.com/qb-0/NimbleImGui/master/screen.png) -------------------------------------------------------------------------------- /NimbleImGui.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "1.0.0" 4 | author = "qb" 5 | description = "ImGui Frontend for Nimble" 6 | license = "MIT" 7 | srcDir = "src" 8 | bin = @["NimbleImGui"] 9 | backend = "cpp" 10 | 11 | 12 | # Dependencies 13 | 14 | requires "nim >= 1.4.2" 15 | requires "nimgl" -------------------------------------------------------------------------------- /src/globals.nim: -------------------------------------------------------------------------------- 1 | import nimgl/glfw 2 | 3 | type 4 | Module* = object 5 | name*, url*, website*, descr*, license*: string 6 | 7 | InstalledModule* = object 8 | name*, version*, descr*: string 9 | 10 | var 11 | Log*, NimbleLog*: seq[string] 12 | Modules*: seq[Module] 13 | Installed*: seq[InstalledModule] 14 | GLFWWin*: GLFWWindow -------------------------------------------------------------------------------- /src/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | [Window][Installed Modules] 7 | Pos=440,165 8 | Size=342,974 9 | Collapsed=0 10 | 11 | [Window][Log] 12 | Pos=791,801 13 | Size=1254,336 14 | Collapsed=0 15 | 16 | [Window][Modules] 17 | Pos=790,166 18 | Size=1255,625 19 | Collapsed=0 20 | 21 | [Window][Draw] 22 | Pos=60,60 23 | Size=2090,1129 24 | Collapsed=0 25 | 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Meowz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/NimbleImGui.nim: -------------------------------------------------------------------------------- 1 | {.passc: "-static -static-libstdc++".} 2 | {.passl: "-static -static-libstdc++ -lpthread".} 3 | 4 | import 5 | os, 6 | nimgl/[glfw, opengl, imgui], 7 | nimgl/imgui/[impl_opengl, impl_glfw], 8 | ui, cmd, globals 9 | 10 | const 11 | uiConfigName = "imgui.ini" 12 | uiConfig = staticRead(uiConfigName) 13 | 14 | template checkConfig = 15 | if not fileExists(uiConfigName): 16 | var f = open(uiConfigName, fmWrite) 17 | f.write(uiConfig) 18 | f.close() 19 | 20 | template init = 21 | checkConfig() 22 | doAssert glfwInit() 23 | glfwWindowHint(GLFWDecorated, GLFWFalse) 24 | glfwWindowHint(GLFWResizable, GLFWFalse) 25 | glfwWindowHint(GLFWTransparentFramebuffer, GLFWTrue) 26 | GLFWWin = glfwCreateWindow( 27 | getVideoMode(glfwGetPrimaryMonitor()).width - 1, 28 | getVideoMode(glfwGetPrimaryMonitor()).height - 1, 29 | icon=false, title="Nimble ImGui" 30 | ) 31 | GlfwWin.makeContextCurrent() 32 | doAssert glInit() 33 | igCreateContext() 34 | doAssert igGlfwInitForOpenGL(GLFWWin, true) 35 | doAssert igOpenGL3Init() 36 | Modules = parseModules() 37 | Installed = parseInstalled() 38 | setStyle() 39 | 40 | template uiLoop = 41 | var show = true 42 | igOpenGL3NewFrame() 43 | igGlfwNewFrame() 44 | igNewFrame() 45 | 46 | igBegin("Modules", show.addr) 47 | uiModules() 48 | igEnd() 49 | 50 | igBegin("Installed Modules") 51 | uiInstalledModules() 52 | igEnd() 53 | 54 | igBegin("Log") 55 | uiLog() 56 | igEnd() 57 | 58 | igRender() 59 | igOpenGL3RenderDrawData(igGetDrawData()) 60 | if not show: 61 | GLFWWin.setWindowShouldClose(true) 62 | 63 | proc main = 64 | init() 65 | while not GLFWWin.windowShouldClose(): 66 | glfwPollEvents() 67 | glClear(GL_COLOR_BUFFER_BIT) 68 | uiLoop() 69 | GLFWWin.swapBuffers() 70 | 71 | if GLFWWin.getMouseButton(GLFWMouseButton.Button1) == 1 and not igGetIO().wantCaptureMouse: 72 | GLFWWin.iconifyWindow() 73 | 74 | when isMainModule: 75 | main() -------------------------------------------------------------------------------- /src/cmd.nim: -------------------------------------------------------------------------------- 1 | import 2 | osproc, strscans, globals 3 | 4 | const 5 | base = "nimble" 6 | opts = {poUsePath, poStdErrToStdOut} 7 | cmds = ( 8 | update: @["update"], 9 | install: @["install", "-y"], 10 | list: @["list"], 11 | installed: @["list", "--installed"], 12 | uninstall: @["uninstall", "-y"] 13 | ) 14 | 15 | proc updateModules* = 16 | var 17 | p = startProcess(base, "", cmds.update, options=opts) 18 | (lines, exCode) = p.readLines() 19 | 20 | NimbleLog.add(lines) 21 | 22 | if exCode == 0: 23 | Log.add("Successfully updated modules") 24 | else: 25 | Log.add("Failed to update modules") 26 | 27 | proc installModule*(m: string) = 28 | Log.add("Installing " & m) 29 | var 30 | p = startProcess(base, "", cmds.install & m, options=opts) 31 | (lines, exCode) = p.readLines() 32 | 33 | NimbleLog.add(lines) 34 | 35 | if exCode == 0: 36 | Log.add("Successfully (re)installed " & m) 37 | else: 38 | Log.add("Failed to install " & m) 39 | 40 | proc uninstallModule*(m: string) = 41 | Log.add("Uninstalling " & m) 42 | var 43 | p = startProcess(base, "", cmds.uninstall & m, options=opts) 44 | (lines, exCode) = p.readLines() 45 | 46 | NimbleLog.add(lines) 47 | 48 | if exCode == 0: 49 | Log.add("Successfully uninstalled " & m) 50 | else: 51 | Log.add("Failed to uninstall " & m) 52 | 53 | proc parseModules*: seq[Module] = 54 | var 55 | p = startProcess(base, "", cmds.list, options=opts) 56 | (lines, exCode) = p.readLines() 57 | m: Module 58 | 59 | NimbleLog.add(lines) 60 | 61 | if exCode == 0: 62 | for l in lines: 63 | discard scanf(l, "$w*:$.", m.name) 64 | discard scanf(l, "$surl:$s$* ", m.url) 65 | discard scanf(l, "$sdescription:$s$*$.", m.descr) 66 | discard scanf(l, "$slicense:$s$*$.", m.license) 67 | if scanf(l, "$swebsite:$s$*$.", m.website): 68 | result.add(m) 69 | m = Module() 70 | Log.add("Load module list") 71 | else: 72 | Log.add("Failed to parse module list") 73 | 74 | proc parseInstalled*: seq[InstalledModule] = 75 | var 76 | p = startProcess(base, "", cmds.installed, options=opts) 77 | (lines, exCode) = p.readLines() 78 | 79 | NimbleLog.add(lines) 80 | 81 | if exCode == 0: 82 | for l in lines: 83 | var im: InstalledModule 84 | discard scanf(l, "$* [$*]", im.name, im.version) 85 | for m in Modules: 86 | if m.name == im.name: 87 | im.descr = m.descr 88 | result.add(im) 89 | Log.add("Load installed module list") 90 | else: 91 | Log.add("Failed to parse installed module list") -------------------------------------------------------------------------------- /src/ui.nim: -------------------------------------------------------------------------------- 1 | import strutils, browsers 2 | import nimgl/imgui 3 | import globals, cmd 4 | 5 | const 6 | debugColor = ImVec4(y: 0.6, z: 1, w: 1) 7 | installedColor = ImVec4(y: 1, z: 0.2, w: 1) 8 | 9 | proc setAlpha*(v: float32) = 10 | var style = igGetStyle() 11 | for i, c in style.colors: 12 | var vec = ImVec4(x: c.x, y: c.y, z: c.z, w: v) 13 | style.colors[i] = vec 14 | 15 | proc uiLog* = 16 | var 17 | autoscroll {.global.}: bool = true 18 | debug {.global.}: bool 19 | 20 | if igButton("Clear"): 21 | Log.setLen(0) 22 | NimbleLog.setLen(0) 23 | igSameLine() 24 | igCheckBox("Autoscroll", autoscroll.addr) 25 | igSameLine() 26 | igCheckBox("Nimble", debug.addr) 27 | igBeginChild("scrolling", flags=ImGuiWindowFlags.NoBackground) 28 | igPushStyleVar(ImguiStyleVar.ItemSpacing, ImVec2(x: 0, y: 1)) 29 | if debug: 30 | for l in NimbleLog: 31 | igTextColored(debugColor, l.strip().cstring) 32 | for l in Log: 33 | igTextColored(installedColor, l.cstring) 34 | if autoscroll: 35 | igSetScrollHereY(1.0) 36 | igPopStyleVar() 37 | igEndChild() 38 | 39 | proc uiInstalledModules* = 40 | var 41 | selected {.global.} = -1 42 | selectedMod {.global.}: InstalledModule 43 | 44 | if igButton("Refresh"): 45 | Installed = parseInstalled() 46 | igSameLine() 47 | if igButton("Uninstall") and selected != -1: 48 | uninstallModule(selectedMod.name) 49 | Installed = parseInstalled() 50 | igSameLine() 51 | if igButton("Reinstall") and selected != -1: 52 | installModule(selectedMod.name) 53 | Installed = parseInstalled() 54 | igBeginChild("installed", flags = ImGuiWindowFlags.NoBackground) 55 | igSeparator() 56 | igColumns(2, "modulelist", false) 57 | igSetColumnWidth(0, 200) 58 | igText("Name") 59 | igNextColumn() 60 | igText("Version") 61 | igNextColumn() 62 | igSeparator() 63 | for i, m in Installed: 64 | if igSelectable(m.name.cstring, selected == i, flags = ImGuiSelectableFlags.SpanAllColumns): 65 | selected = i 66 | selectedMod = m 67 | if igIsItemHovered() and igGetCurrentContext().hoveredIdTimer > 0.3: 68 | igBeginTooltip() 69 | igTextUnformatted(m.descr.cstring) 70 | igEndTooltip() 71 | igNextColumn() 72 | igText(m.version.cstring) 73 | igNextColumn() 74 | igEndChild() 75 | 76 | proc uiModules* = 77 | var 78 | filterBuf {.global.}: string 79 | selected {.global.} = -1 80 | selectedMod {.global.}: Module 81 | transparency {.global.}: float32 = 0.9 82 | 83 | filterBuf.setLen(20) 84 | if igButton("Refresh"): 85 | updateModules() 86 | Modules = parseModules() 87 | igSameLine() 88 | if igButton("Install") and selected != -1 or 89 | igIsAnyItemHovered() and igIsMouseDoubleClicked(ImGuiMouseButton.Left): 90 | installModule(selectedMod.name) 91 | Installed = parseInstalled() 92 | igSameLine() 93 | if igButton("Website") and selected != -1: 94 | Log.add("Visiting " & selectedMod.url) 95 | openDefaultBrowser(selectedMod.url) 96 | igSameLine() 97 | igText(("Modules: " & $len(Modules)).cstring) 98 | igSameLine() 99 | igDummy(ImVec2(x: 500)) 100 | igSameLine() 101 | igSetNextItemWidth(-1) 102 | if igSliderFloat("##Transparency", transparency.addr, 0.1, 1.0, format="Transparency: %.1f"): 103 | setAlpha(transparency) 104 | igSetNextItemWidth(-1) 105 | if igInputText("Filter", filterBuf.cstring, 20): 106 | selected = -1 107 | igSeparator() 108 | igColumns(3, "moduleheader", false) 109 | igSetColumnWidth(0, 150) 110 | igText("Name") 111 | igNextColumn() 112 | igSetColumnWidth(1, 150) 113 | igText("License") 114 | igNextColumn() 115 | igText("Description") 116 | igSeparator() 117 | igEndColumns() 118 | igBeginChild("modules", flags=ImGuiWindowFlags.NoBackground) 119 | igColumns(3, "modulelist", false) 120 | igSetColumnWidth(0, 150) 121 | igSetColumnWidth(1, 150) 122 | var filterStr = $cast[cstring](filterBuf[0].unsafeAddr) 123 | for i, m in Modules: 124 | var installed: bool 125 | if filterStr.toLower() notin m.name.toLower() and 126 | filterStr.toLower() notin m.descr.toLower(): continue 127 | for im in Installed: 128 | if im.name == m.name: 129 | igPushStyleColor(ImGuiCol.Text, installedColor) 130 | installed = true 131 | if igSelectable(m.name.cstring, selected == i, flags = ImGuiSelectableFlags.SpanAllColumns): 132 | selected = i 133 | selectedMod = m 134 | if selected != -1 and igBeginPopupContextItem(): 135 | if installed: 136 | igPopStyleColor() 137 | igText(selectedMod.name.cstring) 138 | igSeparator() 139 | if igButton("Install"): 140 | installModule(selectedMod.name) 141 | Installed = parseInstalled() 142 | igSameLine() 143 | if igButton("Website"): 144 | openDefaultBrowser(selectedMod.url) 145 | igEndPopup() 146 | if installed: 147 | igPushStyleColor(ImGuiCol.Text, installedColor) 148 | igNextColumn() 149 | igText(m.license.cstring) 150 | igNextColumn() 151 | igTextWrapped(m.descr.cstring) 152 | igNextColumn() 153 | if installed: 154 | igPopStyleColor() 155 | igSeparator() 156 | igEndChild() 157 | 158 | proc setStyle* = 159 | proc igVec4(x, y, z, w: float32): ImVec4 = ImVec4(x: x, y: y, z: z, w: w) 160 | 161 | var s = igGetStyle() 162 | 163 | s.colors[ImGuiCol.Text.int32] = igVec4(1.00, 1.00, 1.00, 1.00) 164 | s.colors[ImGuiCol.TextDisabled.int32] = igVec4(0.40, 0.40, 0.40, 1.00) 165 | s.colors[ImGuiCol.ChildBg.int32] = igVec4(0.25, 0.25, 0.25, 1.00) 166 | s.colors[ImGuiCol.WindowBg.int32] = igVec4(0.25, 0.25, 0.25, 1.00) 167 | s.colors[ImGuiCol.PopupBg.int32] = igVec4(0.25, 0.25, 0.25, 1.00) 168 | s.colors[ImGuiCol.Border.int32] = igVec4(0.12, 0.12, 0.12, 0.71) 169 | s.colors[ImGuiCol.BorderShadow.int32] = igVec4(1.00, 1.00, 1.00, 0.06) 170 | s.colors[ImGuiCol.FrameBg.int32] = igVec4(0.42, 0.42, 0.42, 0.54) 171 | s.colors[ImGuiCol.FrameBgHovered.int32] = igVec4(0.42, 0.42, 0.42, 0.40) 172 | s.colors[ImGuiCol.FrameBgActive.int32] = igVec4(0.56, 0.56, 0.56, 0.67) 173 | s.colors[ImGuiCol.TitleBg.int32] = igVec4(0.19, 0.19, 0.19, 1.00) 174 | s.colors[ImGuiCol.TitleBgActive.int32] = igVec4(0.22, 0.22, 0.22, 1.00) 175 | s.colors[ImGuiCol.TitleBgCollapsed.int32] = igVec4(0.17, 0.17, 0.17, 0.90) 176 | s.colors[ImGuiCol.MenuBarBg.int32] = igVec4(0.335, 0.335, 0.335, 1.000) 177 | s.colors[ImGuiCol.ScrollbarBg.int32] = igVec4(0.24, 0.24, 0.24, 0.53) 178 | s.colors[ImGuiCol.ScrollbarGrab.int32] = igVec4(0.41, 0.41, 0.41, 1.00) 179 | s.colors[ImGuiCol.ScrollbarGrabHovered.int32] = igVec4(0.52, 0.52, 0.52, 1.00) 180 | s.colors[ImGuiCol.ScrollbarGrabActive.int32] = igVec4(0.76, 0.76, 0.76, 1.00) 181 | s.colors[ImGuiCol.CheckMark.int32] = igVec4(0.65, 0.65, 0.65, 1.00) 182 | s.colors[ImGuiCol.SliderGrab.int32] = igVec4(0.52, 0.52, 0.52, 1.00) 183 | s.colors[ImGuiCol.SliderGrabActive.int32] = igVec4(0.64, 0.64, 0.64, 1.00) 184 | s.colors[ImGuiCol.Button.int32] = igVec4(0.54, 0.54, 0.54, 0.35) 185 | s.colors[ImGuiCol.ButtonHovered.int32] = igVec4(0.52, 0.52, 0.52, 0.59) 186 | s.colors[ImGuiCol.ButtonActive.int32] = igVec4(0.76, 0.76, 0.76, 1.00) 187 | s.colors[ImGuiCol.Header.int32] = igVec4(0.38, 0.38, 0.38, 1.00) 188 | s.colors[ImGuiCol.HeaderHovered.int32] = igVec4(0.47, 0.47, 0.47, 1.00) 189 | s.colors[ImGuiCol.HeaderActive.int32] = igVec4(0.76, 0.76, 0.76, 0.77) 190 | s.colors[ImGuiCol.Separator.int32] = igVec4(0.000, 0.000, 0.000, 0.137) 191 | s.colors[ImGuiCol.SeparatorHovered.int32] = igVec4(0.700, 0.671, 0.600, 0.290) 192 | s.colors[ImGuiCol.SeparatorActive.int32] = igVec4(0.702, 0.671, 0.600, 0.674) 193 | s.colors[ImGuiCol.ResizeGrip.int32] = igVec4(0.26, 0.59, 0.98, 0.25) 194 | s.colors[ImGuiCol.ResizeGripHovered.int32] = igVec4(0.26, 0.59, 0.98, 0.67) 195 | s.colors[ImGuiCol.ResizeGripActive.int32] = igVec4(0.26, 0.59, 0.98, 0.95) 196 | s.colors[ImGuiCol.PlotLines.int32] = igVec4(0.61, 0.61, 0.61, 1.00) 197 | s.colors[ImGuiCol.PlotLinesHovered.int32] = igVec4(1.00, 0.43, 0.35, 1.00) 198 | s.colors[ImGuiCol.PlotHistogram.int32] = igVec4(0.90, 0.70, 0.00, 1.00) 199 | s.colors[ImGuiCol.PlotHistogramHovered.int32] = igVec4(1.00, 0.60, 0.00, 1.00) 200 | s.colors[ImGuiCol.TextSelectedBg.int32] = igVec4(0.73, 0.73, 0.73, 0.35) 201 | s.colors[ImGuiCol.ModalWindowDimBg.int32] = igVec4(0.80, 0.80, 0.80, 0.35) 202 | s.colors[ImGuiCol.DragDropTarget.int32] = igVec4(1.00, 1.00, 0.00, 0.90) 203 | s.colors[ImGuiCol.NavHighlight.int32] = igVec4(0.26, 0.59, 0.98, 1.00) 204 | s.colors[ImGuiCol.NavWindowingHighlight.int32] = igVec4(1.00, 1.00, 1.00, 0.70) 205 | s.colors[ImGuiCol.NavWindowingDimBg.int32] = igVec4(0.80, 0.80, 0.80, 0.20) 206 | 207 | s.windowPadding = ImVec2(x: 4, y: 4) 208 | s.framePadding = ImVec2(x: 6, y: 4) 209 | s.itemSpacing = ImVec2(x: 6, y: 2) 210 | 211 | s.scrollbarSize = 18 212 | 213 | s.windowBorderSize = 1 214 | s.childBorderSize = 1 215 | s.popupBorderSize = 1 216 | s.frameBorderSize = 0 217 | 218 | s.popupRounding = 3 219 | s.windowRounding = 3 220 | s.childRounding = 3 221 | s.frameRounding = 3 222 | s.scrollbarRounding = 2 223 | s.grabRounding = 2 --------------------------------------------------------------------------------