├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake └── FindLuaJIT.cmake ├── generate_imgui_bindings.pl ├── love-imgui-scm-1.rockspec ├── rockspecs └── love-imgui-0.7-1.rockspec └── src ├── imgui_impl.cpp ├── imgui_impl.h ├── imgui_iterator.h ├── imgui_iterator_dock.h ├── libimgui ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_demo.cpp ├── imgui_dock.cpp ├── imgui_dock.h ├── imgui_draw.cpp ├── imgui_internal.h ├── stb_rect_pack.h ├── stb_textedit.h └── stb_truetype.h ├── wrap_imgui_impl.cpp └── wrap_imgui_impl.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Products 2 | *.dll 3 | *.so 4 | 5 | # CMake 6 | CMakeCache.txt 7 | CMakeFiles 8 | CMakeScripts 9 | Makefile 10 | cmake_install.cmake 11 | install_manifest.txt 12 | CTestTestfile.cmake 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 | 3 | SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 4 | FIND_PACKAGE(LuaJIT REQUIRED) 5 | 6 | SET(LIB_NAME imgui) 7 | 8 | ADD_LIBRARY(${LIB_NAME} 9 | MODULE 10 | src/libimgui/imconfig.h 11 | src/libimgui/imgui.cpp 12 | src/libimgui/imgui.h 13 | src/libimgui/imgui_draw.cpp 14 | src/libimgui/imgui_demo.cpp 15 | src/libimgui/imgui_internal.h 16 | src/libimgui/imgui_dock.cpp 17 | src/libimgui/imgui_dock.h 18 | src/libimgui/stb_rect_pack.h 19 | src/libimgui/stb_textedit.h 20 | src/libimgui/stb_truetype.h 21 | src/imgui_impl.cpp 22 | src/wrap_imgui_impl.cpp 23 | src/imgui_impl.h 24 | src/wrap_imgui_impl.h 25 | src/imgui_iterator.h 26 | src/imgui_iterator_dock.h 27 | ) 28 | 29 | TARGET_INCLUDE_DIRECTORIES(${LIB_NAME} 30 | PUBLIC 31 | ${LUAJIT_INCLUDE_DIR} 32 | ) 33 | 34 | TARGET_LINK_LIBRARIES(${LIB_NAME} 35 | ${LUAJIT_LIBRARY} 36 | ) 37 | 38 | SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "") 39 | 40 | IF(DEFINED "LIB_DIR") 41 | INSTALL(TARGETS ${LIB_NAME} LIBRARY DESTINATION ${LIB_DIR}) 42 | ENDIF() 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 slages 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LOVE-IMGUI 2 | 3 | [imgui](https://github.com/ocornut/imgui) module for the [LÖVE](https://love2d.org/) game engine including lua bindings based on this [project](https://github.com/patrickriordan/imgui_lua_bindings). 4 | **The main difference is that now by default in this version the return values ordering is reverted.** For instance to retrieve the value from a slider, you need to do: 5 | ```lua 6 | floatValue, status = imgui.SliderFloat("SliderFloat", floatValue, 0.0, 1.0); 7 | ``` 8 | Or if you're not interested to know if the field was modified, just: 9 | ```lua 10 | floatValue = imgui.SliderFloat("SliderFloat", floatValue, 0.0, 1.0); 11 | ``` 12 | To reverse this behavior and receive back the return values from a function first before the modified fields, just call at the beginning of your application: 13 | ```lua 14 | imgui.SetReturnValueLast(false) 15 | ``` 16 | 17 | Another notable difference is that enum values are handled using strings (and array of strings) instead of numerical values, for instance to create a window: 18 | ```lua 19 | imgui.Begin("Test Window", true, { "ImGuiWindowFlags_AlwaysAutoResize", "ImGuiWindowFlags_NoTitleBar" }); 20 | ``` 21 | Or for a single flag: 22 | ```lua 23 | imgui.Begin("Test Window", true, "ImGuiWindowFlags_AlwaysAutoResize"); 24 | ``` 25 | 26 | It uses imgui 1.53 and supports 275 functions (43 unsupported), and is based on LÖVE 11.1. 27 | 28 | It also includes the docks extension by @adcox (https://github.com/adcox/imgui) (it's deprecated and will be replaced by imgui native dock management as soon as it's available). 29 | 30 | ## Getting Started 31 | 32 | Just build the project, and copy the generated dynamic module next to your love executable or into the LÖVE application data folder (for instance "C:/Users//AppData/Roaming/LOVE" on Windows or ~/.local/shared/love on Linux). 33 | 34 | Pre-built binaries for Windows and Mas OSX are provided in the [releases](https://github.com/slages/love-imgui/releases) page. 35 | 36 | ## Examples 37 | 38 | Simple integration: 39 | ```lua 40 | require "imgui" 41 | 42 | local showTestWindow = false 43 | local showAnotherWindow = false 44 | local floatValue = 0; 45 | local sliderFloat = { 0.1, 0.5 } 46 | local clearColor = { 0.2, 0.2, 0.2 } 47 | local comboSelection = 1 48 | local textValue = "text" 49 | 50 | -- 51 | -- LOVE callbacks 52 | -- 53 | function love.load(arg) 54 | end 55 | 56 | function love.update(dt) 57 | imgui.NewFrame() 58 | end 59 | 60 | function love.draw() 61 | 62 | -- Menu 63 | if imgui.BeginMainMenuBar() then 64 | if imgui.BeginMenu("File") then 65 | imgui.MenuItem("Test") 66 | imgui.EndMenu() 67 | end 68 | imgui.EndMainMenuBar() 69 | end 70 | 71 | -- Debug window 72 | imgui.Text("Hello, world!"); 73 | clearColor[1], clearColor[2], clearColor[3] = imgui.ColorEdit3("Clear color", clearColor[1], clearColor[2], clearColor[3]); 74 | 75 | -- Sliders 76 | floatValue = imgui.SliderFloat("SliderFloat", floatValue, 0.0, 1.0); 77 | sliderFloat[1], sliderFloat[2] = imgui.SliderFloat2("SliderFloat2", sliderFloat[1], sliderFloat[2], 0.0, 1.0); 78 | 79 | -- Combo 80 | comboSelection = imgui.Combo("Combo", comboSelection, { "combo1", "combo2", "combo3", "combo4" }, 4); 81 | 82 | -- Windows 83 | if imgui.Button("Test Window") then 84 | showTestWindow = not showTestWindow; 85 | end 86 | 87 | if imgui.Button("Another Window") then 88 | showAnotherWindow = not showAnotherWindow; 89 | end 90 | 91 | if showAnotherWindow then 92 | imgui.SetNextWindowPos(50, 50, "ImGuiCond_FirstUseEver") 93 | showAnotherWindow = imgui.Begin("Another Window", true, { "ImGuiWindowFlags_AlwaysAutoResize", "ImGuiWindowFlags_NoTitleBar" }); 94 | imgui.Text("Hello"); 95 | -- Input text 96 | textValue = imgui.InputTextMultiline("InputText", textValue, 200, 300, 200); 97 | imgui.End(); 98 | end 99 | 100 | if showTestWindow then 101 | showTestWindow = imgui.ShowDemoWindow(true) 102 | end 103 | 104 | love.graphics.clear(clearColor[1], clearColor[2], clearColor[3]) 105 | imgui.Render(); 106 | end 107 | 108 | function love.quit() 109 | imgui.ShutDown(); 110 | end 111 | 112 | -- 113 | -- User inputs 114 | -- 115 | function love.textinput(t) 116 | imgui.TextInput(t) 117 | if not imgui.GetWantCaptureKeyboard() then 118 | -- Pass event to the game 119 | end 120 | end 121 | 122 | function love.keypressed(key) 123 | imgui.KeyPressed(key) 124 | if not imgui.GetWantCaptureKeyboard() then 125 | -- Pass event to the game 126 | end 127 | end 128 | 129 | function love.keyreleased(key) 130 | imgui.KeyReleased(key) 131 | if not imgui.GetWantCaptureKeyboard() then 132 | -- Pass event to the game 133 | end 134 | end 135 | 136 | function love.mousemoved(x, y) 137 | imgui.MouseMoved(x, y) 138 | if not imgui.GetWantCaptureMouse() then 139 | -- Pass event to the game 140 | end 141 | end 142 | 143 | function love.mousepressed(x, y, button) 144 | imgui.MousePressed(button) 145 | if not imgui.GetWantCaptureMouse() then 146 | -- Pass event to the game 147 | end 148 | end 149 | 150 | function love.mousereleased(x, y, button) 151 | imgui.MouseReleased(button) 152 | if not imgui.GetWantCaptureMouse() then 153 | -- Pass event to the game 154 | end 155 | end 156 | 157 | function love.wheelmoved(x, y) 158 | imgui.WheelMoved(y) 159 | if not imgui.GetWantCaptureMouse() then 160 | -- Pass event to the game 161 | end 162 | end 163 | ``` 164 | 165 | Docks: 166 | ```lua 167 | require "imgui" 168 | 169 | -- 170 | -- LOVE callbacks 171 | -- 172 | function love.load(arg) 173 | end 174 | 175 | function love.update(dt) 176 | imgui.NewFrame() 177 | end 178 | 179 | function love.draw() 180 | imgui.SetNextWindowPos(0, 0) 181 | imgui.SetNextWindowSize(love.graphics.getWidth(), love.graphics.getHeight()) 182 | if imgui.Begin("DockArea", nil, { "ImGuiWindowFlags_NoTitleBar", "ImGuiWindowFlags_NoResize", "ImGuiWindowFlags_NoMove", "ImGuiWindowFlags_NoBringToFrontOnFocus" }) then 183 | imgui.BeginDockspace() 184 | 185 | -- Create 10 docks 186 | for i = 1, 10 do 187 | if imgui.BeginDock("dock_"..i) then 188 | imgui.Text("Hello, dock "..i.."!"); 189 | end 190 | imgui.EndDock() 191 | end 192 | 193 | imgui.EndDockspace() 194 | end 195 | imgui.End() 196 | 197 | love.graphics.clear(0.2, 0.2, 0.2) 198 | imgui.Render(); 199 | end 200 | 201 | function love.quit() 202 | imgui.ShutDown(); 203 | end 204 | 205 | -- 206 | -- User inputs 207 | -- 208 | function love.textinput(t) 209 | imgui.TextInput(t) 210 | end 211 | 212 | function love.keypressed(key) 213 | imgui.KeyPressed(key) 214 | end 215 | 216 | function love.keyreleased(key) 217 | imgui.KeyReleased(key) 218 | end 219 | 220 | function love.mousemoved(x, y) 221 | imgui.MouseMoved(x, y) 222 | end 223 | 224 | function love.mousepressed(x, y, button) 225 | imgui.MousePressed(button) 226 | end 227 | 228 | function love.mousereleased(x, y, button) 229 | imgui.MouseReleased(button) 230 | end 231 | 232 | function love.wheelmoved(x, y) 233 | imgui.WheelMoved(y) 234 | end 235 | ``` 236 | 237 | ## License 238 | 239 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 240 | 241 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.9.{build} 2 | image: Visual Studio 2017 3 | configuration: Release 4 | platform: x64 5 | 6 | build_script: 7 | - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 8 | - set BUILD_DIR=%cd% 9 | - cd .. 10 | - curl -O http://luajit.org/download/LuaJIT-2.0.5.zip 11 | - unzip LuaJIT-2.0.5.zip 12 | - cd LuaJIT-2.0.5\src 13 | - msvcbuild 14 | - set LUAJIT_DIR=c:\projects\LuaJIT-2.0.5\src 15 | - cd %BUILD_DIR% 16 | - cmake -DCMAKE_GENERATOR_PLATFORM=x64 . 17 | - msbuild Project.sln 18 | - dir /s c:\projects\love-imgui 19 | 20 | test: off 21 | 22 | artifacts: 23 | - path: Release\imgui.dll 24 | name: love-imgui-win64.dll 25 | 26 | deploy: 27 | provider: GitHub 28 | auth_token: 29 | secure: QAwjfXBfk1n/gpJs1AfMe/VLAc3N6PbVOxe9yjLg0I3hVnH6pJXEWzLV5/iwuCKK 30 | release: $(appveyor_repo_branch)-latest 31 | description: 'love-imgui-latest' 32 | prerelease: true 33 | artifact: /.*\.dll/ 34 | -------------------------------------------------------------------------------- /cmake/FindLuaJIT.cmake: -------------------------------------------------------------------------------- 1 | # Sets the following variables: 2 | # 3 | # LUAJIT_FOUND 4 | # LUAJIT_INCLUDE_DIR 5 | # LUAJIT_LIBRARY 6 | 7 | set(LUAJIT_SEARCH_PATHS 8 | /usr/local 9 | /usr 10 | c:/usr/local/lib 11 | c:/usr/local 12 | c:/usr/lib 13 | c:/usr 14 | $ENV{LUAJIT_DIR} 15 | ) 16 | 17 | find_path(LUAJIT_INCLUDE_DIR 18 | NAMES luajit.h 19 | PATH_SUFFIXES include include/luajit-2.0 src 20 | PATHS ${LUAJIT_SEARCH_PATHS}) 21 | 22 | find_library(LUAJIT_LIBRARY 23 | NAMES luajit-5.1 lua51 24 | PATH_SUFFIXES lib 25 | PATHS ${LUAJIT_SEARCH_PATHS}) 26 | 27 | include(FindPackageHandleStandardArgs) 28 | find_package_handle_standard_args(LuaJIT DEFAULT_MSG LUAJIT_LIBRARY LUAJIT_INCLUDE_DIR) 29 | 30 | mark_as_advanced(LUAJIT_INCLUDE_DIR LUAJIT_LIBRARY) 31 | -------------------------------------------------------------------------------- /generate_imgui_bindings.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | use diagnostics; 5 | # This works for IMGUI 1.50 WIP and does not get all functions 6 | # 7 | # to use ./generate_imgui_bindings.pl imgui_iterator.cpp 8 | # and define macros properly as in example imgui_lua_bindings.cpp 9 | # 10 | # check imgui_iterator for explanations of why some functions are not supported yet 11 | 12 | my %bannedNames = ( 13 | "GetColorU32" => "banned", 14 | "NewFrame" => "banned", 15 | "Shutdown" => "banned", 16 | ); 17 | 18 | #define bannedNames with keys of functions to exclude them 19 | # EXAMPLE: 20 | #my %bannedNames = ( 21 | # "NewFrame" => "banned", 22 | # "Render" => "banned", 23 | # "Shutdown" => "banned" ); 24 | 25 | # This is only useful for ENABLE_IM_LUA_END_STACK 26 | # We hold a list of differnet 'things' that can be pushed to the stack 27 | # i.e. Group for BeginGroup 28 | # It usually works like this BeginBlah EndBlah 29 | 30 | # We have to redefine stuff when it doesn't work so cleanly 31 | my %beginN = ( 32 | "TreeNode" => "Tree", 33 | "TreePush" => "Tree" 34 | ); 35 | my %changeN = ( 36 | "Tree" => "TreePop" 37 | ); 38 | my %endN = ( 39 | "TreePop" => "Tree" 40 | ); 41 | my %endOverride = ( 42 | "PopupModal" => "Popup", 43 | "PopupContextItem" => "Popup", 44 | "PopupContextWindow" => "Popup", 45 | "PopupContextVoid" => "Popup" ); 46 | 47 | 48 | my $numSupported = 0; 49 | my $numUnsupported = 0; 50 | my $line; 51 | my %funcNames; 52 | my %endTypeToInt; 53 | my @endTypes; 54 | while ($line = ) { 55 | #replace ImVec2(x, y) with ImVec2 x, y so it's easier for regex 56 | $line =~ s/ImVec2\(([^,]*),([^\)]*)\)/ImVec2 $1 $2/g; 57 | $line =~ s/ImVec4\(([^,]*),([^,]*),([^,]*),([^\)]*)\)/ImVec4 $1 $2 $3 $4/g; 58 | #delete this so it's eaiser for regexes 59 | $line =~ s/\s+IM_FMTARGS\(.\);/;/g; 60 | $line =~ s/\s+IM_FMTLIST\(.\);/;/g; 61 | if ($line =~ m/ *IMGUI_API *(const char*\*|[^ ]+) *([^\(]+)\(([^\;]*)\);/) { 62 | print "//" . $line; 63 | # this will be set to 0 if something is not supported yet 64 | my $shouldPrint = 1; 65 | my @args = split(',', $3); 66 | # things to do before calling real c++ function 67 | my @before; 68 | # arguments to real c++ function 69 | my @funcArgs; 70 | # things to do after callign real c++ function 71 | my @after; 72 | # real c++ function name 73 | my $funcName = $2; 74 | if (defined($bannedNames{$funcName})) { 75 | print "//Not allowed to use this function\n"; 76 | $shouldPrint = 0; 77 | } 78 | # c++ type of return value 79 | my $retLine = $1; 80 | my $retType; 81 | # macro used for calling function 82 | my $callMacro; 83 | # if it has a return value (yes I know this is not the cleanest code) 84 | my $hasRet = 1; 85 | if ($retLine =~ /^void$/) { 86 | $callMacro = "CALL_FUNCTION_NO_RET"; 87 | $hasRet = 0; 88 | } elsif ($retLine =~ /^bool$/) { 89 | $callMacro = "CALL_FUNCTION"; 90 | push(@funcArgs, "bool"); 91 | push(@after, "PUSH_BOOL(ret)"); 92 | } elsif ($retLine =~ /^float$/) { 93 | $callMacro = "CALL_FUNCTION"; 94 | push(@funcArgs, "float"); 95 | push(@after, "PUSH_NUMBER(ret)"); 96 | } elsif ($retLine =~ /^ImVec2$/) { 97 | $callMacro = "CALL_FUNCTION"; 98 | push(@funcArgs, "ImVec2"); 99 | push(@after, "PUSH_NUMBER(ret.x)"); 100 | push(@after, "PUSH_NUMBER(ret.y)"); 101 | } elsif ($retLine =~ /^ImVec4$/) { 102 | $callMacro = "CALL_FUNCTION"; 103 | push(@funcArgs, "ImVec4"); 104 | push(@after, "PUSH_NUMBER(ret.x)"); 105 | push(@after, "PUSH_NUMBER(ret.y)"); 106 | push(@after, "PUSH_NUMBER(ret.z)"); 107 | push(@after, "PUSH_NUMBER(ret.w)"); 108 | } elsif ($retLine =~ /^(unsigned int|ImGuiID|ImU32)$/) { 109 | $callMacro = "CALL_FUNCTION"; 110 | push(@funcArgs, "unsigned int"); 111 | push(@after, "PUSH_NUMBER(ret)"); 112 | } elsif ($retLine =~ /^(ImGuiMouseCursor)$/) { # Enums 113 | $callMacro = "CALL_FUNCTION"; 114 | push(@funcArgs, "int"); 115 | push(@after, "PUSH_NUMBER(ret)"); 116 | } elsif ($retLine =~ /^int$/) { 117 | $callMacro = "CALL_FUNCTION"; 118 | push(@funcArgs, "int"); 119 | push(@after, "PUSH_NUMBER(ret)"); 120 | } elsif ($retLine =~ /^const char*\*$/) { 121 | $callMacro = "CALL_FUNCTION"; 122 | push(@funcArgs, "const char*"); 123 | push(@after, "PUSH_STRING(ret)"); 124 | } else { 125 | print "// Unsupported return type $1\n"; 126 | $shouldPrint = 0; 127 | } 128 | for (my $i = 0; $i < @args; $i++) { 129 | # bool * x = NULL or bool * x 130 | if ($args[$i] =~ m/^ *bool *\* *([^ =\[]*)( = NULL|) *$/) { 131 | my $name = $1; 132 | if ($2 =~ m/^ = NULL$/) { 133 | push(@before, "OPTIONAL_BOOL_POINTER_ARG($name)"); 134 | } else { 135 | push(@before, "BOOL_POINTER_ARG($name)"); 136 | } 137 | push(@funcArgs, $name); 138 | push(@after, "END_BOOL_POINTER($name)"); 139 | # float * x 140 | } elsif ($args[$i] =~ m/^ *float *\* *([^ =\[]*)$/) { 141 | my $name = $1; 142 | push(@before, "FLOAT_POINTER_ARG($name)"); 143 | push(@funcArgs, $name); 144 | push(@after, "END_FLOAT_POINTER($name)"); 145 | # const float * x 146 | } elsif ($args[$i] =~ m/^ *const float *\* *([^ =\[]*)$/) { 147 | my $name = $1; 148 | push(@before, "FLOAT_ARRAY_ARG($name)"); 149 | push(@funcArgs, $name); 150 | #float a or float a = number 151 | } elsif ($args[$i] =~ m/^ *float *([^ =\[]*)( *= *[^ ]*|)$/) { 152 | my $name = $1; 153 | if ($2 =~ m/^ *= *([^ ]*)$/) { 154 | push(@before, "OPTIONAL_NUMBER_ARG($name, $1)"); 155 | } else { 156 | push(@before, "NUMBER_ARG($name)"); 157 | } 158 | push(@funcArgs, $name); 159 | # const char* a or const char* a = NULL or "blah" 160 | } elsif ($args[$i] =~ m/^ *const char\* *([^ =\[]*)( *= *(NULL|".*")|) *$/) { 161 | my $name = $1; 162 | if ($2 =~ m/^ *= *(NULL|".*") *$/) { 163 | push(@before, "OPTIONAL_LABEL_ARG($name, $1)"); 164 | } else { 165 | push(@before, "LABEL_ARG($name)"); 166 | } 167 | push(@funcArgs, $name); 168 | # char * 169 | } elsif ($args[$i] =~ m/^ *char *\* *([^ =\[]*)$/) { 170 | my $name = $1; 171 | push(@before, "LABEL_POINTER_ARG($name)"); 172 | push(@funcArgs, $name); 173 | push(@funcArgs, "buf_size"); 174 | push(@after, "END_LABEL_POINTER($name)"); 175 | # skip next argument 176 | $i = $i + 1; 177 | # const char** a 178 | } elsif ($args[$i] =~ m/^ *const char\*\* *([^ =\[]*) *$/ or $args[$i] =~ m/^ *const char\* const\* *([^ =\[]*) *$/ or $args[$i] =~ m/^ *const char\* const *([^ =\[]*)\[\] *$/) { 179 | my $name = $1; 180 | push(@before, "LABEL_ARRAY_ARG($name)"); 181 | push(@funcArgs, $name); 182 | #const ImVec2& size with or without default value of ImVec(0,0) 183 | } elsif ($args[$i] =~ m/^ *(const)? ImVec2&? ([^ ]*) *(= * ImVec2 .* .*|) *$/) { 184 | my $name = $2; 185 | if ($3 =~ m/^= * ImVec2 (.*) (.*)$/) { 186 | push(@before, "OPTIONAL_IM_VEC_2_ARG($name, $1, $2)"); 187 | } else { 188 | push(@before, "IM_VEC_2_ARG($name)"); 189 | } 190 | push(@funcArgs, $name); 191 | #const ImVec4& size with or without default value of ImVec(0,0) 192 | } elsif ($args[$i] =~ m/^ *const ImVec4& ([^ ]*) *(= * ImVec4 .* .* .* .*|) *$/) { 193 | my $name = $1; 194 | if ($2 =~ m/^= * ImVec4 (.*) (.*) (.*) (.*)$/) { 195 | push(@before, "OPTIONAL_IM_VEC_4_ARG($name, $1, $2, $3, $4)"); 196 | } else { 197 | push(@before, "IM_VEC_4_ARG($name)"); 198 | } 199 | push(@funcArgs, $name); 200 | # one of the various enums 201 | # we are handling these as ints 202 | } elsif ($args[$i] =~ m/^ *(ImGuiWindowFlags|ImGuiCol|ImGuiStyleVar|ImGuiKey|ImGuiAlign|ImGuiColorEditMode|ImGuiMouseCursor|ImGuiSetCond|ImGuiInputTextFlags|ImGuiSelectableFlags|ImGuiTreeNodeFlags|ImGuiComboFlags|ImGuiFocusedFlags|ImGuiHoveredFlags|ImGuiDragDropFlags|ImGuiColorEditFlags|ImGuiCond|ImGuiStyle) ([^ ]*)( = 0|) *$/) { 203 | #These are ints 204 | my $name = $2; 205 | if ($3 =~ m/^ = 0$/) { 206 | push(@before, "OPTIONAL_ENUM_ARG($name, 0)"); 207 | } else { 208 | push(@before, "ENUM_ARG($name)"); 209 | } 210 | push(@funcArgs, $name); 211 | #int with default value or not 212 | } elsif ($args[$i] =~ m/^ *int ([^ =\[]*)( = [^ ]*|) *$/) { 213 | my $name = $1; 214 | if ($2 =~ m/^ = ([^ ]*)$/) { 215 | push(@before, "OPTIONAL_INT_ARG($name, $1)"); 216 | } else { 217 | push(@before, "INT_ARG($name)"); 218 | } 219 | push(@funcArgs, $name); 220 | #unsigned int with default value or not 221 | } elsif ($args[$i] =~ m/^ *(unsigned +int|ImGuiID|ImU32) ([^ =\[]*)( = [^ ]*|) *$/) { 222 | my $name = $2; 223 | if ($2 =~ m/^ = ([^ ]*)$/) { 224 | push(@before, "OPTIONAL_UINT_ARG($name, $1)"); 225 | } else { 226 | push(@before, "UINT_ARG($name)"); 227 | } 228 | push(@funcArgs, $name); 229 | # bool with default value or not 230 | } elsif ($args[$i] =~ m/^ *bool ([^ =\[]*)( *= *true| *= *false|) *$/) { 231 | my $name = $1; 232 | if ($2 =~ m/^ *= *([^ ]*)$/) { 233 | push(@before, "OPTIONAL_BOOL_ARG($name, $1)"); 234 | } else { 235 | push(@before, "BOOL_ARG($name)"); 236 | } 237 | push(@funcArgs, $name); 238 | # int * x 239 | } elsif ($args[$i] =~ m/^ *int *\* *([^ =\[]*)$/) { 240 | my $name = $1; 241 | if ($name eq "current_item") { 242 | push(@before, "INT_CURRENT_ITEM_POINTER_ARG($name)"); 243 | push(@funcArgs, $name); 244 | push(@after, "END_INT_CURRENT_ITEM_POINTER($name)"); 245 | } else { 246 | push(@before, "INT_POINTER_ARG($name)"); 247 | push(@funcArgs, $name); 248 | push(@after, "END_INT_POINTER($name)"); 249 | } 250 | # unsigned int * x 251 | } elsif ($args[$i] =~ m/^ *unsigned +int *\* *([^ =\[]*)$/) { 252 | my $name = $1; 253 | push(@before, "UINT_POINTER_ARG($name)"); 254 | push(@funcArgs, $name); 255 | push(@after, "END_UINT_POINTER($name)"); 256 | # float x[] 257 | } elsif ($args[$i] =~ m/^ *float *([^ =\[]*)\[(.)\]$/) { 258 | my $name = $1; 259 | push(@before, "FLOAT_ARRAY$2_ARG($name)"); 260 | push(@funcArgs, $name); 261 | push(@after, "END_FLOAT_ARRAY$2($name)"); 262 | # int x[] 263 | } elsif ($args[$i] =~ m/^ *int *([^ =\[]*)\[(.)\]$/) { 264 | my $name = $1; 265 | push(@before, "INT_ARRAY$2_ARG($name)"); 266 | push(@funcArgs, $name); 267 | push(@after, "END_INT_ARRAY$2($name)"); 268 | # ImTextureID 269 | } elsif ($args[$i] =~ m/^ *ImTextureID ([^ =\[]*) *$/) { 270 | my $name = $1; 271 | push(@before, "TEXTURE_ARG($name)"); 272 | push(@funcArgs, $name); 273 | } elsif ($args[$i] =~ m/^ *(.*) (.*) = (.*)$/) { 274 | my $type = $1; 275 | my $name = $2; 276 | my $value = $3; 277 | push(@before, "DEFAULT_ARG($type, $name, $value)"); 278 | push(@funcArgs, $name); 279 | } elsif ($args[$i] =~ m/^ *int *\* *([^ =\[]*)$/) { 280 | # we don't support variadic functions yet but we let you use it without extra variables 281 | } elsif ($args[$i] =~ m/^ *\.\.\. *$/) { 282 | print "// Variadic functions aren't suppported but here it is anyway\n"; 283 | } else { 284 | print "// Unsupported arg type " . $args[$i] . "\n"; 285 | $shouldPrint = 0; 286 | } 287 | } 288 | 289 | if ($retLine =~ /^bool$/) { 290 | push(@after, "PUSH_LAST_BOOL(ret)"); 291 | } elsif ($retLine =~ /^float$/) { 292 | push(@after, "PUSH_LAST_NUMBER(ret)"); 293 | } elsif ($retLine =~ /^ImVec2$/) { 294 | push(@after, "PUSH_LAST_NUMBER(ret.x)"); 295 | push(@after, "PUSH_LAST_NUMBER(ret.y)"); 296 | } elsif ($retLine =~ /^ImVec4$/) { 297 | push(@after, "PUSH_LAST_NUMBER(ret.x)"); 298 | push(@after, "PUSH_LAST_NUMBER(ret.y)"); 299 | push(@after, "PUSH_LAST_NUMBER(ret.z)"); 300 | push(@after, "PUSH_LAST_NUMBER(ret.w)"); 301 | } elsif ($retLine =~ /^(unsigned int|ImGuiID|ImU32)$/) { 302 | push(@after, "PUSH_LAST_NUMBER(ret)"); 303 | } elsif ($retLine =~ /^(ImGuiMouseCursor)$/) { # Enums 304 | push(@after, "PUSH_LAST_NUMBER(ret)"); 305 | } elsif ($retLine =~ /^int$/) { 306 | push(@after, "PUSH_LAST_NUMBER(ret)"); 307 | } elsif ($retLine =~ /^const char*\*$/) { 308 | push(@after, "PUSH_LAST_STRING(ret)"); 309 | } 310 | 311 | my $luaFunc = $funcName; 312 | # Stupid way of implementing overriding 313 | if ($funcNames{$luaFunc}) { 314 | $funcNames{$luaFunc} = $funcNames{$luaFunc} + 1; 315 | $luaFunc .= "_" . $funcNames{$luaFunc}; 316 | } else { 317 | $funcNames{$luaFunc} = 1; 318 | } 319 | if ($shouldPrint != 0) { 320 | 321 | print "IMGUI_FUNCTION($luaFunc)\n"; 322 | for (my $i = 0; $i < @before; $i++) { 323 | print $before[$i] . "\n"; 324 | } 325 | 326 | print $callMacro . "($funcName"; 327 | for (my $i = 0; $i < @funcArgs; $i++) { 328 | print ", " . $funcArgs[$i]; 329 | } 330 | print ")\n"; 331 | 332 | #for begin and end stack stuff 333 | if ($funcName =~ m/^Begin(.*)$/ || defined($beginN{$funcName})) { 334 | my $curEndType; 335 | if (defined($beginN{$funcName})) { 336 | $curEndType = $beginN{$funcName}; 337 | } else { 338 | $curEndType = $1; 339 | } 340 | if (defined($endOverride{$curEndType})) { 341 | $curEndType = $endOverride{$curEndType}; 342 | } 343 | if (!defined($endTypeToInt{$curEndType})) { 344 | $endTypeToInt{$curEndType} = scalar(@endTypes); 345 | push(@endTypes, $curEndType); 346 | } 347 | my $curEndTypeInt = $endTypeToInt{$curEndType}; 348 | if ($hasRet) { 349 | print "IF_RET_ADD_END_STACK($curEndTypeInt)\n"; 350 | } else { 351 | print "ADD_END_STACK($curEndTypeInt)\n"; 352 | } 353 | } elsif ($funcName =~ m/^End(.*)$/ || defined($endN{$funcName})) { 354 | my $curEndType; 355 | if (defined($endN{$funcName})) { 356 | $curEndType = $endN{$funcName}; 357 | } else { 358 | $curEndType = $1; 359 | } 360 | if (defined($endOverride{$curEndType})) { 361 | $curEndType = $endOverride{$curEndType}; 362 | } 363 | if (!defined($endTypeToInt{$curEndType})) { 364 | $endTypeToInt{$curEndType} = scalar(@endTypes); 365 | push(@endTypes, $curEndType); 366 | } 367 | my $curEndTypeInt = $endTypeToInt{$curEndType}; 368 | print "POP_END_STACK($curEndTypeInt)\n" 369 | } 370 | 371 | for (my $i = 0; $i < @after; $i++) { 372 | print $after[$i] . "\n"; 373 | } 374 | print "END_IMGUI_FUNC\n"; 375 | $numSupported += 1; 376 | } else { 377 | $numUnsupported += 1; 378 | } 379 | } elsif ($line =~ m/^} \/\/ namespace ImGui$/) { 380 | last; 381 | } 382 | } 383 | #for end stack stuff 384 | print "END_STACK_START\n"; 385 | for (my $i = 0; $i < @endTypes; $i++) { 386 | my $endFunc; 387 | if (defined($changeN{$endTypes[$i]})) { 388 | $endFunc = $changeN{$endTypes[$i]}; 389 | } else { 390 | $endFunc = "End" . $endTypes[$i]; 391 | } 392 | print "END_STACK_OPTION($i, " . $endFunc .")\n"; 393 | } 394 | print "END_STACK_END\n"; 395 | 396 | #debug info 397 | print STDERR "Supported: $numSupported Unsupported: $numUnsupported\n"; 398 | -------------------------------------------------------------------------------- /love-imgui-scm-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "love-imgui" 2 | version = "scm-1" 3 | source = { 4 | url = "git://github.com/slages/love-imgui.git" 5 | } 6 | description = { 7 | summary = "imgui module for the LOVE game engine", 8 | detailed = [[ 9 | dear imgui (AKA ImGui), is a bloat-free graphical user interface library for 10 | C++. ImGui is particularly suited to integration in realtime 3D applications, 11 | fullscreen applications, embedded applications, games, or any applications on 12 | platforms where operating system features are non-standard. This library embeds 13 | ImGui in way that is suitable for use with the LOVE game engine. 14 | ]], 15 | homepage = "https://github.com/slages/love-imgui", 16 | license = "MIT" 17 | } 18 | dependencies = { 19 | "lua ~> 5.1", 20 | "love ~> 0.10" 21 | } 22 | build = { 23 | type = "cmake", 24 | variables = { 25 | LUAJIT_INCLUDE_DIR="$(LUA_INCDIR)", 26 | LIB_DIR="$(LIBDIR)" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rockspecs/love-imgui-0.7-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "love-imgui" 2 | version = "0.7-1" 3 | source = { 4 | url = "git://github.com/slages/love-imgui.git" 5 | } 6 | description = { 7 | summary = "imgui module for the LOVE game engine", 8 | detailed = [[ 9 | dear imgui (AKA ImGui), is a bloat-free graphical user interface library for 10 | C++. ImGui is particularly suited to integration in realtime 3D applications, 11 | fullscreen applications, embedded applications, games, or any applications on 12 | platforms where operating system features are non-standard. This library embeds 13 | ImGui in way that is suitable for use with the LOVE game engine. 14 | ]], 15 | homepage = "https://github.com/slages/love-imgui", 16 | license = "MIT" 17 | } 18 | dependencies = { 19 | "lua ~> 5.1", 20 | "love ~> 0.10" 21 | } 22 | build = { 23 | type = "cmake", 24 | variables = { 25 | LIB_DIR = "$(LIBDIR)", 26 | LUAJIT_INCLUDE_DIR = "$(LUA_INCDIR)" 27 | }, 28 | cmake = [=[ 29 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 30 | 31 | SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 32 | FIND_PACKAGE(LuaJIT REQUIRED) 33 | 34 | SET(LIB_NAME imgui) 35 | 36 | ADD_LIBRARY(${LIB_NAME} 37 | MODULE 38 | src/libimgui/imconfig.h 39 | src/libimgui/imgui.cpp 40 | src/libimgui/imgui.h 41 | src/libimgui/imgui_draw.cpp 42 | src/libimgui/imgui_demo.cpp 43 | src/libimgui/imgui_internal.h 44 | src/libimgui/imgui_dock.cpp 45 | src/libimgui/imgui_dock.h 46 | src/libimgui/stb_rect_pack.h 47 | src/libimgui/stb_textedit.h 48 | src/libimgui/stb_truetype.h 49 | src/imgui_impl.cpp 50 | src/wrap_imgui_impl.cpp 51 | src/imgui_impl.h 52 | src/wrap_imgui_impl.h 53 | src/imgui_iterator.h 54 | src/imgui_iterator_dock.h 55 | ) 56 | 57 | TARGET_INCLUDE_DIRECTORIES(${LIB_NAME} 58 | PUBLIC 59 | ${LUAJIT_INCLUDE_DIR} 60 | ) 61 | 62 | TARGET_LINK_LIBRARIES(${LIB_NAME} 63 | ${LUAJIT_LIBRARY} 64 | ) 65 | 66 | SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES PREFIX "") 67 | 68 | IF(DEFINED "LIB_DIR") 69 | INSTALL(TARGETS ${LIB_NAME} LIBRARY DESTINATION ${LIB_DIR}) 70 | ENDIF() 71 | ]=] 72 | } 73 | -------------------------------------------------------------------------------- /src/imgui_impl.cpp: -------------------------------------------------------------------------------- 1 | // IMGUI 2 | #include "imgui_impl.h" 3 | #include "libimgui/imgui.h" 4 | 5 | // STD 6 | #include 7 | #include 8 | #include 9 | //#include 10 | 11 | // Data 12 | static bool g_MousePressed[3] = { false, false, false }; 13 | static float g_MouseWheel = 0.0f; 14 | static std::string g_iniPath; 15 | static std::map g_keyMap; 16 | static lua_State *g_L; 17 | 18 | // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) 19 | // If text or lines are blurry when integrating ImGui in your engine: 20 | // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) 21 | void ImGui_Impl_RenderDrawLists(ImDrawData* draw_data) 22 | { 23 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 24 | ImGuiIO& io = ImGui::GetIO(); 25 | int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); 26 | int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); 27 | if (fb_width == 0 || fb_height == 0) 28 | return; 29 | draw_data->ScaleClipRects(io.DisplayFramebufferScale); 30 | 31 | lua_getglobal(g_L, "imgui"); 32 | // Render command lists 33 | for (int n = 0; n < draw_data->CmdListsCount; n++) 34 | { 35 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 36 | 37 | lua_newtable(g_L); 38 | for (int i = 1; i <= cmd_list->IdxBuffer.size(); i++) 39 | { 40 | lua_pushnumber(g_L, i); 41 | lua_pushnumber(g_L, cmd_list->IdxBuffer[i - 1] + 1); 42 | lua_rawset(g_L, -3); 43 | } 44 | lua_setfield(g_L, -2, "idx"); 45 | 46 | lua_pushlstring(g_L, (char *)&cmd_list->VtxBuffer.front(), cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); 47 | lua_setfield(g_L, -2, "verticesData"); 48 | lua_pushnumber(g_L, cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); 49 | lua_setfield(g_L, -2, "verticesSize"); 50 | 51 | luaL_dostring(g_L, "imgui.renderMesh = love.graphics.newMesh(imgui.vertexformat, love.image.newImageData(imgui.verticesSize / 4, 1, 'rgba8', imgui.verticesData), \"triangles\")\ 52 | imgui.renderMesh:setTexture(imgui.textureObject)\ 53 | imgui.renderMesh:setVertexMap(imgui.idx)"); 54 | 55 | int position = 1; 56 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) 57 | { 58 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 59 | lua_pushnumber(g_L, pcmd->ElemCount); 60 | lua_setfield(g_L, -2, "vertexCount"); 61 | lua_pushnumber(g_L, position); 62 | lua_setfield(g_L, -2, "vertexPosition"); 63 | position += pcmd->ElemCount; 64 | 65 | lua_pushnumber(g_L, (int)pcmd->ClipRect.x); 66 | lua_setfield(g_L, -2, "clipX"); 67 | lua_pushnumber(g_L, (int)(pcmd->ClipRect.y)); 68 | lua_setfield(g_L, -2, "clipY"); 69 | lua_pushnumber(g_L, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x)); 70 | lua_setfield(g_L, -2, "clipWidth"); 71 | lua_pushnumber(g_L, (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); 72 | lua_setfield(g_L, -2, "clipHeight"); 73 | 74 | luaL_dostring(g_L, "love.graphics.setBlendMode(\"alpha\")"); 75 | if (pcmd->TextureId == NULL) 76 | luaL_dostring(g_L, "imgui.renderMesh:setTexture(imgui.textureObject)"); 77 | else 78 | { 79 | lua_pushnumber(g_L, ((int*)pcmd->TextureId)[0]); 80 | lua_setfield(g_L, -2, "currentTexture"); 81 | luaL_dostring(g_L, "\ 82 | local texture = imgui.textures[imgui.currentTexture]\ 83 | if texture:typeOf(\"Canvas\") then\ 84 | love.graphics.setBlendMode(\"alpha\", \"premultiplied\")\ 85 | end\ 86 | imgui.renderMesh:setTexture(texture)\ 87 | "); 88 | } 89 | 90 | luaL_dostring(g_L, "\ 91 | love.graphics.setScissor(imgui.clipX, imgui.clipY, imgui.clipWidth, imgui.clipHeight) \ 92 | imgui.renderMesh:setDrawRange(imgui.vertexPosition, imgui.vertexCount) \ 93 | love.graphics.draw(imgui.renderMesh) \ 94 | "); 95 | } 96 | } 97 | luaL_dostring(g_L, "love.graphics.setScissor()"); 98 | lua_pop(g_L, 1); 99 | } 100 | 101 | static const char* ImGui_Impl_GetClipboardText(void* user_data) 102 | { 103 | luaL_dostring(g_L, "return love.system.getClipboardText()"); 104 | return luaL_checkstring(g_L, 0); 105 | } 106 | 107 | static void ImGui_Impl_SetClipboardText(void* user_data, const char* text) 108 | { 109 | lua_getglobal(g_L, "imgui"); 110 | lua_pushstring(g_L, text); 111 | lua_setfield(g_L, -2, "clipboardText"); 112 | luaL_dostring(g_L, "love.system.setClipboardText(imgui.clipboardText)"); 113 | lua_pop(g_L, 1); 114 | } 115 | 116 | // 117 | // Public part 118 | // 119 | 120 | bool Init(lua_State *L) 121 | { 122 | ImGuiIO& io = ImGui::GetIO(); 123 | 124 | // LUA state 125 | g_L = L; 126 | 127 | // Create the texture object 128 | unsigned char* pixels; 129 | int width, height; 130 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 131 | 132 | lua_getglobal(L, "imgui"); 133 | lua_pushnumber(L, width); 134 | lua_setfield(L, -2, "textureWidth"); 135 | lua_pushnumber(L, height); 136 | lua_setfield(L, -2, "textureHeight"); 137 | lua_pushlstring(L, (char *)pixels, width * height * 4); 138 | lua_setfield(L, -2, "texturePixels"); 139 | luaL_dostring(L, "imgui.textureObject = love.graphics.newImage(love.image.newImageData(imgui.textureWidth, imgui.textureHeight, 'rgba8', imgui.texturePixels))\ 140 | imgui.vertexformat = { {\"VertexPosition\", \"float\", 2}, {\"VertexTexCoord\", \"float\", 2}, {\"VertexColor\", \"byte\", 4} }"); 141 | lua_pop(L, 1); 142 | 143 | // Key map 144 | g_keyMap["tab"] = 1; 145 | g_keyMap["left"] = 2; 146 | g_keyMap["right"] = 3; 147 | g_keyMap["up"] = 4; 148 | g_keyMap["down"] = 5; 149 | g_keyMap["pageup"] = 6; 150 | g_keyMap["pagedown"] = 7; 151 | g_keyMap["home"] = 8; 152 | g_keyMap["end"] = 9; 153 | g_keyMap["delete"] = 10; 154 | g_keyMap["backspace"] = 11; 155 | g_keyMap["return"] = 12; 156 | g_keyMap["escape"] = 13; 157 | g_keyMap["a"] = 14; 158 | g_keyMap["c"] = 15; 159 | g_keyMap["v"] = 16; 160 | g_keyMap["x"] = 17; 161 | g_keyMap["y"] = 18; 162 | g_keyMap["z"] = 19; 163 | 164 | io.KeyMap[ImGuiKey_Tab] = g_keyMap["tab"]; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. 165 | io.KeyMap[ImGuiKey_LeftArrow] = g_keyMap["left"]; 166 | io.KeyMap[ImGuiKey_RightArrow] = g_keyMap["right"]; 167 | io.KeyMap[ImGuiKey_UpArrow] = g_keyMap["up"]; 168 | io.KeyMap[ImGuiKey_DownArrow] = g_keyMap["down"]; 169 | io.KeyMap[ImGuiKey_PageUp] = g_keyMap["pageup"]; 170 | io.KeyMap[ImGuiKey_PageDown] = g_keyMap["pagedown"]; 171 | io.KeyMap[ImGuiKey_Home] = g_keyMap["home"]; 172 | io.KeyMap[ImGuiKey_End] = g_keyMap["end"]; 173 | io.KeyMap[ImGuiKey_Delete] = g_keyMap["delete"]; 174 | io.KeyMap[ImGuiKey_Backspace] = g_keyMap["backspace"]; 175 | io.KeyMap[ImGuiKey_Enter] = g_keyMap["return"]; 176 | io.KeyMap[ImGuiKey_Escape] = g_keyMap["escape"]; 177 | io.KeyMap[ImGuiKey_A] = g_keyMap["a"]; 178 | io.KeyMap[ImGuiKey_C] = g_keyMap["c"]; 179 | io.KeyMap[ImGuiKey_V] = g_keyMap["v"]; 180 | io.KeyMap[ImGuiKey_X] = g_keyMap["x"]; 181 | io.KeyMap[ImGuiKey_Y] = g_keyMap["y"]; 182 | io.KeyMap[ImGuiKey_Z] = g_keyMap["z"]; 183 | 184 | io.RenderDrawListsFn = ImGui_Impl_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. 185 | io.SetClipboardTextFn = ImGui_Impl_SetClipboardText; 186 | io.GetClipboardTextFn = ImGui_Impl_GetClipboardText; 187 | 188 | io.Fonts->TexID = NULL; 189 | 190 | luaL_dostring(L, "love.filesystem.createDirectory('/') return love.filesystem.getSaveDirectory()"); 191 | const char *path = luaL_checkstring(L, 1); 192 | g_iniPath = std::string(path) + std::string("/imgui.ini"); 193 | io.IniFilename = g_iniPath.c_str(); 194 | return true; 195 | } 196 | 197 | void ShutDown() 198 | { 199 | ImGui::Shutdown(); 200 | } 201 | 202 | void NewFrame() 203 | { 204 | ImGuiIO& io = ImGui::GetIO(); 205 | 206 | // Setup display size (every frame to accommodate for window resizing) 207 | luaL_dostring(g_L, "return love.graphics.getWidth()"); 208 | float w = luaL_checknumber(g_L, 0); 209 | luaL_dostring(g_L, "return love.graphics.getHeight()"); 210 | float h = luaL_checknumber(g_L, 0); 211 | //int display_w, display_h; 212 | // SDL_GL_GetDrawableSize(window, &display_w, &display_h); 213 | io.DisplaySize = ImVec2(w, h); 214 | // io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); 215 | io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); 216 | 217 | // Setup time step 218 | luaL_dostring(g_L, "return love.timer.getDelta()"); 219 | double time = luaL_checknumber(g_L, 0); 220 | io.DeltaTime = (float)time; 221 | 222 | // Setup input 223 | io.MouseDown[0] = g_MousePressed[0]; 224 | io.MouseDown[1] = g_MousePressed[1]; 225 | io.MouseDown[2] = g_MousePressed[2]; 226 | io.MouseWheel = g_MouseWheel; 227 | g_MouseWheel = 0.0f; 228 | 229 | // Hide OS mouse cursor if ImGui is drawing it 230 | lua_getglobal(g_L, "imgui"); 231 | lua_pushboolean(g_L, (int)io.MouseDrawCursor); 232 | lua_setfield(g_L, -2, "mouseDrawCursor"); 233 | luaL_dostring(g_L, "love.mouse.setVisible(not imgui.mouseDrawCursor)"); 234 | 235 | // Init lua data 236 | luaL_dostring(g_L, "imgui.textures = nil"); 237 | lua_pop(g_L, 1); 238 | 239 | // Start the frame 240 | ImGui::NewFrame(); 241 | } 242 | 243 | // 244 | // Inputs 245 | // 246 | void MouseMoved(int x, int y) 247 | { 248 | if (g_L) 249 | { 250 | ImGuiIO& io = ImGui::GetIO(); 251 | luaL_dostring(g_L, "return love.window.hasMouseFocus()"); 252 | int focus = lua_toboolean(g_L, 3); 253 | if (focus > 0) 254 | io.MousePos = ImVec2((float)x, (float)y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) 255 | else 256 | io.MousePos = ImVec2(-1, -1); 257 | } 258 | } 259 | 260 | void MousePressed(int button) 261 | { 262 | if (button == 1) g_MousePressed[0] = true; 263 | if (button == 2) g_MousePressed[1] = true; 264 | if (button == 3) g_MousePressed[2] = true; 265 | } 266 | 267 | void MouseReleased(int button) 268 | { 269 | if (button == 1) g_MousePressed[0] = false; 270 | if (button == 2) g_MousePressed[1] = false; 271 | if (button == 3) g_MousePressed[2] = false; 272 | } 273 | 274 | void WheelMoved(int y) 275 | { 276 | if (y > 0) 277 | g_MouseWheel = 1; 278 | if (y < 0) 279 | g_MouseWheel = -1; 280 | } 281 | 282 | void KeyPressed(const char *key) 283 | { 284 | if (g_L) 285 | { 286 | std::string k(key); 287 | if (k == "kpenter") 288 | k = "return"; 289 | ImGuiIO& io = ImGui::GetIO(); 290 | io.KeysDown[g_keyMap[k]] = true; 291 | luaL_dostring(g_L, "return (love.keyboard.isDown('rshift') or love.keyboard.isDown('lshift'))"); 292 | bool down = lua_toboolean(g_L, 2) > 0; 293 | io.KeyShift = down; 294 | luaL_dostring(g_L, "return (love.keyboard.isDown('rctrl') or love.keyboard.isDown('lctrl'))"); 295 | down = lua_toboolean(g_L, 3) > 0; 296 | io.KeyCtrl = down; 297 | luaL_dostring(g_L, "return (love.keyboard.isDown('ralt') or love.keyboard.isDown('lalt'))"); 298 | down = lua_toboolean(g_L, 4) > 0; 299 | io.KeyAlt = down; 300 | luaL_dostring(g_L, "return (love.keyboard.isDown('rgui') or love.keyboard.isDown('lgui'))"); 301 | down = lua_toboolean(g_L, 5) > 0; 302 | io.KeySuper = down; 303 | } 304 | } 305 | 306 | void KeyReleased(const char *key) 307 | { 308 | if (g_L) 309 | { 310 | std::string k(key); 311 | if (k == "kpenter") 312 | k = "return"; 313 | ImGuiIO& io = ImGui::GetIO(); 314 | io.KeysDown[g_keyMap[k.c_str()]] = false; 315 | luaL_dostring(g_L, "return (love.keyboard.isDown('rshift') or love.keyboard.isDown('lshift'))"); 316 | bool down = lua_toboolean(g_L, 2) > 0; 317 | io.KeyShift = down; 318 | luaL_dostring(g_L, "return (love.keyboard.isDown('rctrl') or love.keyboard.isDown('lctrl'))"); 319 | down = lua_toboolean(g_L, 3) > 0; 320 | io.KeyCtrl = down; 321 | luaL_dostring(g_L, "return (love.keyboard.isDown('ralt') or love.keyboard.isDown('lalt'))"); 322 | down = lua_toboolean(g_L, 4) > 0; 323 | io.KeyAlt = down; 324 | luaL_dostring(g_L, "return (love.keyboard.isDown('rgui') or love.keyboard.isDown('lgui'))"); 325 | down = lua_toboolean(g_L, 5) > 0; 326 | io.KeySuper = down; 327 | } 328 | } 329 | 330 | void TextInput(const char *text) 331 | { 332 | ImGuiIO& io = ImGui::GetIO(); 333 | io.AddInputCharactersUTF8(text); 334 | } 335 | 336 | // Inputs state 337 | bool GetWantCaptureMouse() 338 | { 339 | ImGuiIO& io = ImGui::GetIO(); 340 | return io.WantCaptureMouse; 341 | } 342 | 343 | bool GetWantCaptureKeyboard() 344 | { 345 | ImGuiIO& io = ImGui::GetIO(); 346 | return io.WantCaptureKeyboard; 347 | } 348 | 349 | bool GetWantTextInput() 350 | { 351 | ImGuiIO& io = ImGui::GetIO(); 352 | return io.WantTextInput; 353 | } 354 | 355 | // Fonts 356 | void SetGlobalFontFromFileTTF(const char *path, float size_pixels, float spacing_x, float spacing_y, float oversample_x, float oversample_y) 357 | { 358 | ImGuiIO& io = ImGui::GetIO(); 359 | ImFontConfig conf; 360 | conf.OversampleH = oversample_x; 361 | conf.OversampleV = oversample_y; 362 | conf.GlyphExtraSpacing.x = spacing_x; 363 | conf.GlyphExtraSpacing.y = spacing_y; 364 | io.Fonts->AddFontFromFileTTF(path, size_pixels, &conf); 365 | } 366 | -------------------------------------------------------------------------------- /src/imgui_impl.h: -------------------------------------------------------------------------------- 1 | // Lua 2 | extern "C" { 3 | #define LUA_COMPAT_ALL 4 | #include 5 | #include 6 | #include 7 | } 8 | 9 | bool Init(lua_State *L); 10 | void ShutDown(); 11 | void NewFrame(); 12 | // Inputs 13 | void MouseMoved(int x, int y); 14 | void MousePressed(int button); 15 | void MouseReleased(int button); 16 | void WheelMoved(int y); 17 | void KeyPressed(const char *key); 18 | void KeyReleased(const char *key); 19 | void TextInput(const char *text); 20 | // Inputs state 21 | bool GetWantCaptureMouse(); 22 | bool GetWantCaptureKeyboard(); 23 | bool GetWantTextInput(); 24 | // Fonts 25 | void SetGlobalFontFromFileTTF(const char *path, float size_pixels, 26 | float spacing_x, float spacing_y, float oversample_x, float oversample_y); 27 | -------------------------------------------------------------------------------- /src/imgui_iterator_dock.h: -------------------------------------------------------------------------------- 1 | //IMGUI_API void BeginDockspace(); 2 | IMGUI_FUNCTION(BeginDockspace) 3 | CALL_FUNCTION_NO_RET(BeginDockspace) 4 | ADD_END_STACK(0) 5 | END_IMGUI_FUNC 6 | //IMGUI_API void EndDockspace(); 7 | IMGUI_FUNCTION(EndDockspace) 8 | CALL_FUNCTION_NO_RET(EndDockspace) 9 | POP_END_STACK(0) 10 | END_IMGUI_FUNC 11 | //IMGUI_API void ShutdownDock(); 12 | IMGUI_FUNCTION(ShutdownDock) 13 | CALL_FUNCTION_NO_RET(ShutdownDock) 14 | END_IMGUI_FUNC 15 | //IMGUI_API void SetNextDock(ImGuiDockSlot slot); 16 | IMGUI_FUNCTION(SetNextDock) 17 | OPTIONAL_ENUM_ARG(slot, 6) 18 | CALL_FUNCTION_NO_RET(SetNextDock, (ImGuiDockSlot)slot) 19 | END_IMGUI_FUNC 20 | //IMGUI_API bool BeginDock(const char* label, bool* opened = nullptr, ImGuiWindowFlags extra_flags = 0); 21 | IMGUI_FUNCTION(BeginDock) 22 | LABEL_ARG(label) 23 | DEFAULT_ARG(bool*, opened, NULL) 24 | OPTIONAL_ENUM_ARG(extra_flags, 0) 25 | CALL_FUNCTION(BeginDock, bool, label, opened, extra_flags) 26 | IF_RET_ADD_END_STACK(1) 27 | PUSH_BOOL(ret) 28 | END_IMGUI_FUNC 29 | //IMGUI_API void SetNextDockSplitRatio(const ImVec2& split_ratio = ImVec2 0.5 0.5); 30 | IMGUI_FUNCTION(SetNextDockSplitRatio) 31 | OPTIONAL_IM_VEC_2_ARG(split_ratio, 0.5 , 0.5) 32 | CALL_FUNCTION_NO_RET(SetNextDockSplitRatio, split_ratio) 33 | END_IMGUI_FUNC 34 | //IMGUI_API void SetNextDockFloatingSize(const ImVec2& floating_size = ImVec2 0.5 0.5); 35 | IMGUI_FUNCTION(SetNextDockFloatingSize) 36 | OPTIONAL_IM_VEC_2_ARG(floating_size, 0.5 , 0.5) 37 | CALL_FUNCTION_NO_RET(SetNextDockFloatingSize, floating_size) 38 | END_IMGUI_FUNC 39 | //IMGUI_API void EndDock(); 40 | IMGUI_FUNCTION(EndDock) 41 | CALL_FUNCTION_NO_RET(EndDock) 42 | POP_END_STACK(1) 43 | END_IMGUI_FUNC 44 | //IMGUI_API void SetDockActive(); 45 | IMGUI_FUNCTION(SetDockActive) 46 | CALL_FUNCTION_NO_RET(SetDockActive) 47 | END_IMGUI_FUNC 48 | //IMGUI_API void DockDebugWindow(); 49 | IMGUI_FUNCTION(DockDebugWindow) 50 | CALL_FUNCTION_NO_RET(DockDebugWindow) 51 | END_IMGUI_FUNC 52 | END_STACK_START 53 | END_STACK_OPTION(0, EndDockspace) 54 | END_STACK_OPTION(1, EndDock) 55 | END_STACK_END 56 | -------------------------------------------------------------------------------- /src/libimgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // USER IMPLEMENTATION 3 | // This file contains compile-time options for ImGui. 4 | // Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO(). 5 | //----------------------------------------------------------------------------- 6 | 7 | #pragma once 8 | 9 | //---- Define assertion handler. Defaults to calling assert(). 10 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 11 | 12 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. 13 | //#define IMGUI_API __declspec( dllexport ) 14 | //#define IMGUI_API __declspec( dllimport ) 15 | 16 | //---- Don't define obsolete functions names. Consider enabling from time to time or when updating to reduce like hood of using already obsolete function/names 17 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 18 | 19 | //---- Include imgui_user.h at the end of imgui.h 20 | //#define IMGUI_INCLUDE_IMGUI_USER_H 21 | 22 | //---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions) 23 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS 24 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS 25 | 26 | //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) 27 | //---- It is very strongly recommended to NOT disable the demo windows. Please read the comment at the top of imgui_demo.cpp to learn why. 28 | //#define IMGUI_DISABLE_DEMO_WINDOWS 29 | 30 | //---- Don't implement ImFormatString(), ImFormatStringV() so you can reimplement them yourself. 31 | //#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS 32 | 33 | //---- Pack colors to BGRA instead of RGBA (remove need to post process vertex buffer in back ends) 34 | //#define IMGUI_USE_BGRA_PACKED_COLOR 35 | 36 | //---- Implement STB libraries in a namespace to avoid linkage conflicts 37 | //#define IMGUI_STB_NAMESPACE ImGuiStb 38 | 39 | //---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. 40 | /* 41 | #define IM_VEC2_CLASS_EXTRA \ 42 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 43 | operator MyVec2() const { return MyVec2(x,y); } 44 | 45 | #define IM_VEC4_CLASS_EXTRA \ 46 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 47 | operator MyVec4() const { return MyVec4(x,y,z,w); } 48 | */ 49 | 50 | //---- Use 32-bit vertex indices (instead of default: 16-bit) to allow meshes with more than 64K vertices 51 | //#define ImDrawIdx unsigned int 52 | 53 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 54 | //---- e.g. create variants of the ImGui::Value() helper for your low-level math types, or your own widgets/helpers. 55 | /* 56 | namespace ImGui 57 | { 58 | void Value(const char* prefix, const MyMatrix44& v, const char* float_format = NULL); 59 | } 60 | */ 61 | 62 | -------------------------------------------------------------------------------- /src/libimgui/imgui_dock.cpp: -------------------------------------------------------------------------------- 1 | // based on https://github.com/nem0/LumixEngine/blob/master/external/imgui/imgui_dock.inl 2 | // modified from https://bitbucket.org/duangle/liminal/src/tip/src/liminal/imgui_dock.cpp 3 | 4 | #include "imgui.h" 5 | #define IMGUI_DEFINE_PLACEMENT_NEW 6 | #define IMGUI_DEFINE_MATH_OPERATORS 7 | #include "imgui_internal.h" 8 | #include "imgui_dock.h" 9 | 10 | using namespace ImGui; 11 | 12 | #define nullptr NULL 13 | 14 | struct DockContext 15 | { 16 | enum EndAction_ 17 | { 18 | EndAction_None, 19 | EndAction_Panel, 20 | EndAction_End, 21 | EndAction_EndChild 22 | }; 23 | 24 | 25 | enum Status_ 26 | { 27 | Status_Docked, 28 | Status_Float, 29 | Status_Dragged 30 | }; 31 | 32 | 33 | struct Dock 34 | { 35 | Dock() 36 | : id(0) 37 | , next_tab(nullptr) 38 | , prev_tab(nullptr) 39 | , parent(nullptr) 40 | , pos(0, 0) 41 | , size(-1, -1) 42 | , active(true) 43 | , movable(true) 44 | , status(Status_Float) 45 | , split_ratio(0.5, 0.5) 46 | , label(nullptr) 47 | , opened(false) 48 | 49 | { 50 | location[0] = 0; 51 | children[0] = children[1] = nullptr; 52 | } 53 | 54 | 55 | ~Dock() { MemFree(label); } 56 | 57 | 58 | ImVec2 getMinSize() const 59 | { 60 | if (!children[0]) return ImVec2(16, 16 + GetTextLineHeightWithSpacing()); 61 | 62 | ImVec2 s0 = children[0]->getMinSize(); 63 | ImVec2 s1 = children[1]->getMinSize(); 64 | return isHorizontal() ? ImVec2(s0.x + s1.x, ImMax(s0.y, s1.y)) 65 | : ImVec2(ImMax(s0.x, s1.x), s0.y + s1.y); 66 | } 67 | 68 | 69 | bool isHorizontal() const { return children[0]->pos.x < children[1]->pos.x; } 70 | 71 | 72 | void setParent(Dock* dock) 73 | { 74 | parent = dock; 75 | for (Dock* tmp = prev_tab; tmp; tmp = tmp->prev_tab) tmp->parent = dock; 76 | for (Dock* tmp = next_tab; tmp; tmp = tmp->next_tab) tmp->parent = dock; 77 | } 78 | 79 | Dock& getRoot() 80 | { 81 | Dock *dock = this; 82 | while (dock->parent) 83 | dock = dock->parent; 84 | return *dock; 85 | } 86 | 87 | 88 | Dock& getSibling() 89 | { 90 | IM_ASSERT(parent); 91 | if (parent->children[0] == &getFirstTab()) return *parent->children[1]; 92 | return *parent->children[0]; 93 | } 94 | 95 | 96 | Dock& getFirstTab() 97 | { 98 | Dock* tmp = this; 99 | while (tmp->prev_tab) tmp = tmp->prev_tab; 100 | return *tmp; 101 | } 102 | 103 | 104 | void setActive() 105 | { 106 | active = true; 107 | for (Dock* tmp = prev_tab; tmp; tmp = tmp->prev_tab) tmp->active = false; 108 | for (Dock* tmp = next_tab; tmp; tmp = tmp->next_tab) tmp->active = false; 109 | } 110 | 111 | 112 | bool isContainer() const { return children[0] != nullptr; } 113 | 114 | 115 | void setChildrenPosSize(const ImVec2& _pos, const ImVec2& _size) 116 | { 117 | ImVec2 s = children[0]->size; 118 | if (isHorizontal()) 119 | { 120 | s.y = _size.y; 121 | s.x = (float)int( 122 | _size.x * children[0]->size.x / (children[0]->size.x + children[1]->size.x)); 123 | if (s.x < children[0]->getMinSize().x) 124 | { 125 | s.x = children[0]->getMinSize().x; 126 | } 127 | else if (_size.x - s.x < children[1]->getMinSize().x) 128 | { 129 | s.x = _size.x - children[1]->getMinSize().x; 130 | } 131 | children[0]->setPosSize(_pos, s); 132 | 133 | s.x = _size.x - children[0]->size.x; 134 | ImVec2 p = _pos; 135 | p.x += children[0]->size.x; 136 | children[1]->setPosSize(p, s); 137 | } 138 | else 139 | { 140 | s.x = _size.x; 141 | s.y = (float)int( 142 | _size.y * children[0]->size.y / (children[0]->size.y + children[1]->size.y)); 143 | if (s.y < children[0]->getMinSize().y) 144 | { 145 | s.y = children[0]->getMinSize().y; 146 | } 147 | else if (_size.y - s.y < children[1]->getMinSize().y) 148 | { 149 | s.y = _size.y - children[1]->getMinSize().y; 150 | } 151 | children[0]->setPosSize(_pos, s); 152 | 153 | s.y = _size.y - children[0]->size.y; 154 | ImVec2 p = _pos; 155 | p.y += children[0]->size.y; 156 | children[1]->setPosSize(p, s); 157 | } 158 | } 159 | 160 | 161 | void setPosSize(const ImVec2& _pos, const ImVec2& _size) 162 | { 163 | size = _size; 164 | pos = _pos; 165 | for (Dock* tmp = prev_tab; tmp; tmp = tmp->prev_tab) 166 | { 167 | tmp->size = _size; 168 | tmp->pos = _pos; 169 | } 170 | for (Dock* tmp = next_tab; tmp; tmp = tmp->next_tab) 171 | { 172 | tmp->size = _size; 173 | tmp->pos = _pos; 174 | } 175 | 176 | if (!isContainer()) return; 177 | setChildrenPosSize(_pos, _size); 178 | } 179 | 180 | 181 | char* label; 182 | ImU32 id; 183 | Dock* next_tab; 184 | Dock* prev_tab; 185 | Dock* children[2]; 186 | Dock* parent; 187 | bool active; 188 | bool movable; 189 | ImVec2 pos; 190 | ImVec2 size; 191 | Status_ status; 192 | ImVec2 split_ratio; 193 | int last_frame; 194 | int invalid_frames; 195 | char location[16]; 196 | bool opened; 197 | bool first; 198 | }; 199 | 200 | 201 | ImVector m_docks; 202 | ImVec2 m_drag_offset; 203 | Dock* m_current; 204 | Dock *m_next_parent; 205 | int m_last_frame; 206 | EndAction_ m_end_action; 207 | ImVec2 m_workspace_pos; 208 | ImVec2 m_workspace_size; 209 | ImGuiDockSlot m_next_dock_slot; 210 | ImVec2 m_next_split_ratio; 211 | ImVec2 m_next_floating_size; 212 | 213 | DockContext() 214 | : m_current(nullptr) 215 | , m_next_parent(nullptr) 216 | , m_last_frame(0) 217 | , m_next_dock_slot(ImGuiDockSlot_Tab) 218 | , m_next_split_ratio(0.5, 0.5) 219 | , m_next_floating_size(-1, -1) 220 | { 221 | } 222 | 223 | ~DockContext() {} 224 | 225 | Dock& getDock(const char* label, bool opened) 226 | { 227 | ImU32 id = ImHash(label, 0); 228 | for (int i = 0; i < m_docks.size(); ++i) 229 | { 230 | if (m_docks[i]->id == id) return *m_docks[i]; 231 | } 232 | 233 | Dock* new_dock = (Dock*)MemAlloc(sizeof(Dock)); 234 | IM_PLACEMENT_NEW(new_dock) Dock(); 235 | m_docks.push_back(new_dock); 236 | new_dock->label = ImStrdup(label); 237 | IM_ASSERT(new_dock->label); 238 | new_dock->id = id; 239 | new_dock->setActive(); 240 | new_dock->status = (m_docks.size() == 1)?Status_Docked:Status_Float; 241 | new_dock->pos = ImVec2(0, 0); 242 | if (m_next_floating_size.x >= 0 && m_next_floating_size.y >= 0) 243 | { 244 | new_dock->size.x = m_next_floating_size.x < 0 ? GetIO().DisplaySize.x : m_next_floating_size.x; 245 | new_dock->size.y = m_next_floating_size.y < 0 ? GetIO().DisplaySize.y : m_next_floating_size.y; 246 | } 247 | else 248 | { 249 | new_dock->size.x = new_dock->size.x < 0 ? GetIO().DisplaySize.x : m_next_floating_size.x; 250 | new_dock->size.y = new_dock->size.y < 0 ? GetIO().DisplaySize.y : m_next_floating_size.y; 251 | } 252 | new_dock->split_ratio = m_next_split_ratio; 253 | new_dock->opened = opened; 254 | new_dock->first = true; 255 | new_dock->last_frame = 0; 256 | new_dock->invalid_frames = 0; 257 | new_dock->location[0] = 0; 258 | return *new_dock; 259 | } 260 | 261 | 262 | void putInBackground() 263 | { 264 | ImGuiWindow* win = GetCurrentWindow(); 265 | ImGuiContext& g = *GImGui; 266 | if (g.Windows[0] == win) return; 267 | 268 | for (int i = 0; i < g.Windows.Size; i++) 269 | { 270 | if (g.Windows[i] == win) 271 | { 272 | for (int j = i - 1; j >= 0; --j) 273 | { 274 | g.Windows[j + 1] = g.Windows[j]; 275 | } 276 | g.Windows[0] = win; 277 | break; 278 | } 279 | } 280 | } 281 | 282 | 283 | void splits() 284 | { 285 | if (GetFrameCount() == m_last_frame) return; 286 | m_last_frame = GetFrameCount(); 287 | 288 | putInBackground(); 289 | 290 | for (int i = 0; i < m_docks.size(); ++i) { 291 | Dock& dock = *m_docks[i]; 292 | if (!dock.parent && (dock.status == Status_Docked)) { 293 | dock.setPosSize(m_workspace_pos, m_workspace_size); 294 | } 295 | } 296 | 297 | ImU32 color = GetColorU32(ImGuiCol_Button); 298 | ImU32 color_hovered = GetColorU32(ImGuiCol_ButtonHovered); 299 | ImDrawList* draw_list = GetWindowDrawList(); 300 | ImGuiIO& io = GetIO(); 301 | for (int i = 0; i < m_docks.size(); ++i) 302 | { 303 | Dock& dock = *m_docks[i]; 304 | if (!dock.isContainer()) continue; 305 | 306 | PushID(i); 307 | if (!IsMouseDown(0)) dock.status = Status_Docked; 308 | 309 | ImVec2 pos0 = dock.children[0]->pos; 310 | ImVec2 pos1 = dock.children[1]->pos; 311 | ImVec2 size0 = dock.children[0]->size; 312 | ImVec2 size1 = dock.children[1]->size; 313 | 314 | ImGuiMouseCursor cursor; 315 | 316 | ImVec2 dsize(0, 0); 317 | ImVec2 min_size0 = dock.children[0]->getMinSize(); 318 | ImVec2 min_size1 = dock.children[1]->getMinSize(); 319 | if (dock.isHorizontal()) 320 | { 321 | cursor = ImGuiMouseCursor_ResizeEW; 322 | SetCursorScreenPos(ImVec2(dock.pos.x + size0.x, dock.pos.y)); 323 | InvisibleButton("split", ImVec2(3, dock.size.y)); 324 | if (dock.status == Status_Dragged) dsize.x = io.MouseDelta.x; 325 | dsize.x = -ImMin(-dsize.x, dock.children[0]->size.x - min_size0.x); 326 | dsize.x = ImMin(dsize.x, dock.children[1]->size.x - min_size1.x); 327 | size0 += dsize; 328 | size1 -= dsize; 329 | pos0 = dock.pos; 330 | pos1.x = pos0.x + size0.x; 331 | pos1.y = dock.pos.y; 332 | size0.y = size1.y = dock.size.y; 333 | size1.x = ImMax(min_size1.x, dock.size.x - size0.x); 334 | size0.x = ImMax(min_size0.x, dock.size.x - size1.x); 335 | } 336 | else 337 | { 338 | cursor = ImGuiMouseCursor_ResizeNS; 339 | SetCursorScreenPos(ImVec2(dock.pos.x, dock.pos.y + size0.y)); 340 | InvisibleButton("split", ImVec2(dock.size.x, 3)); 341 | if (dock.status == Status_Dragged) dsize.y = io.MouseDelta.y; 342 | dsize.y = -ImMin(-dsize.y, dock.children[0]->size.y - min_size0.y); 343 | dsize.y = ImMin(dsize.y, dock.children[1]->size.y - min_size1.y); 344 | size0 += dsize; 345 | size1 -= dsize; 346 | pos0 = dock.pos; 347 | pos1.x = dock.pos.x; 348 | pos1.y = pos0.y + size0.y; 349 | size0.x = size1.x = dock.size.x; 350 | size1.y = ImMax(min_size1.y, dock.size.y - size0.y); 351 | size0.y = ImMax(min_size0.y, dock.size.y - size1.y); 352 | } 353 | dock.children[0]->setPosSize(pos0, size0); 354 | dock.children[1]->setPosSize(pos1, size1); 355 | 356 | if (IsItemHovered()) { 357 | SetMouseCursor(cursor); 358 | } 359 | 360 | if (IsItemHovered() && IsMouseClicked(0) && dock.movable) 361 | { 362 | dock.status = Status_Dragged; 363 | } 364 | 365 | draw_list->AddRectFilled( 366 | GetItemRectMin(), GetItemRectMax(), IsItemHovered() ? color_hovered : color); 367 | PopID(); 368 | } 369 | } 370 | 371 | 372 | void checkNonexistent() 373 | { 374 | int frame_limit = ImMax(0, ImGui::GetFrameCount() - 2); 375 | for (int i = 0; i < m_docks.size(); ++i) 376 | { 377 | Dock *dock = m_docks[i]; 378 | if (dock->isContainer()) continue; 379 | if (dock->status == Status_Float) continue; 380 | if (dock->last_frame < frame_limit) 381 | { 382 | ++dock->invalid_frames; 383 | if (dock->invalid_frames > 2) 384 | { 385 | doUndock(*dock); 386 | dock->status = Status_Float; 387 | } 388 | return; 389 | } 390 | dock->invalid_frames = 0; 391 | } 392 | } 393 | 394 | 395 | Dock* getDockAt(const ImVec2& pos) const 396 | { 397 | for (int i = 0; i < m_docks.size(); ++i) 398 | { 399 | Dock& dock = *m_docks[i]; 400 | if (dock.isContainer()) continue; 401 | if (dock.status != Status_Docked) continue; 402 | if (IsMouseHoveringRect(dock.pos, dock.pos + dock.size, false)) 403 | { 404 | return &dock; 405 | } 406 | } 407 | 408 | return nullptr; 409 | } 410 | 411 | 412 | static ImRect getDockedRect(const ImRect& rect, ImGuiDockSlot dock_slot) 413 | { 414 | ImVec2 half_size = rect.GetSize() * 0.5f; 415 | switch (dock_slot) 416 | { 417 | default: return rect; 418 | case ImGuiDockSlot_Top: return ImRect(rect.Min, ImVec2(rect.Max.x, rect.Min.y + half_size.y)); 419 | case ImGuiDockSlot_Right: return ImRect(rect.Min + ImVec2(half_size.x, 0), rect.Max); 420 | case ImGuiDockSlot_Bottom: return ImRect(rect.Min + ImVec2(0, half_size.y), rect.Max); 421 | case ImGuiDockSlot_Left: return ImRect(rect.Min, ImVec2(rect.Min.x + half_size.x, rect.Max.y)); 422 | } 423 | } 424 | 425 | 426 | static ImRect getSlotRect(ImRect parent_rect, ImGuiDockSlot dock_slot) 427 | { 428 | ImVec2 size = parent_rect.Max - parent_rect.Min; 429 | ImVec2 center = parent_rect.Min + size * 0.5f; 430 | switch (dock_slot) 431 | { 432 | default: return ImRect(center - ImVec2(20, 20), center + ImVec2(20, 20)); 433 | case ImGuiDockSlot_Top: return ImRect(center + ImVec2(-20, -50), center + ImVec2(20, -30)); 434 | case ImGuiDockSlot_Right: return ImRect(center + ImVec2(30, -20), center + ImVec2(50, 20)); 435 | case ImGuiDockSlot_Bottom: return ImRect(center + ImVec2(-20, +30), center + ImVec2(20, 50)); 436 | case ImGuiDockSlot_Left: return ImRect(center + ImVec2(-50, -20), center + ImVec2(-30, 20)); 437 | } 438 | } 439 | 440 | 441 | static ImRect getSlotRectOnBorder(ImRect parent_rect, ImGuiDockSlot dock_slot) 442 | { 443 | ImVec2 size = parent_rect.Max - parent_rect.Min; 444 | ImVec2 center = parent_rect.Min + size * 0.5f; 445 | switch (dock_slot) 446 | { 447 | case ImGuiDockSlot_Top: 448 | return ImRect(ImVec2(center.x - 20, parent_rect.Min.y + 10), 449 | ImVec2(center.x + 20, parent_rect.Min.y + 30)); 450 | case ImGuiDockSlot_Left: 451 | return ImRect(ImVec2(parent_rect.Min.x + 10, center.y - 20), 452 | ImVec2(parent_rect.Min.x + 30, center.y + 20)); 453 | case ImGuiDockSlot_Bottom: 454 | return ImRect(ImVec2(center.x - 20, parent_rect.Max.y - 30), 455 | ImVec2(center.x + 20, parent_rect.Max.y - 10)); 456 | case ImGuiDockSlot_Right: 457 | return ImRect(ImVec2(parent_rect.Max.x - 30, center.y - 20), 458 | ImVec2(parent_rect.Max.x - 10, center.y + 20)); 459 | default: IM_ASSERT(false); 460 | } 461 | IM_ASSERT(false); 462 | return ImRect(); 463 | } 464 | 465 | 466 | Dock* getRootDock() 467 | { 468 | for (int i = 0; i < m_docks.size(); ++i) 469 | { 470 | if (!m_docks[i]->parent && 471 | (m_docks[i]->status == Status_Docked || m_docks[i]->children[0])) 472 | { 473 | return m_docks[i]; 474 | } 475 | } 476 | return nullptr; 477 | } 478 | 479 | 480 | bool dockSlots(Dock& dock, Dock* dest_dock, const ImRect& rect, bool on_border) 481 | { 482 | ImDrawList* canvas = GetWindowDrawList(); 483 | ImU32 color = GetColorU32(ImGuiCol_Button); 484 | ImU32 color_hovered = GetColorU32(ImGuiCol_ButtonHovered); 485 | ImVec2 mouse_pos = GetIO().MousePos; 486 | for (int i = 0; i < (on_border ? 4 : 5); ++i) 487 | { 488 | ImRect r = 489 | on_border ? getSlotRectOnBorder(rect, (ImGuiDockSlot)i) : getSlotRect(rect, (ImGuiDockSlot)i); 490 | bool hovered = r.Contains(mouse_pos); 491 | canvas->AddRectFilled(r.Min, r.Max, hovered ? color_hovered : color); 492 | if (!hovered) continue; 493 | 494 | if (!IsMouseDown(0)) 495 | { 496 | doDock(dock, dest_dock ? dest_dock : getRootDock(), (ImGuiDockSlot)i); 497 | return true; 498 | } 499 | ImRect docked_rect = getDockedRect(rect, (ImGuiDockSlot)i); 500 | canvas->AddRectFilled(docked_rect.Min, docked_rect.Max, GetColorU32(ImGuiCol_Button)); 501 | } 502 | return false; 503 | } 504 | 505 | 506 | void handleDrag(Dock& dock) 507 | { 508 | Dock* dest_dock = getDockAt(GetIO().MousePos); 509 | 510 | Begin("##Overlay", 511 | NULL, 512 | ImVec2(0, 0), 513 | 0.f, 514 | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | 515 | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | 516 | ImGuiWindowFlags_AlwaysAutoResize); 517 | ImDrawList* canvas = GetWindowDrawList(); 518 | 519 | canvas->PushClipRectFullScreen(); 520 | 521 | ImU32 docked_color = GetColorU32(ImGuiCol_FrameBg); 522 | docked_color = (docked_color & 0x00ffFFFF) | 0x80000000; 523 | dock.pos = GetIO().MousePos - m_drag_offset; 524 | if (dest_dock) 525 | { 526 | if (dockSlots(dock, 527 | dest_dock, 528 | ImRect(dest_dock->pos, dest_dock->pos + dest_dock->size), 529 | false)) 530 | { 531 | canvas->PopClipRect(); 532 | End(); 533 | return; 534 | } 535 | } 536 | if (dockSlots(dock, nullptr, ImRect(m_workspace_pos, m_workspace_pos + m_workspace_size), true)) 537 | { 538 | canvas->PopClipRect(); 539 | End(); 540 | return; 541 | } 542 | canvas->AddRectFilled(dock.pos, dock.pos + dock.size, docked_color); 543 | canvas->PopClipRect(); 544 | 545 | if (!IsMouseDown(0)) 546 | { 547 | dock.status = Status_Float; 548 | dock.location[0] = 0; 549 | dock.setActive(); 550 | } 551 | 552 | End(); 553 | } 554 | 555 | 556 | void fillLocation(Dock& dock) 557 | { 558 | if (dock.status == Status_Float) return; 559 | char* c = dock.location; 560 | Dock* tmp = &dock; 561 | while (tmp->parent) 562 | { 563 | *c = getLocationCode(tmp); 564 | tmp = tmp->parent; 565 | ++c; 566 | } 567 | *c = 0; 568 | } 569 | 570 | 571 | void doUndock(Dock& dock) 572 | { 573 | if (dock.prev_tab) 574 | dock.prev_tab->setActive(); 575 | else if (dock.next_tab) 576 | dock.next_tab->setActive(); 577 | else 578 | dock.active = false; 579 | Dock* container = dock.parent; 580 | 581 | if (container) 582 | { 583 | Dock& sibling = dock.getSibling(); 584 | if (container->children[0] == &dock) 585 | { 586 | container->children[0] = dock.next_tab; 587 | } 588 | else if (container->children[1] == &dock) 589 | { 590 | container->children[1] = dock.next_tab; 591 | } 592 | 593 | bool remove_container = !container->children[0] || !container->children[1]; 594 | if (remove_container) 595 | { 596 | if (container->parent) 597 | { 598 | Dock*& child = container->parent->children[0] == container 599 | ? container->parent->children[0] 600 | : container->parent->children[1]; 601 | child = &sibling; 602 | child->setPosSize(container->pos, container->size); 603 | child->setParent(container->parent); 604 | } 605 | else 606 | { 607 | if (container->children[0]) 608 | { 609 | container->children[0]->setParent(nullptr); 610 | container->children[0]->setPosSize(container->pos, container->size); 611 | } 612 | if (container->children[1]) 613 | { 614 | container->children[1]->setParent(nullptr); 615 | container->children[1]->setPosSize(container->pos, container->size); 616 | } 617 | } 618 | for (int i = 0; i < m_docks.size(); ++i) 619 | { 620 | if (m_docks[i] == container) 621 | { 622 | m_docks.erase(m_docks.begin() + i); 623 | break; 624 | } 625 | } 626 | if (container == m_next_parent) 627 | m_next_parent = nullptr; 628 | container->~Dock(); 629 | MemFree(container); 630 | } 631 | } 632 | if (dock.prev_tab) dock.prev_tab->next_tab = dock.next_tab; 633 | if (dock.next_tab) dock.next_tab->prev_tab = dock.prev_tab; 634 | dock.parent = nullptr; 635 | dock.prev_tab = dock.next_tab = nullptr; 636 | } 637 | 638 | 639 | void drawTabbarListButton(Dock& dock) 640 | { 641 | if (!dock.next_tab) return; 642 | 643 | ImDrawList* draw_list = GetWindowDrawList(); 644 | if (InvisibleButton("list", ImVec2(16, 16))) 645 | { 646 | OpenPopup("tab_list_popup"); 647 | } 648 | if (BeginPopup("tab_list_popup")) 649 | { 650 | Dock* tmp = &dock; 651 | while (tmp) 652 | { 653 | bool dummy = false; 654 | if (Selectable(tmp->label, &dummy)) 655 | { 656 | tmp->setActive(); 657 | m_next_parent = tmp; 658 | } 659 | tmp = tmp->next_tab; 660 | } 661 | EndPopup(); 662 | } 663 | 664 | bool hovered = IsItemHovered(); 665 | ImVec2 min = GetItemRectMin(); 666 | ImVec2 max = GetItemRectMax(); 667 | ImVec2 center = (min + max) * 0.5f; 668 | ImU32 text_color = GetColorU32(ImGuiCol_Text); 669 | ImU32 color_active = GetColorU32(ImGuiCol_FrameBgActive); 670 | draw_list->AddRectFilled(ImVec2(center.x - 4, min.y + 3), 671 | ImVec2(center.x + 4, min.y + 5), 672 | hovered ? color_active : text_color); 673 | draw_list->AddTriangleFilled(ImVec2(center.x - 4, min.y + 7), 674 | ImVec2(center.x + 4, min.y + 7), 675 | ImVec2(center.x, min.y + 12), 676 | hovered ? color_active : text_color); 677 | } 678 | 679 | 680 | bool tabbar(Dock& dock, bool close_button) 681 | { 682 | float tabbar_height = 2 * GetTextLineHeightWithSpacing(); 683 | ImVec2 size(dock.size.x, tabbar_height); 684 | bool tab_closed = false; 685 | 686 | SetCursorScreenPos(dock.pos); 687 | char tmp[20]; 688 | ImFormatString(tmp, IM_ARRAYSIZE(tmp), "tabs%d", (int)dock.id); 689 | if (BeginChild(tmp, size, true)) 690 | { 691 | Dock* dock_tab = &dock; 692 | 693 | ImDrawList* draw_list = GetWindowDrawList(); 694 | ImU32 color = GetColorU32(ImGuiCol_FrameBg); 695 | ImU32 color_active = GetColorU32(ImGuiCol_FrameBgActive); 696 | ImU32 color_hovered = GetColorU32(ImGuiCol_FrameBgHovered); 697 | ImU32 text_color = GetColorU32(ImGuiCol_Text); 698 | float line_height = GetTextLineHeightWithSpacing(); 699 | float tab_base; 700 | 701 | drawTabbarListButton(dock); 702 | 703 | while (dock_tab) 704 | { 705 | SameLine(0, 15); 706 | 707 | const char* text_end = FindRenderedTextEnd(dock_tab->label); 708 | ImVec2 size(CalcTextSize(dock_tab->label, text_end).x, line_height); 709 | if (InvisibleButton(dock_tab->label, size)) 710 | { 711 | dock_tab->setActive(); 712 | m_next_parent = dock_tab; 713 | } 714 | 715 | if (IsItemActive() && IsMouseDragging() && dock_tab->movable) 716 | { 717 | m_drag_offset = GetMousePos() - dock_tab->pos; 718 | doUndock(*dock_tab); 719 | dock_tab->status = Status_Dragged; 720 | } 721 | 722 | bool hovered = IsItemHovered(); 723 | ImVec2 pos = GetItemRectMin(); 724 | if (dock_tab->active && close_button) 725 | { 726 | size.x += 16 + GetStyle().ItemSpacing.x; 727 | SameLine(); 728 | tab_closed = InvisibleButton("close", ImVec2(16, 16)); 729 | ImVec2 center = (GetItemRectMin() + GetItemRectMax()) * 0.5f; 730 | draw_list->AddLine( 731 | center + ImVec2(-3.5f, -3.5f), center + ImVec2(3.5f, 3.5f), text_color); 732 | draw_list->AddLine( 733 | center + ImVec2(3.5f, -3.5f), center + ImVec2(-3.5f, 3.5f), text_color); 734 | } 735 | tab_base = pos.y; 736 | draw_list->PathClear(); 737 | draw_list->PathLineTo(pos + ImVec2(-15, size.y)); 738 | draw_list->PathBezierCurveTo( 739 | pos + ImVec2(-10, size.y), pos + ImVec2(-5, 0), pos + ImVec2(0, 0), 10); 740 | draw_list->PathLineTo(pos + ImVec2(size.x, 0)); 741 | draw_list->PathBezierCurveTo(pos + ImVec2(size.x + 5, 0), 742 | pos + ImVec2(size.x + 10, size.y), 743 | pos + ImVec2(size.x + 15, size.y), 744 | 10); 745 | draw_list->PathFillConvex( 746 | hovered ? color_hovered : (dock_tab->active ? color_active : color)); 747 | draw_list->AddText(pos + ImVec2(0, 1), text_color, dock_tab->label, text_end); 748 | 749 | dock_tab = dock_tab->next_tab; 750 | } 751 | ImVec2 cp(dock.pos.x, tab_base + line_height); 752 | draw_list->AddLine(cp, cp + ImVec2(dock.size.x, 0), color); 753 | } 754 | EndChild(); 755 | return tab_closed; 756 | } 757 | 758 | 759 | static void setDockPosSize(Dock& dest, Dock& dock, ImGuiDockSlot dock_slot, Dock& container) 760 | { 761 | IM_ASSERT(!dock.prev_tab && !dock.next_tab && !dock.children[0] && !dock.children[1]); 762 | 763 | dest.pos = container.pos; 764 | dest.size = container.size; 765 | dock.pos = container.pos; 766 | dock.size = container.size; 767 | 768 | switch (dock_slot) 769 | { 770 | case ImGuiDockSlot_Bottom: 771 | dest.size.y *= 1.-dock.split_ratio.y; 772 | dock.size.y *= dock.split_ratio.y; 773 | dock.pos.y += dest.size.y; 774 | break; 775 | case ImGuiDockSlot_Right: 776 | dest.size.x *= 1.-dock.split_ratio.x; 777 | dock.size.x *= dock.split_ratio.x; 778 | dock.pos.x += dest.size.x; 779 | break; 780 | case ImGuiDockSlot_Left: 781 | dest.size.x *= 1.-dock.split_ratio.x; 782 | dock.size.x *= dock.split_ratio.x; 783 | dest.pos.x += dock.size.x; 784 | break; 785 | case ImGuiDockSlot_Top: 786 | dest.size.y *= 1.-dock.split_ratio.y; 787 | dock.size.y *= dock.split_ratio.y; 788 | dest.pos.y += dock.size.y; 789 | break; 790 | default: IM_ASSERT(false); break; 791 | } 792 | dest.setPosSize(dest.pos, dest.size); 793 | 794 | if (container.children[1]->pos.x < container.children[0]->pos.x || 795 | container.children[1]->pos.y < container.children[0]->pos.y) 796 | { 797 | Dock* tmp = container.children[0]; 798 | container.children[0] = container.children[1]; 799 | container.children[1] = tmp; 800 | } 801 | } 802 | 803 | 804 | void doDock(Dock& dock, Dock* dest, ImGuiDockSlot dock_slot) 805 | { 806 | IM_ASSERT(!dock.parent); 807 | if (!dest) 808 | { 809 | dock.status = Status_Docked; 810 | dock.setPosSize(m_workspace_pos, m_workspace_size); 811 | } 812 | else if (dock_slot == ImGuiDockSlot_Tab) 813 | { 814 | Dock* tmp = dest; 815 | while (tmp->next_tab) 816 | { 817 | tmp = tmp->next_tab; 818 | } 819 | 820 | tmp->next_tab = &dock; 821 | dock.prev_tab = tmp; 822 | dock.size = tmp->size; 823 | dock.pos = tmp->pos; 824 | dock.parent = dest->parent; 825 | dock.status = Status_Docked; 826 | } 827 | else if (dock_slot == ImGuiDockSlot_None) 828 | { 829 | dock.status = Status_Float; 830 | } 831 | else 832 | { 833 | Dock* container = (Dock*)MemAlloc(sizeof(Dock)); 834 | IM_PLACEMENT_NEW(container) Dock(); 835 | m_docks.push_back(container); 836 | container->children[0] = &dest->getFirstTab(); 837 | container->children[1] = &dock; 838 | container->next_tab = nullptr; 839 | container->prev_tab = nullptr; 840 | container->parent = dest->parent; 841 | container->size = dest->size; 842 | container->pos = dest->pos; 843 | container->status = Status_Docked; 844 | container->label = ImStrdup(""); 845 | 846 | if (!dest->parent) 847 | { 848 | } 849 | else if (&dest->getFirstTab() == dest->parent->children[0]) 850 | { 851 | dest->parent->children[0] = container; 852 | } 853 | else 854 | { 855 | dest->parent->children[1] = container; 856 | } 857 | 858 | dest->setParent(container); 859 | dock.parent = container; 860 | dock.status = Status_Docked; 861 | 862 | setDockPosSize(*dest, dock, dock_slot, *container); 863 | } 864 | dock.setActive(); 865 | } 866 | 867 | 868 | void rootDock(const ImVec2& pos, const ImVec2& size) 869 | { 870 | Dock* root = getRootDock(); 871 | if (!root) return; 872 | 873 | ImVec2 min_size = root->getMinSize(); 874 | ImVec2 requested_size = size; 875 | root->setPosSize(pos, ImMax(min_size, requested_size)); 876 | } 877 | 878 | 879 | void setDockActive() 880 | { 881 | IM_ASSERT(m_current); 882 | if (m_current) m_current->setActive(); 883 | } 884 | 885 | 886 | static ImGuiDockSlot getSlotFromLocationCode(char code) 887 | { 888 | switch (code) 889 | { 890 | case '1': return ImGuiDockSlot_Left; 891 | case '2': return ImGuiDockSlot_Top; 892 | case '3': return ImGuiDockSlot_Bottom; 893 | default: return ImGuiDockSlot_Right; 894 | } 895 | } 896 | 897 | 898 | static char getLocationCode(Dock* dock) 899 | { 900 | if (!dock) return '0'; 901 | 902 | if (dock->parent->isHorizontal()) 903 | { 904 | if (dock->pos.x < dock->parent->children[0]->pos.x) return '1'; 905 | if (dock->pos.x < dock->parent->children[1]->pos.x) return '1'; 906 | return '0'; 907 | } 908 | else 909 | { 910 | if (dock->pos.y < dock->parent->children[0]->pos.y) return '2'; 911 | if (dock->pos.y < dock->parent->children[1]->pos.y) return '2'; 912 | return '3'; 913 | } 914 | } 915 | 916 | 917 | void tryDockToStoredLocation(Dock& dock) 918 | { 919 | if (dock.status == Status_Docked) return; 920 | if (dock.location[0] == 0) return; 921 | 922 | Dock* tmp = getRootDock(); 923 | if (!tmp) return; 924 | 925 | Dock* prev = nullptr; 926 | char* c = dock.location + strlen(dock.location) - 1; 927 | while (c >= dock.location && tmp) 928 | { 929 | prev = tmp; 930 | tmp = *c == getLocationCode(tmp->children[0]) ? tmp->children[0] : tmp->children[1]; 931 | if(tmp) --c; 932 | } 933 | doDock(dock, tmp ? tmp : prev, tmp ? ImGuiDockSlot_Tab : getSlotFromLocationCode(*c)); 934 | } 935 | 936 | 937 | bool begin(const char* label, bool* opened, ImGuiWindowFlags extra_flags) 938 | { 939 | ImGuiDockSlot next_slot = m_next_dock_slot; 940 | m_next_dock_slot = ImGuiDockSlot_Tab; 941 | Dock& dock = getDock(label, !opened || *opened); 942 | if (!dock.opened && (!opened || *opened)) tryDockToStoredLocation(dock); 943 | dock.last_frame = ImGui::GetFrameCount(); 944 | if (strcmp(dock.label, label) != 0) 945 | { 946 | MemFree(dock.label); 947 | dock.label = ImStrdup(label); 948 | } 949 | 950 | dock.movable = (extra_flags & ImGuiWindowFlags_NoMove) != ImGuiWindowFlags_NoMove; 951 | 952 | m_end_action = EndAction_None; 953 | 954 | bool prev_opened = dock.opened; 955 | bool first = dock.first; 956 | if (dock.first && opened) *opened = dock.opened; 957 | dock.first = false; 958 | if (opened && !*opened) 959 | { 960 | if (dock.status != Status_Float) 961 | { 962 | fillLocation(dock); 963 | doUndock(dock); 964 | dock.status = Status_Float; 965 | } 966 | dock.opened = false; 967 | return false; 968 | } 969 | dock.opened = true; 970 | 971 | checkNonexistent(); 972 | 973 | if (first || (prev_opened != dock.opened)) { 974 | Dock* root = m_next_parent ? m_next_parent : getRootDock(); 975 | if (root && (&dock != root) && !dock.parent) { 976 | doDock(dock, root, next_slot); 977 | } 978 | m_next_parent = &dock; 979 | } 980 | 981 | m_current = &dock; 982 | if (dock.status == Status_Dragged) handleDrag(dock); 983 | 984 | bool is_float = dock.status == Status_Float; 985 | 986 | if (is_float) 987 | { 988 | SetNextWindowPos(dock.pos); 989 | SetNextWindowSize(dock.size); 990 | bool ret = Begin(label, 991 | opened, 992 | dock.size, 993 | -1.0f, 994 | ImGuiWindowFlags_NoCollapse | extra_flags); 995 | m_end_action = EndAction_End; 996 | dock.pos = GetWindowPos(); 997 | dock.size = GetWindowSize(); 998 | 999 | ImGuiContext& g = *GImGui; 1000 | 1001 | if (g.ActiveId == GetCurrentWindow()->MoveId && g.IO.MouseDown[0]) 1002 | { 1003 | m_drag_offset = GetMousePos() - dock.pos; 1004 | doUndock(dock); 1005 | dock.status = Status_Dragged; 1006 | } 1007 | return ret; 1008 | } 1009 | 1010 | if (!dock.active && dock.status != Status_Dragged) return false; 1011 | 1012 | m_end_action = EndAction_EndChild; 1013 | 1014 | splits(); 1015 | 1016 | PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); 1017 | float tabbar_height = GetTextLineHeightWithSpacing(); 1018 | if (tabbar(dock.getFirstTab(), opened != nullptr)) 1019 | { 1020 | fillLocation(dock); 1021 | *opened = false; 1022 | } 1023 | ImVec2 pos = dock.pos; 1024 | ImVec2 size = dock.size; 1025 | pos.y += tabbar_height + GetStyle().WindowPadding.y; 1026 | size.y -= tabbar_height + GetStyle().WindowPadding.y; 1027 | 1028 | SetCursorScreenPos(pos); 1029 | ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | 1030 | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | 1031 | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoBringToFrontOnFocus | 1032 | extra_flags; 1033 | bool ret = BeginChild(label, size, true, flags); 1034 | PopStyleColor(); 1035 | 1036 | return ret; 1037 | } 1038 | 1039 | 1040 | void end() 1041 | { 1042 | m_current = nullptr; 1043 | if (m_end_action != EndAction_None) { 1044 | if (m_end_action == EndAction_End) 1045 | { 1046 | End(); 1047 | } 1048 | else if (m_end_action == EndAction_EndChild) 1049 | { 1050 | PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); 1051 | EndChild(); 1052 | PopStyleColor(); 1053 | } 1054 | } 1055 | } 1056 | 1057 | void debugWindow() { 1058 | if (Begin("Dock Debug Info")) { 1059 | for (int i = 0; i < m_docks.size(); ++i) { 1060 | if (TreeNode((void*)&i, "Dock %d (%p)", i, m_docks[i])) { 1061 | Dock &dock = *m_docks[i]; 1062 | Text("pos=(%.1f %.1f) size=(%.1f %.1f)", 1063 | dock.pos.x, dock.pos.y, 1064 | dock.size.x, dock.size.y); 1065 | Text("parent = %p\n", 1066 | dock.parent); 1067 | Text("isContainer() == %s\n", 1068 | dock.isContainer()?"true":"false"); 1069 | Text("status = %s\n", 1070 | (dock.status == Status_Docked)?"Docked": 1071 | ((dock.status == Status_Dragged)?"Dragged": 1072 | ((dock.status == Status_Float)?"Float": "?"))); 1073 | TreePop(); 1074 | } 1075 | } 1076 | 1077 | } 1078 | End(); 1079 | } 1080 | 1081 | int getDockIndex(Dock* dock) 1082 | { 1083 | if (!dock) return -1; 1084 | 1085 | for (int i = 0; i < m_docks.size(); ++i) 1086 | { 1087 | if (dock == m_docks[i]) return i; 1088 | } 1089 | 1090 | IM_ASSERT(false); 1091 | return -1; 1092 | } 1093 | }; 1094 | 1095 | 1096 | static DockContext g_dock; 1097 | 1098 | void ImGui::ShutdownDock() 1099 | { 1100 | for (int i = 0; i < g_dock.m_docks.size(); ++i) 1101 | { 1102 | g_dock.m_docks[i]->~Dock(); 1103 | MemFree(g_dock.m_docks[i]); 1104 | } 1105 | g_dock.m_docks.clear(); 1106 | } 1107 | 1108 | void ImGui::SetNextDock(ImGuiDockSlot slot) { 1109 | g_dock.m_next_dock_slot = slot; 1110 | } 1111 | 1112 | void ImGui::BeginDockspace() { 1113 | ImGuiWindowFlags flags = ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar; 1114 | BeginChild("###workspace", ImVec2(0,0), false, flags); 1115 | g_dock.m_workspace_pos = GetWindowPos(); 1116 | g_dock.m_workspace_size = GetWindowSize(); 1117 | } 1118 | 1119 | void ImGui::EndDockspace() { 1120 | EndChild(); 1121 | } 1122 | 1123 | void ImGui::SetDockActive() 1124 | { 1125 | g_dock.setDockActive(); 1126 | } 1127 | 1128 | bool ImGui::BeginDock(const char* label, bool* opened, ImGuiWindowFlags extra_flags) 1129 | { 1130 | return g_dock.begin(label, opened, extra_flags); 1131 | } 1132 | 1133 | void ImGui::SetNextDockSplitRatio(const ImVec2& split_ratio) 1134 | { 1135 | g_dock.m_next_split_ratio = split_ratio; 1136 | } 1137 | 1138 | void ImGui::SetNextDockFloatingSize(const ImVec2& floating_size) 1139 | { 1140 | g_dock.m_next_floating_size = floating_size; 1141 | } 1142 | 1143 | void ImGui::EndDock() 1144 | { 1145 | g_dock.end(); 1146 | } 1147 | 1148 | void ImGui::DockDebugWindow() 1149 | { 1150 | g_dock.debugWindow(); 1151 | } 1152 | -------------------------------------------------------------------------------- /src/libimgui/imgui_dock.h: -------------------------------------------------------------------------------- 1 | // based on https://github.com/nem0/LumixEngine/blob/master/external/imgui/imgui_dock.h 2 | // modified from https://bitbucket.org/duangle/liminal/src/tip/src/liminal/imgui_dock.h 3 | 4 | #pragma once 5 | 6 | // Forward declarations 7 | typedef int ImGuiWindowFlags; 8 | 9 | typedef enum ImGuiDockSlot { 10 | ImGuiDockSlot_Left, 11 | ImGuiDockSlot_Right, 12 | ImGuiDockSlot_Top, 13 | ImGuiDockSlot_Bottom, 14 | ImGuiDockSlot_Tab, 15 | 16 | ImGuiDockSlot_Float, 17 | ImGuiDockSlot_None 18 | } ImGuiDockSlot; 19 | 20 | namespace ImGui{ 21 | 22 | IMGUI_API void BeginDockspace(); 23 | IMGUI_API void EndDockspace(); 24 | IMGUI_API void ShutdownDock(); 25 | IMGUI_API void SetNextDock(ImGuiDockSlot slot); 26 | IMGUI_API bool BeginDock(const char* label, bool* opened = NULL, ImGuiWindowFlags extra_flags = 0); 27 | IMGUI_API void SetNextDockSplitRatio(const ImVec2& split_ratio = ImVec2(0.5, 0.5)); 28 | IMGUI_API void SetNextDockFloatingSize(const ImVec2& floating_size = ImVec2(0.5, 0.5)); 29 | IMGUI_API void EndDock(); 30 | IMGUI_API void SetDockActive(); 31 | IMGUI_API void DockDebugWindow(); 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /src/libimgui/stb_rect_pack.h: -------------------------------------------------------------------------------- 1 | // stb_rect_pack.h - v0.10 - public domain - rectangle packing 2 | // Sean Barrett 2014 3 | // 4 | // Useful for e.g. packing rectangular textures into an atlas. 5 | // Does not do rotation. 6 | // 7 | // Not necessarily the awesomest packing method, but better than 8 | // the totally naive one in stb_truetype (which is primarily what 9 | // this is meant to replace). 10 | // 11 | // Has only had a few tests run, may have issues. 12 | // 13 | // More docs to come. 14 | // 15 | // No memory allocations; uses qsort() and assert() from stdlib. 16 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 17 | // 18 | // This library currently uses the Skyline Bottom-Left algorithm. 19 | // 20 | // Please note: better rectangle packers are welcome! Please 21 | // implement them to the same API, but with a different init 22 | // function. 23 | // 24 | // Credits 25 | // 26 | // Library 27 | // Sean Barrett 28 | // Minor features 29 | // Martins Mozeiko 30 | // Bugfixes / warning fixes 31 | // Jeremy Jaussaud 32 | // 33 | // Version history: 34 | // 35 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 36 | // 0.09 (2016-08-27) fix compiler warnings 37 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 38 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 39 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 40 | // 0.05: added STBRP_ASSERT to allow replacing assert 41 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 42 | // 0.01: initial release 43 | // 44 | // LICENSE 45 | // 46 | // This software is dual-licensed to the public domain and under the following 47 | // license: you are granted a perpetual, irrevocable license to copy, modify, 48 | // publish, and distribute this file as you see fit. 49 | 50 | ////////////////////////////////////////////////////////////////////////////// 51 | // 52 | // INCLUDE SECTION 53 | // 54 | 55 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 56 | #define STB_INCLUDE_STB_RECT_PACK_H 57 | 58 | #define STB_RECT_PACK_VERSION 1 59 | 60 | #ifdef STBRP_STATIC 61 | #define STBRP_DEF static 62 | #else 63 | #define STBRP_DEF extern 64 | #endif 65 | 66 | #ifdef __cplusplus 67 | extern "C" { 68 | #endif 69 | 70 | typedef struct stbrp_context stbrp_context; 71 | typedef struct stbrp_node stbrp_node; 72 | typedef struct stbrp_rect stbrp_rect; 73 | 74 | #ifdef STBRP_LARGE_RECTS 75 | typedef int stbrp_coord; 76 | #else 77 | typedef unsigned short stbrp_coord; 78 | #endif 79 | 80 | STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 81 | // Assign packed locations to rectangles. The rectangles are of type 82 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 83 | // are 'num_rects' many of them. 84 | // 85 | // Rectangles which are successfully packed have the 'was_packed' flag 86 | // set to a non-zero value and 'x' and 'y' store the minimum location 87 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 88 | // if you imagine y increasing downwards). Rectangles which do not fit 89 | // have the 'was_packed' flag set to 0. 90 | // 91 | // You should not try to access the 'rects' array from another thread 92 | // while this function is running, as the function temporarily reorders 93 | // the array while it executes. 94 | // 95 | // To pack into another rectangle, you need to call stbrp_init_target 96 | // again. To continue packing into the same rectangle, you can call 97 | // this function again. Calling this multiple times with multiple rect 98 | // arrays will probably produce worse packing results than calling it 99 | // a single time with the full rectangle array, but the option is 100 | // available. 101 | 102 | struct stbrp_rect 103 | { 104 | // reserved for your use: 105 | int id; 106 | 107 | // input: 108 | stbrp_coord w, h; 109 | 110 | // output: 111 | stbrp_coord x, y; 112 | int was_packed; // non-zero if valid packing 113 | 114 | }; // 16 bytes, nominally 115 | 116 | 117 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 118 | // Initialize a rectangle packer to: 119 | // pack a rectangle that is 'width' by 'height' in dimensions 120 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 121 | // 122 | // You must call this function every time you start packing into a new target. 123 | // 124 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 125 | // the following stbrp_pack_rects() call (or calls), but can be freed after 126 | // the call (or calls) finish. 127 | // 128 | // Note: to guarantee best results, either: 129 | // 1. make sure 'num_nodes' >= 'width' 130 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 131 | // 132 | // If you don't do either of the above things, widths will be quantized to multiples 133 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 134 | // 135 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 136 | // may run out of temporary storage and be unable to pack some rectangles. 137 | 138 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 139 | // Optionally call this function after init but before doing any packing to 140 | // change the handling of the out-of-temp-memory scenario, described above. 141 | // If you call init again, this will be reset to the default (false). 142 | 143 | 144 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 145 | // Optionally select which packing heuristic the library should use. Different 146 | // heuristics will produce better/worse results for different data sets. 147 | // If you call init again, this will be reset to the default. 148 | 149 | enum 150 | { 151 | STBRP_HEURISTIC_Skyline_default=0, 152 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 153 | STBRP_HEURISTIC_Skyline_BF_sortHeight 154 | }; 155 | 156 | 157 | ////////////////////////////////////////////////////////////////////////////// 158 | // 159 | // the details of the following structures don't matter to you, but they must 160 | // be visible so you can handle the memory allocations for them 161 | 162 | struct stbrp_node 163 | { 164 | stbrp_coord x,y; 165 | stbrp_node *next; 166 | }; 167 | 168 | struct stbrp_context 169 | { 170 | int width; 171 | int height; 172 | int align; 173 | int init_mode; 174 | int heuristic; 175 | int num_nodes; 176 | stbrp_node *active_head; 177 | stbrp_node *free_head; 178 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 179 | }; 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif 184 | 185 | #endif 186 | 187 | ////////////////////////////////////////////////////////////////////////////// 188 | // 189 | // IMPLEMENTATION SECTION 190 | // 191 | 192 | #ifdef STB_RECT_PACK_IMPLEMENTATION 193 | #ifndef STBRP_SORT 194 | #include 195 | #define STBRP_SORT qsort 196 | #endif 197 | 198 | #ifndef STBRP_ASSERT 199 | #include 200 | #define STBRP_ASSERT assert 201 | #endif 202 | 203 | #ifdef _MSC_VER 204 | #define STBRP__NOTUSED(v) (void)(v) 205 | #else 206 | #define STBRP__NOTUSED(v) (void)sizeof(v) 207 | #endif 208 | 209 | enum 210 | { 211 | STBRP__INIT_skyline = 1 212 | }; 213 | 214 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 215 | { 216 | switch (context->init_mode) { 217 | case STBRP__INIT_skyline: 218 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 219 | context->heuristic = heuristic; 220 | break; 221 | default: 222 | STBRP_ASSERT(0); 223 | } 224 | } 225 | 226 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 227 | { 228 | if (allow_out_of_mem) 229 | // if it's ok to run out of memory, then don't bother aligning them; 230 | // this gives better packing, but may fail due to OOM (even though 231 | // the rectangles easily fit). @TODO a smarter approach would be to only 232 | // quantize once we've hit OOM, then we could get rid of this parameter. 233 | context->align = 1; 234 | else { 235 | // if it's not ok to run out of memory, then quantize the widths 236 | // so that num_nodes is always enough nodes. 237 | // 238 | // I.e. num_nodes * align >= width 239 | // align >= width / num_nodes 240 | // align = ceil(width/num_nodes) 241 | 242 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 243 | } 244 | } 245 | 246 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 247 | { 248 | int i; 249 | #ifndef STBRP_LARGE_RECTS 250 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 251 | #endif 252 | 253 | for (i=0; i < num_nodes-1; ++i) 254 | nodes[i].next = &nodes[i+1]; 255 | nodes[i].next = NULL; 256 | context->init_mode = STBRP__INIT_skyline; 257 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 258 | context->free_head = &nodes[0]; 259 | context->active_head = &context->extra[0]; 260 | context->width = width; 261 | context->height = height; 262 | context->num_nodes = num_nodes; 263 | stbrp_setup_allow_out_of_mem(context, 0); 264 | 265 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 266 | context->extra[0].x = 0; 267 | context->extra[0].y = 0; 268 | context->extra[0].next = &context->extra[1]; 269 | context->extra[1].x = (stbrp_coord) width; 270 | #ifdef STBRP_LARGE_RECTS 271 | context->extra[1].y = (1<<30); 272 | #else 273 | context->extra[1].y = 65535; 274 | #endif 275 | context->extra[1].next = NULL; 276 | } 277 | 278 | // find minimum y position if it starts at x1 279 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 280 | { 281 | stbrp_node *node = first; 282 | int x1 = x0 + width; 283 | int min_y, visited_width, waste_area; 284 | 285 | STBRP__NOTUSED(c); 286 | 287 | STBRP_ASSERT(first->x <= x0); 288 | 289 | #if 0 290 | // skip in case we're past the node 291 | while (node->next->x <= x0) 292 | ++node; 293 | #else 294 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 295 | #endif 296 | 297 | STBRP_ASSERT(node->x <= x0); 298 | 299 | min_y = 0; 300 | waste_area = 0; 301 | visited_width = 0; 302 | while (node->x < x1) { 303 | if (node->y > min_y) { 304 | // raise min_y higher. 305 | // we've accounted for all waste up to min_y, 306 | // but we'll now add more waste for everything we've visted 307 | waste_area += visited_width * (node->y - min_y); 308 | min_y = node->y; 309 | // the first time through, visited_width might be reduced 310 | if (node->x < x0) 311 | visited_width += node->next->x - x0; 312 | else 313 | visited_width += node->next->x - node->x; 314 | } else { 315 | // add waste area 316 | int under_width = node->next->x - node->x; 317 | if (under_width + visited_width > width) 318 | under_width = width - visited_width; 319 | waste_area += under_width * (min_y - node->y); 320 | visited_width += under_width; 321 | } 322 | node = node->next; 323 | } 324 | 325 | *pwaste = waste_area; 326 | return min_y; 327 | } 328 | 329 | typedef struct 330 | { 331 | int x,y; 332 | stbrp_node **prev_link; 333 | } stbrp__findresult; 334 | 335 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 336 | { 337 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 338 | stbrp__findresult fr; 339 | stbrp_node **prev, *node, *tail, **best = NULL; 340 | 341 | // align to multiple of c->align 342 | width = (width + c->align - 1); 343 | width -= width % c->align; 344 | STBRP_ASSERT(width % c->align == 0); 345 | 346 | node = c->active_head; 347 | prev = &c->active_head; 348 | while (node->x + width <= c->width) { 349 | int y,waste; 350 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 351 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 352 | // bottom left 353 | if (y < best_y) { 354 | best_y = y; 355 | best = prev; 356 | } 357 | } else { 358 | // best-fit 359 | if (y + height <= c->height) { 360 | // can only use it if it first vertically 361 | if (y < best_y || (y == best_y && waste < best_waste)) { 362 | best_y = y; 363 | best_waste = waste; 364 | best = prev; 365 | } 366 | } 367 | } 368 | prev = &node->next; 369 | node = node->next; 370 | } 371 | 372 | best_x = (best == NULL) ? 0 : (*best)->x; 373 | 374 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 375 | // 376 | // e.g, if fitting 377 | // 378 | // ____________________ 379 | // |____________________| 380 | // 381 | // into 382 | // 383 | // | | 384 | // | ____________| 385 | // |____________| 386 | // 387 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 388 | // 389 | // This makes BF take about 2x the time 390 | 391 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 392 | tail = c->active_head; 393 | node = c->active_head; 394 | prev = &c->active_head; 395 | // find first node that's admissible 396 | while (tail->x < width) 397 | tail = tail->next; 398 | while (tail) { 399 | int xpos = tail->x - width; 400 | int y,waste; 401 | STBRP_ASSERT(xpos >= 0); 402 | // find the left position that matches this 403 | while (node->next->x <= xpos) { 404 | prev = &node->next; 405 | node = node->next; 406 | } 407 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 408 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 409 | if (y + height < c->height) { 410 | if (y <= best_y) { 411 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 412 | best_x = xpos; 413 | STBRP_ASSERT(y <= best_y); 414 | best_y = y; 415 | best_waste = waste; 416 | best = prev; 417 | } 418 | } 419 | } 420 | tail = tail->next; 421 | } 422 | } 423 | 424 | fr.prev_link = best; 425 | fr.x = best_x; 426 | fr.y = best_y; 427 | return fr; 428 | } 429 | 430 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 431 | { 432 | // find best position according to heuristic 433 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 434 | stbrp_node *node, *cur; 435 | 436 | // bail if: 437 | // 1. it failed 438 | // 2. the best node doesn't fit (we don't always check this) 439 | // 3. we're out of memory 440 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 441 | res.prev_link = NULL; 442 | return res; 443 | } 444 | 445 | // on success, create new node 446 | node = context->free_head; 447 | node->x = (stbrp_coord) res.x; 448 | node->y = (stbrp_coord) (res.y + height); 449 | 450 | context->free_head = node->next; 451 | 452 | // insert the new node into the right starting point, and 453 | // let 'cur' point to the remaining nodes needing to be 454 | // stiched back in 455 | 456 | cur = *res.prev_link; 457 | if (cur->x < res.x) { 458 | // preserve the existing one, so start testing with the next one 459 | stbrp_node *next = cur->next; 460 | cur->next = node; 461 | cur = next; 462 | } else { 463 | *res.prev_link = node; 464 | } 465 | 466 | // from here, traverse cur and free the nodes, until we get to one 467 | // that shouldn't be freed 468 | while (cur->next && cur->next->x <= res.x + width) { 469 | stbrp_node *next = cur->next; 470 | // move the current node to the free list 471 | cur->next = context->free_head; 472 | context->free_head = cur; 473 | cur = next; 474 | } 475 | 476 | // stitch the list back in 477 | node->next = cur; 478 | 479 | if (cur->x < res.x + width) 480 | cur->x = (stbrp_coord) (res.x + width); 481 | 482 | #ifdef _DEBUG 483 | cur = context->active_head; 484 | while (cur->x < context->width) { 485 | STBRP_ASSERT(cur->x < cur->next->x); 486 | cur = cur->next; 487 | } 488 | STBRP_ASSERT(cur->next == NULL); 489 | 490 | { 491 | stbrp_node *L1 = NULL, *L2 = NULL; 492 | int count=0; 493 | cur = context->active_head; 494 | while (cur) { 495 | L1 = cur; 496 | cur = cur->next; 497 | ++count; 498 | } 499 | cur = context->free_head; 500 | while (cur) { 501 | L2 = cur; 502 | cur = cur->next; 503 | ++count; 504 | } 505 | STBRP_ASSERT(count == context->num_nodes+2); 506 | } 507 | #endif 508 | 509 | return res; 510 | } 511 | 512 | static int rect_height_compare(const void *a, const void *b) 513 | { 514 | const stbrp_rect *p = (const stbrp_rect *) a; 515 | const stbrp_rect *q = (const stbrp_rect *) b; 516 | if (p->h > q->h) 517 | return -1; 518 | if (p->h < q->h) 519 | return 1; 520 | return (p->w > q->w) ? -1 : (p->w < q->w); 521 | } 522 | 523 | static int rect_width_compare(const void *a, const void *b) 524 | { 525 | const stbrp_rect *p = (const stbrp_rect *) a; 526 | const stbrp_rect *q = (const stbrp_rect *) b; 527 | if (p->w > q->w) 528 | return -1; 529 | if (p->w < q->w) 530 | return 1; 531 | return (p->h > q->h) ? -1 : (p->h < q->h); 532 | } 533 | 534 | static int rect_original_order(const void *a, const void *b) 535 | { 536 | const stbrp_rect *p = (const stbrp_rect *) a; 537 | const stbrp_rect *q = (const stbrp_rect *) b; 538 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 539 | } 540 | 541 | #ifdef STBRP_LARGE_RECTS 542 | #define STBRP__MAXVAL 0xffffffff 543 | #else 544 | #define STBRP__MAXVAL 0xffff 545 | #endif 546 | 547 | STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 548 | { 549 | int i; 550 | 551 | // we use the 'was_packed' field internally to allow sorting/unsorting 552 | for (i=0; i < num_rects; ++i) { 553 | rects[i].was_packed = i; 554 | #ifndef STBRP_LARGE_RECTS 555 | STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); 556 | #endif 557 | } 558 | 559 | // sort according to heuristic 560 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 561 | 562 | for (i=0; i < num_rects; ++i) { 563 | if (rects[i].w == 0 || rects[i].h == 0) { 564 | rects[i].x = rects[i].y = 0; // empty rect needs no space 565 | } else { 566 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 567 | if (fr.prev_link) { 568 | rects[i].x = (stbrp_coord) fr.x; 569 | rects[i].y = (stbrp_coord) fr.y; 570 | } else { 571 | rects[i].x = rects[i].y = STBRP__MAXVAL; 572 | } 573 | } 574 | } 575 | 576 | // unsort 577 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 578 | 579 | // set was_packed flags 580 | for (i=0; i < num_rects; ++i) 581 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 582 | } 583 | #endif 584 | -------------------------------------------------------------------------------- /src/libimgui/stb_textedit.h: -------------------------------------------------------------------------------- 1 | // [ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb 2 | // [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815) 3 | // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715) 4 | // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) 5 | // [ImGui] - fixed some minor warnings 6 | 7 | // stb_textedit.h - v1.9 - public domain - Sean Barrett 8 | // Development of this library was sponsored by RAD Game Tools 9 | // 10 | // This C header file implements the guts of a multi-line text-editing 11 | // widget; you implement display, word-wrapping, and low-level string 12 | // insertion/deletion, and stb_textedit will map user inputs into 13 | // insertions & deletions, plus updates to the cursor position, 14 | // selection state, and undo state. 15 | // 16 | // It is intended for use in games and other systems that need to build 17 | // their own custom widgets and which do not have heavy text-editing 18 | // requirements (this library is not recommended for use for editing large 19 | // texts, as its performance does not scale and it has limited undo). 20 | // 21 | // Non-trivial behaviors are modelled after Windows text controls. 22 | // 23 | // 24 | // LICENSE 25 | // 26 | // This software is dual-licensed to the public domain and under the following 27 | // license: you are granted a perpetual, irrevocable license to copy, modify, 28 | // publish, and distribute this file as you see fit. 29 | // 30 | // 31 | // DEPENDENCIES 32 | // 33 | // Uses the C runtime function 'memmove', which you can override 34 | // by defining STB_TEXTEDIT_memmove before the implementation. 35 | // Uses no other functions. Performs no runtime allocations. 36 | // 37 | // 38 | // VERSION HISTORY 39 | // 40 | // 1.9 (2016-08-27) customizable move-by-word 41 | // 1.8 (2016-04-02) better keyboard handling when mouse button is down 42 | // 1.7 (2015-09-13) change y range handling in case baseline is non-0 43 | // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove 44 | // 1.5 (2014-09-10) add support for secondary keys for OS X 45 | // 1.4 (2014-08-17) fix signed/unsigned warnings 46 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary 47 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code 48 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) 49 | // 1.0 (2012-07-26) improve documentation, initial public release 50 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode 51 | // 0.2 (2011-11-28) fixes to undo/redo 52 | // 0.1 (2010-07-08) initial version 53 | // 54 | // ADDITIONAL CONTRIBUTORS 55 | // 56 | // Ulf Winklemann: move-by-word in 1.1 57 | // Fabian Giesen: secondary key inputs in 1.5 58 | // Martins Mozeiko: STB_TEXTEDIT_memmove 59 | // 60 | // Bugfixes: 61 | // Scott Graham 62 | // Daniel Keller 63 | // Omar Cornut 64 | // 65 | // USAGE 66 | // 67 | // This file behaves differently depending on what symbols you define 68 | // before including it. 69 | // 70 | // 71 | // Header-file mode: 72 | // 73 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, 74 | // it will operate in "header file" mode. In this mode, it declares a 75 | // single public symbol, STB_TexteditState, which encapsulates the current 76 | // state of a text widget (except for the string, which you will store 77 | // separately). 78 | // 79 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a 80 | // primitive type that defines a single character (e.g. char, wchar_t, etc). 81 | // 82 | // To save space or increase undo-ability, you can optionally define the 83 | // following things that are used by the undo system: 84 | // 85 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position 86 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 87 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 88 | // 89 | // If you don't define these, they are set to permissive types and 90 | // moderate sizes. The undo system does no memory allocations, so 91 | // it grows STB_TexteditState by the worst-case storage which is (in bytes): 92 | // 93 | // [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 94 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 95 | // 96 | // 97 | // Implementation mode: 98 | // 99 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it 100 | // will compile the implementation of the text edit widget, depending 101 | // on a large number of symbols which must be defined before the include. 102 | // 103 | // The implementation is defined only as static functions. You will then 104 | // need to provide your own APIs in the same file which will access the 105 | // static functions. 106 | // 107 | // The basic concept is that you provide a "string" object which 108 | // behaves like an array of characters. stb_textedit uses indices to 109 | // refer to positions in the string, implicitly representing positions 110 | // in the displayed textedit. This is true for both plain text and 111 | // rich text; even with rich text stb_truetype interacts with your 112 | // code as if there was an array of all the displayed characters. 113 | // 114 | // Symbols that must be the same in header-file and implementation mode: 115 | // 116 | // STB_TEXTEDIT_CHARTYPE the character type 117 | // STB_TEXTEDIT_POSITIONTYPE small type that a valid cursor position 118 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 119 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 120 | // 121 | // Symbols you must define for implementation mode: 122 | // 123 | // STB_TEXTEDIT_STRING the type of object representing a string being edited, 124 | // typically this is a wrapper object with other data you need 125 | // 126 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) 127 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters 128 | // starting from character #n (see discussion below) 129 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character 130 | // to the xpos of the i+1'th char for a line of characters 131 | // starting at character #n (i.e. accounts for kerning 132 | // with previous char) 133 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character 134 | // (return type is int, -1 means not valid to insert) 135 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based 136 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize 137 | // as manually wordwrapping for end-of-line positioning 138 | // 139 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i 140 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) 141 | // 142 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key 143 | // 144 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left 145 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right 146 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up 147 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 148 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 149 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END 150 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME 151 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END 152 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor 153 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor 154 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo 155 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo 156 | // 157 | // Optional: 158 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode 159 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), 160 | // required for default WORDLEFT/WORDRIGHT handlers 161 | // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to 162 | // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to 163 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT 164 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT 165 | // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line 166 | // STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line 167 | // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text 168 | // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 169 | // 170 | // Todo: 171 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 172 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 173 | // 174 | // Keyboard input must be encoded as a single integer value; e.g. a character code 175 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must 176 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 177 | // i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 178 | // 179 | // You can encode other things, such as CONTROL or ALT, in additional bits, and 180 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, 181 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN 182 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, 183 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the 184 | // API below. The control keys will only match WM_KEYDOWN events because of the 185 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN 186 | // bit so it only decodes WM_CHAR events. 187 | // 188 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed 189 | // row of characters assuming they start on the i'th character--the width and 190 | // the height and the number of characters consumed. This allows this library 191 | // to traverse the entire layout incrementally. You need to compute word-wrapping 192 | // here. 193 | // 194 | // Each textfield keeps its own insert mode state, which is not how normal 195 | // applications work. To keep an app-wide insert mode, update/copy the 196 | // "insert_mode" field of STB_TexteditState before/after calling API functions. 197 | // 198 | // API 199 | // 200 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 201 | // 202 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 203 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 204 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 205 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 206 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) 207 | // 208 | // Each of these functions potentially updates the string and updates the 209 | // state. 210 | // 211 | // initialize_state: 212 | // set the textedit state to a known good default state when initially 213 | // constructing the textedit. 214 | // 215 | // click: 216 | // call this with the mouse x,y on a mouse down; it will update the cursor 217 | // and reset the selection start/end to the cursor point. the x,y must 218 | // be relative to the text widget, with (0,0) being the top left. 219 | // 220 | // drag: 221 | // call this with the mouse x,y on a mouse drag/up; it will update the 222 | // cursor and the selection end point 223 | // 224 | // cut: 225 | // call this to delete the current selection; returns true if there was 226 | // one. you should FIRST copy the current selection to the system paste buffer. 227 | // (To copy, just copy the current selection out of the string yourself.) 228 | // 229 | // paste: 230 | // call this to paste text at the current cursor point or over the current 231 | // selection if there is one. 232 | // 233 | // key: 234 | // call this for keyboard inputs sent to the textfield. you can use it 235 | // for "key down" events or for "translated" key events. if you need to 236 | // do both (as in Win32), or distinguish Unicode characters from control 237 | // inputs, set a high bit to distinguish the two; then you can define the 238 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 239 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 240 | // clear. 241 | // 242 | // When rendering, you can read the cursor position and selection state from 243 | // the STB_TexteditState. 244 | // 245 | // 246 | // Notes: 247 | // 248 | // This is designed to be usable in IMGUI, so it allows for the possibility of 249 | // running in an IMGUI that has NOT cached the multi-line layout. For this 250 | // reason, it provides an interface that is compatible with computing the 251 | // layout incrementally--we try to make sure we make as few passes through 252 | // as possible. (For example, to locate the mouse pointer in the text, we 253 | // could define functions that return the X and Y positions of characters 254 | // and binary search Y and then X, but if we're doing dynamic layout this 255 | // will run the layout algorithm many times, so instead we manually search 256 | // forward in one pass. Similar logic applies to e.g. up-arrow and 257 | // down-arrow movement.) 258 | // 259 | // If it's run in a widget that *has* cached the layout, then this is less 260 | // efficient, but it's not horrible on modern computers. But you wouldn't 261 | // want to edit million-line files with it. 262 | 263 | 264 | //////////////////////////////////////////////////////////////////////////// 265 | //////////////////////////////////////////////////////////////////////////// 266 | //// 267 | //// Header-file mode 268 | //// 269 | //// 270 | 271 | #ifndef INCLUDE_STB_TEXTEDIT_H 272 | #define INCLUDE_STB_TEXTEDIT_H 273 | 274 | //////////////////////////////////////////////////////////////////////// 275 | // 276 | // STB_TexteditState 277 | // 278 | // Definition of STB_TexteditState which you should store 279 | // per-textfield; it includes cursor position, selection state, 280 | // and undo state. 281 | // 282 | 283 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT 284 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99 285 | #endif 286 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT 287 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999 288 | #endif 289 | #ifndef STB_TEXTEDIT_CHARTYPE 290 | #define STB_TEXTEDIT_CHARTYPE int 291 | #endif 292 | #ifndef STB_TEXTEDIT_POSITIONTYPE 293 | #define STB_TEXTEDIT_POSITIONTYPE int 294 | #endif 295 | 296 | typedef struct 297 | { 298 | // private data 299 | STB_TEXTEDIT_POSITIONTYPE where; 300 | short insert_length; 301 | short delete_length; 302 | short char_storage; 303 | } StbUndoRecord; 304 | 305 | typedef struct 306 | { 307 | // private data 308 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 309 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 310 | short undo_point, redo_point; 311 | short undo_char_point, redo_char_point; 312 | } StbUndoState; 313 | 314 | typedef struct 315 | { 316 | ///////////////////// 317 | // 318 | // public data 319 | // 320 | 321 | int cursor; 322 | // position of the text cursor within the string 323 | 324 | int select_start; // selection start point 325 | int select_end; 326 | // selection start and end point in characters; if equal, no selection. 327 | // note that start may be less than or greater than end (e.g. when 328 | // dragging the mouse, start is where the initial click was, and you 329 | // can drag in either direction) 330 | 331 | unsigned char insert_mode; 332 | // each textfield keeps its own insert mode state. to keep an app-wide 333 | // insert mode, copy this value in/out of the app state 334 | 335 | ///////////////////// 336 | // 337 | // private data 338 | // 339 | unsigned char cursor_at_end_of_line; // not implemented yet 340 | unsigned char initialized; 341 | unsigned char has_preferred_x; 342 | unsigned char single_line; 343 | unsigned char padding1, padding2, padding3; 344 | float preferred_x; // this determines where the cursor up/down tries to seek to along x 345 | StbUndoState undostate; 346 | } STB_TexteditState; 347 | 348 | 349 | //////////////////////////////////////////////////////////////////////// 350 | // 351 | // StbTexteditRow 352 | // 353 | // Result of layout query, used by stb_textedit to determine where 354 | // the text in each row is. 355 | 356 | // result of layout query 357 | typedef struct 358 | { 359 | float x0,x1; // starting x location, end x location (allows for align=right, etc) 360 | float baseline_y_delta; // position of baseline relative to previous row's baseline 361 | float ymin,ymax; // height of row above and below baseline 362 | int num_chars; 363 | } StbTexteditRow; 364 | #endif //INCLUDE_STB_TEXTEDIT_H 365 | 366 | 367 | //////////////////////////////////////////////////////////////////////////// 368 | //////////////////////////////////////////////////////////////////////////// 369 | //// 370 | //// Implementation mode 371 | //// 372 | //// 373 | 374 | 375 | // implementation isn't include-guarded, since it might have indirectly 376 | // included just the "header" portion 377 | #ifdef STB_TEXTEDIT_IMPLEMENTATION 378 | 379 | #ifndef STB_TEXTEDIT_memmove 380 | #include 381 | #define STB_TEXTEDIT_memmove memmove 382 | #endif 383 | 384 | 385 | ///////////////////////////////////////////////////////////////////////////// 386 | // 387 | // Mouse input handling 388 | // 389 | 390 | // traverse the layout to locate the nearest character to a display position 391 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) 392 | { 393 | StbTexteditRow r; 394 | int n = STB_TEXTEDIT_STRINGLEN(str); 395 | float base_y = 0, prev_x; 396 | int i=0, k; 397 | 398 | r.x0 = r.x1 = 0; 399 | r.ymin = r.ymax = 0; 400 | r.num_chars = 0; 401 | 402 | // search rows to find one that straddles 'y' 403 | while (i < n) { 404 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 405 | if (r.num_chars <= 0) 406 | return n; 407 | 408 | if (i==0 && y < base_y + r.ymin) 409 | return 0; 410 | 411 | if (y < base_y + r.ymax) 412 | break; 413 | 414 | i += r.num_chars; 415 | base_y += r.baseline_y_delta; 416 | } 417 | 418 | // below all text, return 'after' last character 419 | if (i >= n) 420 | return n; 421 | 422 | // check if it's before the beginning of the line 423 | if (x < r.x0) 424 | return i; 425 | 426 | // check if it's before the end of the line 427 | if (x < r.x1) { 428 | // search characters in row for one that straddles 'x' 429 | prev_x = r.x0; 430 | for (k=0; k < r.num_chars; ++k) { 431 | float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 432 | if (x < prev_x+w) { 433 | if (x < prev_x+w/2) 434 | return k+i; 435 | else 436 | return k+i+1; 437 | } 438 | prev_x += w; 439 | } 440 | // shouldn't happen, but if it does, fall through to end-of-line case 441 | } 442 | 443 | // if the last character is a newline, return that. otherwise return 'after' the last character 444 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 445 | return i+r.num_chars-1; 446 | else 447 | return i+r.num_chars; 448 | } 449 | 450 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection 451 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 452 | { 453 | state->cursor = stb_text_locate_coord(str, x, y); 454 | state->select_start = state->cursor; 455 | state->select_end = state->cursor; 456 | state->has_preferred_x = 0; 457 | } 458 | 459 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location 460 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 461 | { 462 | int p = stb_text_locate_coord(str, x, y); 463 | if (state->select_start == state->select_end) 464 | state->select_start = state->cursor; 465 | state->cursor = state->select_end = p; 466 | } 467 | 468 | ///////////////////////////////////////////////////////////////////////////// 469 | // 470 | // Keyboard input handling 471 | // 472 | 473 | // forward declarations 474 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 475 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 476 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); 477 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); 478 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); 479 | 480 | typedef struct 481 | { 482 | float x,y; // position of n'th character 483 | float height; // height of line 484 | int first_char, length; // first char of row, and length 485 | int prev_first; // first char of previous row 486 | } StbFindState; 487 | 488 | // find the x/y location of a character, and remember info about the previous row in 489 | // case we get a move-up event (for page up, we'll have to rescan) 490 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) 491 | { 492 | StbTexteditRow r; 493 | int prev_start = 0; 494 | int z = STB_TEXTEDIT_STRINGLEN(str); 495 | int i=0, first; 496 | 497 | if (n == z) { 498 | // if it's at the end, then find the last line -- simpler than trying to 499 | // explicitly handle this case in the regular code 500 | if (single_line) { 501 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 502 | find->y = 0; 503 | find->first_char = 0; 504 | find->length = z; 505 | find->height = r.ymax - r.ymin; 506 | find->x = r.x1; 507 | } else { 508 | find->y = 0; 509 | find->x = 0; 510 | find->height = 1; 511 | while (i < z) { 512 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 513 | prev_start = i; 514 | i += r.num_chars; 515 | } 516 | find->first_char = i; 517 | find->length = 0; 518 | find->prev_first = prev_start; 519 | } 520 | return; 521 | } 522 | 523 | // search rows to find the one that straddles character n 524 | find->y = 0; 525 | 526 | for(;;) { 527 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 528 | if (n < i + r.num_chars) 529 | break; 530 | prev_start = i; 531 | i += r.num_chars; 532 | find->y += r.baseline_y_delta; 533 | } 534 | 535 | find->first_char = first = i; 536 | find->length = r.num_chars; 537 | find->height = r.ymax - r.ymin; 538 | find->prev_first = prev_start; 539 | 540 | // now scan to find xpos 541 | find->x = r.x0; 542 | i = 0; 543 | for (i=0; first+i < n; ++i) 544 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 545 | } 546 | 547 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 548 | 549 | // make the selection/cursor state valid if client altered the string 550 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 551 | { 552 | int n = STB_TEXTEDIT_STRINGLEN(str); 553 | if (STB_TEXT_HAS_SELECTION(state)) { 554 | if (state->select_start > n) state->select_start = n; 555 | if (state->select_end > n) state->select_end = n; 556 | // if clamping forced them to be equal, move the cursor to match 557 | if (state->select_start == state->select_end) 558 | state->cursor = state->select_start; 559 | } 560 | if (state->cursor > n) state->cursor = n; 561 | } 562 | 563 | // delete characters while updating undo 564 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) 565 | { 566 | stb_text_makeundo_delete(str, state, where, len); 567 | STB_TEXTEDIT_DELETECHARS(str, where, len); 568 | state->has_preferred_x = 0; 569 | } 570 | 571 | // delete the section 572 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 573 | { 574 | stb_textedit_clamp(str, state); 575 | if (STB_TEXT_HAS_SELECTION(state)) { 576 | if (state->select_start < state->select_end) { 577 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 578 | state->select_end = state->cursor = state->select_start; 579 | } else { 580 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 581 | state->select_start = state->cursor = state->select_end; 582 | } 583 | state->has_preferred_x = 0; 584 | } 585 | } 586 | 587 | // canoncialize the selection so start <= end 588 | static void stb_textedit_sortselection(STB_TexteditState *state) 589 | { 590 | if (state->select_end < state->select_start) { 591 | int temp = state->select_end; 592 | state->select_end = state->select_start; 593 | state->select_start = temp; 594 | } 595 | } 596 | 597 | // move cursor to first character of selection 598 | static void stb_textedit_move_to_first(STB_TexteditState *state) 599 | { 600 | if (STB_TEXT_HAS_SELECTION(state)) { 601 | stb_textedit_sortselection(state); 602 | state->cursor = state->select_start; 603 | state->select_end = state->select_start; 604 | state->has_preferred_x = 0; 605 | } 606 | } 607 | 608 | // move cursor to last character of selection 609 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 610 | { 611 | if (STB_TEXT_HAS_SELECTION(state)) { 612 | stb_textedit_sortselection(state); 613 | stb_textedit_clamp(str, state); 614 | state->cursor = state->select_end; 615 | state->select_start = state->select_end; 616 | state->has_preferred_x = 0; 617 | } 618 | } 619 | 620 | #ifdef STB_TEXTEDIT_IS_SPACE 621 | static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 622 | { 623 | return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 624 | } 625 | 626 | #ifndef STB_TEXTEDIT_MOVEWORDLEFT 627 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 628 | { 629 | --c; // always move at least one character 630 | while( c >= 0 && !is_word_boundary( str, c ) ) 631 | --c; 632 | 633 | if( c < 0 ) 634 | c = 0; 635 | 636 | return c; 637 | } 638 | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 639 | #endif 640 | 641 | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 642 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 643 | { 644 | const int len = STB_TEXTEDIT_STRINGLEN(str); 645 | ++c; // always move at least one character 646 | while( c < len && !is_word_boundary( str, c ) ) 647 | ++c; 648 | 649 | if( c > len ) 650 | c = len; 651 | 652 | return c; 653 | } 654 | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 655 | #endif 656 | 657 | #endif 658 | 659 | // update selection and cursor to match each other 660 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) 661 | { 662 | if (!STB_TEXT_HAS_SELECTION(state)) 663 | state->select_start = state->select_end = state->cursor; 664 | else 665 | state->cursor = state->select_end; 666 | } 667 | 668 | // API cut: delete selection 669 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 670 | { 671 | if (STB_TEXT_HAS_SELECTION(state)) { 672 | stb_textedit_delete_selection(str,state); // implicity clamps 673 | state->has_preferred_x = 0; 674 | return 1; 675 | } 676 | return 0; 677 | } 678 | 679 | // API paste: replace existing selection with passed-in text 680 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 681 | { 682 | STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext; 683 | // if there's a selection, the paste should delete it 684 | stb_textedit_clamp(str, state); 685 | stb_textedit_delete_selection(str,state); 686 | // try to insert the characters 687 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { 688 | stb_text_makeundo_insert(state, state->cursor, len); 689 | state->cursor += len; 690 | state->has_preferred_x = 0; 691 | return 1; 692 | } 693 | // remove the undo since we didn't actually insert the characters 694 | if (state->undostate.undo_point) 695 | --state->undostate.undo_point; 696 | return 0; 697 | } 698 | 699 | // API key: process a keyboard input 700 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) 701 | { 702 | retry: 703 | switch (key) { 704 | default: { 705 | int c = STB_TEXTEDIT_KEYTOTEXT(key); 706 | if (c > 0) { 707 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 708 | 709 | // can't add newline in single-line mode 710 | if (c == '\n' && state->single_line) 711 | break; 712 | 713 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 714 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 715 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 716 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 717 | ++state->cursor; 718 | state->has_preferred_x = 0; 719 | } 720 | } else { 721 | stb_textedit_delete_selection(str,state); // implicity clamps 722 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 723 | stb_text_makeundo_insert(state, state->cursor, 1); 724 | ++state->cursor; 725 | state->has_preferred_x = 0; 726 | } 727 | } 728 | } 729 | break; 730 | } 731 | 732 | #ifdef STB_TEXTEDIT_K_INSERT 733 | case STB_TEXTEDIT_K_INSERT: 734 | state->insert_mode = !state->insert_mode; 735 | break; 736 | #endif 737 | 738 | case STB_TEXTEDIT_K_UNDO: 739 | stb_text_undo(str, state); 740 | state->has_preferred_x = 0; 741 | break; 742 | 743 | case STB_TEXTEDIT_K_REDO: 744 | stb_text_redo(str, state); 745 | state->has_preferred_x = 0; 746 | break; 747 | 748 | case STB_TEXTEDIT_K_LEFT: 749 | // if currently there's a selection, move cursor to start of selection 750 | if (STB_TEXT_HAS_SELECTION(state)) 751 | stb_textedit_move_to_first(state); 752 | else 753 | if (state->cursor > 0) 754 | --state->cursor; 755 | state->has_preferred_x = 0; 756 | break; 757 | 758 | case STB_TEXTEDIT_K_RIGHT: 759 | // if currently there's a selection, move cursor to end of selection 760 | if (STB_TEXT_HAS_SELECTION(state)) 761 | stb_textedit_move_to_last(str, state); 762 | else 763 | ++state->cursor; 764 | stb_textedit_clamp(str, state); 765 | state->has_preferred_x = 0; 766 | break; 767 | 768 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 769 | stb_textedit_clamp(str, state); 770 | stb_textedit_prep_selection_at_cursor(state); 771 | // move selection left 772 | if (state->select_end > 0) 773 | --state->select_end; 774 | state->cursor = state->select_end; 775 | state->has_preferred_x = 0; 776 | break; 777 | 778 | #ifdef STB_TEXTEDIT_MOVEWORDLEFT 779 | case STB_TEXTEDIT_K_WORDLEFT: 780 | if (STB_TEXT_HAS_SELECTION(state)) 781 | stb_textedit_move_to_first(state); 782 | else { 783 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 784 | stb_textedit_clamp( str, state ); 785 | } 786 | break; 787 | 788 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 789 | if( !STB_TEXT_HAS_SELECTION( state ) ) 790 | stb_textedit_prep_selection_at_cursor(state); 791 | 792 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 793 | state->select_end = state->cursor; 794 | 795 | stb_textedit_clamp( str, state ); 796 | break; 797 | #endif 798 | 799 | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 800 | case STB_TEXTEDIT_K_WORDRIGHT: 801 | if (STB_TEXT_HAS_SELECTION(state)) 802 | stb_textedit_move_to_last(str, state); 803 | else { 804 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 805 | stb_textedit_clamp( str, state ); 806 | } 807 | break; 808 | 809 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 810 | if( !STB_TEXT_HAS_SELECTION( state ) ) 811 | stb_textedit_prep_selection_at_cursor(state); 812 | 813 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 814 | state->select_end = state->cursor; 815 | 816 | stb_textedit_clamp( str, state ); 817 | break; 818 | #endif 819 | 820 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 821 | stb_textedit_prep_selection_at_cursor(state); 822 | // move selection right 823 | ++state->select_end; 824 | stb_textedit_clamp(str, state); 825 | state->cursor = state->select_end; 826 | state->has_preferred_x = 0; 827 | break; 828 | 829 | case STB_TEXTEDIT_K_DOWN: 830 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { 831 | StbFindState find; 832 | StbTexteditRow row; 833 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 834 | 835 | if (state->single_line) { 836 | // on windows, up&down in single-line behave like left&right 837 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 838 | goto retry; 839 | } 840 | 841 | if (sel) 842 | stb_textedit_prep_selection_at_cursor(state); 843 | else if (STB_TEXT_HAS_SELECTION(state)) 844 | stb_textedit_move_to_last(str,state); 845 | 846 | // compute current position of cursor point 847 | stb_textedit_clamp(str, state); 848 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 849 | 850 | // now find character position down a row 851 | if (find.length) { 852 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x; 853 | float x; 854 | int start = find.first_char + find.length; 855 | state->cursor = start; 856 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 857 | x = row.x0; 858 | for (i=0; i < row.num_chars; ++i) { 859 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 860 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 861 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 862 | break; 863 | #endif 864 | x += dx; 865 | if (x > goal_x) 866 | break; 867 | ++state->cursor; 868 | } 869 | stb_textedit_clamp(str, state); 870 | 871 | state->has_preferred_x = 1; 872 | state->preferred_x = goal_x; 873 | 874 | if (sel) 875 | state->select_end = state->cursor; 876 | } 877 | break; 878 | } 879 | 880 | case STB_TEXTEDIT_K_UP: 881 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { 882 | StbFindState find; 883 | StbTexteditRow row; 884 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 885 | 886 | if (state->single_line) { 887 | // on windows, up&down become left&right 888 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 889 | goto retry; 890 | } 891 | 892 | if (sel) 893 | stb_textedit_prep_selection_at_cursor(state); 894 | else if (STB_TEXT_HAS_SELECTION(state)) 895 | stb_textedit_move_to_first(state); 896 | 897 | // compute current position of cursor point 898 | stb_textedit_clamp(str, state); 899 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 900 | 901 | // can only go up if there's a previous row 902 | if (find.prev_first != find.first_char) { 903 | // now find character position up a row 904 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x; 905 | float x; 906 | state->cursor = find.prev_first; 907 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 908 | x = row.x0; 909 | for (i=0; i < row.num_chars; ++i) { 910 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 911 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 912 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 913 | break; 914 | #endif 915 | x += dx; 916 | if (x > goal_x) 917 | break; 918 | ++state->cursor; 919 | } 920 | stb_textedit_clamp(str, state); 921 | 922 | state->has_preferred_x = 1; 923 | state->preferred_x = goal_x; 924 | 925 | if (sel) 926 | state->select_end = state->cursor; 927 | } 928 | break; 929 | } 930 | 931 | case STB_TEXTEDIT_K_DELETE: 932 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 933 | if (STB_TEXT_HAS_SELECTION(state)) 934 | stb_textedit_delete_selection(str, state); 935 | else { 936 | int n = STB_TEXTEDIT_STRINGLEN(str); 937 | if (state->cursor < n) 938 | stb_textedit_delete(str, state, state->cursor, 1); 939 | } 940 | state->has_preferred_x = 0; 941 | break; 942 | 943 | case STB_TEXTEDIT_K_BACKSPACE: 944 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 945 | if (STB_TEXT_HAS_SELECTION(state)) 946 | stb_textedit_delete_selection(str, state); 947 | else { 948 | stb_textedit_clamp(str, state); 949 | if (state->cursor > 0) { 950 | stb_textedit_delete(str, state, state->cursor-1, 1); 951 | --state->cursor; 952 | } 953 | } 954 | state->has_preferred_x = 0; 955 | break; 956 | 957 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 958 | case STB_TEXTEDIT_K_TEXTSTART2: 959 | #endif 960 | case STB_TEXTEDIT_K_TEXTSTART: 961 | state->cursor = state->select_start = state->select_end = 0; 962 | state->has_preferred_x = 0; 963 | break; 964 | 965 | #ifdef STB_TEXTEDIT_K_TEXTEND2 966 | case STB_TEXTEDIT_K_TEXTEND2: 967 | #endif 968 | case STB_TEXTEDIT_K_TEXTEND: 969 | state->cursor = STB_TEXTEDIT_STRINGLEN(str); 970 | state->select_start = state->select_end = 0; 971 | state->has_preferred_x = 0; 972 | break; 973 | 974 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 975 | case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 976 | #endif 977 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 978 | stb_textedit_prep_selection_at_cursor(state); 979 | state->cursor = state->select_end = 0; 980 | state->has_preferred_x = 0; 981 | break; 982 | 983 | #ifdef STB_TEXTEDIT_K_TEXTEND2 984 | case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 985 | #endif 986 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 987 | stb_textedit_prep_selection_at_cursor(state); 988 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 989 | state->has_preferred_x = 0; 990 | break; 991 | 992 | 993 | #ifdef STB_TEXTEDIT_K_LINESTART2 994 | case STB_TEXTEDIT_K_LINESTART2: 995 | #endif 996 | case STB_TEXTEDIT_K_LINESTART: 997 | stb_textedit_clamp(str, state); 998 | stb_textedit_move_to_first(state); 999 | if (state->single_line) 1000 | state->cursor = 0; 1001 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1002 | --state->cursor; 1003 | state->has_preferred_x = 0; 1004 | break; 1005 | 1006 | #ifdef STB_TEXTEDIT_K_LINEEND2 1007 | case STB_TEXTEDIT_K_LINEEND2: 1008 | #endif 1009 | case STB_TEXTEDIT_K_LINEEND: { 1010 | int n = STB_TEXTEDIT_STRINGLEN(str); 1011 | stb_textedit_clamp(str, state); 1012 | stb_textedit_move_to_first(state); 1013 | if (state->single_line) 1014 | state->cursor = n; 1015 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1016 | ++state->cursor; 1017 | state->has_preferred_x = 0; 1018 | break; 1019 | } 1020 | 1021 | #ifdef STB_TEXTEDIT_K_LINESTART2 1022 | case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1023 | #endif 1024 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1025 | stb_textedit_clamp(str, state); 1026 | stb_textedit_prep_selection_at_cursor(state); 1027 | if (state->single_line) 1028 | state->cursor = 0; 1029 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1030 | --state->cursor; 1031 | state->select_end = state->cursor; 1032 | state->has_preferred_x = 0; 1033 | break; 1034 | 1035 | #ifdef STB_TEXTEDIT_K_LINEEND2 1036 | case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1037 | #endif 1038 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1039 | int n = STB_TEXTEDIT_STRINGLEN(str); 1040 | stb_textedit_clamp(str, state); 1041 | stb_textedit_prep_selection_at_cursor(state); 1042 | if (state->single_line) 1043 | state->cursor = n; 1044 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1045 | ++state->cursor; 1046 | state->select_end = state->cursor; 1047 | state->has_preferred_x = 0; 1048 | break; 1049 | } 1050 | 1051 | // @TODO: 1052 | // STB_TEXTEDIT_K_PGUP - move cursor up a page 1053 | // STB_TEXTEDIT_K_PGDOWN - move cursor down a page 1054 | } 1055 | } 1056 | 1057 | ///////////////////////////////////////////////////////////////////////////// 1058 | // 1059 | // Undo processing 1060 | // 1061 | // @OPTIMIZE: the undo/redo buffer should be circular 1062 | 1063 | static void stb_textedit_flush_redo(StbUndoState *state) 1064 | { 1065 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1066 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1067 | } 1068 | 1069 | // discard the oldest entry in the undo list 1070 | static void stb_textedit_discard_undo(StbUndoState *state) 1071 | { 1072 | if (state->undo_point > 0) { 1073 | // if the 0th undo state has characters, clean those up 1074 | if (state->undo_rec[0].char_storage >= 0) { 1075 | int n = state->undo_rec[0].insert_length, i; 1076 | // delete n characters from all other records 1077 | state->undo_char_point = state->undo_char_point - (short) n; // vsnet05 1078 | STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1079 | for (i=0; i < state->undo_point; ++i) 1080 | if (state->undo_rec[i].char_storage >= 0) 1081 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it 1082 | } 1083 | --state->undo_point; 1084 | STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0]))); 1085 | } 1086 | } 1087 | 1088 | // discard the oldest entry in the redo list--it's bad if this 1089 | // ever happens, but because undo & redo have to store the actual 1090 | // characters in different cases, the redo character buffer can 1091 | // fill up even though the undo buffer didn't 1092 | static void stb_textedit_discard_redo(StbUndoState *state) 1093 | { 1094 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1095 | 1096 | if (state->redo_point <= k) { 1097 | // if the k'th undo state has characters, clean those up 1098 | if (state->undo_rec[k].char_storage >= 0) { 1099 | int n = state->undo_rec[k].insert_length, i; 1100 | // delete n characters from all other records 1101 | state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 1102 | STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1103 | for (i=state->redo_point; i < k; ++i) 1104 | if (state->undo_rec[i].char_storage >= 0) 1105 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 1106 | } 1107 | STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point-1, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); 1108 | ++state->redo_point; 1109 | } 1110 | } 1111 | 1112 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) 1113 | { 1114 | // any time we create a new undo record, we discard redo 1115 | stb_textedit_flush_redo(state); 1116 | 1117 | // if we have no free records, we have to make room, by sliding the 1118 | // existing records down 1119 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1120 | stb_textedit_discard_undo(state); 1121 | 1122 | // if the characters to store won't possibly fit in the buffer, we can't undo 1123 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { 1124 | state->undo_point = 0; 1125 | state->undo_char_point = 0; 1126 | return NULL; 1127 | } 1128 | 1129 | // if we don't have enough free characters in the buffer, we have to make room 1130 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) 1131 | stb_textedit_discard_undo(state); 1132 | 1133 | return &state->undo_rec[state->undo_point++]; 1134 | } 1135 | 1136 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) 1137 | { 1138 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); 1139 | if (r == NULL) 1140 | return NULL; 1141 | 1142 | r->where = pos; 1143 | r->insert_length = (short) insert_len; 1144 | r->delete_length = (short) delete_len; 1145 | 1146 | if (insert_len == 0) { 1147 | r->char_storage = -1; 1148 | return NULL; 1149 | } else { 1150 | r->char_storage = state->undo_char_point; 1151 | state->undo_char_point = state->undo_char_point + (short) insert_len; 1152 | return &state->undo_char[r->char_storage]; 1153 | } 1154 | } 1155 | 1156 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1157 | { 1158 | StbUndoState *s = &state->undostate; 1159 | StbUndoRecord u, *r; 1160 | if (s->undo_point == 0) 1161 | return; 1162 | 1163 | // we need to do two things: apply the undo record, and create a redo record 1164 | u = s->undo_rec[s->undo_point-1]; 1165 | r = &s->undo_rec[s->redo_point-1]; 1166 | r->char_storage = -1; 1167 | 1168 | r->insert_length = u.delete_length; 1169 | r->delete_length = u.insert_length; 1170 | r->where = u.where; 1171 | 1172 | if (u.delete_length) { 1173 | // if the undo record says to delete characters, then the redo record will 1174 | // need to re-insert the characters that get deleted, so we need to store 1175 | // them. 1176 | 1177 | // there are three cases: 1178 | // there's enough room to store the characters 1179 | // characters stored for *redoing* don't leave room for redo 1180 | // characters stored for *undoing* don't leave room for redo 1181 | // if the last is true, we have to bail 1182 | 1183 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { 1184 | // the undo records take up too much character space; there's no space to store the redo characters 1185 | r->insert_length = 0; 1186 | } else { 1187 | int i; 1188 | 1189 | // there's definitely room to store the characters eventually 1190 | while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1191 | // there's currently not enough room, so discard a redo record 1192 | stb_textedit_discard_redo(s); 1193 | // should never happen: 1194 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1195 | return; 1196 | } 1197 | r = &s->undo_rec[s->redo_point-1]; 1198 | 1199 | r->char_storage = s->redo_char_point - u.delete_length; 1200 | s->redo_char_point = s->redo_char_point - (short) u.delete_length; 1201 | 1202 | // now save the characters 1203 | for (i=0; i < u.delete_length; ++i) 1204 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1205 | } 1206 | 1207 | // now we can carry out the deletion 1208 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); 1209 | } 1210 | 1211 | // check type of recorded action: 1212 | if (u.insert_length) { 1213 | // easy case: was a deletion, so we need to insert n characters 1214 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); 1215 | s->undo_char_point -= u.insert_length; 1216 | } 1217 | 1218 | state->cursor = u.where + u.insert_length; 1219 | 1220 | s->undo_point--; 1221 | s->redo_point--; 1222 | } 1223 | 1224 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1225 | { 1226 | StbUndoState *s = &state->undostate; 1227 | StbUndoRecord *u, r; 1228 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1229 | return; 1230 | 1231 | // we need to do two things: apply the redo record, and create an undo record 1232 | u = &s->undo_rec[s->undo_point]; 1233 | r = s->undo_rec[s->redo_point]; 1234 | 1235 | // we KNOW there must be room for the undo record, because the redo record 1236 | // was derived from an undo record 1237 | 1238 | u->delete_length = r.insert_length; 1239 | u->insert_length = r.delete_length; 1240 | u->where = r.where; 1241 | u->char_storage = -1; 1242 | 1243 | if (r.delete_length) { 1244 | // the redo record requires us to delete characters, so the undo record 1245 | // needs to store the characters 1246 | 1247 | if (s->undo_char_point + u->insert_length > s->redo_char_point) { 1248 | u->insert_length = 0; 1249 | u->delete_length = 0; 1250 | } else { 1251 | int i; 1252 | u->char_storage = s->undo_char_point; 1253 | s->undo_char_point = s->undo_char_point + u->insert_length; 1254 | 1255 | // now save the characters 1256 | for (i=0; i < u->insert_length; ++i) 1257 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1258 | } 1259 | 1260 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); 1261 | } 1262 | 1263 | if (r.insert_length) { 1264 | // easy case: need to insert n characters 1265 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); 1266 | s->redo_char_point += r.insert_length; 1267 | } 1268 | 1269 | state->cursor = r.where + r.insert_length; 1270 | 1271 | s->undo_point++; 1272 | s->redo_point++; 1273 | } 1274 | 1275 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) 1276 | { 1277 | stb_text_createundo(&state->undostate, where, 0, length); 1278 | } 1279 | 1280 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) 1281 | { 1282 | int i; 1283 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1284 | if (p) { 1285 | for (i=0; i < length; ++i) 1286 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1287 | } 1288 | } 1289 | 1290 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) 1291 | { 1292 | int i; 1293 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1294 | if (p) { 1295 | for (i=0; i < old_length; ++i) 1296 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1297 | } 1298 | } 1299 | 1300 | // reset the state to default 1301 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) 1302 | { 1303 | state->undostate.undo_point = 0; 1304 | state->undostate.undo_char_point = 0; 1305 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1306 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1307 | state->select_end = state->select_start = 0; 1308 | state->cursor = 0; 1309 | state->has_preferred_x = 0; 1310 | state->preferred_x = 0; 1311 | state->cursor_at_end_of_line = 0; 1312 | state->initialized = 1; 1313 | state->single_line = (unsigned char) is_single_line; 1314 | state->insert_mode = 0; 1315 | } 1316 | 1317 | // API initialize 1318 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 1319 | { 1320 | stb_textedit_clear_state(state, is_single_line); 1321 | } 1322 | #endif//STB_TEXTEDIT_IMPLEMENTATION 1323 | -------------------------------------------------------------------------------- /src/wrap_imgui_impl.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2006-2016 LOVE Development Team 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * 8 | * Permission is granted to anyone to use this software for any purpose, 9 | * including commercial applications, and to alter it and redistribute it 10 | * freely, subject to the following restrictions: 11 | * 12 | * 1. The origin of this software must not be misrepresented; you must not 13 | * claim that you wrote the original software. If you use this software 14 | * in a product, an acknowledgment in the product documentation would be 15 | * appreciated but is not required. 16 | * 2. Altered source versions must be plainly marked as such, and must not be 17 | * misrepresented as being the original software. 18 | * 3. This notice may not be removed or altered from any source distribution. 19 | **/ 20 | 21 | #include "libimgui/imgui.h" 22 | #include "libimgui/imgui_dock.h" 23 | #include "imgui_impl.h" 24 | #include "wrap_imgui_impl.h" 25 | 26 | #include 27 | #include 28 | 29 | #if defined(_WIN32) || defined(_WIN64) 30 | 31 | #include 32 | 33 | // strndup() is not available on Windows 34 | char *strndup( const char *s1, size_t n) 35 | { 36 | char *copy= (char*)malloc( n+1 ); 37 | memcpy( copy, s1, n ); 38 | copy[n] = 0; 39 | return copy; 40 | }; 41 | 42 | #endif 43 | 44 | /* 45 | ** Love implentation functions 46 | */ 47 | static bool g_inited = false; 48 | static int g_textures[250]; // Should be enough 49 | static bool g_returnValueLast = true; 50 | 51 | static int w_ShutDown(lua_State *L) 52 | { 53 | ShutDown(); 54 | return 0; 55 | } 56 | 57 | static int w_NewFrame(lua_State *L) 58 | { 59 | if (!g_inited) 60 | { 61 | Init(L); 62 | g_inited = true; 63 | } 64 | NewFrame(); 65 | return 0; 66 | } 67 | 68 | // Util 69 | const char* getRealDirectoryIfExists(lua_State *L, const char* relativePath) 70 | { 71 | if (L == nullptr || relativePath == nullptr) 72 | { 73 | return nullptr; 74 | } 75 | 76 | int originalStackSize = lua_gettop(L); 77 | lua_getglobal(L, "love"); 78 | if (lua_isnil(L, -1)) 79 | { 80 | lua_pop(L, 1); 81 | return nullptr; 82 | } 83 | 84 | lua_getfield(L, -1, "filesystem"); 85 | lua_getfield(L, -1, "getRealDirectory"); 86 | lua_pushstring(L, relativePath); 87 | lua_call(L, 1, 1); 88 | 89 | char* result = nullptr; 90 | if (!lua_isnil(L, -1)) 91 | { 92 | size_t size = 0; 93 | const char* tmp = lua_tolstring(L, -1, &size); 94 | result = strndup(tmp, size); 95 | } 96 | 97 | lua_pop(L, lua_gettop(L) - originalStackSize); 98 | return result; 99 | } 100 | 101 | // Inputs 102 | 103 | static int w_MouseMoved(lua_State *L) 104 | { 105 | int x = (int)luaL_checknumber(L, 1); 106 | int y = (int)luaL_checknumber(L, 2); 107 | MouseMoved(x, y); 108 | return 0; 109 | } 110 | 111 | static int w_MousePressed(lua_State *L) 112 | { 113 | int button = (int)luaL_checknumber(L, 1); 114 | MousePressed(button); 115 | return 0; 116 | } 117 | 118 | static int w_MouseReleased(lua_State *L) 119 | { 120 | int button = (int)luaL_checknumber(L, 1); 121 | MouseReleased(button); 122 | return 0; 123 | } 124 | 125 | static int w_WheelMoved(lua_State *L) 126 | { 127 | int y = (int)luaL_checknumber(L, 1); 128 | WheelMoved(y); 129 | return 0; 130 | } 131 | 132 | static int w_KeyPressed(lua_State *L) 133 | { 134 | size_t size; 135 | const char *key = luaL_checklstring(L, 1, &size); 136 | KeyPressed(key); 137 | return 0; 138 | } 139 | 140 | static int w_KeyReleased(lua_State *L) 141 | { 142 | size_t size; 143 | const char *key = luaL_checklstring(L, 1, &size); 144 | KeyReleased(key); 145 | return 0; 146 | } 147 | 148 | static int w_TextInput(lua_State *L) 149 | { 150 | size_t size; 151 | const char *text = luaL_checklstring(L, 1, &size); 152 | TextInput(text); 153 | return 0; 154 | } 155 | 156 | static int w_GetWantCaptureMouse(lua_State *L) 157 | { 158 | lua_pushboolean(L, GetWantCaptureMouse()); 159 | return 1; 160 | } 161 | 162 | static int w_GetWantCaptureKeyboard(lua_State *L) 163 | { 164 | lua_pushboolean(L, GetWantCaptureKeyboard()); 165 | return 1; 166 | } 167 | 168 | static int w_GetWantTextInput(lua_State *L) 169 | { 170 | lua_pushboolean(L, GetWantTextInput()); 171 | return 1; 172 | } 173 | 174 | static int w_SetReturnValueLast(lua_State *L) 175 | { 176 | g_returnValueLast = (bool)lua_toboolean(L, 1); 177 | return 0; 178 | } 179 | 180 | /* 181 | ** Custom bindings 182 | */ 183 | 184 | static int w_GetStyleColorName(lua_State *L) 185 | { 186 | int idx = luaL_checkint(L, 1); 187 | lua_pushstring(L, ImGui::GetStyleColorName(idx - 1)); 188 | return 1; 189 | } 190 | 191 | static int w_GetStyleColCount(lua_State *L) 192 | { 193 | lua_pushinteger(L, ImGuiCol_COUNT); 194 | return 1; 195 | } 196 | 197 | static int w_SetGlobalFontFromFileTTF(lua_State *L) 198 | { 199 | size_t size; 200 | const char *path = luaL_checklstring(L, 1, &size); 201 | float size_pixels = luaL_checknumber(L, 2); 202 | float spacing_x = luaL_optnumber(L, 3, 0); 203 | float spacing_y = luaL_optnumber(L, 4, 0); 204 | float oversample_x = luaL_optnumber(L, 5, 1); 205 | float oversample_y = luaL_optnumber(L, 6, 1); 206 | 207 | const char* basePath = getRealDirectoryIfExists(L, path); 208 | if (basePath == nullptr) { 209 | lua_pushstring(L, "File does not exist."); 210 | lua_error(L); 211 | return 0; 212 | } 213 | 214 | char fullPath[4096] = {0}; 215 | snprintf(&(fullPath[0]), sizeof(fullPath) - 1, "%s/%s", basePath, path); 216 | SetGlobalFontFromFileTTF(&(fullPath[0]), size_pixels, spacing_x, spacing_y, 217 | oversample_x, oversample_y); 218 | lua_settop(L, 0); 219 | return 0; 220 | } 221 | 222 | static int w_AddFontFromFileTTF(lua_State *L) { 223 | size_t filenameSize; 224 | const char* filename = luaL_checklstring(L, 1, &filenameSize); 225 | float pixelSize = luaL_checknumber(L, 2); 226 | 227 | const char* basePath = getRealDirectoryIfExists(L, filename); 228 | if (basePath == nullptr) { 229 | lua_pushstring(L, "File does not exist."); 230 | lua_error(L); 231 | return 0; 232 | } 233 | 234 | char fullPath[4096] = {0}; 235 | snprintf(&(fullPath[0]), sizeof(fullPath) - 1, "%s/%s", basePath, filename); 236 | 237 | ImFontConfig* fontCfg = (ImFontConfig*)lua_touserdata(L, 3); 238 | 239 | ImGuiIO& io = ImGui::GetIO(); 240 | ImFont* font = io.Fonts->AddFontFromFileTTF(&(fullPath[0]), pixelSize); 241 | lua_settop(L, 0); 242 | 243 | if (font == nullptr) { 244 | return luaL_error(L, "Could not load font"); 245 | } else { 246 | lua_pushlightuserdata(L, (void*)font); 247 | return 1; 248 | } 249 | } 250 | 251 | /* 252 | ** Wrapped functions 253 | */ 254 | 255 | #define IMGUI_FUNCTION(name) \ 256 | static int impl_##name(lua_State *L) { \ 257 | int max_args = lua_gettop(L); \ 258 | int arg = 1; \ 259 | int stackval = 0; 260 | 261 | #define TEXTURE_ARG(name) \ 262 | lua_getglobal(L, "imgui"); \ 263 | lua_pushvalue(L, arg++); \ 264 | lua_setfield(L, -2, "textureID"); \ 265 | luaL_dostring(L, "imgui.textures = imgui.textures or {}\ 266 | table.insert(imgui.textures, imgui.textureID)\ 267 | return #imgui.textures"); \ 268 | lua_pop(L, 1); \ 269 | int index = luaL_checkint(L, 0);\ 270 | g_textures[index - 1] = index; \ 271 | void *name = &g_textures[index - 1]; \ 272 | 273 | #define OPTIONAL_LABEL_ARG(name, value) \ 274 | const char* name; \ 275 | if (arg <= max_args) { \ 276 | name = lua_tostring(L, arg++); \ 277 | } else { \ 278 | name = value; \ 279 | } 280 | 281 | #define LABEL_ARG(name) \ 282 | size_t i_##name##_size; \ 283 | const char * name = luaL_checklstring(L, arg++, &(i_##name##_size)); 284 | 285 | #define LABEL_POINTER_ARG(name) \ 286 | size_t i_##name##_size; \ 287 | const char * content = luaL_checklstring(L, arg++, &(i_##name##_size)); \ 288 | size_t buf_size = luaL_checknumber(L, arg++); \ 289 | char * name = new char [buf_size]; \ 290 | std::strcpy(name, content); 291 | 292 | #define END_LABEL_POINTER(name) \ 293 | if (name != NULL) { \ 294 | lua_pushstring(L, name); \ 295 | delete[] name; \ 296 | stackval++; \ 297 | } 298 | 299 | #define LABEL_ARRAY_ARG(name) \ 300 | luaL_checktype(L, arg, LUA_TTABLE); \ 301 | int len = lua_objlen(L, arg++); \ 302 | std::vector list; \ 303 | for (int i = 0; i < len; i++) \ 304 | { \ 305 | lua_pushinteger(L, i + 1); \ 306 | lua_gettable(L, arg - 1); \ 307 | size_t current_size; \ 308 | list.push_back(luaL_checklstring(L, -1, &(current_size))); \ 309 | } \ 310 | const char **name = list.data(); \ 311 | 312 | #define IM_VEC_2_ARG(name)\ 313 | const lua_Number i_##name##_x = luaL_checknumber(L, arg++); \ 314 | const lua_Number i_##name##_y = luaL_checknumber(L, arg++); \ 315 | ImVec2 name((float)i_##name##_x, (float)i_##name##_y); 316 | 317 | #define OPTIONAL_IM_VEC_2_ARG(name, x, y) \ 318 | lua_Number i_##name##_x = x; \ 319 | lua_Number i_##name##_y = y; \ 320 | if (arg <= max_args - 1) { \ 321 | i_##name##_x = luaL_checknumber(L, arg++); \ 322 | i_##name##_y = luaL_checknumber(L, arg++); \ 323 | } \ 324 | const ImVec2 name((float)i_##name##_x, (float)i_##name##_y); 325 | 326 | #define IM_VEC_4_ARG(name)\ 327 | const lua_Number i_##name##_x = luaL_checknumber(L, arg++); \ 328 | const lua_Number i_##name##_y = luaL_checknumber(L, arg++); \ 329 | const lua_Number i_##name##_z = luaL_checknumber(L, arg++); \ 330 | const lua_Number i_##name##_w = luaL_checknumber(L, arg++); \ 331 | const ImVec4 name((float)i_##name##_x, (float)i_##name##_y, (float)i_##name##_z, (float)i_##name##_w); 332 | 333 | #define OPTIONAL_IM_VEC_4_ARG(name, x, y, z, w) \ 334 | lua_Number i_##name##_x = x; \ 335 | lua_Number i_##name##_y = y; \ 336 | lua_Number i_##name##_z = z; \ 337 | lua_Number i_##name##_w = w; \ 338 | if (arg <= max_args - 1) { \ 339 | i_##name##_x = luaL_checknumber(L, arg++); \ 340 | i_##name##_y = luaL_checknumber(L, arg++); \ 341 | i_##name##_z = luaL_checknumber(L, arg++); \ 342 | i_##name##_w = luaL_checknumber(L, arg++); \ 343 | } \ 344 | const ImVec4 name((float)i_##name##_x, (float)i_##name##_y, (float)i_##name##_z, (float)i_##name##_w); 345 | 346 | #define NUMBER_ARG(name)\ 347 | lua_Number name = luaL_checknumber(L, arg++); 348 | 349 | #define OPTIONAL_NUMBER_ARG(name, otherwise)\ 350 | lua_Number name = otherwise; \ 351 | if (arg <= max_args) { \ 352 | name = luaL_checknumber(L, arg++); \ 353 | } 354 | 355 | #define FLOAT_POINTER_ARG(name) \ 356 | float i_##name##_value = (float)luaL_checknumber(L, arg++); \ 357 | float* name = &(i_##name##_value); 358 | 359 | #define END_FLOAT_POINTER(name) \ 360 | if (name != NULL) { \ 361 | lua_pushnumber(L, i_##name##_value); \ 362 | stackval++; \ 363 | } 364 | 365 | #define FLOAT_ARRAY_ARG(name) \ 366 | luaL_checktype(L, arg, LUA_TTABLE); \ 367 | int len = lua_objlen(L, arg++); \ 368 | std::vector list; \ 369 | for (int i = 0; i < len; i++) \ 370 | { \ 371 | lua_pushinteger(L, i + 1); \ 372 | lua_gettable(L, arg - 1); \ 373 | list.push_back(luaL_checknumber(L, -1)); \ 374 | } \ 375 | const float *name = list.data(); \ 376 | 377 | #define FLOAT_ARRAY2_ARG(name) \ 378 | float i_##name##_1 = (float)luaL_checknumber(L, arg++); \ 379 | float i_##name##_2 = (float)luaL_checknumber(L, arg++); \ 380 | float name[2] = { i_##name##_1, i_##name##_2 }; 381 | 382 | #define END_FLOAT_ARRAY2(name) \ 383 | lua_pushnumber(L, name[0]); \ 384 | lua_pushnumber(L, name[1]); \ 385 | stackval += 2; \ 386 | 387 | #define FLOAT_ARRAY3_ARG(name) \ 388 | float i_##name##_1 = (float)luaL_checknumber(L, arg++); \ 389 | float i_##name##_2 = (float)luaL_checknumber(L, arg++); \ 390 | float i_##name##_3 = (float)luaL_checknumber(L, arg++); \ 391 | float name[3] = { i_##name##_1, i_##name##_2, i_##name##_3 }; 392 | 393 | #define END_FLOAT_ARRAY3(name) \ 394 | lua_pushnumber(L, name[0]); \ 395 | lua_pushnumber(L, name[1]); \ 396 | lua_pushnumber(L, name[2]); \ 397 | stackval += 3; \ 398 | 399 | #define FLOAT_ARRAY4_ARG(name) \ 400 | float i_##name##_1 = (float)luaL_checknumber(L, arg++); \ 401 | float i_##name##_2 = (float)luaL_checknumber(L, arg++); \ 402 | float i_##name##_3 = (float)luaL_checknumber(L, arg++); \ 403 | float i_##name##_4 = (float)luaL_checknumber(L, arg++); \ 404 | float name[4] = { i_##name##_1, i_##name##_2, i_##name##_3, i_##name##_4 }; 405 | 406 | #define END_FLOAT_ARRAY4(name) \ 407 | lua_pushnumber(L, name[0]); \ 408 | lua_pushnumber(L, name[1]); \ 409 | lua_pushnumber(L, name[2]); \ 410 | lua_pushnumber(L, name[3]); \ 411 | stackval += 4; \ 412 | 413 | #define INT_ARRAY2_ARG(name) \ 414 | int i_##name##_1 = (int)luaL_checkinteger(L, arg++); \ 415 | int i_##name##_2 = (int)luaL_checkinteger(L, arg++); \ 416 | int name[2] = { i_##name##_1, i_##name##_2 }; 417 | 418 | #define END_INT_ARRAY2(name) \ 419 | lua_pushnumber(L, name[0]); \ 420 | lua_pushnumber(L, name[1]); \ 421 | stackval += 2; \ 422 | 423 | #define INT_ARRAY3_ARG(name) \ 424 | int i_##name##_1 = (int)luaL_checkinteger(L, arg++); \ 425 | int i_##name##_2 = (int)luaL_checkinteger(L, arg++); \ 426 | int i_##name##_3 = (int)luaL_checkinteger(L, arg++); \ 427 | int name[3] = { i_##name##_1, i_##name##_2, i_##name##_3 }; 428 | 429 | #define END_INT_ARRAY3(name) \ 430 | lua_pushnumber(L, name[0]); \ 431 | lua_pushnumber(L, name[1]); \ 432 | lua_pushnumber(L, name[2]); \ 433 | stackval += 3; \ 434 | 435 | #define INT_ARRAY4_ARG(name) \ 436 | int i_##name##_1 = (int)luaL_checkinteger(L, arg++); \ 437 | int i_##name##_2 = (int)luaL_checkinteger(L, arg++); \ 438 | int i_##name##_3 = (int)luaL_checkinteger(L, arg++); \ 439 | int i_##name##_4 = (int)luaL_checkinteger(L, arg++); \ 440 | int name[4] = { i_##name##_1, i_##name##_2, i_##name##_3, i_##name##_4 }; 441 | 442 | #define END_INT_ARRAY4(name) \ 443 | lua_pushnumber(L, name[0]); \ 444 | lua_pushnumber(L, name[1]); \ 445 | lua_pushnumber(L, name[2]); \ 446 | lua_pushnumber(L, name[3]); \ 447 | stackval += 4; \ 448 | 449 | #define OPTIONAL_INT_ARG(name, otherwise)\ 450 | int name = otherwise; \ 451 | if (arg <= max_args) { \ 452 | name = (int)luaL_checkinteger(L, arg++); \ 453 | } 454 | 455 | #define INT_ARG(name) \ 456 | const int name = (int)luaL_checkinteger(L, arg++); 457 | 458 | #define OPTIONAL_ENUM_ARG(name, otherwise)\ 459 | int name = otherwise; \ 460 | if (arg <= max_args) { \ 461 | if (lua_istable(L, arg++)) { \ 462 | int len = lua_objlen(L, -1); \ 463 | for (int i = 0; i < len; i++) { \ 464 | lua_pushinteger(L, i + 1); \ 465 | lua_gettable(L, arg - 1); \ 466 | lua_pushvalue(L, -1); \ 467 | lua_gettable(L, lua_upvalueindex(1)); \ 468 | name = name | (int)lua_tonumber(L, -1); \ 469 | lua_pop(L, 1); \ 470 | } \ 471 | } else { \ 472 | lua_pushvalue(L, arg - 1); \ 473 | lua_gettable(L, lua_upvalueindex(1)); \ 474 | name = (int)lua_tonumber(L, -1); \ 475 | lua_pop(L, 1); \ 476 | } \ 477 | } 478 | 479 | #define ENUM_ARG(name) \ 480 | int name = 0; \ 481 | if (lua_istable(L, arg++)) { \ 482 | int len = lua_objlen(L, -1); \ 483 | for (int i = 0; i < len; i++) { \ 484 | lua_pushinteger(L, i + 1); \ 485 | lua_gettable(L, arg - 1); \ 486 | lua_pushvalue(L, -1); \ 487 | lua_gettable(L, lua_upvalueindex(1)); \ 488 | name = name | (int)lua_tonumber(L, -1); \ 489 | lua_pop(L, 1); \ 490 | } \ 491 | } else { \ 492 | lua_pushvalue(L, arg - 1); \ 493 | lua_gettable(L, lua_upvalueindex(1)); \ 494 | name = (int)lua_tonumber(L, -1); \ 495 | lua_pop(L, 1); \ 496 | } 497 | 498 | #define OPTIONAL_UINT_ARG(name, otherwise)\ 499 | unsigned int name = otherwise; \ 500 | if (arg <= max_args) { \ 501 | name = (unsigned int)luaL_checkint(L, arg++); \ 502 | } 503 | 504 | #define UINT_ARG(name) \ 505 | const unsigned int name = (unsigned int)luaL_checkinteger(L, arg++); 506 | 507 | #define INT_POINTER_ARG(name) \ 508 | int i_##name##_value = (int)luaL_checkinteger(L, arg++); \ 509 | int* name = &(i_##name##_value); 510 | 511 | #define END_INT_POINTER(name) \ 512 | if (name != NULL) { \ 513 | lua_pushnumber(L, i_##name##_value); \ 514 | stackval++; \ 515 | } 516 | 517 | #define INT_CURRENT_ITEM_POINTER_ARG(name) \ 518 | int i_##name##_value = (int)luaL_checkinteger(L, arg++) - 1; \ 519 | int* name = &(i_##name##_value); 520 | 521 | #define END_INT_CURRENT_ITEM_POINTER(name) \ 522 | if (name != NULL) { \ 523 | lua_pushnumber(L, i_##name##_value + 1); \ 524 | stackval++; \ 525 | } 526 | 527 | #define UINT_POINTER_ARG(name) \ 528 | unsigned int i_##name##_value = (unsigned int)luaL_checkinteger(L, arg++); \ 529 | unsigned int* name = &(i_##name##_value); 530 | 531 | #define END_UINT_POINTER(name) \ 532 | if (name != NULL) { \ 533 | lua_pushnumber(L, i_##name##_value); \ 534 | stackval++; \ 535 | } 536 | 537 | #define BOOL_POINTER_ARG(name) \ 538 | bool i_##name##_value = (bool)lua_toboolean(L, arg++); \ 539 | bool* name = &(i_##name##_value); 540 | 541 | #define OPTIONAL_BOOL_POINTER_ARG(name) \ 542 | bool i_##name##_value; \ 543 | bool* name = NULL; \ 544 | if (arg <= max_args) { \ 545 | if (lua_isboolean(L, arg++)) \ 546 | { \ 547 | i_##name##_value = (bool)lua_toboolean(L, arg - 1); \ 548 | name = &(i_##name##_value); \ 549 | } \ 550 | } 551 | 552 | #define OPTIONAL_BOOL_ARG(name, otherwise) \ 553 | bool name = otherwise; \ 554 | if (arg <= max_args) { \ 555 | name = (bool)lua_toboolean(L, arg++); \ 556 | } 557 | 558 | #define DEFAULT_ARG(type, name, value) \ 559 | type name = value; \ 560 | 561 | #define BOOL_ARG(name) \ 562 | bool name = (bool)lua_toboolean(L, arg++); 563 | 564 | #define CALL_FUNCTION(name, retType,...) \ 565 | retType ret = ImGui::name(__VA_ARGS__); 566 | 567 | #define CALL_FUNCTION_NO_RET(name, ...) \ 568 | ImGui::name(__VA_ARGS__); 569 | 570 | #define PUSH_NUMBER(name) \ 571 | if (!g_returnValueLast) { \ 572 | lua_pushnumber(L, name); \ 573 | stackval++; \ 574 | } 575 | 576 | #define PUSH_STRING(name) \ 577 | if (!g_returnValueLast) { \ 578 | lua_pushstring(L, name); \ 579 | stackval++; \ 580 | } 581 | 582 | #define PUSH_BOOL(name) \ 583 | if (!g_returnValueLast) { \ 584 | lua_pushboolean(L, (int) name); \ 585 | stackval++; \ 586 | } 587 | 588 | #define PUSH_LAST_NUMBER(name) \ 589 | if (g_returnValueLast) { \ 590 | lua_pushnumber(L, name); \ 591 | stackval++; \ 592 | } 593 | 594 | #define PUSH_LAST_STRING(name) \ 595 | if (g_returnValueLast) { \ 596 | lua_pushstring(L, name); \ 597 | stackval++; \ 598 | } 599 | 600 | #define PUSH_LAST_BOOL(name) \ 601 | if (g_returnValueLast) { \ 602 | lua_pushboolean(L, (int) name); \ 603 | stackval++; \ 604 | } 605 | 606 | #define END_BOOL_POINTER(name) \ 607 | if (name != NULL) { \ 608 | lua_pushboolean(L, (int)i_##name##_value); \ 609 | stackval++; \ 610 | } 611 | 612 | #define END_IMGUI_FUNC \ 613 | return stackval; \ 614 | } 615 | 616 | #ifdef ENABLE_IM_LUA_END_STACK 617 | #define IF_RET_ADD_END_STACK(type) \ 618 | if (ret) { \ 619 | AddToStack(type); \ 620 | } 621 | 622 | #define ADD_END_STACK(type) \ 623 | AddToStack(type); 624 | 625 | #define POP_END_STACK(type) \ 626 | PopEndStack(type); 627 | 628 | #define END_STACK_START \ 629 | static void ImEndStack(int type) { \ 630 | switch(type) { 631 | 632 | #define END_STACK_OPTION(type, function) \ 633 | case type: \ 634 | ImGui::function(); \ 635 | break; 636 | 637 | #define END_STACK_END \ 638 | } \ 639 | } 640 | #else 641 | #define END_STACK_START 642 | #define END_STACK_OPTION(type, function) 643 | #define END_STACK_END 644 | #define IF_RET_ADD_END_STACK(type) 645 | #define ADD_END_STACK(type) 646 | #define POP_END_STACK(type) 647 | #endif 648 | 649 | #include "imgui_iterator.h" 650 | #include "imgui_iterator_dock.h" 651 | 652 | /* 653 | ** Hand made overrides 654 | */ 655 | 656 | static int w_Value(lua_State *L) 657 | { 658 | if (lua_isboolean(L, 2)) 659 | { 660 | return impl_Value(L); 661 | } 662 | return impl_Value_4(L); 663 | } 664 | 665 | static int w_CollapsingHeader(lua_State *L) 666 | { 667 | if (lua_isboolean(L, 2)) 668 | { 669 | return impl_CollapsingHeader_2(L); 670 | } 671 | return impl_CollapsingHeader(L); 672 | } 673 | 674 | static int w_TreeNodeEx(lua_State *L) 675 | { 676 | if (lua_gettop(L) > 2) 677 | { 678 | return impl_TreeNodeEx_2(L); 679 | } 680 | return impl_TreeNodeEx(L); 681 | } 682 | 683 | static int w_TreeNode(lua_State *L) 684 | { 685 | if (lua_gettop(L) > 1) 686 | { 687 | return impl_TreeNode_2(L); 688 | } 689 | return impl_TreeNode(L); 690 | } 691 | 692 | static int w_Combo(lua_State *L) 693 | { 694 | if (lua_isstring(L, 3)) 695 | { 696 | return impl_Combo_2(L); 697 | } 698 | return impl_Combo(L); 699 | } 700 | 701 | static int w_RadioButton(lua_State *L) 702 | { 703 | if (lua_gettop(L) > 2) 704 | { 705 | return impl_RadioButton_2(L); 706 | } 707 | return impl_RadioButton(L); 708 | } 709 | 710 | static int w_PushID(lua_State *L) 711 | { 712 | if (lua_gettop(L) > 1) 713 | { 714 | return impl_PushID_2(L); 715 | } 716 | return impl_PushID(L); 717 | } 718 | 719 | static int w_GetID(lua_State *L) 720 | { 721 | if (lua_gettop(L) > 1) 722 | { 723 | return impl_GetID_2(L); 724 | } 725 | return impl_GetID(L); 726 | } 727 | 728 | static int w_PushStyleVar(lua_State *L) 729 | { 730 | if (lua_gettop(L) > 2) 731 | { 732 | return impl_PushStyleVar_2(L); 733 | } 734 | return impl_PushStyleVar(L); 735 | } 736 | 737 | static int w_PushStyleColor(lua_State *L) 738 | { 739 | if (lua_gettop(L) > 2) 740 | { 741 | return impl_PushStyleColor_2(L); 742 | } 743 | return impl_PushStyleColor(L); 744 | } 745 | 746 | static int w_SetWindowPos(lua_State *L) 747 | { 748 | if (lua_isstring(L, 1)) 749 | { 750 | return impl_SetWindowPos_2(L); 751 | } 752 | return impl_SetWindowPos(L); 753 | } 754 | 755 | static int w_SetWindowSize(lua_State *L) 756 | { 757 | if (lua_isstring(L, 1)) 758 | { 759 | return impl_SetWindowSize_2(L); 760 | } 761 | return impl_SetWindowSize(L); 762 | } 763 | 764 | static int w_SetWindowCollapsed(lua_State *L) 765 | { 766 | if (lua_isstring(L, 1)) 767 | { 768 | return impl_SetWindowCollapsed_2(L); 769 | } 770 | return impl_SetWindowCollapsed(L); 771 | } 772 | 773 | static int w_SetWindowFocus(lua_State *L) 774 | { 775 | if (lua_isstring(L, 1)) 776 | { 777 | return impl_SetWindowFocus_2(L); 778 | } 779 | return impl_SetWindowFocus(L); 780 | } 781 | 782 | static int w_BeginChild(lua_State *L) 783 | { 784 | if (lua_isstring(L, 1)) 785 | { 786 | return impl_BeginChild(L); 787 | } 788 | return impl_BeginChild_2(L); 789 | } 790 | 791 | /* 792 | ** Reg 793 | */ 794 | 795 | static const struct luaL_Reg imguilib[] = { 796 | #undef IMGUI_FUNCTION 797 | #define IMGUI_FUNCTION(name) {#name, impl_##name}, 798 | // These defines are just redefining everything to nothing so 799 | // we can get the function names 800 | #undef DEFAULT_ARG 801 | #define DEFAULT_ARG(type, name, value) 802 | #undef TEXTURE_ARG 803 | #define TEXTURE_ARG(name) 804 | #undef OPTIONAL_LABEL_ARG 805 | #define OPTIONAL_LABEL_ARG(name, value) 806 | #undef LABEL_ARG 807 | #define LABEL_ARG(name) 808 | #undef LABEL_POINTER_ARG 809 | #define LABEL_POINTER_ARG(name) 810 | #undef END_LABEL_POINTER 811 | #define END_LABEL_POINTER(name) 812 | #undef LABEL_ARRAY_ARG 813 | #define LABEL_ARRAY_ARG(name) 814 | #undef IM_VEC_2_ARG 815 | #define IM_VEC_2_ARG(name) 816 | #undef OPTIONAL_IM_VEC_2_ARG 817 | #define OPTIONAL_IM_VEC_2_ARG(name, x, y) 818 | #undef IM_VEC_4_ARG 819 | #define IM_VEC_4_ARG(name) 820 | #undef OPTIONAL_IM_VEC_4_ARG 821 | #define OPTIONAL_IM_VEC_4_ARG(name, x, y, z, w) 822 | #undef NUMBER_ARG 823 | #define NUMBER_ARG(name) 824 | #undef OPTIONAL_NUMBER_ARG 825 | #define OPTIONAL_NUMBER_ARG(name, otherwise) 826 | #undef FLOAT_POINTER_ARG 827 | #define FLOAT_POINTER_ARG(name) 828 | #undef END_FLOAT_POINTER 829 | #define END_FLOAT_POINTER(name) 830 | #undef FLOAT_ARRAY_ARG 831 | #define FLOAT_ARRAY_ARG(name) 832 | #undef FLOAT_ARRAY2_ARG 833 | #define FLOAT_ARRAY2_ARG(name) 834 | #undef END_FLOAT_ARRAY2 835 | #define END_FLOAT_ARRAY2(name) 836 | #undef FLOAT_ARRAY3_ARG 837 | #define FLOAT_ARRAY3_ARG(name) 838 | #undef END_FLOAT_ARRAY3 839 | #define END_FLOAT_ARRAY3(name) 840 | #undef FLOAT_ARRAY4_ARG 841 | #define FLOAT_ARRAY4_ARG(name) 842 | #undef END_FLOAT_ARRAY4 843 | #define END_FLOAT_ARRAY4(name) 844 | #undef INT_ARRAY2_ARG 845 | #define INT_ARRAY2_ARG(name) 846 | #undef END_INT_ARRAY2 847 | #define END_INT_ARRAY2(name) 848 | #undef INT_ARRAY3_ARG 849 | #define INT_ARRAY3_ARG(name) 850 | #undef END_INT_ARRAY3 851 | #define END_INT_ARRAY3(name) 852 | #undef INT_ARRAY4_ARG 853 | #define INT_ARRAY4_ARG(name) 854 | #undef END_INT_ARRAY4 855 | #define END_INT_ARRAY4(name) 856 | #undef OPTIONAL_INT_ARG 857 | #define OPTIONAL_INT_ARG(name, otherwise) 858 | #undef INT_ARG 859 | #define INT_ARG(name) 860 | #undef OPTIONAL_ENUM_ARG 861 | #define OPTIONAL_ENUM_ARG(name, otherwise) 862 | #undef ENUM_ARG 863 | #define ENUM_ARG(name) 864 | #undef OPTIONAL_UINT_ARG 865 | #define OPTIONAL_UINT_ARG(name, otherwise) 866 | #undef UINT_ARG 867 | #define UINT_ARG(name) 868 | #undef INT_POINTER_ARG 869 | #define INT_POINTER_ARG(name) 870 | #undef END_INT_POINTER 871 | #define END_INT_POINTER(name) 872 | #undef INT_CURRENT_ITEM_POINTER_ARG 873 | #define INT_CURRENT_ITEM_POINTER_ARG(name) 874 | #undef END_INT_CURRENT_ITEM_POINTER 875 | #define END_INT_CURRENT_ITEM_POINTER(name) 876 | #undef UINT_POINTER_ARG 877 | #define UINT_POINTER_ARG(name) 878 | #undef END_UINT_POINTER 879 | #define END_UINT_POINTER(name) 880 | #undef BOOL_POINTER_ARG 881 | #define BOOL_POINTER_ARG(name) 882 | #undef OPTIONAL_BOOL_POINTER_ARG 883 | #define OPTIONAL_BOOL_POINTER_ARG(name) 884 | #undef OPTIONAL_BOOL_ARG 885 | #define OPTIONAL_BOOL_ARG(name, otherwise) 886 | #undef BOOL_ARG 887 | #define BOOL_ARG(name) 888 | #undef CALL_FUNCTION 889 | #define CALL_FUNCTION(name, retType, ...) 890 | #undef CALL_FUNCTION_NO_RET 891 | #define CALL_FUNCTION_NO_RET(name, ...) 892 | #undef PUSH_NUMBER 893 | #define PUSH_NUMBER(name) 894 | #undef PUSH_BOOL 895 | #define PUSH_BOOL(name) 896 | #undef PUSH_STRING 897 | #define PUSH_STRING(name) 898 | #undef PUSH_LAST_NUMBER 899 | #define PUSH_LAST_NUMBER(name) 900 | #undef PUSH_LAST_BOOL 901 | #define PUSH_LAST_BOOL(name) 902 | #undef PUSH_LAST_STRING 903 | #define PUSH_LAST_STRING(name) 904 | #undef END_BOOL_POINTER 905 | #define END_BOOL_POINTER(name) 906 | #undef END_IMGUI_FUNC 907 | #define END_IMGUI_FUNC 908 | #undef END_STACK_START 909 | #define END_STACK_START 910 | #undef END_STACK_OPTION 911 | #define END_STACK_OPTION(type, function) 912 | #undef END_STACK_END 913 | #define END_STACK_END 914 | #undef IF_RET_ADD_END_STACK 915 | #define IF_RET_ADD_END_STACK(type) 916 | #undef ADD_END_STACK 917 | #define ADD_END_STACK(type) 918 | #undef POP_END_STACK 919 | #define POP_END_STACK(type) 920 | 921 | #include "imgui_iterator.h" 922 | #include "imgui_iterator_dock.h" 923 | 924 | // Custom 925 | { "GetStyleColName", w_GetStyleColorName }, 926 | { "GetStyleColCount", w_GetStyleColCount }, 927 | { "SetGlobalFontFromFileTTF", w_SetGlobalFontFromFileTTF }, 928 | { "AddFontFromFileTTF", w_AddFontFromFileTTF }, 929 | 930 | // Overrides 931 | { "Value", w_Value }, 932 | { "CollapsingHeader", w_CollapsingHeader }, 933 | { "Combo", w_Combo }, 934 | { "RadioButton", w_RadioButton }, 935 | { "PushID", w_PushID }, 936 | { "GetID", w_GetID }, 937 | { "PushStyleVar", w_PushStyleVar }, 938 | { "PushStyleColor", w_PushStyleColor }, 939 | { "SetWindowPos", w_SetWindowPos }, 940 | { "SetWindowSize", w_SetWindowSize }, 941 | { "SetWindowCollapsed", w_SetWindowCollapsed }, 942 | { "SetWindowFocus", w_SetWindowFocus }, 943 | { "BeginChild", w_BeginChild }, 944 | 945 | // Implementation 946 | { "ShutDown", w_ShutDown }, 947 | { "NewFrame", w_NewFrame }, 948 | { "MouseMoved", w_MouseMoved }, 949 | { "MousePressed", w_MousePressed }, 950 | { "MouseReleased", w_MouseReleased }, 951 | { "WheelMoved", w_WheelMoved }, 952 | { "KeyPressed", w_KeyPressed }, 953 | { "KeyReleased", w_KeyReleased }, 954 | { "TextInput", w_TextInput }, 955 | { "GetWantCaptureKeyboard", w_GetWantCaptureKeyboard }, 956 | { "GetWantCaptureMouse", w_GetWantCaptureMouse }, 957 | { "GetWantTextInput", w_GetWantTextInput }, 958 | 959 | // Return value ordering 960 | { "SetReturnValueLast", w_SetReturnValueLast }, 961 | 962 | { NULL, NULL } 963 | }; 964 | 965 | extern "C" { 966 | void luax_register(lua_State *L, const char *name, const luaL_Reg *l); 967 | } 968 | 969 | #define WRAP_ENUM(L, name, val) \ 970 | lua_pushlstring(L, #name, sizeof(#name)-1); \ 971 | lua_pushnumber(L, val); \ 972 | lua_settable(L, -3); 973 | 974 | extern "C" LOVE_IMGUI_EXPORT int luaopen_imgui(lua_State *L) 975 | { 976 | // Enums not handled by iterator yet 977 | lua_newtable(L); 978 | 979 | // ImGuiWindowFlags, prefer using the ImGuiXXX_ version instead of the short version as it's deprecated and will be removed 980 | WRAP_ENUM(L, NoTitleBar, ImGuiWindowFlags_NoTitleBar); 981 | WRAP_ENUM(L, NoResize, ImGuiWindowFlags_NoResize); 982 | WRAP_ENUM(L, NoMove, ImGuiWindowFlags_NoMove); 983 | WRAP_ENUM(L, NoScrollbar, ImGuiWindowFlags_NoScrollbar); 984 | WRAP_ENUM(L, NoScrollWithMouse, ImGuiWindowFlags_NoScrollWithMouse); 985 | WRAP_ENUM(L, NoCollapse, ImGuiWindowFlags_NoCollapse); 986 | WRAP_ENUM(L, AlwaysAutoResize, ImGuiWindowFlags_AlwaysAutoResize); 987 | WRAP_ENUM(L, NoSavedSettings, ImGuiWindowFlags_NoSavedSettings); 988 | WRAP_ENUM(L, NoInputs, ImGuiWindowFlags_NoInputs); 989 | WRAP_ENUM(L, MenuBar, ImGuiWindowFlags_MenuBar); 990 | WRAP_ENUM(L, HorizontalScrollbar, ImGuiWindowFlags_HorizontalScrollbar); 991 | WRAP_ENUM(L, NoFocusOnAppearing, ImGuiWindowFlags_NoFocusOnAppearing); 992 | WRAP_ENUM(L, NoBringToFrontOnFocus, ImGuiWindowFlags_NoBringToFrontOnFocus); 993 | WRAP_ENUM(L, AlwaysVerticalScrollbar, ImGuiWindowFlags_AlwaysVerticalScrollbar); 994 | WRAP_ENUM(L, AlwaysHorizontalScrollbar, ImGuiWindowFlags_AlwaysHorizontalScrollbar); 995 | WRAP_ENUM(L, AlwaysUseWindowPadding, ImGuiWindowFlags_AlwaysUseWindowPadding); 996 | WRAP_ENUM(L, ResizeFromAnySide, ImGuiWindowFlags_ResizeFromAnySide); 997 | 998 | WRAP_ENUM(L, ImGuiWindowFlags_NoTitleBar, ImGuiWindowFlags_NoTitleBar); 999 | WRAP_ENUM(L, ImGuiWindowFlags_NoResize, ImGuiWindowFlags_NoResize); 1000 | WRAP_ENUM(L, ImGuiWindowFlags_NoMove, ImGuiWindowFlags_NoMove); 1001 | WRAP_ENUM(L, ImGuiWindowFlags_NoScrollbar, ImGuiWindowFlags_NoScrollbar); 1002 | WRAP_ENUM(L, ImGuiWindowFlags_NoScrollWithMouse, ImGuiWindowFlags_NoScrollWithMouse); 1003 | WRAP_ENUM(L, ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoCollapse); 1004 | WRAP_ENUM(L, ImGuiWindowFlags_AlwaysAutoResize, ImGuiWindowFlags_AlwaysAutoResize); 1005 | WRAP_ENUM(L, ImGuiWindowFlags_NoSavedSettings, ImGuiWindowFlags_NoSavedSettings); 1006 | WRAP_ENUM(L, ImGuiWindowFlags_NoInputs, ImGuiWindowFlags_NoInputs); 1007 | WRAP_ENUM(L, ImGuiWindowFlags_MenuBar, ImGuiWindowFlags_MenuBar); 1008 | WRAP_ENUM(L, ImGuiWindowFlags_HorizontalScrollbar, ImGuiWindowFlags_HorizontalScrollbar); 1009 | WRAP_ENUM(L, ImGuiWindowFlags_NoFocusOnAppearing, ImGuiWindowFlags_NoFocusOnAppearing); 1010 | WRAP_ENUM(L, ImGuiWindowFlags_NoBringToFrontOnFocus, ImGuiWindowFlags_NoBringToFrontOnFocus); 1011 | WRAP_ENUM(L, ImGuiWindowFlags_AlwaysVerticalScrollbar, ImGuiWindowFlags_AlwaysVerticalScrollbar); 1012 | WRAP_ENUM(L, ImGuiWindowFlags_AlwaysHorizontalScrollbar, ImGuiWindowFlags_AlwaysHorizontalScrollbar); 1013 | WRAP_ENUM(L, ImGuiWindowFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_AlwaysUseWindowPadding); 1014 | WRAP_ENUM(L, ImGuiWindowFlags_ResizeFromAnySide, ImGuiWindowFlags_ResizeFromAnySide); 1015 | 1016 | // ImGuiInputTextFlags 1017 | WRAP_ENUM(L, CharsDecimal, ImGuiInputTextFlags_CharsDecimal); 1018 | WRAP_ENUM(L, CharsHexadecimal, ImGuiInputTextFlags_CharsHexadecimal); 1019 | WRAP_ENUM(L, CharsUppercase, ImGuiInputTextFlags_CharsUppercase); 1020 | WRAP_ENUM(L, CharsNoBlank, ImGuiInputTextFlags_CharsNoBlank); 1021 | WRAP_ENUM(L, AutoSelectAll, ImGuiInputTextFlags_AutoSelectAll); 1022 | WRAP_ENUM(L, EnterReturnsTrue, ImGuiInputTextFlags_EnterReturnsTrue); 1023 | WRAP_ENUM(L, CallbackCompletion, ImGuiInputTextFlags_CallbackCompletion); 1024 | WRAP_ENUM(L, CallbackHistory, ImGuiInputTextFlags_CallbackHistory); 1025 | WRAP_ENUM(L, CallbackAlways, ImGuiInputTextFlags_CallbackAlways); 1026 | WRAP_ENUM(L, CallbackCharFilter, ImGuiInputTextFlags_CallbackCharFilter); 1027 | WRAP_ENUM(L, AllowTabInput, ImGuiInputTextFlags_AllowTabInput); 1028 | WRAP_ENUM(L, CtrlEnterForNewLine, ImGuiInputTextFlags_CtrlEnterForNewLine); 1029 | WRAP_ENUM(L, NoHorizontalScroll, ImGuiInputTextFlags_NoHorizontalScroll); 1030 | WRAP_ENUM(L, AlwaysInsertMode, ImGuiInputTextFlags_AlwaysInsertMode); 1031 | WRAP_ENUM(L, ReadOnly, ImGuiInputTextFlags_ReadOnly); 1032 | WRAP_ENUM(L, Password, ImGuiInputTextFlags_Password); 1033 | WRAP_ENUM(L, NoUndoRedo, ImGuiInputTextFlags_NoUndoRedo); 1034 | 1035 | WRAP_ENUM(L, ImGuiInputTextFlags_CharsDecimal, ImGuiInputTextFlags_CharsDecimal); 1036 | WRAP_ENUM(L, ImGuiInputTextFlags_CharsHexadecimal, ImGuiInputTextFlags_CharsHexadecimal); 1037 | WRAP_ENUM(L, ImGuiInputTextFlags_CharsUppercase, ImGuiInputTextFlags_CharsUppercase); 1038 | WRAP_ENUM(L, ImGuiInputTextFlags_CharsNoBlank, ImGuiInputTextFlags_CharsNoBlank); 1039 | WRAP_ENUM(L, ImGuiInputTextFlags_AutoSelectAll, ImGuiInputTextFlags_AutoSelectAll); 1040 | WRAP_ENUM(L, ImGuiInputTextFlags_EnterReturnsTrue, ImGuiInputTextFlags_EnterReturnsTrue); 1041 | WRAP_ENUM(L, ImGuiInputTextFlags_CallbackCompletion, ImGuiInputTextFlags_CallbackCompletion); 1042 | WRAP_ENUM(L, ImGuiInputTextFlags_CallbackHistory, ImGuiInputTextFlags_CallbackHistory); 1043 | WRAP_ENUM(L, ImGuiInputTextFlags_CallbackAlways, ImGuiInputTextFlags_CallbackAlways); 1044 | WRAP_ENUM(L, ImGuiInputTextFlags_CallbackCharFilter, ImGuiInputTextFlags_CallbackCharFilter); 1045 | WRAP_ENUM(L, ImGuiInputTextFlags_AllowTabInput, ImGuiInputTextFlags_AllowTabInput); 1046 | WRAP_ENUM(L, ImGuiInputTextFlags_CtrlEnterForNewLine, ImGuiInputTextFlags_CtrlEnterForNewLine); 1047 | WRAP_ENUM(L, ImGuiInputTextFlags_NoHorizontalScroll, ImGuiInputTextFlags_NoHorizontalScroll); 1048 | WRAP_ENUM(L, ImGuiInputTextFlags_AlwaysInsertMode, ImGuiInputTextFlags_AlwaysInsertMode); 1049 | WRAP_ENUM(L, ImGuiInputTextFlags_ReadOnly, ImGuiInputTextFlags_ReadOnly); 1050 | WRAP_ENUM(L, ImGuiInputTextFlags_Password, ImGuiInputTextFlags_Password); 1051 | WRAP_ENUM(L, ImGuiInputTextFlags_NoUndoRedo, ImGuiInputTextFlags_NoUndoRedo); 1052 | 1053 | // ImGuiTreeNodeFlags 1054 | WRAP_ENUM(L, Selected, ImGuiTreeNodeFlags_Selected); 1055 | WRAP_ENUM(L, Framed, ImGuiTreeNodeFlags_Framed); 1056 | WRAP_ENUM(L, AllowItemOverlap, ImGuiTreeNodeFlags_AllowItemOverlap); 1057 | WRAP_ENUM(L, NoTreePushOnOpen, ImGuiTreeNodeFlags_NoTreePushOnOpen); 1058 | WRAP_ENUM(L, NoAutoOpenOnLog, ImGuiTreeNodeFlags_NoAutoOpenOnLog); 1059 | WRAP_ENUM(L, DefaultOpen, ImGuiTreeNodeFlags_DefaultOpen); 1060 | WRAP_ENUM(L, OpenOnDoubleClick, ImGuiTreeNodeFlags_OpenOnDoubleClick); 1061 | WRAP_ENUM(L, OpenOnArrow, ImGuiTreeNodeFlags_OpenOnArrow); 1062 | WRAP_ENUM(L, Leaf, ImGuiTreeNodeFlags_Leaf); 1063 | WRAP_ENUM(L, Bullet, ImGuiTreeNodeFlags_Bullet); 1064 | WRAP_ENUM(L, FramePadding, ImGuiTreeNodeFlags_FramePadding); 1065 | WRAP_ENUM(L, CollapsingHeader, ImGuiTreeNodeFlags_CollapsingHeader); 1066 | 1067 | WRAP_ENUM(L, ImGuiTreeNodeFlags_Selected, ImGuiTreeNodeFlags_Selected); 1068 | WRAP_ENUM(L, ImGuiTreeNodeFlags_Framed, ImGuiTreeNodeFlags_Framed); 1069 | WRAP_ENUM(L, ImGuiTreeNodeFlags_AllowItemOverlap, ImGuiTreeNodeFlags_AllowItemOverlap); 1070 | WRAP_ENUM(L, ImGuiTreeNodeFlags_NoTreePushOnOpen, ImGuiTreeNodeFlags_NoTreePushOnOpen); 1071 | WRAP_ENUM(L, ImGuiTreeNodeFlags_NoAutoOpenOnLog, ImGuiTreeNodeFlags_NoAutoOpenOnLog); 1072 | WRAP_ENUM(L, ImGuiTreeNodeFlags_DefaultOpen, ImGuiTreeNodeFlags_DefaultOpen); 1073 | WRAP_ENUM(L, ImGuiTreeNodeFlags_OpenOnDoubleClick, ImGuiTreeNodeFlags_OpenOnDoubleClick); 1074 | WRAP_ENUM(L, ImGuiTreeNodeFlags_OpenOnArrow, ImGuiTreeNodeFlags_OpenOnArrow); 1075 | WRAP_ENUM(L, ImGuiTreeNodeFlags_Leaf, ImGuiTreeNodeFlags_Leaf); 1076 | WRAP_ENUM(L, ImGuiTreeNodeFlags_Bullet, ImGuiTreeNodeFlags_Bullet); 1077 | WRAP_ENUM(L, ImGuiTreeNodeFlags_FramePadding, ImGuiTreeNodeFlags_FramePadding); 1078 | WRAP_ENUM(L, ImGuiTreeNodeFlags_CollapsingHeader, ImGuiTreeNodeFlags_CollapsingHeader); 1079 | 1080 | // ImGuiSelectableFlags 1081 | WRAP_ENUM(L, DontClosePopups, ImGuiSelectableFlags_DontClosePopups); 1082 | WRAP_ENUM(L, SpanAllColumns, ImGuiSelectableFlags_SpanAllColumns); 1083 | WRAP_ENUM(L, AllowDoubleClick, ImGuiSelectableFlags_AllowDoubleClick); 1084 | 1085 | WRAP_ENUM(L, ImGuiSelectableFlags_DontClosePopups, ImGuiSelectableFlags_DontClosePopups); 1086 | WRAP_ENUM(L, ImGuiSelectableFlags_SpanAllColumns, ImGuiSelectableFlags_SpanAllColumns); 1087 | WRAP_ENUM(L, ImGuiSelectableFlags_AllowDoubleClick, ImGuiSelectableFlags_AllowDoubleClick); 1088 | 1089 | // ImGuiComboFlags 1090 | WRAP_ENUM(L, PopupAlignLeft, ImGuiComboFlags_PopupAlignLeft); 1091 | WRAP_ENUM(L, HeightSmall, ImGuiComboFlags_HeightSmall); 1092 | WRAP_ENUM(L, HeightRegular, ImGuiComboFlags_HeightRegular); 1093 | WRAP_ENUM(L, HeightLarge, ImGuiComboFlags_HeightLarge); 1094 | WRAP_ENUM(L, HeightLargest, ImGuiComboFlags_HeightLargest); 1095 | WRAP_ENUM(L, HeightMask_, ImGuiComboFlags_HeightMask_); 1096 | 1097 | WRAP_ENUM(L, ImGuiComboFlags_PopupAlignLeft, ImGuiComboFlags_PopupAlignLeft); 1098 | WRAP_ENUM(L, ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightSmall); 1099 | WRAP_ENUM(L, ImGuiComboFlags_HeightRegular, ImGuiComboFlags_HeightRegular); 1100 | WRAP_ENUM(L, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLarge); 1101 | WRAP_ENUM(L, ImGuiComboFlags_HeightLargest, ImGuiComboFlags_HeightLargest); 1102 | WRAP_ENUM(L, ImGuiComboFlags_HeightMask_, ImGuiComboFlags_HeightMask_); 1103 | 1104 | // ImGuiFocusedFlags 1105 | WRAP_ENUM(L, ImGuiFocusedFlags_ChildWindows, ImGuiFocusedFlags_ChildWindows); 1106 | WRAP_ENUM(L, ImGuiFocusedFlags_RootWindow, ImGuiFocusedFlags_RootWindow); 1107 | WRAP_ENUM(L, ImGuiFocusedFlags_RootAndChildWindows, ImGuiFocusedFlags_RootAndChildWindows); 1108 | 1109 | // ImGuiHoveredFlags 1110 | WRAP_ENUM(L, ImGuiHoveredFlags_Default, ImGuiHoveredFlags_Default); 1111 | WRAP_ENUM(L, ImGuiHoveredFlags_ChildWindows, ImGuiHoveredFlags_ChildWindows); 1112 | WRAP_ENUM(L, ImGuiHoveredFlags_RootWindow, ImGuiHoveredFlags_RootWindow); 1113 | WRAP_ENUM(L, ImGuiHoveredFlags_AllowWhenBlockedByPopup, ImGuiHoveredFlags_AllowWhenBlockedByPopup); 1114 | WRAP_ENUM(L, ImGuiHoveredFlags_AllowWhenBlockedByActiveItem, ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); 1115 | WRAP_ENUM(L, ImGuiHoveredFlags_AllowWhenOverlapped, ImGuiHoveredFlags_AllowWhenOverlapped); 1116 | WRAP_ENUM(L, ImGuiHoveredFlags_RectOnly, ImGuiHoveredFlags_RectOnly); 1117 | WRAP_ENUM(L, ImGuiHoveredFlags_RootAndChildWindows, ImGuiHoveredFlags_RootAndChildWindows); 1118 | 1119 | // ImGuiDragDropFlags_ 1120 | WRAP_ENUM(L, SourceNoPreviewTooltip, ImGuiDragDropFlags_SourceNoPreviewTooltip); 1121 | WRAP_ENUM(L, SourceNoDisableHover, ImGuiDragDropFlags_SourceNoDisableHover); 1122 | WRAP_ENUM(L, SourceNoHoldToOpenOthers, ImGuiDragDropFlags_SourceNoHoldToOpenOthers); 1123 | WRAP_ENUM(L, SourceAllowNullID, ImGuiDragDropFlags_SourceAllowNullID); 1124 | WRAP_ENUM(L, SourceExtern, ImGuiDragDropFlags_SourceExtern); 1125 | WRAP_ENUM(L, AcceptBeforeDelivery, ImGuiDragDropFlags_AcceptBeforeDelivery); 1126 | WRAP_ENUM(L, AcceptNoDrawDefaultRect, ImGuiDragDropFlags_AcceptNoDrawDefaultRect); 1127 | WRAP_ENUM(L, AcceptPeekOnly, ImGuiDragDropFlags_AcceptPeekOnly); 1128 | 1129 | WRAP_ENUM(L, ImGuiDragDropFlags_SourceNoPreviewTooltip, ImGuiDragDropFlags_SourceNoPreviewTooltip); 1130 | WRAP_ENUM(L, ImGuiDragDropFlags_SourceNoDisableHover, ImGuiDragDropFlags_SourceNoDisableHover); 1131 | WRAP_ENUM(L, ImGuiDragDropFlags_SourceNoHoldToOpenOthers, ImGuiDragDropFlags_SourceNoHoldToOpenOthers); 1132 | WRAP_ENUM(L, ImGuiDragDropFlags_SourceAllowNullID, ImGuiDragDropFlags_SourceAllowNullID); 1133 | WRAP_ENUM(L, ImGuiDragDropFlags_SourceExtern, ImGuiDragDropFlags_SourceExtern); 1134 | WRAP_ENUM(L, ImGuiDragDropFlags_AcceptBeforeDelivery, ImGuiDragDropFlags_AcceptBeforeDelivery); 1135 | WRAP_ENUM(L, ImGuiDragDropFlags_AcceptNoDrawDefaultRect, ImGuiDragDropFlags_AcceptNoDrawDefaultRect); 1136 | WRAP_ENUM(L, ImGuiDragDropFlags_AcceptPeekOnly, ImGuiDragDropFlags_AcceptPeekOnly); 1137 | 1138 | // ImGuiCol 1139 | WRAP_ENUM(L, Text, ImGuiCol_Text); 1140 | WRAP_ENUM(L, TextDisabled, ImGuiCol_TextDisabled); 1141 | WRAP_ENUM(L, WindowBg, ImGuiCol_WindowBg); 1142 | WRAP_ENUM(L, ChildBg, ImGuiCol_ChildBg); 1143 | WRAP_ENUM(L, PopupBg, ImGuiCol_PopupBg); 1144 | WRAP_ENUM(L, Border, ImGuiCol_Border); 1145 | WRAP_ENUM(L, BorderShadow, ImGuiCol_BorderShadow); 1146 | WRAP_ENUM(L, FrameBg, ImGuiCol_FrameBg); 1147 | WRAP_ENUM(L, FrameBgHovered, ImGuiCol_FrameBgHovered); 1148 | WRAP_ENUM(L, FrameBgActive, ImGuiCol_FrameBgActive); 1149 | WRAP_ENUM(L, TitleBg, ImGuiCol_TitleBg); 1150 | WRAP_ENUM(L, TitleBgActive, ImGuiCol_TitleBgActive); 1151 | WRAP_ENUM(L, TitleBgCollapsed, ImGuiCol_TitleBgCollapsed); 1152 | WRAP_ENUM(L, MenuBarBg, ImGuiCol_MenuBarBg); 1153 | WRAP_ENUM(L, ScrollbarBg, ImGuiCol_ScrollbarBg); 1154 | WRAP_ENUM(L, ScrollbarGrab, ImGuiCol_ScrollbarGrab); 1155 | WRAP_ENUM(L, ScrollbarGrabHovered, ImGuiCol_ScrollbarGrabHovered); 1156 | WRAP_ENUM(L, ScrollbarGrabActive, ImGuiCol_ScrollbarGrabActive); 1157 | WRAP_ENUM(L, CheckMark, ImGuiCol_CheckMark); 1158 | WRAP_ENUM(L, SliderGrab, ImGuiCol_SliderGrab); 1159 | WRAP_ENUM(L, SliderGrabActive, ImGuiCol_SliderGrabActive); 1160 | WRAP_ENUM(L, Button, ImGuiCol_Button); 1161 | WRAP_ENUM(L, ButtonHovered, ImGuiCol_ButtonHovered); 1162 | WRAP_ENUM(L, ButtonActive, ImGuiCol_ButtonActive); 1163 | WRAP_ENUM(L, Header, ImGuiCol_Header); 1164 | WRAP_ENUM(L, HeaderHovered, ImGuiCol_HeaderHovered); 1165 | WRAP_ENUM(L, HeaderActive, ImGuiCol_HeaderActive); 1166 | WRAP_ENUM(L, Separator, ImGuiCol_Separator); 1167 | WRAP_ENUM(L, SeparatorHovered, ImGuiCol_SeparatorHovered); 1168 | WRAP_ENUM(L, SeparatorActive, ImGuiCol_SeparatorActive); 1169 | WRAP_ENUM(L, ResizeGrip, ImGuiCol_ResizeGrip); 1170 | WRAP_ENUM(L, ResizeGripHovered, ImGuiCol_ResizeGripHovered); 1171 | WRAP_ENUM(L, ResizeGripActive, ImGuiCol_ResizeGripActive); 1172 | WRAP_ENUM(L, CloseButton, ImGuiCol_CloseButton); 1173 | WRAP_ENUM(L, CloseButtonHovered, ImGuiCol_CloseButtonHovered); 1174 | WRAP_ENUM(L, CloseButtonActive, ImGuiCol_CloseButtonActive); 1175 | WRAP_ENUM(L, PlotLines, ImGuiCol_PlotLines); 1176 | WRAP_ENUM(L, PlotLinesHovered, ImGuiCol_PlotLinesHovered); 1177 | WRAP_ENUM(L, PlotHistogram, ImGuiCol_PlotHistogram); 1178 | WRAP_ENUM(L, PlotHistogramHovered, ImGuiCol_PlotHistogramHovered); 1179 | WRAP_ENUM(L, TextSelectedBg, ImGuiCol_TextSelectedBg); 1180 | WRAP_ENUM(L, ModalWindowDarkening, ImGuiCol_ModalWindowDarkening); 1181 | WRAP_ENUM(L, DragDropTarget, ImGuiCol_DragDropTarget); 1182 | 1183 | WRAP_ENUM(L, ImGuiCol_Text, ImGuiCol_Text); 1184 | WRAP_ENUM(L, ImGuiCol_TextDisabled, ImGuiCol_TextDisabled); 1185 | WRAP_ENUM(L, ImGuiCol_WindowBg, ImGuiCol_WindowBg); 1186 | WRAP_ENUM(L, ImGuiCol_ChildBg, ImGuiCol_ChildBg); 1187 | WRAP_ENUM(L, ImGuiCol_PopupBg, ImGuiCol_PopupBg); 1188 | WRAP_ENUM(L, ImGuiCol_Border, ImGuiCol_Border); 1189 | WRAP_ENUM(L, ImGuiCol_BorderShadow, ImGuiCol_BorderShadow); 1190 | WRAP_ENUM(L, ImGuiCol_FrameBg, ImGuiCol_FrameBg); 1191 | WRAP_ENUM(L, ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgHovered); 1192 | WRAP_ENUM(L, ImGuiCol_FrameBgActive, ImGuiCol_FrameBgActive); 1193 | WRAP_ENUM(L, ImGuiCol_TitleBg, ImGuiCol_TitleBg); 1194 | WRAP_ENUM(L, ImGuiCol_TitleBgActive, ImGuiCol_TitleBgActive); 1195 | WRAP_ENUM(L, ImGuiCol_TitleBgCollapsed, ImGuiCol_TitleBgCollapsed); 1196 | WRAP_ENUM(L, ImGuiCol_MenuBarBg, ImGuiCol_MenuBarBg); 1197 | WRAP_ENUM(L, ImGuiCol_ScrollbarBg, ImGuiCol_ScrollbarBg); 1198 | WRAP_ENUM(L, ImGuiCol_ScrollbarGrab, ImGuiCol_ScrollbarGrab); 1199 | WRAP_ENUM(L, ImGuiCol_ScrollbarGrabHovered, ImGuiCol_ScrollbarGrabHovered); 1200 | WRAP_ENUM(L, ImGuiCol_ScrollbarGrabActive, ImGuiCol_ScrollbarGrabActive); 1201 | WRAP_ENUM(L, ImGuiCol_CheckMark, ImGuiCol_CheckMark); 1202 | WRAP_ENUM(L, ImGuiCol_SliderGrab, ImGuiCol_SliderGrab); 1203 | WRAP_ENUM(L, ImGuiCol_SliderGrabActive, ImGuiCol_SliderGrabActive); 1204 | WRAP_ENUM(L, ImGuiCol_Button, ImGuiCol_Button); 1205 | WRAP_ENUM(L, ImGuiCol_ButtonHovered, ImGuiCol_ButtonHovered); 1206 | WRAP_ENUM(L, ImGuiCol_ButtonActive, ImGuiCol_ButtonActive); 1207 | WRAP_ENUM(L, ImGuiCol_Header, ImGuiCol_Header); 1208 | WRAP_ENUM(L, ImGuiCol_HeaderHovered, ImGuiCol_HeaderHovered); 1209 | WRAP_ENUM(L, ImGuiCol_HeaderActive, ImGuiCol_HeaderActive); 1210 | WRAP_ENUM(L, ImGuiCol_Separator, ImGuiCol_Separator); 1211 | WRAP_ENUM(L, ImGuiCol_SeparatorHovered, ImGuiCol_SeparatorHovered); 1212 | WRAP_ENUM(L, ImGuiCol_SeparatorActive, ImGuiCol_SeparatorActive); 1213 | WRAP_ENUM(L, ImGuiCol_ResizeGrip, ImGuiCol_ResizeGrip); 1214 | WRAP_ENUM(L, ImGuiCol_ResizeGripHovered, ImGuiCol_ResizeGripHovered); 1215 | WRAP_ENUM(L, ImGuiCol_ResizeGripActive, ImGuiCol_ResizeGripActive); 1216 | WRAP_ENUM(L, ImGuiCol_CloseButton, ImGuiCol_CloseButton); 1217 | WRAP_ENUM(L, ImGuiCol_CloseButtonHovered, ImGuiCol_CloseButtonHovered); 1218 | WRAP_ENUM(L, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonActive); 1219 | WRAP_ENUM(L, ImGuiCol_PlotLines, ImGuiCol_PlotLines); 1220 | WRAP_ENUM(L, ImGuiCol_PlotLinesHovered, ImGuiCol_PlotLinesHovered); 1221 | WRAP_ENUM(L, ImGuiCol_PlotHistogram, ImGuiCol_PlotHistogram); 1222 | WRAP_ENUM(L, ImGuiCol_PlotHistogramHovered, ImGuiCol_PlotHistogramHovered); 1223 | WRAP_ENUM(L, ImGuiCol_TextSelectedBg, ImGuiCol_TextSelectedBg); 1224 | WRAP_ENUM(L, ImGuiCol_ModalWindowDarkening, ImGuiCol_ModalWindowDarkening); 1225 | WRAP_ENUM(L, ImGuiCol_DragDropTarget, ImGuiCol_DragDropTarget); 1226 | 1227 | // ImGuiStyleVar 1228 | WRAP_ENUM(L, Alpha, ImGuiStyleVar_Alpha); 1229 | WRAP_ENUM(L, WindowPadding, ImGuiStyleVar_WindowPadding); 1230 | WRAP_ENUM(L, WindowRounding, ImGuiStyleVar_WindowRounding); 1231 | WRAP_ENUM(L, WindowBorderSize, ImGuiStyleVar_WindowBorderSize); 1232 | WRAP_ENUM(L, WindowMinSize, ImGuiStyleVar_WindowMinSize); 1233 | WRAP_ENUM(L, ChildRounding, ImGuiStyleVar_ChildRounding); 1234 | WRAP_ENUM(L, ChildBorderSize, ImGuiStyleVar_ChildBorderSize); 1235 | WRAP_ENUM(L, PopupRounding, ImGuiStyleVar_PopupRounding); 1236 | WRAP_ENUM(L, PopupBorderSize, ImGuiStyleVar_PopupBorderSize); 1237 | WRAP_ENUM(L, FramePadding, ImGuiStyleVar_FramePadding); 1238 | WRAP_ENUM(L, FrameRounding, ImGuiStyleVar_FrameRounding); 1239 | WRAP_ENUM(L, FrameBorderSize, ImGuiStyleVar_FrameBorderSize); 1240 | WRAP_ENUM(L, ItemSpacing, ImGuiStyleVar_ItemSpacing); 1241 | WRAP_ENUM(L, ItemInnerSpacing, ImGuiStyleVar_ItemInnerSpacing); 1242 | WRAP_ENUM(L, IndentSpacing, ImGuiStyleVar_IndentSpacing); 1243 | WRAP_ENUM(L, GrabMinSize, ImGuiStyleVar_GrabMinSize); 1244 | WRAP_ENUM(L, ButtonTextAlign, ImGuiStyleVar_ButtonTextAlign); 1245 | 1246 | WRAP_ENUM(L, ImGuiStyleVar_Alpha, ImGuiStyleVar_Alpha); 1247 | WRAP_ENUM(L, ImGuiStyleVar_WindowPadding, ImGuiStyleVar_WindowPadding); 1248 | WRAP_ENUM(L, ImGuiStyleVar_WindowRounding, ImGuiStyleVar_WindowRounding); 1249 | WRAP_ENUM(L, ImGuiStyleVar_WindowBorderSize, ImGuiStyleVar_WindowBorderSize); 1250 | WRAP_ENUM(L, ImGuiStyleVar_WindowMinSize, ImGuiStyleVar_WindowMinSize); 1251 | WRAP_ENUM(L, ImGuiStyleVar_ChildRounding, ImGuiStyleVar_ChildRounding); 1252 | WRAP_ENUM(L, ImGuiStyleVar_ChildBorderSize, ImGuiStyleVar_ChildBorderSize); 1253 | WRAP_ENUM(L, ImGuiStyleVar_PopupRounding, ImGuiStyleVar_PopupRounding); 1254 | WRAP_ENUM(L, ImGuiStyleVar_PopupBorderSize, ImGuiStyleVar_PopupBorderSize); 1255 | WRAP_ENUM(L, ImGuiStyleVar_FramePadding, ImGuiStyleVar_FramePadding); 1256 | WRAP_ENUM(L, ImGuiStyleVar_FrameRounding, ImGuiStyleVar_FrameRounding); 1257 | WRAP_ENUM(L, ImGuiStyleVar_FrameBorderSize, ImGuiStyleVar_FrameBorderSize); 1258 | WRAP_ENUM(L, ImGuiStyleVar_ItemSpacing, ImGuiStyleVar_ItemSpacing); 1259 | WRAP_ENUM(L, ImGuiStyleVar_ItemInnerSpacing, ImGuiStyleVar_ItemInnerSpacing); 1260 | WRAP_ENUM(L, ImGuiStyleVar_IndentSpacing, ImGuiStyleVar_IndentSpacing); 1261 | WRAP_ENUM(L, ImGuiStyleVar_GrabMinSize, ImGuiStyleVar_GrabMinSize); 1262 | WRAP_ENUM(L, ImGuiStyleVar_ButtonTextAlign, ImGuiStyleVar_ButtonTextAlign); 1263 | 1264 | // ImGuiColorEditFlags 1265 | WRAP_ENUM(L, NoAlpha, ImGuiColorEditFlags_NoAlpha); 1266 | WRAP_ENUM(L, NoPicker, ImGuiColorEditFlags_NoPicker); 1267 | WRAP_ENUM(L, NoOptions, ImGuiColorEditFlags_NoOptions); 1268 | WRAP_ENUM(L, NoSmallPreview, ImGuiColorEditFlags_NoSmallPreview); 1269 | WRAP_ENUM(L, NoInputs, ImGuiColorEditFlags_NoInputs); 1270 | WRAP_ENUM(L, NoTooltip, ImGuiColorEditFlags_NoTooltip); 1271 | WRAP_ENUM(L, NoLabel, ImGuiColorEditFlags_NoLabel); 1272 | WRAP_ENUM(L, NoSidePreview, ImGuiColorEditFlags_NoSidePreview); 1273 | WRAP_ENUM(L, AlphaBar, ImGuiColorEditFlags_AlphaBar); 1274 | WRAP_ENUM(L, AlphaPreview, ImGuiColorEditFlags_AlphaPreview); 1275 | WRAP_ENUM(L, AlphaPreviewHalf, ImGuiColorEditFlags_AlphaPreviewHalf); 1276 | WRAP_ENUM(L, HDR, ImGuiColorEditFlags_HDR); 1277 | WRAP_ENUM(L, RGB, ImGuiColorEditFlags_RGB); 1278 | WRAP_ENUM(L, HSV, ImGuiColorEditFlags_HSV); 1279 | WRAP_ENUM(L, HEX, ImGuiColorEditFlags_HEX); 1280 | WRAP_ENUM(L, Uint8, ImGuiColorEditFlags_Uint8); 1281 | WRAP_ENUM(L, Float, ImGuiColorEditFlags_Float); 1282 | WRAP_ENUM(L, PickerHueBar, ImGuiColorEditFlags_PickerHueBar); 1283 | WRAP_ENUM(L, PickerHueWheel, ImGuiColorEditFlags_PickerHueWheel); 1284 | 1285 | WRAP_ENUM(L, ImGuiColorEditFlags_NoAlpha, ImGuiColorEditFlags_NoAlpha); 1286 | WRAP_ENUM(L, ImGuiColorEditFlags_NoPicker, ImGuiColorEditFlags_NoPicker); 1287 | WRAP_ENUM(L, ImGuiColorEditFlags_NoOptions, ImGuiColorEditFlags_NoOptions); 1288 | WRAP_ENUM(L, ImGuiColorEditFlags_NoSmallPreview, ImGuiColorEditFlags_NoSmallPreview); 1289 | WRAP_ENUM(L, ImGuiColorEditFlags_NoInputs, ImGuiColorEditFlags_NoInputs); 1290 | WRAP_ENUM(L, ImGuiColorEditFlags_NoTooltip, ImGuiColorEditFlags_NoTooltip); 1291 | WRAP_ENUM(L, ImGuiColorEditFlags_NoLabel, ImGuiColorEditFlags_NoLabel); 1292 | WRAP_ENUM(L, ImGuiColorEditFlags_NoSidePreview, ImGuiColorEditFlags_NoSidePreview); 1293 | WRAP_ENUM(L, ImGuiColorEditFlags_AlphaBar, ImGuiColorEditFlags_AlphaBar); 1294 | WRAP_ENUM(L, ImGuiColorEditFlags_AlphaPreview, ImGuiColorEditFlags_AlphaPreview); 1295 | WRAP_ENUM(L, ImGuiColorEditFlags_AlphaPreviewHalf, ImGuiColorEditFlags_AlphaPreviewHalf); 1296 | WRAP_ENUM(L, ImGuiColorEditFlags_HDR, ImGuiColorEditFlags_HDR); 1297 | WRAP_ENUM(L, ImGuiColorEditFlags_RGB, ImGuiColorEditFlags_RGB); 1298 | WRAP_ENUM(L, ImGuiColorEditFlags_HSV, ImGuiColorEditFlags_HSV); 1299 | WRAP_ENUM(L, ImGuiColorEditFlags_HEX, ImGuiColorEditFlags_HEX); 1300 | WRAP_ENUM(L, ImGuiColorEditFlags_Uint8, ImGuiColorEditFlags_Uint8); 1301 | WRAP_ENUM(L, ImGuiColorEditFlags_Float, ImGuiColorEditFlags_Float); 1302 | WRAP_ENUM(L, ImGuiColorEditFlags_PickerHueBar, ImGuiColorEditFlags_PickerHueBar); 1303 | WRAP_ENUM(L, ImGuiColorEditFlags_PickerHueWheel, ImGuiColorEditFlags_PickerHueWheel); 1304 | 1305 | // ImGuiMouseCursor 1306 | WRAP_ENUM(L, None, ImGuiMouseCursor_None); 1307 | WRAP_ENUM(L, Arrow, ImGuiMouseCursor_Arrow); 1308 | WRAP_ENUM(L, TextInput, ImGuiMouseCursor_TextInput); 1309 | WRAP_ENUM(L, Move, ImGuiMouseCursor_Move); 1310 | WRAP_ENUM(L, ResizeNS, ImGuiMouseCursor_ResizeNS); 1311 | WRAP_ENUM(L, ResizeEW, ImGuiMouseCursor_ResizeEW); 1312 | WRAP_ENUM(L, ResizeNESW, ImGuiMouseCursor_ResizeNESW); 1313 | WRAP_ENUM(L, ResizeNWSE, ImGuiMouseCursor_ResizeNWSE); 1314 | 1315 | WRAP_ENUM(L, ImGuiMouseCursor_None, ImGuiMouseCursor_None); 1316 | WRAP_ENUM(L, ImGuiMouseCursor_Arrow, ImGuiMouseCursor_Arrow); 1317 | WRAP_ENUM(L, ImGuiMouseCursor_TextInput, ImGuiMouseCursor_TextInput); 1318 | WRAP_ENUM(L, ImGuiMouseCursor_Move, ImGuiMouseCursor_Move); 1319 | WRAP_ENUM(L, ImGuiMouseCursor_ResizeNS, ImGuiMouseCursor_ResizeNS); 1320 | WRAP_ENUM(L, ImGuiMouseCursor_ResizeEW, ImGuiMouseCursor_ResizeEW); 1321 | WRAP_ENUM(L, ImGuiMouseCursor_ResizeNESW, ImGuiMouseCursor_ResizeNESW); 1322 | WRAP_ENUM(L, ImGuiMouseCursor_ResizeNWSE, ImGuiMouseCursor_ResizeNWSE); 1323 | 1324 | // ImGuiCond 1325 | WRAP_ENUM(L, Always, ImGuiCond_Always); 1326 | WRAP_ENUM(L, Once, ImGuiCond_Once); 1327 | WRAP_ENUM(L, FirstUseEver, ImGuiCond_FirstUseEver); 1328 | WRAP_ENUM(L, Appearing, ImGuiCond_Appearing); 1329 | 1330 | WRAP_ENUM(L, ImGuiCond_Always, ImGuiCond_Always); 1331 | WRAP_ENUM(L, ImGuiCond_Once, ImGuiCond_Once); 1332 | WRAP_ENUM(L, ImGuiCond_FirstUseEver, ImGuiCond_FirstUseEver); 1333 | WRAP_ENUM(L, ImGuiCond_Appearing, ImGuiCond_Appearing); 1334 | 1335 | // Docks 1336 | WRAP_ENUM(L, ImGuiDockSlot_Left, ImGuiDockSlot_Left); 1337 | WRAP_ENUM(L, ImGuiDockSlot_Right, ImGuiDockSlot_Right); 1338 | WRAP_ENUM(L, ImGuiDockSlot_Top, ImGuiDockSlot_Top); 1339 | WRAP_ENUM(L, ImGuiDockSlot_Bottom, ImGuiDockSlot_Bottom); 1340 | WRAP_ENUM(L, ImGuiDockSlot_Tab, ImGuiDockSlot_Tab); 1341 | WRAP_ENUM(L, ImGuiDockSlot_Float, ImGuiDockSlot_Float); 1342 | WRAP_ENUM(L, ImGuiDockSlot_None, ImGuiDockSlot_None); 1343 | 1344 | luaL_openlib(L, "imgui", imguilib, 1); 1345 | return 1; 1346 | } 1347 | -------------------------------------------------------------------------------- /src/wrap_imgui_impl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2006-2016 LOVE Development Team 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any damages 6 | * arising from the use of this software. 7 | * 8 | * Permission is granted to anyone to use this software for any purpose, 9 | * including commercial applications, and to alter it and redistribute it 10 | * freely, subject to the following restrictions: 11 | * 12 | * 1. The origin of this software must not be misrepresented; you must not 13 | * claim that you wrote the original software. If you use this software 14 | * in a product, an acknowledgment in the product documentation would be 15 | * appreciated but is not required. 16 | * 2. Altered source versions must be plainly marked as such, and must not be 17 | * misrepresented as being the original software. 18 | * 3. This notice may not be removed or altered from any source distribution. 19 | **/ 20 | 21 | // Lua 22 | extern "C" { 23 | #define LUA_COMPAT_ALL 24 | #include 25 | #include 26 | #include 27 | } 28 | 29 | #ifdef WIN32 30 | # define LOVE_IMGUI_EXPORT __declspec(dllexport) 31 | #else 32 | # define LOVE_IMGUI_EXPORT 33 | #endif 34 | 35 | extern "C" LOVE_IMGUI_EXPORT int loveopen_imgui(lua_State *L); 36 | --------------------------------------------------------------------------------