├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── area.c ├── area.h ├── callback.c ├── callback.h ├── control-common.c ├── control-common.h ├── controls.c ├── controls.h ├── draw.c ├── draw.h ├── examples ├── control-gallery.lua ├── gtk3.png ├── text-x-lua.png ├── text-x-lua.svg └── windows.png ├── image.c ├── image.h ├── libui-lua-git-0.rockspec ├── libui-lua.c ├── lua-compat.c ├── lua-compat.h ├── menu.c ├── menu.h ├── object.c ├── object.h └── signatures.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required( VERSION 2.8.8 ) 2 | project( libui-lua ) 3 | 4 | SET( LUA_VERSION 5.3 ) 5 | 6 | SET( LUA_DIR "" ) 7 | if( WIN32 ) 8 | SET( LUA_DIR "../lua-5.3.3" ) 9 | endif( WIN32 ) 10 | 11 | find_package( PkgConfig QUIET ) 12 | if( PkgConfig_FOUND ) 13 | pkg_check_modules( PC_LUA lua-${LUA_VERSION} ) 14 | endif( PkgConfig_FOUND ) 15 | 16 | if( PC_LUA_FOUND ) 17 | set( LUA_DEFINITIONS ${PC_LUA_CFLAGS_OTHER}) 18 | set( LUA_INCLUDES ${PC_LUA_INCLUDE_DIRS} ) 19 | set( LUA_LIBRARY ${PC_LUA_LIBRARIES} ) 20 | else( PC_LUA_FOUND ) 21 | find_path( LUA_INCLUDES lua.h HINTS ${LUA_DIR} PATH_SUFFIXES src ) 22 | find_library( LUA_LIBRARY NAMES lua lua52 lua53 liblua liblua52 liblua53 HINTS ${LUA_DIR} PATH_SUFFIXES build-vs/src ) 23 | endif( PC_LUA_FOUND ) 24 | 25 | find_path( LIBUI_INCLUDES ui.h HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../libui ) 26 | find_library( LIBUI_LIBRARY NAMES libui ui HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../libui PATH_SUFFIXES out build/out build-vs/out ) 27 | 28 | set( libui-lua-sources callback.c control-common.c controls.c image.c libui-lua.c menu.c object.c area.c draw.c lua-compat.c ) 29 | 30 | include_directories( ${LUA_INCLUDES} ${LIBUI_INCLUDES} ) 31 | 32 | add_library( libui SHARED ${libui-lua-sources} ) 33 | set_target_properties( libui PROPERTIES PREFIX "" ) 34 | target_link_libraries( libui ${LIBUI_LIBRARY} ${LUA_LIBRARY} ) 35 | 36 | set_target_properties( libui PROPERTIES COMPILE_FLAGS "-fvisibility=hidden" ) 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Matthew Dombroski 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 | # libui-lua 2 | Simple Lua binding to libui library. 3 | 4 | Compatable with Lua >= 5.1 5 | 6 | Depends on changes to libui library that are not in the upstream repository. 7 | You should therefore you should use libui from https://github.com/mdombroski/libui. 8 | 9 | This unfortunately excludes mac compatability. I don't own a mac, don't intend to, and I don't know objective-C. 10 | 11 | ## Screenshots 12 | 13 | ![GTK3](examples/gtk3.png) 14 | ![Windows](examples/windows.png) 15 | -------------------------------------------------------------------------------- /area.c: -------------------------------------------------------------------------------- 1 | #include "area.h" 2 | 3 | #include "object.h" 4 | #include "control-common.h" 5 | #include "draw.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | 15 | static int l_uiAreaSetSize( lua_State* L ) 16 | { 17 | uiArea* a = (uiArea*) check_object( L, 1, uiAreaSignature ); 18 | uiAreaSetSize( a, luaL_checkinteger( L, 2 ), luaL_checkinteger( L, 3 ) ); 19 | lua_pushvalue( L, 1 ); 20 | return 1; 21 | } 22 | 23 | static int l_uiAreaQueueRedrawAll( lua_State* L ) 24 | { 25 | uiAreaQueueRedrawAll( (uiArea*) check_object( L, 1, uiAreaSignature ) ); 26 | lua_pushvalue( L, 1 ); 27 | return 1; 28 | } 29 | 30 | static int l_uiAreaScrollTo( lua_State* L ) 31 | { 32 | uiArea* a = (uiArea*) check_object( L, 1, uiAreaSignature ); 33 | // x, y, width, height 34 | uiAreaScrollTo( a, luaL_checknumber( L, 2 ), luaL_checknumber( L, 3 ), luaL_checknumber( L, 4 ), luaL_checknumber( L, 5 ) ); 35 | lua_pushvalue( L, 1 ); 36 | return 1; 37 | } 38 | 39 | static luaL_Reg _area_functions[] = 40 | { 41 | { "SetSize", l_uiAreaSetSize }, 42 | { "QueueRedrawAll", l_uiAreaQueueRedrawAll }, 43 | { "ScrollTo", l_uiAreaScrollTo }, 44 | { 0, 0 } 45 | }; 46 | 47 | // wow, this has lots of overhead! 48 | static void draw( uiAreaHandler* handler, uiArea* area, uiAreaDrawParams* params ) 49 | { 50 | lua_State* L = *( (lua_State**)( handler + 1 ) ); 51 | object_retreive_with_function( L, area, "Draw" ); 52 | 53 | if( lua_isfunction( L, -2 ) ) 54 | { 55 | // draw context 56 | draw_new_context( L, params->Context ); 57 | 58 | // geometry 59 | lua_newtable( L ); 60 | lua_pushnumber( L, params->ClipX ); 61 | lua_setfield( L, -2, "x" ); 62 | lua_pushnumber( L, params->ClipY ); 63 | lua_setfield( L, -2, "y" ); 64 | lua_pushnumber( L, params->ClipWidth ); 65 | lua_setfield( L, -2, "w" ); 66 | lua_pushnumber( L, params->ClipHeight ); 67 | lua_setfield( L, -2, "h" ); 68 | 69 | lua_call( L, 3, 0 ); 70 | } 71 | else 72 | { 73 | lua_pop( L, 2 ); 74 | } 75 | } 76 | 77 | static void mouseevent( uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* m ) 78 | { 79 | lua_State* L = *( (lua_State**)( handler + 1 ) ); 80 | object_retreive_with_function( L, area, "MouseEvent" ); 81 | 82 | if( lua_isfunction( L, -2 ) ) 83 | { 84 | lua_newtable( L ); 85 | lua_pushnumber( L, m->X ); 86 | lua_setfield( L, -2, "x" ); 87 | lua_pushnumber( L, m->Y ); 88 | lua_setfield( L, -2, "y" ); 89 | lua_pushnumber( L, m->AreaWidth ); 90 | lua_setfield( L, -2, "w" ); 91 | lua_pushnumber( L, m->AreaHeight ); 92 | lua_setfield( L, -2, "h" ); 93 | lua_pushnumber( L, m->Down ); 94 | lua_setfield( L, -2, "down" ); 95 | lua_pushnumber( L, m->Up ); 96 | lua_setfield( L, -2, "up" ); 97 | lua_pushnumber( L, m->Count ); 98 | lua_setfield( L, -2, "count" ); 99 | 100 | lua_pushnumber( L, m->Modifiers ); 101 | lua_setfield( L, -2, "modifiers" ); 102 | lua_pushnumber( L, m->Held1To64 ); 103 | lua_setfield( L, -2, "held1to64" ); 104 | 105 | lua_call( L, 2, 0 ); 106 | } 107 | else 108 | { 109 | lua_pop( L, 2 ); 110 | } 111 | } 112 | 113 | static void mousecrossed( uiAreaHandler* handler, uiArea* area, int left ) 114 | { 115 | lua_State* L = *( (lua_State**)( handler + 1 ) ); 116 | object_retreive_with_function( L, area, "MouseCrossed" ); 117 | 118 | if( lua_isfunction( L, -2 ) ) 119 | { 120 | lua_pushboolean( L, left ); 121 | lua_call( L, 2, 0 ); 122 | } 123 | else 124 | { 125 | lua_pop( L, 2 ); 126 | } 127 | } 128 | 129 | static void dragbroken( uiAreaHandler* handler, uiArea* area ) 130 | { 131 | lua_State* L = *( (lua_State**)( handler + 1 ) ); 132 | object_retreive_with_function( L, area, "DragBroken" ); 133 | 134 | if( lua_isfunction( L, -2 ) ) 135 | { 136 | lua_call( L, 1, 0 ); 137 | } 138 | else 139 | { 140 | lua_pop( L, 2 ); 141 | } 142 | } 143 | 144 | static int keyevent( uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* k ) 145 | { 146 | lua_State* L = *( (lua_State**)( handler + 1 ) ); 147 | object_retreive_with_function( L, area, "KeyEvent" ); 148 | 149 | if( lua_isfunction( L, -2 ) ) 150 | { 151 | lua_newtable( L ); 152 | lua_pushnumber( L, k->Key ); 153 | lua_setfield( L, -2, "key" ); 154 | lua_pushnumber( L, k->ExtKey ); 155 | lua_setfield( L, -2, "extkey" ); 156 | lua_pushnumber( L, k->Modifier ); 157 | lua_setfield( L, -2, "modifier" ); 158 | lua_pushnumber( L, k->Modifiers ); 159 | lua_setfield( L, -2, "modifiers" ); 160 | lua_pushnumber( L, k->Up ); 161 | lua_setfield( L, -2, "up" ); 162 | 163 | lua_call( L, 2, 0 ); 164 | } 165 | else 166 | { 167 | lua_pop( L, 2 ); 168 | } 169 | return 0; 170 | } 171 | 172 | 173 | static int new_area( lua_State* L ) 174 | { 175 | // TODO 176 | uiArea* a; 177 | uiAreaHandler* ah = malloc( sizeof(uiAreaHandler) + sizeof(lua_State*) ); 178 | ah->Draw = draw; 179 | ah->MouseEvent = mouseevent; 180 | ah->MouseCrossed = mousecrossed; 181 | ah->DragBroken = dragbroken; 182 | ah->KeyEvent = keyevent; 183 | *( (lua_State**)( ah + 1 ) ) = L; 184 | 185 | if( lua_isinteger( L, 2 ) && lua_isinteger( L, 3 ) ) 186 | { 187 | a = uiNewScrollingArea( ah, lua_tointeger( L, 2 ), lua_tointeger( L, 3 ) ); 188 | } 189 | else 190 | { 191 | a = uiNewArea( ah ); 192 | } 193 | 194 | object_create( L, a, uiAreaSignature, control_common, _area_functions, 0 ); 195 | return 1; 196 | } 197 | 198 | luaL_Reg area_functions[] = 199 | { 200 | { "NewArea", new_area }, 201 | { 0, 0 } 202 | }; 203 | -------------------------------------------------------------------------------- /area.h: -------------------------------------------------------------------------------- 1 | #ifndef AREA_H 2 | #define AREA_H 3 | 4 | #include 5 | 6 | extern luaL_Reg area_functions[]; 7 | 8 | #endif /* AREA_H */ 9 | 10 | -------------------------------------------------------------------------------- /callback.c: -------------------------------------------------------------------------------- 1 | #include "callback.h" 2 | 3 | #include 4 | 5 | 6 | void register_callback( lua_State* L, int idx, void* sender, int callback ) 7 | { 8 | if( sender == NULL ) 9 | return; 10 | 11 | lua_pushvalue( L, idx ); 12 | lua_pushlightuserdata( L, sender ); 13 | lua_pushlightuserdata( L, sender ); 14 | lua_gettable( L, LUA_REGISTRYINDEX ); 15 | 16 | if( lua_type( L, -1 ) != LUA_TTABLE ) 17 | { 18 | lua_pop( L, 1 ); // remove nil 19 | lua_newtable( L ); 20 | } 21 | 22 | lua_pushinteger( L, callback ); 23 | lua_pushvalue( L, -4 ); 24 | lua_settable( L, -3 ); 25 | 26 | lua_settable( L, LUA_REGISTRYINDEX ); 27 | lua_pop( L, 1 ); 28 | } 29 | 30 | int invoke_callback( lua_State* L, void* id, int callback, int args ) 31 | { 32 | int err = 0; 33 | 34 | if( L && id ) 35 | { 36 | // fetch the callback function from the registry meta data table 37 | lua_pushlightuserdata( L, id ); 38 | lua_gettable( L, LUA_REGISTRYINDEX ); 39 | lua_pushinteger( L, callback ); 40 | lua_gettable( L, -2 ); 41 | lua_rotate( L, -2, 1 ); 42 | lua_pop( L, 1 ); 43 | 44 | // not a function 45 | if( ! lua_isfunction( L, -1 ) ) 46 | { 47 | lua_pop( L, args + 1 ); 48 | return err; 49 | } 50 | 51 | // get object/self argument from registry (function argument) 52 | if( object_copy( L, id ) ) 53 | args++; 54 | 55 | // make sure things are in the right order 56 | if( args > 1 ) 57 | lua_rotate( L, -( args + 1 ), 2 ); 58 | 59 | if( lua_pcall( L, args, 1, 0 ) ) // call the callback 60 | printf( "%s\n", lua_tostring( L, -1 ) ); // print the error 61 | 62 | if( lua_isinteger( L, -1 ) ) 63 | err = lua_tointeger( L, -1 ); 64 | 65 | lua_pop( L, 1 ); 66 | } 67 | 68 | return err; 69 | } 70 | -------------------------------------------------------------------------------- /callback.h: -------------------------------------------------------------------------------- 1 | #ifndef CALLBACK_H 2 | #define CALLBACK_H 3 | 4 | #include 5 | #include "lua-compat.h" 6 | 7 | #include "object.h" 8 | 9 | enum 10 | { 11 | callback_ShouldQuit = 0xDA0, 12 | callback_OnClosing = 0xDA1, 13 | callback_OnClicked = 0xDA2, 14 | callback_OnToggled = 0xDA3, 15 | callback_OnChanged = 0xDA4, 16 | callback_OnSelected = 0xDA5, 17 | callback_OnPositionChanged = 0xDA6, 18 | callback_OnContentSizeChanged = 0xDA7, 19 | }; 20 | 21 | 22 | void register_callback( lua_State* L, int idx, void* sender, int callback ); 23 | int invoke_callback( lua_State* L, void* id, int callback, int args ); 24 | 25 | #define DECLARE_CALLBACK_FUNCTION( typename, action ) \ 26 | static void callback_ ## typename ## action( typename *c, void* data ) { \ 27 | invoke_callback( (lua_State*) data, c, callback_ ## action, 0 ); \ 28 | } 29 | #define DECLARE_CALLBACK_REGISTER( typename, signature, action ) \ 30 | static int l_ ## typename ## action( lua_State* L ) { \ 31 | typename* c = (typename*) check_object( L, 1, signature ); \ 32 | register_callback( L, 2, c, callback_ ## action ); \ 33 | if( lua_type( L, 2 ) == LUA_TFUNCTION ) \ 34 | typename ## action( c, callback_ ## typename ## action, L ); \ 35 | lua_pushvalue( L, 1 ); \ 36 | return 1; \ 37 | } 38 | #define DECLARE_CALLBACK( typename, action ) \ 39 | DECLARE_CALLBACK_FUNCTION( typename, action ) \ 40 | DECLARE_CALLBACK_REGISTER( typename, typename ## Signature, action ) 41 | 42 | 43 | #endif /* CALLBACK_H */ 44 | -------------------------------------------------------------------------------- /control-common.c: -------------------------------------------------------------------------------- 1 | #include "control-common.h" 2 | #include "object.h" 3 | 4 | #include 5 | 6 | 7 | int is_control( int signature ) 8 | { 9 | switch( signature ) 10 | { 11 | // ONLY CONTROLS/WIDGETS 12 | // IMPORTANT, NOT MENUS or IMAGES 13 | case uiAreaSignature: 14 | case uiBoxSignature: 15 | case uiButtonSignature: 16 | case uiCheckboxSignature: 17 | case uiColorButtonSignature: 18 | case uiComboboxSignature: 19 | case uiDateTimePickerSignature: 20 | case uiEditableComboboxSignature: 21 | case uiEntrySignature: 22 | case uiFontButtonSignature: 23 | case uiFormSignature: 24 | case uiGridSignature: 25 | case uiGroupSignature: 26 | case uiLabelSignature: 27 | case uiImageBoxSignature: 28 | case uiMultilineEntrySignature: 29 | case uiProgressBarSignature: 30 | case uiRadioButtonsSignature: 31 | case uiSeparatorSignature: 32 | case uiSliderSignature: 33 | case uiSpinboxSignature: 34 | case uiTabSignature: 35 | case uiWindowSignature: 36 | return 1; 37 | default: 38 | return 0; 39 | } 40 | } 41 | 42 | uiControl* check_control( lua_State* L, int idx, int signature ) 43 | { 44 | int s; 45 | uiControl* c = (uiControl*) get_object( L, idx, &s ); 46 | 47 | if( is_control( s ) ) 48 | { 49 | if( signature == 0 || signature == s ) 50 | { 51 | return c; 52 | } 53 | } 54 | 55 | luaL_error( L, "libui object is not a control" ); 56 | return 0; 57 | } 58 | 59 | 60 | int l_uiControlDestroy( lua_State* L ) 61 | { 62 | uiControl* c = check_control( L, 1, 0 ); 63 | uiControlDestroy( c ); 64 | 65 | // destroy registry meta table 66 | lua_pushlightuserdata( L, c ); 67 | lua_pushnil( L ); 68 | lua_settable( L, LUA_REGISTRYINDEX ); 69 | 70 | return 0; 71 | } 72 | 73 | static int l_uiControlParent( lua_State* L ) 74 | { 75 | return object_copy( L, uiControlParent( check_control( L,-1, 0 ) ) ); 76 | } 77 | 78 | static int l_uiControlSetParent( lua_State* L ) 79 | { 80 | uiControl* c = check_control( L, 1, 0 ); 81 | uiControl* p = check_control( L, 2, 0 ); 82 | uiControlSetParent( c, p ); 83 | lua_pushvalue( L, 1 ); 84 | return 1; 85 | } 86 | 87 | #undef DECLARE_GETTER 88 | #define DECLARE_GETTER( typename, action, type ) \ 89 | int l_ ## typename ## action( lua_State* L ) { \ 90 | lua_push ## type ( L, typename ## action ( (typename*) check_control( L, 1, 0 ) ) ); \ 91 | return 1; \ 92 | } 93 | 94 | #undef DECLARE_ACTION 95 | #define DECLARE_ACTION( typename, action ) \ 96 | int l_ ## typename ## action( lua_State* L ) { \ 97 | typename ## action ( (typename*) check_control( L, 1, 0 ) ); \ 98 | lua_pushvalue( L, 1 ); \ 99 | return 1; \ 100 | } 101 | 102 | DECLARE_GETTER( uiControl, Handle, integer ) 103 | DECLARE_GETTER( uiControl, Visible, boolean ) 104 | DECLARE_ACTION( uiControl, Show ) 105 | DECLARE_ACTION( uiControl, Hide ) 106 | DECLARE_GETTER( uiControl, Enabled, boolean ) 107 | DECLARE_ACTION( uiControl, Enable ) 108 | DECLARE_ACTION( uiControl, Disable ) 109 | DECLARE_GETTER( uiControl, Toplevel, boolean ) 110 | DECLARE_GETTER( uiControl, EnabledToUser, boolean ) 111 | 112 | luaL_Reg control_common[] = 113 | { 114 | { "Destroy", l_uiControlDestroy }, 115 | { "Handle", l_uiControlHandle }, 116 | { "Parent", l_uiControlParent }, 117 | { "SetParent", l_uiControlSetParent }, 118 | { "TopLevel", l_uiControlToplevel }, 119 | { "Visible", l_uiControlVisible }, 120 | { "Show", l_uiControlShow }, 121 | { "Hide", l_uiControlHide }, 122 | { "Enabled", l_uiControlEnabled }, 123 | { "Enable", l_uiControlEnable }, 124 | { "Disable", l_uiControlDisable }, 125 | { "EnabledToUser", l_uiControlEnabledToUser }, 126 | { 0, 0 } 127 | }; 128 | -------------------------------------------------------------------------------- /control-common.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTROL_COMMON_H 2 | #define CONTROL_COMMON_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "signatures.h" 10 | 11 | int is_control( int signature ); 12 | uiControl* check_control( lua_State* L, int idx, int signature ); 13 | 14 | 15 | extern luaL_Reg control_common[]; 16 | 17 | 18 | #endif /* CONTROL_COMMON_H */ 19 | -------------------------------------------------------------------------------- /controls.c: -------------------------------------------------------------------------------- 1 | #include "controls.h" 2 | 3 | #include "object.h" 4 | #include "callback.h" 5 | #include "control-common.h" 6 | #include "image.h" 7 | #include "draw.h" 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | 15 | static int callback_uiWindowOnClosing( uiWindow* w, void* d ) 16 | { 17 | invoke_callback( (lua_State*) d, w, callback_OnClosing, 0 ); 18 | return 0; 19 | } 20 | 21 | static int l_uiWindowTitle( lua_State* L ) 22 | { 23 | char* s = uiWindowTitle( (uiWindow*) check_object( L, 1, uiWindowSignature ) ); 24 | lua_pushstring( L, s ); 25 | uiFreeText( s ); 26 | return 1; 27 | } 28 | 29 | static int l_uiWindowSetIcon( lua_State* L ) 30 | { 31 | uiWindowSetIcon( (uiWindow*) check_object( L, 1, uiWindowSignature ), check_image( L, 2 ) ); 32 | lua_pushvalue( L, 1 ); 33 | return 1; 34 | } 35 | 36 | //DECLARE_GETTER( uiWindow, Title, string ) 37 | DECLARE_SETTER( uiWindow, SetTitle, string ) 38 | DECLARE_GETTER_2( uiWindow, Position, integer, integer ) 39 | DECLARE_SETTER_2( uiWindow, SetPosition, integer, integer ) 40 | DECLARE_ACTION( uiWindow, Center ) 41 | DECLARE_GETTER_2( uiWindow, ContentSize, integer, integer ) 42 | DECLARE_SETTER_2( uiWindow, SetContentSize, integer, integer ) 43 | DECLARE_GETTER( uiWindow, Fullscreen, boolean ) 44 | DECLARE_SETTER( uiWindow, SetFullscreen, boolean ) 45 | DECLARE_GETTER( uiWindow, Borderless, boolean ) 46 | DECLARE_SETTER( uiWindow, SetBorderless, boolean ) 47 | DECLARE_GETTER( uiWindow, Margined, boolean) 48 | DECLARE_SETTER( uiWindow, SetMargined, boolean ) 49 | DECLARE_CALLBACK_REGISTER( uiWindow, uiWindowSignature, OnClosing ) 50 | DECLARE_CALLBACK( uiWindow, OnPositionChanged ) 51 | DECLARE_CALLBACK( uiWindow, OnContentSizeChanged ) 52 | 53 | static int window_setchild( lua_State* L ) 54 | { 55 | uiWindow* w = (uiWindow*) check_object( L, 1, uiWindowSignature ); 56 | uiControl* c = (uiControl*) check_control( L, 2, 0 ); 57 | uiWindowSetChild( w, c ); 58 | lua_pushvalue( L, 1 ); 59 | return 1; 60 | } 61 | 62 | 63 | static luaL_Reg window_functions[] = 64 | { 65 | { "Title", l_uiWindowTitle }, 66 | { "SetTitle", l_uiWindowSetTitle }, 67 | { "SetIcon", l_uiWindowSetIcon }, 68 | { "Position", l_uiWindowPosition }, 69 | { "SetPosition", l_uiWindowPosition }, 70 | { "Center", l_uiWindowCenter }, 71 | { "OnPositionChanged", l_uiWindowOnPositionChanged }, 72 | { "ContentSize", l_uiWindowContentSize }, 73 | { "SetContentSize", l_uiWindowSetContentSize }, 74 | { "OnContentSizeChanged", l_uiWindowOnContentSizeChanged }, 75 | { "Fullscreen", l_uiWindowFullscreen }, 76 | { "SetFullscreen", l_uiWindowSetFullscreen }, 77 | { "Borderless", l_uiWindowBorderless }, 78 | { "SetBorderless", l_uiWindowSetBorderless }, 79 | { "Margined", l_uiWindowMargined }, 80 | { "SetMargined", l_uiWindowSetMargined }, 81 | { "SetChild", window_setchild }, 82 | { "OnClosing", l_uiWindowOnClosing }, 83 | { 0, 0 } 84 | }; 85 | 86 | static int new_window( lua_State* L ) 87 | { 88 | uiWindow* w = uiNewWindow( luaL_optlstring( L, 1, "Lua", NULL ), luaL_optinteger( L, 2, 640 ), luaL_optinteger( L, 3, 480 ), lua_toboolean( L, 4 ) ); 89 | object_create( L, w, uiWindowSignature, control_common, window_functions, 0 ); 90 | 91 | return 1; 92 | } 93 | 94 | 95 | static int l_uiButtonText( lua_State* L ) 96 | { 97 | char* s = uiButtonText( (uiButton*) check_object( L, 1, uiButtonSignature ) ); 98 | lua_pushstring( L, s ); 99 | return 1; 100 | } 101 | 102 | static int l_uiButtonSetIcon( lua_State* L ) 103 | { 104 | uiButtonSetIcon( (uiButton*) check_object( L, 1, uiButtonSignature ), check_image( L, 2 ) ); 105 | lua_pushvalue( L, 1 ); 106 | return 1; 107 | } 108 | 109 | //DECLARE_GETTER( uiButton, Text, string ) 110 | DECLARE_SETTER( uiButton, SetText, string ) 111 | DECLARE_CALLBACK( uiButton, OnClicked ) 112 | 113 | static luaL_Reg button_functions[] = 114 | { 115 | { "Text", l_uiButtonText }, 116 | { "SetText", l_uiButtonSetText }, 117 | { "SetIcon", l_uiButtonSetIcon }, 118 | { "OnClicked", l_uiButtonOnClicked }, 119 | { 0, 0 } 120 | }; 121 | 122 | static int new_button( lua_State* L ) 123 | { 124 | uiButton* b = uiNewButton( luaL_optlstring( L, 1, "Button", NULL ) ); 125 | object_create( L, b, uiButtonSignature, control_common, button_functions, 0 ); 126 | 127 | return 1; 128 | } 129 | 130 | 131 | static int l_uiBoxAppend( lua_State* L ) 132 | { 133 | uiBox* b = (uiBox*) check_object( L, 1, uiBoxSignature ); 134 | uiControl* o = (uiControl*) check_control( L, 2, 0 ); 135 | uiBoxAppend( b, o, lua_toboolean( L, 3 ) ); 136 | lua_pushvalue( L, 1 ); 137 | return 1; 138 | } 139 | 140 | DECLARE_GETTER( uiBox, Padded, boolean ) 141 | DECLARE_SETTER( uiBox, SetPadded, boolean ) 142 | DECLARE_SETTER( uiBox, Delete, integer ) 143 | 144 | static luaL_Reg box_functions[] = 145 | { 146 | { "Append", l_uiBoxAppend }, 147 | { "Delete", l_uiBoxDelete }, 148 | { "Padded", l_uiBoxPadded }, 149 | { "SetPadded", l_uiBoxSetPadded }, 150 | { 0, 0 } 151 | }; 152 | 153 | static int new_hbox( lua_State* L ) 154 | { 155 | uiBox* b = uiNewHorizontalBox(); 156 | object_create( L, b, uiBoxSignature, control_common, box_functions, 0 ); 157 | if( lua_isboolean( L, 1 ) ) 158 | { 159 | uiBoxSetPadded( b, lua_toboolean( L, 1 ) ); 160 | } 161 | return 1; 162 | } 163 | 164 | static int new_vbox( lua_State* L ) 165 | { 166 | uiBox* b = uiNewVerticalBox(); 167 | object_create( L, b, uiBoxSignature, control_common, box_functions, 0 ); 168 | if( lua_isboolean( L, 1 ) ) 169 | { 170 | uiBoxSetPadded( b, lua_toboolean( L, 1 ) ); 171 | } 172 | return 1; 173 | } 174 | 175 | 176 | static int l_uiCheckboxText( lua_State* L ) 177 | { 178 | char* s = uiCheckboxText( (uiCheckbox*) check_object( L, 1, uiCheckboxSignature ) ); 179 | lua_pushstring( L, s ); 180 | uiFreeText( s ); 181 | return 1; 182 | } 183 | 184 | static void callback_uiCheckboxOnToggled( uiCheckbox* c, void* d ) 185 | { 186 | lua_State* L = (lua_State*) d; 187 | if( L ) 188 | { 189 | lua_pushboolean( L, uiCheckboxChecked( c ) ); 190 | invoke_callback( L, c, callback_OnToggled, 1 ); 191 | } 192 | } 193 | 194 | //DECLARE_GETTER( uiCheckbox, Text, string ) 195 | DECLARE_SETTER( uiCheckbox, SetText, string ) 196 | DECLARE_GETTER( uiCheckbox, Checked, boolean ) 197 | DECLARE_SETTER( uiCheckbox, SetChecked, boolean ) 198 | DECLARE_CALLBACK_REGISTER( uiCheckbox, uiCheckboxSignature, OnToggled ) 199 | 200 | static luaL_Reg checkbox_functions[] = 201 | { 202 | { "Text", l_uiCheckboxText }, 203 | { "SetText", l_uiCheckboxSetText }, 204 | { "OnToggled", l_uiCheckboxOnToggled }, 205 | { "Checked", l_uiCheckboxChecked }, 206 | { "SetChecked", l_uiCheckboxSetChecked }, 207 | { 0, 0 } 208 | }; 209 | 210 | static int new_checkbox( lua_State* L ) 211 | { 212 | uiCheckbox* c = uiNewCheckbox( luaL_optlstring( L, 1, "Checkbox", NULL ) ); 213 | object_create( L, c, uiCheckboxSignature, control_common, checkbox_functions, 0 ); 214 | return 1; 215 | } 216 | 217 | 218 | static int l_uiEntryText( lua_State* L ) 219 | { 220 | char* s = uiEntryText( (uiEntry*) check_object( L, 1, uiEntrySignature ) ); 221 | lua_pushstring( L, s ); 222 | uiFreeText( s ); 223 | return 1; 224 | } 225 | 226 | static void callback_uiEntryOnChanged( uiEntry* c, void* d ) 227 | { 228 | lua_State* L = (lua_State*) d; 229 | if( L ) 230 | { 231 | char* str = uiEntryText( c ); 232 | lua_pushstring( L, str ); 233 | uiFreeText( str ); 234 | invoke_callback( L, c, callback_OnChanged, 1 ); 235 | } 236 | } 237 | 238 | //DECLARE_GETTER( uiEntry, Text, string ) 239 | DECLARE_SETTER( uiEntry, SetText, string ) 240 | DECLARE_GETTER( uiEntry, ReadOnly, boolean ) 241 | DECLARE_SETTER( uiEntry, SetReadOnly, boolean ) 242 | DECLARE_CALLBACK_REGISTER( uiEntry, uiEntrySignature, OnChanged ) 243 | 244 | static luaL_Reg entry_functions[] = 245 | { 246 | { "Text", l_uiEntryText }, 247 | { "SetText", l_uiEntrySetText }, 248 | { "OnChanged", l_uiEntryOnChanged }, 249 | { "ReadOnly", l_uiEntryReadOnly }, 250 | { "SetReadOnly", l_uiEntrySetReadOnly }, 251 | { 0, 0 } 252 | }; 253 | 254 | static int new_entry( lua_State* L ) 255 | { 256 | object_create( L, uiNewEntry(), uiEntrySignature, control_common, entry_functions, 0 ); 257 | return 1; 258 | } 259 | 260 | static int new_password_entry( lua_State* L ) 261 | { 262 | object_create( L, uiNewPasswordEntry(), uiEntrySignature, control_common, entry_functions, 0 ); 263 | return 1; 264 | } 265 | 266 | static int new_search_entry( lua_State* L ) 267 | { 268 | object_create( L, uiNewSearchEntry(), uiEntrySignature, control_common, entry_functions, 0 ); 269 | return 1; 270 | } 271 | 272 | 273 | static int l_uiLabelText( lua_State* L ) 274 | { 275 | char* s = uiLabelText( (uiLabel*) check_object( L, 1, uiLabelSignature ) ); 276 | lua_pushstring( L, s ); 277 | uiFreeText( s ); 278 | return 1; 279 | } 280 | 281 | //DECLARE_GETTER( uiLabel, Text, string ) 282 | DECLARE_SETTER( uiLabel, SetText, string ) 283 | 284 | static luaL_Reg label_functions[] = 285 | { 286 | { "Text", l_uiLabelText }, 287 | { "SetText", l_uiLabelSetText }, 288 | { 0, 0 } 289 | }; 290 | 291 | static int new_label( lua_State* L ) 292 | { 293 | uiLabel* l = uiNewLabel( luaL_optlstring( L, 1, "Label", NULL ) ); 294 | object_create( L, l, uiLabelSignature, control_common, label_functions, 0 ); 295 | return 1; 296 | } 297 | 298 | static int l_uiImageBoxSetImage( lua_State* L ) 299 | { 300 | uiImageBox* i = (uiImageBox*) check_object( L, 1, uiImageBoxSignature ); 301 | 302 | if( lua_isnoneornil( L, 2 ) ) 303 | { 304 | uiImageBoxSetImage( i, 0 ); 305 | } 306 | else 307 | { 308 | uiImageBoxSetImage( i, check_image( L, 2 ) ); 309 | } 310 | 311 | lua_pushvalue( L, 1 ); 312 | return 1; 313 | } 314 | 315 | static luaL_Reg imagebox_functions[] = 316 | { 317 | { "SetImage", l_uiImageBoxSetImage }, 318 | { 0, 0 } 319 | }; 320 | 321 | static int new_imagebox( lua_State* L ) 322 | { 323 | // image as parameter 324 | uiImage *i = NULL; 325 | if( ! lua_isnoneornil( L, 1 ) ) 326 | { 327 | i = check_image( L, 1 ); 328 | } 329 | 330 | uiImageBox* b = uiNewImageBox( i ); 331 | object_create( L, b, uiImageBoxSignature, control_common, imagebox_functions, 0 ); 332 | return 1; 333 | } 334 | 335 | 336 | static int tab_append( lua_State* L ) 337 | { 338 | uiTab* t = (uiTab*) check_object( L, 1, uiTabSignature ); 339 | uiControl* c = check_control( L, 3, 0 ); 340 | uiTabAppend( t, luaL_checkstring( L, 2 ), c ); 341 | if( lua_isboolean( L, 4 ) ) 342 | { 343 | uiTabSetMargined( t, uiTabNumPages( t ) - 1, lua_toboolean( L, 4 ) ); 344 | } 345 | lua_pushvalue( L, 1 ); 346 | return 1; 347 | } 348 | 349 | static int tab_insert( lua_State* L ) 350 | { 351 | uiTab* t = (uiTab*) check_object( L, 1, uiTabSignature ); 352 | uiControl* c = check_control( L, 4, 0 ); 353 | uiTabInsertAt( t, luaL_checkstring( L, 3 ), luaL_checkinteger( L, 2 ), c ); 354 | lua_pushvalue( L, 1 ); 355 | return 1; 356 | } 357 | 358 | DECLARE_SETTER( uiTab, Delete, integer ) 359 | DECLARE_GETTER( uiTab, NumPages, integer ) 360 | 361 | static int l_uiTabMargined( lua_State* L ) 362 | { 363 | uiTab* t = (uiTab*) check_object( L, 1, uiTabSignature ); 364 | lua_pushboolean( L, uiTabMargined( t, luaL_checkinteger( L, 2 ) ) ); 365 | return 0; 366 | } 367 | 368 | static int l_uiTabSetMargined( lua_State* L ) 369 | { 370 | uiTab* t = (uiTab*) check_object( L, 1, uiTabSignature ); 371 | uiTabSetMargined( t, luaL_checkinteger( L, 2 ), lua_toboolean( L, 3 ) ); 372 | lua_pushvalue( L, 1 ); 373 | return 1; 374 | } 375 | 376 | static luaL_Reg tab_functions[] = 377 | { 378 | { "Append", tab_append }, 379 | { "Insert", tab_insert }, 380 | { "Delete", l_uiTabDelete }, 381 | { "NumPages", l_uiTabNumPages }, 382 | { "Margined", l_uiTabMargined }, 383 | { "SetMargined", l_uiTabSetMargined }, 384 | { 0, 0 } 385 | }; 386 | 387 | static int new_tab( lua_State* L ) 388 | { 389 | object_create( L, uiNewTab(), uiTabSignature, control_common, tab_functions, 0 ); 390 | return 1; 391 | } 392 | 393 | 394 | static int l_uiGroupTitle( lua_State* L ) 395 | { 396 | char* s = uiGroupTitle( (uiGroup*) check_object( L, 1, uiGroupSignature ) ); 397 | lua_pushstring( L, s ); 398 | uiFreeText( s ); 399 | return 1; 400 | } 401 | 402 | //DECLARE_GETTER( uiGroup, Title, string ) 403 | DECLARE_SETTER( uiGroup, SetTitle, string ) 404 | DECLARE_GETTER( uiGroup, Margined, boolean ) 405 | DECLARE_SETTER( uiGroup, SetMargined, boolean ) 406 | 407 | static int group_setchild( lua_State* L ) 408 | { 409 | uiGroup* g = (uiGroup*) check_object( L, 1, uiGroupSignature ); 410 | uiControl* c = check_control( L, 2, 0 ); 411 | uiGroupSetChild( g, c ); 412 | lua_pushvalue( L, 1 ); 413 | return 1; 414 | } 415 | 416 | static luaL_Reg group_functions[] = 417 | { 418 | { "Title", l_uiGroupTitle }, 419 | { "SetTitle", l_uiGroupSetTitle }, 420 | { "SetChild", group_setchild }, 421 | { "Margined", l_uiGroupMargined }, 422 | { "SetMargined", l_uiGroupSetMargined }, 423 | { 0, 0 } 424 | }; 425 | 426 | static int new_group( lua_State* L ) 427 | { 428 | uiGroup* g = uiNewGroup( luaL_optlstring( L, 1, "Label", NULL ) ); 429 | object_create( L, g, uiGroupSignature, control_common, group_functions, 0 ); 430 | return 1; 431 | } 432 | 433 | static void callback_uiSpinboxOnChanged( uiSpinbox* c, void* d ) 434 | { 435 | lua_State* L = (lua_State*) d; 436 | if( L ) 437 | { 438 | lua_pushinteger( L, uiSpinboxValue( c ) ); 439 | invoke_callback( L, c, callback_OnChanged, 1 ); 440 | } 441 | } 442 | 443 | DECLARE_GETTER( uiSpinbox, Value, integer ) 444 | DECLARE_SETTER( uiSpinbox, SetValue, integer ) 445 | DECLARE_CALLBACK_REGISTER( uiSpinbox, uiSpinboxSignature, OnChanged ) 446 | 447 | static luaL_Reg spinbox_functions[] = 448 | { 449 | { "Value", l_uiSpinboxValue }, 450 | { "SetValue", l_uiSpinboxSetValue }, 451 | { "OnChanged", l_uiSpinboxOnChanged }, 452 | { 0, 0 } 453 | }; 454 | 455 | static int new_spinbox( lua_State* L ) 456 | { 457 | uiSpinbox* s = uiNewSpinbox( luaL_optinteger( L, 1, 0 ), luaL_optinteger( L, 2, 100 ) ); 458 | object_create( L, s, uiSpinboxSignature, control_common, spinbox_functions, 0 ); 459 | return 1; 460 | } 461 | 462 | 463 | DECLARE_GETTER( uiProgressBar, Value, integer ) 464 | DECLARE_SETTER( uiProgressBar, SetValue, integer ) 465 | 466 | static luaL_Reg progress_functions[] = 467 | { 468 | { "Value", l_uiProgressBarValue }, 469 | { "SetValue", l_uiProgressBarSetValue }, 470 | { 0, 0 } 471 | }; 472 | 473 | static int new_progress( lua_State* L ) 474 | { 475 | uiProgressBar* p = uiNewProgressBar(); 476 | object_create( L, p, uiProgressBarSignature, control_common, progress_functions, 0 ); 477 | if( lua_isinteger( L, 1 ) ) 478 | { 479 | uiProgressBarSetValue( p, lua_tointeger( L, 1 ) ); 480 | } 481 | return 1; 482 | } 483 | 484 | 485 | static void callback_uiSliderOnChanged( uiSlider* c, void* d ) 486 | { 487 | lua_State* L = (lua_State*) d; 488 | if( L ) 489 | { 490 | lua_pushinteger( L, uiSliderValue( c ) ); 491 | invoke_callback( L, c, callback_OnChanged, 1 ); 492 | } 493 | } 494 | 495 | DECLARE_GETTER( uiSlider, Value, integer ) 496 | DECLARE_SETTER( uiSlider, SetValue, integer ) 497 | DECLARE_CALLBACK_REGISTER( uiSlider, uiSliderSignature, OnChanged ) 498 | 499 | static luaL_Reg slider_functions[] = 500 | { 501 | { "Value", l_uiSliderValue }, 502 | { "SetValue", l_uiSliderSetValue }, 503 | { "OnChanged", l_uiSliderOnChanged }, 504 | { 0, 0 } 505 | }; 506 | 507 | static int new_slider( lua_State* L ) 508 | { 509 | uiSlider* s = uiNewSlider( luaL_optinteger( L, 1, 0 ), luaL_optinteger( L, 2, 100 ) ); 510 | object_create( L, s, uiSliderSignature, control_common, slider_functions, 0 ); 511 | return 1; 512 | } 513 | 514 | 515 | static int new_hseparator( lua_State* L ) 516 | { 517 | object_create( L, uiNewHorizontalSeparator(), uiSeparatorSignature, control_common, 0 ); 518 | return 1; 519 | } 520 | 521 | static int new_vseparator( lua_State* L ) 522 | { 523 | object_create( L, uiNewVerticalSeparator(), uiSeparatorSignature, control_common, 0 ); 524 | return 1; 525 | } 526 | 527 | static void callback_uiComboboxOnSelected( uiCombobox* c, void* d ) 528 | { 529 | lua_State* L = (lua_State*) d; 530 | if( L ) 531 | { 532 | lua_pushinteger( L, uiComboboxSelected( c ) ); 533 | invoke_callback( L, c, callback_OnSelected, 1 ); 534 | } 535 | } 536 | 537 | DECLARE_SETTER( uiCombobox, Append, string ) 538 | DECLARE_GETTER( uiCombobox, Selected, integer ) 539 | DECLARE_SETTER( uiCombobox, SetSelected, integer ) 540 | DECLARE_CALLBACK_REGISTER( uiCombobox, uiComboboxSignature, OnSelected ) 541 | 542 | static luaL_Reg combobox_functions[] = 543 | { 544 | { "Append", l_uiComboboxAppend }, 545 | { "Selected", l_uiComboboxSelected }, 546 | { "SetSelected", l_uiComboboxSetSelected }, 547 | { "OnSelected", l_uiComboboxOnSelected }, 548 | { 0, 0 } 549 | }; 550 | 551 | static int new_combobox( lua_State* L ) 552 | { 553 | object_create( L, uiNewCombobox(), uiComboboxSignature, control_common, combobox_functions, 0 ); 554 | return 1; 555 | } 556 | 557 | 558 | static void callback_uiEditableComboboxOnChanged( uiEditableCombobox* c, void* d ) 559 | { 560 | lua_State* L = (lua_State*) d; 561 | if( L ) 562 | { 563 | object_create( L, uiNewCombobox(), uiComboboxSignature, control_common, combobox_functions, 0 ); 564 | char* text = uiEditableComboboxText( c ); 565 | lua_pushstring( L, text ); 566 | invoke_callback( L, c, callback_OnChanged, 1 ); 567 | uiFreeText( text ); 568 | } 569 | } 570 | 571 | static int l_uiEditableComboboxText( lua_State* L ) 572 | { 573 | char* s = uiEditableComboboxText( (uiEditableCombobox*) check_object( L, 1, uiEditableComboboxSignature ) ); 574 | lua_pushstring( L, s ); 575 | uiFreeText( s ); 576 | return 1; 577 | } 578 | 579 | DECLARE_SETTER( uiEditableCombobox, SetText, string ) 580 | DECLARE_SETTER( uiEditableCombobox, Append, string ) 581 | DECLARE_CALLBACK_REGISTER( uiEditableCombobox, uiEditableComboboxSignature, OnChanged ) 582 | 583 | static luaL_Reg editable_combobox_functions[] = 584 | { 585 | { "Text", l_uiEditableComboboxText }, 586 | { "SetText", l_uiEditableComboboxSetText }, 587 | { "Append", l_uiEditableComboboxAppend }, 588 | { "OnChanged", l_uiEditableComboboxOnChanged }, 589 | { 0, 0 } 590 | }; 591 | 592 | static int new_editablecombobox( lua_State* L ) 593 | { 594 | object_create( L, uiNewEditableCombobox(), uiEditableComboboxSignature, control_common, editable_combobox_functions, 0 ); 595 | return 1; 596 | } 597 | 598 | 599 | DECLARE_SETTER( uiRadioButtons, Append, string ) 600 | DECLARE_GETTER( uiRadioButtons, Selected, boolean ) 601 | DECLARE_SETTER( uiRadioButtons, SetSelected, boolean ) 602 | DECLARE_CALLBACK( uiRadioButtons, OnSelected ) 603 | 604 | static luaL_Reg radiobuttons_functions[] = 605 | { 606 | { "Append", l_uiRadioButtonsAppend }, 607 | { "Selected", l_uiRadioButtonsSelected }, 608 | { "SetSelected", l_uiRadioButtonsSetSelected }, 609 | { "OnSelected", l_uiRadioButtonsOnSelected }, 610 | { 0, 0 } 611 | }; 612 | 613 | static int new_radiobuttons( lua_State* L ) 614 | { 615 | object_create( L, uiNewRadioButtons(), uiRadioButtonsSignature, control_common, radiobuttons_functions, 0 ); 616 | return 1; 617 | } 618 | 619 | 620 | static luaL_Reg datetimepicker_functions[] = 621 | { 622 | { 0, 0 } 623 | }; 624 | 625 | static int new_datetimepicker( lua_State* L ) 626 | { 627 | object_create( L, uiNewDateTimePicker(), uiDateTimePickerSignature, control_common, datetimepicker_functions, 0 ); 628 | return 1; 629 | } 630 | 631 | static int new_timepicker( lua_State* L ) 632 | { 633 | object_create( L, uiNewTimePicker(), uiDateTimePickerSignature, control_common, datetimepicker_functions, 0 ); 634 | return 1; 635 | } 636 | 637 | static int new_datepicker( lua_State* L ) 638 | { 639 | object_create( L, uiNewDatePicker(), uiDateTimePickerSignature, control_common, datetimepicker_functions, 0 ); 640 | return 1; 641 | } 642 | 643 | 644 | static int l_uiMultilineEntryText( lua_State* L ) 645 | { 646 | char* s = uiMultilineEntryText( (uiMultilineEntry*) check_object( L, 1, uiMultilineEntrySignature ) ); 647 | lua_pushstring( L, s ); 648 | uiFreeText( s ); 649 | return 1; 650 | } 651 | 652 | static void callback_uiMultilineEntryOnChanged( uiMultilineEntry* c, void* d ) 653 | { 654 | lua_State* L = (lua_State*) d; 655 | if( L ) 656 | { 657 | char* str = uiMultilineEntryText( c ); 658 | lua_pushstring( L, str ); 659 | uiFreeText( str ); 660 | invoke_callback( L, c, callback_OnChanged, 1 ); 661 | } 662 | } 663 | 664 | //DECLARE_GETTER( uiMultilineEntry, Text, string ) 665 | DECLARE_SETTER( uiMultilineEntry, SetText, string ) 666 | DECLARE_SETTER( uiMultilineEntry, Append, string ) 667 | DECLARE_GETTER( uiMultilineEntry, ReadOnly, boolean ) 668 | DECLARE_SETTER( uiMultilineEntry, SetReadOnly, boolean ) 669 | DECLARE_CALLBACK_REGISTER( uiMultilineEntry, uiMultilineEntrySignature, OnChanged ) 670 | 671 | static luaL_Reg multilineentry_functions[] = 672 | { 673 | { "Text", l_uiMultilineEntryText }, 674 | { "SetText", l_uiMultilineEntrySetText }, 675 | { "Append", l_uiMultilineEntryAppend }, 676 | { "ReadOnly", l_uiMultilineEntryReadOnly }, 677 | { "SetReadOnly", l_uiMultilineEntrySetReadOnly }, 678 | { "OnChanged", l_uiMultilineEntryOnChanged }, 679 | { 0, 0 } 680 | }; 681 | 682 | static int new_multilineentry( lua_State* L ) 683 | { 684 | object_create( L, uiNewMultilineEntry(), uiMultilineEntrySignature, control_common, multilineentry_functions, 0 ); 685 | return 1; 686 | } 687 | 688 | static int new_nonwrapping_multilineentry( lua_State* L ) 689 | { 690 | object_create( L, uiNewNonWrappingMultilineEntry(), uiMultilineEntrySignature, control_common, multilineentry_functions, 0 ); 691 | return 1; 692 | } 693 | 694 | 695 | static int l_uiFontButtonFont( lua_State* L ) 696 | { 697 | uiFontButton* fb = check_object( L, 1, uiFontButtonSignature ); 698 | uiDrawTextFont* f = uiFontButtonFont( fb ); 699 | 700 | return draw_new_font( L, f ); 701 | } 702 | 703 | DECLARE_CALLBACK( uiFontButton, OnChanged ) 704 | 705 | static luaL_Reg fontbutton_functions[] = 706 | { 707 | { "Font", l_uiFontButtonFont }, 708 | { "OnChanged", l_uiFontButtonOnChanged }, 709 | { 0, 0 } 710 | }; 711 | 712 | static int new_fontbutton( lua_State* L ) 713 | { 714 | object_create( L, uiNewFontButton(), uiFontButtonSignature, control_common, fontbutton_functions, 0 ); 715 | return 1; 716 | } 717 | 718 | 719 | static int l_uiColorButtonColor( lua_State* L ) 720 | { 721 | double r,g,b,a; 722 | uiColorButtonColor( (uiColorButton*) check_object( L, 1, uiColorButtonSignature ), &r, &g, &b, &a ); 723 | lua_pushnumber( L, r ); 724 | lua_pushnumber( L, g ); 725 | lua_pushnumber( L, b ); 726 | lua_pushnumber( L, a ); 727 | return 4; 728 | } 729 | 730 | static int l_uiColorButtonSetColor( lua_State* L ) 731 | { 732 | uiColorButtonSetColor( (uiColorButton*) check_object( L, 1, uiColorButtonSignature ), 733 | luaL_checknumber( L, 2 ), // r 734 | luaL_checknumber( L, 3 ), // g 735 | luaL_checknumber( L, 4 ), // b 736 | luaL_checknumber( L, 5 ) ); // a 737 | lua_pushvalue( L, 1 ); 738 | return 1; 739 | } 740 | 741 | static void callback_uiColorButtonOnChanged( uiColorButton* c, void* d ) 742 | { 743 | lua_State* L = (lua_State*) d; 744 | if( L ) 745 | { 746 | double r,g,b,a; 747 | uiColorButtonColor( c, &r, &g, &b, &a ); 748 | lua_pushnumber( L, r ); 749 | lua_pushnumber( L, g ); 750 | lua_pushnumber( L, b ); 751 | lua_pushnumber( L, a ); 752 | invoke_callback( L, c, callback_OnChanged, 4 ); 753 | } 754 | } 755 | 756 | DECLARE_CALLBACK_REGISTER( uiColorButton, uiColorButtonSignature, OnChanged ) 757 | 758 | static luaL_Reg colorbutton_functions[] = 759 | { 760 | { "Color", l_uiColorButtonColor }, 761 | { "Colour", l_uiColorButtonColor }, 762 | { "SetColor", l_uiColorButtonSetColor }, 763 | { "SetColour", l_uiColorButtonSetColor }, 764 | { "OnChanged", l_uiColorButtonOnChanged }, 765 | { 0, 0 } 766 | }; 767 | 768 | static int new_colorbutton( lua_State* L ) 769 | { 770 | object_create( L, uiNewColorButton(), uiColorButtonSignature, control_common, colorbutton_functions, 0 ); 771 | return 1; 772 | } 773 | 774 | 775 | int l_uiFormAppend( lua_State* L ) 776 | { 777 | uiFormAppend( 778 | (uiForm*) check_object( L, 1, uiFormSignature ), 779 | luaL_checkstring( L, 2 ), 780 | check_control( L, 3, 0 ), 781 | lua_toboolean( L, 4 ) ); 782 | lua_pushvalue( L, 1 ); 783 | return 1; 784 | } 785 | 786 | DECLARE_GETTER( uiForm, Padded, boolean ) 787 | DECLARE_SETTER( uiForm, SetPadded, boolean ) 788 | DECLARE_SETTER( uiForm, Delete, integer ) 789 | 790 | static luaL_Reg form_functions[] = 791 | { 792 | { "Append", l_uiFormAppend }, 793 | { "Delete", l_uiFormDelete }, 794 | { "Padded", l_uiFormPadded }, 795 | { "SetPadded", l_uiFormSetPadded }, 796 | { 0, 0 } 797 | }; 798 | 799 | static int new_form( lua_State* L ) 800 | { 801 | uiForm* f = uiNewForm(); 802 | object_create( L, f, uiFormSignature, control_common, form_functions, 0 ); 803 | if( lua_isboolean( L, 1 ) ) 804 | { 805 | uiFormSetPadded( f, lua_toboolean( L, 1 ) ); 806 | } 807 | return 1; 808 | } 809 | 810 | 811 | int l_uiGridAppend( lua_State* L ) 812 | { 813 | uiGrid* g = (uiGrid*) check_object( L, 1, uiGridSignature ); 814 | uiControl* c = check_control( L, 2, 0 ); 815 | int left = luaL_checkinteger( L, 3 ); 816 | int top = luaL_checkinteger( L, 4 ); 817 | int xspan = luaL_optinteger( L, 5, 1 ); 818 | int yspan = luaL_optinteger( L, 6, 1 ); 819 | int hexpand = luaL_optinteger( L, 7, 1 ); 820 | uiAlign halign = luaL_optinteger( L, 8, uiAlignFill ); 821 | int vexpand = luaL_optinteger( L, 9, 1 ); 822 | uiAlign valign = luaL_optinteger( L, 10, uiAlignFill ); 823 | uiGridAppend( g, c, left, top, xspan, yspan, hexpand, halign, vexpand, valign ); 824 | lua_pushvalue( L, 1 ); 825 | return 1; 826 | } 827 | 828 | int l_uiGridInsertAt( lua_State* L ) 829 | { 830 | return 1; 831 | } 832 | 833 | DECLARE_GETTER( uiGrid, Padded, boolean ) 834 | DECLARE_SETTER( uiGrid, SetPadded, boolean ) 835 | 836 | static luaL_Reg grid_functions[] = 837 | { 838 | { "Append", l_uiGridAppend }, 839 | { "InsertAt", l_uiGridInsertAt }, 840 | { "Padded", l_uiGridPadded }, 841 | { "SetPadded", l_uiGridSetPadded }, 842 | { 0, 0 } 843 | }; 844 | 845 | static int new_grid( lua_State* L ) 846 | { 847 | uiGrid* g = uiNewGrid(); 848 | object_create( L, g, uiGridSignature, control_common, grid_functions, 0 ); 849 | if( lua_isboolean( L, 1 ) ) 850 | { 851 | uiGridSetPadded( g, lua_toboolean( L, 1 ) ); 852 | } 853 | 854 | return 1; 855 | } 856 | 857 | luaL_Reg controls_functions[] = 858 | { 859 | { "NewWindow", new_window }, 860 | { "NewButton", new_button }, 861 | { "NewHBox", new_hbox }, 862 | { "NewVBox", new_vbox }, 863 | { "NewEntry", new_entry }, 864 | { "NewPasswordEntry", new_password_entry }, 865 | { "NewSearchEntry", new_search_entry }, 866 | { "NewCheckbox", new_checkbox }, 867 | { "NewLabel", new_label }, 868 | { "NewImageBox", new_imagebox }, 869 | { "NewTab", new_tab }, 870 | { "NewGroup", new_group }, 871 | { "NewSpinbox", new_spinbox }, 872 | { "NewProgressBar", new_progress }, 873 | { "NewSlider", new_slider }, 874 | { "NewHSeparator", new_hseparator }, 875 | { "NewVSeparator", new_vseparator }, 876 | { "NewCombobox", new_combobox }, 877 | { "NewEditableCombobox", new_editablecombobox }, 878 | { "NewRadioButtons", new_radiobuttons }, 879 | { "NewDateTimePicker", new_datetimepicker }, 880 | { "NewTimePicker", new_timepicker }, 881 | { "NewDatePicker", new_datepicker }, 882 | { "NewMultilineEntry", new_multilineentry }, 883 | { "NewNonWrappingMultilineEntry", new_nonwrapping_multilineentry }, 884 | { "NewFontButton", new_fontbutton }, 885 | { "NewColorButton", new_colorbutton }, 886 | { "NewColourButton", new_colorbutton }, 887 | { "NewForm", new_form }, 888 | { "NewGrid", new_grid }, 889 | { 0, 0 } 890 | }; 891 | 892 | -------------------------------------------------------------------------------- /controls.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTROLS_H 2 | #define CONTROLS_H 3 | 4 | #include 5 | 6 | extern luaL_Reg controls_functions[]; 7 | 8 | #endif /* CONTROLS_H */ 9 | 10 | -------------------------------------------------------------------------------- /draw.c: -------------------------------------------------------------------------------- 1 | #include "draw.h" 2 | 3 | #include "object.h" 4 | #include "callback.h" 5 | #include "control-common.h" 6 | #include "image.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | // for the meta-object type verification (check_object) 14 | #define uiDrawContextSignature 0xabe45355 15 | #define uiDrawPathSignature 0x99334fe4 16 | #define uiDrawBrushSignature 0x9673443a 17 | #define uiDrawTextFontSignature 0xab233454 18 | #define uiDrawTextLayoutSignature 0xcd345326 19 | #define uiDrawMatrixSignature 0xaef44356 20 | 21 | 22 | #define DRAW_SETFIELD_NUMBER( L, n, name ) \ 23 | lua_pushnumber( L, n ); \ 24 | lua_setfield( L, -2, name ); 25 | 26 | // this is a GCC language extension! 27 | // https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html 28 | #define DRAW_TABLE_NUMBER_OR_DEFAULT( L, idx, name, def ) ({ \ 29 | double v = def; \ 30 | lua_getfield( L, idx, name ); \ 31 | if( lua_isnumber( L, -1 ) ) \ 32 | v = lua_tonumber( L, -1 ); \ 33 | lua_pop( L, 1 ); v; }) 34 | 35 | #define check_context( L, idx ) ( (uiDrawContext*) check_object( L, idx, uiDrawContextSignature ) ) 36 | #define check_path( L, idx ) ( (uiDrawPath*) check_object( L, idx, uiDrawPathSignature ) ) 37 | #define check_font( L, idx ) ( (uiDrawTextFont*) check_object( L, idx, uiDrawTextFontSignature ) ) 38 | #define check_layout( L, idx ) ( (uiDrawTextLayout*) check_object( L, idx, uiDrawTextLayoutSignature ) ) 39 | #define check_brush( L, idx ) ( (uiDrawBrush*) check_object( L, idx, uiDrawBrushSignature ) ) 40 | #define check_matrix( L, idx ) ( (uiDrawMatrix*) check_object( L, idx, uiDrawMatrixSignature ) ) 41 | 42 | 43 | 44 | static int l_draw_stroke( lua_State* L ) 45 | { 46 | struct uiDrawStrokeParams params; 47 | params.Cap = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "cap", uiDrawLineCapFlat ); 48 | params.Join = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "join", uiDrawLineJoinMiter ); 49 | params.Thickness = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "thickness", 1 ); 50 | params.MiterLimit = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "miterlimit", 1 ); 51 | // TODO: support dashes 52 | params.NumDashes = 0; 53 | params.DashPhase = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "dashphase", 0 ); 54 | 55 | uiDrawStroke( check_context( L, 1 ), check_path( L, 2 ), check_brush( L, 3 ), ¶ms ); 56 | lua_pushvalue( L, 1 ); 57 | return 1; 58 | } 59 | 60 | static int l_draw_fill( lua_State* L ) 61 | { 62 | uiDrawFill( check_context( L, 1 ), check_path( L, 2 ), check_brush( L, 3 ) ); 63 | lua_pushvalue( L, 1 ); 64 | return 1; 65 | } 66 | 67 | static int l_draw_transform( lua_State* L ) 68 | { 69 | uiDrawTransform( check_context( L, 1 ), check_matrix( L, 2 ) ); 70 | lua_pushvalue( L, 1 ); 71 | return 1; 72 | } 73 | 74 | static int l_draw_clip( lua_State* L ) 75 | { 76 | uiDrawClip( check_context( L, 1 ), check_path( L, 2 ) ); 77 | lua_pushvalue( L, 1 ); 78 | return 1; 79 | } 80 | 81 | static int l_draw_save( lua_State* L ) 82 | { 83 | uiDrawSave( check_context( L, 1 ) ); 84 | lua_pushvalue( L, 1 ); 85 | return 1; 86 | } 87 | 88 | static int l_draw_restore( lua_State* L ) 89 | { 90 | uiDrawRestore( check_context( L, 1 ) ); 91 | lua_pushvalue( L, 1 ); 92 | return 1; 93 | } 94 | 95 | static int l_draw_text( lua_State* L ) 96 | { 97 | uiDrawText( check_context( L, 1 ), luaL_checknumber( L, 3 ), luaL_checknumber( L, 4 ), check_layout( L, 2 ) ); 98 | lua_pushvalue( L, 1 ); 99 | return 1; 100 | } 101 | 102 | static int l_draw_image( lua_State* L ) 103 | { 104 | uiDrawImage( check_context( L, 1 ), luaL_checknumber( L, 3 ), luaL_checknumber( L, 4 ), check_image( L, 2 ) ); 105 | lua_pushvalue( L, 1 ); 106 | return 1; 107 | } 108 | 109 | static luaL_Reg context_functions[] = 110 | { 111 | { "Stroke", l_draw_stroke }, 112 | { "Fill", l_draw_fill }, 113 | { "Transform", l_draw_transform }, 114 | { "Clip", l_draw_clip }, 115 | { "Save", l_draw_save }, 116 | { "Restore", l_draw_restore }, 117 | { "Text", l_draw_text }, 118 | { "Image", l_draw_image }, 119 | { 0, 0 } 120 | }; 121 | 122 | int draw_new_context( lua_State* L, uiDrawContext* ctx ) 123 | { 124 | object_create( L, ctx, uiDrawContextSignature, context_functions, 0 ); 125 | return 1; 126 | } 127 | 128 | 129 | 130 | static int l_path_new_figure( lua_State* L ) 131 | { 132 | uiDrawPathNewFigure( 133 | (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ), 134 | luaL_checknumber( L, 2 ), 135 | luaL_checknumber( L, 3 ) ); 136 | lua_pushvalue( L, 1 ); 137 | return 1; 138 | } 139 | 140 | static int l_path_new_figure_arc( lua_State* L ) 141 | { 142 | uiDrawPathNewFigureWithArc( 143 | (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ), 144 | luaL_checknumber( L, 2 ), 145 | luaL_checknumber( L, 3 ), 146 | luaL_checknumber( L, 4 ), 147 | luaL_checknumber( L, 5 ), 148 | luaL_checknumber( L, 6 ), 149 | luaL_checknumber( L, 7 ) ); 150 | lua_pushvalue( L, 1 ); 151 | return 1; 152 | } 153 | 154 | static int l_path_lineto( lua_State* L ) 155 | { 156 | uiDrawPathLineTo( 157 | (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ), 158 | luaL_checknumber( L, 2 ), 159 | luaL_checknumber( L, 3 ) ); 160 | lua_pushvalue( L, 1 ); 161 | return 1; 162 | } 163 | 164 | static int l_path_arcto( lua_State* L ) 165 | { 166 | uiDrawPathArcTo( 167 | (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ), 168 | luaL_checknumber( L, 2 ), 169 | luaL_checknumber( L, 3 ), 170 | luaL_checknumber( L, 4 ), 171 | luaL_checknumber( L, 5 ), 172 | luaL_checknumber( L, 6 ), 173 | luaL_checknumber( L, 7 ) ); 174 | lua_pushvalue( L, 1 ); 175 | return 1; 176 | } 177 | 178 | static int l_path_bezierto( lua_State* L ) 179 | { 180 | uiDrawPathBezierTo( 181 | (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ), 182 | luaL_checknumber( L, 2 ), 183 | luaL_checknumber( L, 3 ), 184 | luaL_checknumber( L, 4 ), 185 | luaL_checknumber( L, 5 ), 186 | luaL_checknumber( L, 6 ), 187 | luaL_checknumber( L, 7 ) ); 188 | lua_pushvalue( L, 1 ); 189 | return 1; 190 | } 191 | 192 | static int l_path_add_rectangle( lua_State* L ) 193 | { 194 | uiDrawPathAddRectangle( 195 | (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ), 196 | luaL_checknumber( L, 2 ), 197 | luaL_checknumber( L, 3 ), 198 | luaL_checknumber( L, 4 ), 199 | luaL_checknumber( L, 5 ) ); 200 | lua_pushvalue( L, 1 ); 201 | return 1; 202 | } 203 | 204 | DECLARE_ACTION( uiDrawPath, CloseFigure ) 205 | DECLARE_ACTION( uiDrawPath, End ) 206 | 207 | static int l_path_gc( lua_State* L ) 208 | { 209 | uiDrawFreePath( (uiDrawPath*) check_object( L, 1, uiDrawPathSignature ) ); 210 | return 0; 211 | } 212 | 213 | 214 | static luaL_Reg path_functions[] = 215 | { 216 | { "NewFigure", l_path_new_figure }, 217 | { "NewFigureWithArc", l_path_new_figure_arc }, 218 | { "LineTo", l_path_lineto }, 219 | { "ArcTo", l_path_arcto }, 220 | { "BezierTo", l_path_bezierto }, 221 | { "AddRectangle", l_path_add_rectangle }, 222 | 223 | { "CloseFigure", l_uiDrawPathCloseFigure }, 224 | { "End", l_uiDrawPathEnd }, 225 | 226 | { "__gc", l_path_gc }, 227 | { 0, 0 } 228 | }; 229 | 230 | static int new_path( lua_State* L ) 231 | { 232 | uiDrawPath* path = uiDrawNewPath( luaL_checknumber( L, 1 ) ); 233 | object_create( L, path, uiDrawPathSignature, path_functions, 0 ); 234 | return 1; 235 | } 236 | 237 | 238 | 239 | static int l_brush_rgba( lua_State* L ) 240 | { 241 | uiDrawBrush* brush = check_brush( L, 1 ); 242 | if( brush->Stops ) 243 | { 244 | free( brush->Stops ); 245 | } 246 | memset( brush, 0, sizeof(*brush) ); 247 | 248 | brush->Type = uiDrawBrushTypeSolid; 249 | brush->R = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 2, "r", 0 ); 250 | brush->G = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 2, "g", 0 ); 251 | brush->B = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 2, "b", 0 ); 252 | brush->A = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 2, "a", 1.0 ); 253 | 254 | lua_pushvalue( L, 1 ); 255 | return 1; 256 | } 257 | 258 | static void brush_gradient_common( lua_State* L, uiDrawBrush* brush ) 259 | { 260 | // number of stops 261 | lua_len( L, 3 ); 262 | int n = lua_tonumber( L, -1 ); 263 | lua_pop( L, 1 ); 264 | if( n < 1 ) 265 | { 266 | return; 267 | } 268 | 269 | // get first coordinate (X0,Y0) 270 | lua_pushnumber( L, 1 ); 271 | lua_gettable( L, 2 ); 272 | brush->X0 = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "x", 0 ); 273 | brush->Y0 = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "y", 0 ); 274 | lua_pop( L, 1 ); 275 | 276 | // get second coordinate (X1,Y1) 277 | lua_pushnumber( L, 2 ); 278 | lua_gettable( L, 2 ); 279 | brush->X1 = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "x", 0 ); 280 | brush->Y1 = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "y", 0 ); 281 | lua_pop( L, 1 ); 282 | 283 | // For radial only: Outer Radius 284 | brush->OuterRadius = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 2, "OuterRadius", 0 ); 285 | 286 | brush->Stops = malloc( sizeof(uiDrawBrushGradientStop) * n ); 287 | memset( brush->Stops, 0, sizeof(uiDrawBrushGradientStop) * n ); 288 | brush->NumStops = n; 289 | 290 | for( int i = 0; i < n; ++i ) 291 | { 292 | // get table for gradient stop 293 | lua_pushnumber( L, i + 1 ); 294 | lua_gettable( L, 3 ); 295 | 296 | brush->Stops[ i ].Pos = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "pos", 0 ); 297 | brush->Stops[ i ].R = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "r", 0 ); 298 | brush->Stops[ i ].G = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "g", 0 ); 299 | brush->Stops[ i ].B = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "b", 0 ); 300 | brush->Stops[ i ].A = DRAW_TABLE_NUMBER_OR_DEFAULT( L, -1, "a", 1.0 ); 301 | 302 | lua_pop( L, 1 ); 303 | } 304 | } 305 | 306 | static int l_brush_linear( lua_State* L ) 307 | { 308 | uiDrawBrush* brush = check_brush( L, 1 ); 309 | if( brush->Stops ) 310 | { 311 | free( brush->Stops ); 312 | } 313 | memset( brush, 0, sizeof(*brush) ); 314 | 315 | if( ! lua_istable( L, 2 ) || ! lua_istable( L, 3 ) ) 316 | { 317 | luaL_error( L, "incorrect arguments (should be tables)" ); 318 | } 319 | 320 | brush->Type = uiDrawBrushTypeLinearGradient; 321 | 322 | brush_gradient_common( L, brush ); 323 | 324 | lua_pushvalue( L, 1 ); 325 | return 1; 326 | } 327 | 328 | static int l_brush_radial( lua_State* L ) 329 | { 330 | uiDrawBrush* brush = check_brush( L, 1 ); 331 | if( brush->Stops ) 332 | { 333 | free( brush->Stops ); 334 | } 335 | memset( brush, 0, sizeof(*brush) ); 336 | 337 | brush->Type = uiDrawBrushTypeRadialGradient; 338 | 339 | brush_gradient_common( L, brush ); 340 | 341 | lua_pushvalue( L, 1 ); 342 | return 1; 343 | } 344 | 345 | static int l_brush_gc( lua_State* L ) 346 | { 347 | uiDrawBrush* brush = check_brush( L, 1 ); 348 | if( brush->Stops ) 349 | { 350 | free( brush->Stops ); 351 | } 352 | free( brush ); 353 | return 0; 354 | } 355 | 356 | static luaL_Reg brush_functions[] = 357 | { 358 | { "rgba", l_brush_rgba }, 359 | { "linear", l_brush_linear }, 360 | { "radial", l_brush_radial }, 361 | { "__gc", l_brush_gc }, 362 | { 0, 0 } 363 | }; 364 | 365 | static int new_brush( lua_State* L ) 366 | { 367 | uiDrawBrush* brush = malloc( sizeof(uiDrawBrush) ); 368 | memset( brush, 0, sizeof(*brush) ); 369 | 370 | object_create( L, brush, uiDrawBrushSignature, brush_functions, 0 ); 371 | return 1; 372 | } 373 | 374 | 375 | 376 | // this isnt fully implemented upsteam in libui! 377 | // don't trust it! 378 | static int l_font_describe( lua_State* L ) 379 | { 380 | uiDrawTextFontDescriptor desc; 381 | memset( &desc, 0, sizeof(desc) ); 382 | 383 | uiDrawTextFont* font = check_object( L, 1, uiDrawTextFontSignature ); 384 | uiDrawTextFontDescribe( font, &desc ); 385 | 386 | lua_newtable( L ); 387 | if( desc.Family ) 388 | { 389 | lua_pushstring( L, desc.Family ); 390 | lua_setfield( L, -2, "family" ); 391 | } 392 | lua_pushnumber( L, desc.Size ); 393 | lua_setfield( L, -2, "size" ); 394 | lua_pushnumber( L, desc.Weight ); 395 | lua_setfield( L, -2, "weight" ); 396 | lua_pushnumber( L, desc.Italic ); 397 | lua_setfield( L, -2, "style" ); 398 | lua_pushnumber( L, desc.Stretch ); 399 | lua_setfield( L, -2, "stretch" ); 400 | return 1; 401 | } 402 | 403 | static int l_font_metrics( lua_State* L ) 404 | { 405 | uiDrawTextFontMetrics metrics; 406 | uiDrawTextFont* font = check_object( L, 1, uiDrawTextFontSignature ); 407 | uiDrawTextFontGetMetrics( font, &metrics ); 408 | 409 | lua_newtable( L ); 410 | lua_pushnumber( L, metrics.Ascent ); 411 | lua_setfield( L, -2, "ascent" ); 412 | lua_pushnumber( L, metrics.Descent ); 413 | lua_setfield( L, -2, "descent" ); 414 | lua_pushnumber( L, metrics.Leading ); 415 | lua_setfield( L, -2, "leading" ); 416 | lua_newtable( L ); 417 | lua_pushnumber( L, metrics.UnderlinePos ); 418 | lua_setfield( L, -2, "position" ); 419 | lua_pushnumber( L, metrics.UnderlineThickness ); 420 | lua_setfield( L, -2, "thickness" ); 421 | lua_setfield( L, -2, "underline" ); 422 | return 1; 423 | } 424 | 425 | static int l_font_gc( lua_State* L ) 426 | { 427 | uiDrawFreeTextFont( (uiDrawTextFont*) check_object( L, 1, uiDrawTextFontSignature ) ); 428 | return 0; 429 | } 430 | 431 | static luaL_Reg font_functions[] = 432 | { 433 | { "Describe", l_font_describe }, 434 | { "Metrics", l_font_metrics }, 435 | { "__gc", l_font_gc }, 436 | { 0, 0 } 437 | }; 438 | 439 | int draw_new_font( lua_State* L, uiDrawTextFont* font ) 440 | { 441 | if( font ) 442 | object_create( L, font, uiDrawTextFontSignature, font_functions, 0 ); 443 | else 444 | lua_pushnil( L ); 445 | return 1; 446 | } 447 | 448 | static int new_font( lua_State* L ) 449 | { 450 | uiDrawTextFontDescriptor descriptor; 451 | 452 | descriptor.Size = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 1, "size", 10 ); 453 | descriptor.Weight = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 1, "weight", uiDrawTextWeightNormal ); 454 | descriptor.Italic = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 1, "style", uiDrawTextItalicNormal ); 455 | descriptor.Stretch = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 1, "stretch", uiDrawTextStretchNormal ); 456 | 457 | descriptor.Family = "sans-serif"; 458 | lua_getfield( L, 1, "family" ); 459 | if( lua_isstring( L, -1 ) ) 460 | descriptor.Family = lua_tostring( L, -1 ); 461 | 462 | uiDrawTextFont* font = uiDrawLoadClosestFont( &descriptor ); 463 | 464 | // font family name is now invalid 465 | lua_pop( L, 1 ); 466 | 467 | return draw_new_font( L, font ); 468 | } 469 | 470 | 471 | static int l_layout_set_width( lua_State* L ) 472 | { 473 | uiDrawTextLayoutSetWidth( (uiDrawTextLayout*) check_object( L, 1, uiDrawTextLayoutSignature ), luaL_checknumber( L, 2 ) ); 474 | lua_pushvalue( L, 1 ); 475 | return 1; 476 | } 477 | 478 | static int l_layout_extents( lua_State* L ) 479 | { 480 | double width, height; 481 | uiDrawTextLayoutExtents( (uiDrawTextLayout*) check_object( L, 1, uiDrawTextLayoutSignature ), &width, &height ); 482 | lua_newtable( L ); 483 | lua_pushnumber( L, width ); 484 | lua_setfield( L, -2, "width" ); 485 | lua_pushnumber( L, height ); 486 | lua_setfield( L, -2, "height" ); 487 | return 1; 488 | } 489 | 490 | static int l_layout_set_colour( lua_State* L ) 491 | { 492 | uiDrawTextLayout* layout = check_object( L, 1, uiDrawTextLayoutSignature ); 493 | int startchar = luaL_checknumber( L, 2 ); 494 | int endchar = luaL_checknumber( L, 3 ); 495 | 496 | double r = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "r", 0 ); 497 | double g = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "g", 0 ); 498 | double b = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "b", 0 ); 499 | double a = DRAW_TABLE_NUMBER_OR_DEFAULT( L, 4, "a", 1.0 ); 500 | 501 | uiDrawTextLayoutSetColor( layout, startchar, endchar, r, g, b, a ); 502 | 503 | lua_pushvalue( L, 1 ); 504 | return 1; 505 | } 506 | 507 | static int l_layout_gc( lua_State* L ) 508 | { 509 | uiDrawFreeTextLayout( (uiDrawTextLayout*) check_object( L, 1, uiDrawTextLayoutSignature ) ); 510 | return 0; 511 | } 512 | 513 | static luaL_Reg layout_functions[] = 514 | { 515 | { "SetWidth", l_layout_set_width }, 516 | { "Extents", l_layout_extents }, 517 | { "SetColour", l_layout_set_colour }, 518 | { "SetColor", l_layout_set_colour }, 519 | { "__gc", l_layout_gc }, 520 | { 0, 0 } 521 | }; 522 | 523 | static int new_layout( lua_State* L ) 524 | { 525 | char const* text = luaL_checkstring( L, 1 ); 526 | uiDrawTextFont* font = check_object( L, 2, uiDrawTextFontSignature ); 527 | double width = luaL_checknumber( L, 3 ); 528 | 529 | uiDrawTextLayout* layout = uiDrawNewTextLayout( text, font, width ); 530 | object_create( L, layout, uiDrawTextLayoutSignature, layout_functions, 0 ); 531 | return 1; 532 | } 533 | 534 | 535 | 536 | DECLARE_SETTER_2( uiDrawMatrix, Translate, number, number ) 537 | DECLARE_GETTER( uiDrawMatrix, Invertible, boolean ) 538 | DECLARE_ACTION( uiDrawMatrix, Invert ) 539 | 540 | static int l_matrix_identity( lua_State* L ); 541 | 542 | static int l_matrix_scale( lua_State* L ) 543 | { 544 | uiDrawMatrixScale( check_matrix( L, 1 ), luaL_checknumber( L, 2 ), luaL_checknumber( L, 3 ), luaL_checknumber( L, 4 ), luaL_checknumber( L, 5 ) ); 545 | lua_pushvalue( L, 1 ); 546 | return 1; 547 | } 548 | 549 | static int l_matrix_rotate( lua_State* L ) 550 | { 551 | uiDrawMatrixRotate( check_matrix( L, 1 ), luaL_checknumber( L, 2 ), luaL_checknumber( L, 3 ), luaL_checknumber( L, 4 ) ); 552 | lua_pushvalue( L, 1 ); 553 | return 1; 554 | } 555 | 556 | static int l_matrix_skew( lua_State* L ) 557 | { 558 | uiDrawMatrixSkew( check_matrix( L, 1 ), luaL_checknumber( L, 2 ), luaL_checknumber( L, 3 ), luaL_checknumber( L, 4 ), luaL_checknumber( L, 5 ) ); 559 | lua_pushvalue( L, 1 ); 560 | return 1; 561 | } 562 | 563 | static int l_matrix_multiply( lua_State* L ) 564 | { 565 | uiDrawMatrixMultiply( check_matrix( L, 1 ), check_matrix( L, 2 ) ); 566 | lua_pushvalue( L, 1 ); 567 | return 1; 568 | } 569 | 570 | static int l_matrix_transform_point( lua_State* L ) 571 | { 572 | double x = luaL_checknumber( L, 2 ); 573 | double y = luaL_checknumber( L, 3 ); 574 | uiDrawMatrixTransformPoint( check_matrix( L, 1 ), &x, &y ); 575 | lua_pushnumber( L, x ); 576 | lua_pushnumber( L, y ); 577 | return 2; 578 | } 579 | 580 | static int l_matrix_transform_size( lua_State* L ) 581 | { 582 | double x = luaL_checknumber( L, 2 ); 583 | double y = luaL_checknumber( L, 3 ); 584 | uiDrawMatrixTransformSize( check_matrix( L, 1 ), &x, &y ); 585 | lua_pushnumber( L, x ); 586 | lua_pushnumber( L, y ); 587 | return 2; 588 | } 589 | 590 | static int l_matrix_get( lua_State* L ) 591 | { 592 | uiDrawMatrix* m = check_matrix( L, 1 ); 593 | lua_newtable( L ); 594 | lua_pushnumber( L, 1 ); 595 | lua_newtable( L ); 596 | lua_pushnumber( L, 1 ); 597 | lua_pushnumber( L, m->M11 ); 598 | lua_settable( L, -3 ); 599 | lua_pushnumber( L, 2 ); 600 | lua_pushnumber( L, m->M12 ); 601 | lua_settable( L, -3 ); 602 | lua_settable( L, -3 ); 603 | lua_pushnumber( L, 2 ); 604 | lua_newtable( L ); 605 | lua_pushnumber( L, 1 ); 606 | lua_pushnumber( L, m->M21 ); 607 | lua_settable( L, -3 ); 608 | lua_pushnumber( L, 2 ); 609 | lua_pushnumber( L, m->M22 ); 610 | lua_settable( L, -3 ); 611 | lua_settable( L, -3 ); 612 | lua_pushnumber( L, 3 ); 613 | lua_newtable( L ); 614 | lua_pushnumber( L, 1 ); 615 | lua_pushnumber( L, m->M31 ); 616 | lua_settable( L, -3 ); 617 | lua_pushnumber( L, 2 ); 618 | lua_pushnumber( L, m->M32 ); 619 | lua_settable( L, -3 ); 620 | lua_settable( L, -3 ); 621 | return 1; 622 | } 623 | 624 | static void matrix_set_helper( lua_State* L, uiDrawMatrix* m, int idx ) 625 | { 626 | // get row 0 627 | lua_pushnumber( L, 1 ); 628 | lua_gettable( L, idx); 629 | lua_pushnumber( L, 1 ); 630 | lua_gettable( L, -2 ); 631 | lua_pushnumber( L, 2 ); 632 | lua_gettable( L, -3 ); 633 | m->M11 = lua_tonumber( L, -2 ); 634 | m->M12 = lua_tonumber( L, -1 ); 635 | lua_pop( L, 3 ); 636 | // get row 1 637 | lua_pushnumber( L, 2 ); 638 | lua_gettable( L, idx ); 639 | lua_pushnumber( L, 1 ); 640 | lua_gettable( L, -2 ); 641 | lua_pushnumber( L, 2 ); 642 | lua_gettable( L, -3 ); 643 | m->M21 = lua_tonumber( L, -2 ); 644 | m->M22 = lua_tonumber( L, -1 ); 645 | lua_pop( L, 3 ); 646 | // get row 2 647 | lua_pushnumber( L, 3 ); 648 | lua_gettable( L, idx ); 649 | lua_pushnumber( L, 1 ); 650 | lua_gettable( L, -2 ); 651 | lua_pushnumber( L, 2 ); 652 | lua_gettable( L, -3 ); 653 | m->M31 = lua_tonumber( L, -2 ); 654 | m->M32 = lua_tonumber( L, -1 ); 655 | lua_pop( L, 3 ); 656 | } 657 | 658 | static int l_matrix_set( lua_State* L ) 659 | { 660 | matrix_set_helper( L, check_matrix( L, 1 ), 2 ); 661 | lua_pushvalue( L, 1 ); 662 | return 1; 663 | } 664 | 665 | static int l_matrix_tostring( lua_State* L ) 666 | { 667 | uiDrawMatrix* m = check_matrix( L, 1 ); 668 | lua_pushfstring( L, "((%f,%f),(%f,%f),(%f,%f))", m->M11, m->M12, m->M21, m->M22, m->M31, m->M32 ); 669 | return 1; 670 | } 671 | 672 | static int l_matrix_gc( lua_State* L ) 673 | { 674 | uiDrawMatrix* m = check_matrix( L, 1 ); 675 | free( m ); 676 | return 0; 677 | } 678 | 679 | static luaL_Reg matrix_functions[] = 680 | { 681 | { "Translate", l_uiDrawMatrixTranslate }, 682 | { "Invertible", l_uiDrawMatrixInvertible }, 683 | { "Invert", l_uiDrawMatrixInvert }, 684 | 685 | { "Identity", l_matrix_identity }, 686 | { "Scale", l_matrix_scale }, 687 | { "Rotate", l_matrix_rotate }, 688 | { "Skew", l_matrix_skew }, 689 | { "Multiply", l_matrix_multiply }, 690 | { "TransformPoint", l_matrix_transform_point }, 691 | { "TransformSize", l_matrix_transform_size }, 692 | 693 | { "Get", l_matrix_get }, 694 | { "Set", l_matrix_set }, 695 | 696 | { "__tostring", l_matrix_tostring }, 697 | { "__gc", l_matrix_gc }, 698 | 699 | { 0, 0 } 700 | }; 701 | 702 | static int l_matrix_identity( lua_State* L ) 703 | { 704 | if( is_object( L, 1, uiDrawMatrixSignature ) ) 705 | { 706 | uiDrawMatrixSetIdentity( (uiDrawMatrix*) get_object_unsafe( L, 1 ) ); 707 | lua_pushvalue( L, 1 ); 708 | } 709 | else 710 | { 711 | uiDrawMatrix* m = malloc( sizeof(uiDrawMatrix) ); 712 | uiDrawMatrixSetIdentity( m ); 713 | 714 | object_create( L, m, uiDrawMatrixSignature, matrix_functions, 0 ); 715 | } 716 | 717 | return 1; 718 | } 719 | 720 | static int new_matrix( lua_State* L ) 721 | { 722 | uiDrawMatrix* m = malloc( sizeof(uiDrawMatrix) ); 723 | 724 | // copy 725 | if( is_object( L, 1, uiDrawMatrixSignature ) ) 726 | { 727 | memcpy( m, get_object_unsafe( L, 1 ), sizeof(*m) ); 728 | } 729 | // supplied table with states 730 | else 731 | if( lua_istable( L, 1 ) ) 732 | { 733 | matrix_set_helper( L, m, 1 ); 734 | } 735 | // identity 736 | else 737 | { 738 | uiDrawMatrixSetIdentity( m ); 739 | } 740 | 741 | object_create( L, m, uiDrawMatrixSignature, matrix_functions, 0 ); 742 | return 1; 743 | } 744 | 745 | static int get_font_families( lua_State* L ) 746 | { 747 | lua_newtable( L ); 748 | 749 | uiDrawFontFamilies* families = uiDrawListFontFamilies(); 750 | int n = uiDrawFontFamiliesNumFamilies( families ); 751 | 752 | for( int i = 0; i < n; ++i ) 753 | { 754 | lua_pushnumber( L, i + 1 ); 755 | lua_pushstring( L, uiDrawFontFamiliesFamily( families, i ) ); 756 | lua_settable( L, -3 ); 757 | } 758 | 759 | uiDrawFreeFontFamilies( families ); 760 | 761 | return 1; 762 | } 763 | 764 | static luaL_Reg draw_functions[] = 765 | { 766 | { "Path", new_path }, 767 | { "Brush", new_brush }, 768 | { "TextLayout", new_layout }, 769 | { 0, 0 } 770 | }; 771 | 772 | void draw_init( lua_State* L ) 773 | { 774 | lua_newtable( L ); // Draw 775 | 776 | luaL_setfuncs( L, draw_functions, 0 ); 777 | 778 | lua_newtable( L ); // Draw.Line 779 | lua_newtable( L ); // Draw.Line.Cap 780 | DRAW_SETFIELD_NUMBER( L, uiDrawLineCapFlat, "Flat" ); 781 | DRAW_SETFIELD_NUMBER( L, uiDrawLineCapRound, "Round" ); 782 | DRAW_SETFIELD_NUMBER( L, uiDrawLineCapSquare, "Square" ); 783 | lua_setfield( L, -2, "Cap" ); 784 | 785 | lua_newtable( L ); // Draw.Line.Join 786 | DRAW_SETFIELD_NUMBER( L, uiDrawLineJoinMiter, "Miter" ); 787 | DRAW_SETFIELD_NUMBER( L, uiDrawLineJoinRound, "Round" ); 788 | DRAW_SETFIELD_NUMBER( L, uiDrawLineJoinBevel, "Bevel" ); 789 | lua_setfield( L, -2, "Join" ); 790 | lua_setfield( L, -2, "Line" ); 791 | 792 | lua_newtable( L ); // Draw.FillMode 793 | DRAW_SETFIELD_NUMBER( L, uiDrawFillModeWinding, "Winding" ); 794 | DRAW_SETFIELD_NUMBER( L, uiDrawFillModeAlternate, "Alternate" ); 795 | lua_setfield( L, -2, "FillMode" ); 796 | 797 | lua_pushcfunction( L, new_font ); // Draw.Font 798 | lua_newtable( L ); 799 | lua_pushvalue( L, -1 ); 800 | lua_setfield( L, -2, "__index" ); 801 | lua_pushcfunction( L, get_font_families ); 802 | lua_setfield( L, -2, "Families" ); 803 | lua_newtable( L ); // Draw.Font.Weight 804 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightThin, "Thin" ); 805 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightUltraLight, "UltraLight" ); 806 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightLight, "Light" ); 807 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightBook, "Book" ); 808 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightNormal, "Normal" ); 809 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightMedium, "Medium" ); 810 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightSemiBold, "SemiBold" ); 811 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightBold, "Bold" ); 812 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightUtraBold, "UltraBold" ); 813 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightHeavy, "Heavy" ); 814 | DRAW_SETFIELD_NUMBER( L, uiDrawTextWeightUltraHeavy, "UltraHeavy" ); 815 | lua_setfield( L, -2, "Weight" ); 816 | 817 | lua_newtable( L ); // Draw.Font.Style 818 | DRAW_SETFIELD_NUMBER( L, uiDrawTextItalicNormal, "Normal" ); 819 | DRAW_SETFIELD_NUMBER( L, uiDrawTextItalicOblique, "Oblique" ); 820 | DRAW_SETFIELD_NUMBER( L, uiDrawTextItalicItalic, "Italic" ); 821 | lua_setfield( L, -2, "Style" ); 822 | 823 | lua_newtable( L ); // Draw.Font.Stretch 824 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchUltraCondensed, "UltraCondensed" ); 825 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchExtraCondensed, "ExtraCondensed" ); 826 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchCondensed, "Condensed" ); 827 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchSemiCondensed, "SemiCondensed" ); 828 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchNormal, "Normal" ); 829 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchSemiExpanded, "SemiExpanded" ); 830 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchExpanded, "Expanded" ); 831 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchExtraExpanded, "ExtraExpanded" ); 832 | DRAW_SETFIELD_NUMBER( L, uiDrawTextStretchUltraExpanded, "UltraExpanded" ); 833 | lua_setfield( L, -2, "Stretch" ); 834 | lua_setmetatable( L, -2 ); 835 | lua_setfield( L, -2, "Font" ); 836 | 837 | lua_pushcfunction( L, new_matrix ); 838 | lua_newtable( L ); 839 | lua_pushvalue( L, -1 ); 840 | lua_setfield( L, -2, "__index" ); 841 | lua_pushcfunction( L, l_matrix_identity ); 842 | lua_setfield( L, -2, "Identity" ); 843 | lua_setmetatable( L, -2 ); 844 | lua_setfield( L, -2, "Matrix" ); 845 | 846 | lua_setfield( L, -2, "Draw" ); 847 | } 848 | -------------------------------------------------------------------------------- /draw.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAW_H 2 | #define DRAW_H 3 | 4 | #include 5 | #include 6 | 7 | void draw_init( lua_State* L ); 8 | 9 | int draw_new_context( lua_State* L, uiDrawContext* ctx ); 10 | int draw_new_font( lua_State* L, uiDrawTextFont* font ); 11 | 12 | #endif /* DRAW_H */ 13 | -------------------------------------------------------------------------------- /examples/control-gallery.lua: -------------------------------------------------------------------------------- 1 | local ui = require "libui" 2 | 3 | local menu = ui.NewMenu( "File" ) 4 | menu:AppendItem( "Open" ) 5 | :OnClicked( function( m, w ) 6 | local filename = ui.OpenFile( w ) 7 | w:SetTitle( filename or "" ) 8 | if not filename then 9 | ui.MsgBoxError( w, "No file selected", "Don't be alarmed!" ) 10 | else 11 | ui.MsgBox( w, "File selected", filename ) 12 | end 13 | end ) 14 | menu:AppendItem( "Save" ) 15 | :OnClicked( function( m, w ) 16 | local filename = ui.SaveFile( w ) 17 | if not filename then 18 | ui.MsgBoxError( w, "No file selected", "Don't be alarmed!" ) 19 | else 20 | ui.MsgBox( w, "File selected (don't worry, it's still there)", filename ) 21 | end 22 | end ) 23 | menu:AppendQuitItem() 24 | 25 | 26 | local menu = ui.NewMenu( "Edit" ) 27 | menu:AppendCheckItem( "Checkable Item" ) 28 | menu:AppendSeparator() 29 | menu:AppendItem( "Disabled Item" ):Disable() 30 | menu:AppendPreferencesItem() 31 | 32 | local menu = ui.NewMenu( "Help" ) 33 | menu:AppendItem( "Help" ) 34 | menu:AppendAboutItem() 35 | :OnClicked( function() 36 | local w = ui.NewWindow( "About", 320, 120 ):SetMargined( true ):SetIcon( ui.NewImage( "examples/text-x-lua.png" ) ) 37 | w:SetChild( 38 | ui.NewVBox() 39 | :Append( ui.NewHBox():Append( ui.NewLabel( "LibUI Widget Gallery (Lua)\r\n\r\nAuthor: M. Dombroski" ), true ), true ) 40 | :Append( ui.NewHBox() 41 | :Append( ui.NewHBox(), true ) 42 | :Append( ui.NewButton( "Close" ):OnClicked( function() w:Destroy() end ), true ) 43 | :Append( ui.NewHBox(), true ) ) 44 | ):Show():Center() 45 | end ) 46 | 47 | 48 | local window = ui.NewWindow( "Control Gallery", 640, 480, true ) 49 | :SetIcon( ui.NewImage( "examples/text-x-lua.svg" ) ) 50 | :SetMargined( true ) 51 | window:OnClosing( function() 52 | window:Destroy() 53 | ui.Quit() 54 | end ) 55 | 56 | 57 | -- Basic controls category 58 | 59 | local basic = ui.NewVBox( true ) 60 | basic:Append( ui.NewHBox( true ):Append( ui.NewButton( "Button" ) ):Append( ui.NewCheckbox( "Checkbox" ) ):Append( ui.NewImageBox( ui.NewImage( "examples/text-x-lua.png" ):Resize( 32, 32 ) ) ) ) 61 | basic:Append( ui.NewLabel( "This is a label. Right now, labels can only span one line." ) ) 62 | basic:Append( ui.NewHSeparator() ) 63 | basic:Append( ui.NewGroup( "Entries" ):SetMargined( true ):SetChild( ui.NewForm():SetPadded( true ) 64 | :Append( "Entry", ui.NewEntry() ) 65 | :Append( "Password", ui.NewPasswordEntry() ) 66 | :Append( "Search", ui.NewSearchEntry() ) 67 | :Append( "Multiline", ui.NewMultilineEntry(), true ) 68 | :Append( "Multiline (no wrap)", ui.NewNonWrappingMultilineEntry(), true ) ) ) 69 | 70 | 71 | -- Lists and Choosers category 72 | 73 | local lists = ui.NewHBox( true ) 74 | 75 | local spinbox = ui.NewSpinbox( 0, 100 ) 76 | local slider = ui.NewSlider( 0, 100 ) 77 | local progress = ui.NewProgressBar( 0 ) 78 | spinbox:OnChanged( function( s, v ) slider:SetValue( v ) progress:SetValue( v ) end ) 79 | slider:OnChanged( function( s, v ) spinbox:SetValue( v ) progress:SetValue( v ) end ) 80 | 81 | lists:Append( ui.NewGroup( "Numbers" ):SetMargined( true ):SetChild( ui.NewVBox( true ) 82 | :Append( spinbox ):Append( slider ):Append( progress ) 83 | :Append( ui.NewProgressBar( -1 ) ) ), true ) 84 | lists:Append( ui.NewGroup( "Lists" ):SetMargined( true ):SetChild( ui.NewVBox( true ) 85 | :Append( ui.NewCombobox():Append( "Conbobox Item 1" ):Append( "Combobox Item 2 " ):Append( "Combobox Item 3" ) ) 86 | :Append( ui.NewEditableCombobox():Append( "Editable Item 1" ):Append( "Editable Item 2" ):Append( "Editable Item 3" ) ) 87 | :Append( ui.NewRadioButtons():Append( "Radio Button 1" ):Append( "Radio Button 2" ):Append( "Radio Button 3" ) ) ), true ) 88 | 89 | 90 | -- Choosers category 91 | 92 | local choosers = ui.NewHBox( true ) 93 | choosers:Append( ui.NewVBox( true ) 94 | :Append( ui.NewDatePicker() ) 95 | :Append( ui.NewTimePicker() ) 96 | :Append( ui.NewDateTimePicker() ) 97 | :Append( ui:NewFontButton() ) 98 | :Append( ui:NewColorButton() ) ) 99 | choosers:Append( ui.NewHSeparator() ) 100 | local bopen = ui.NewButton( "Open File" ) 101 | local bsave = ui.NewButton( "Save File" ) 102 | local eopen = ui.NewEntry( "Open File" ):SetReadOnly( true ) 103 | local esave = ui.NewEntry( "Save File" ):SetReadOnly( true ) 104 | bopen:OnClicked( 105 | function( b ) 106 | eopen:SetText( ui.OpenFile( window ) or "(cancelled)" ) 107 | end ) 108 | bsave:OnClicked( 109 | function( b ) 110 | esave:SetText( ui.SaveFile( window ) or "(cancelled)" ) 111 | end ) 112 | choosers:Append( ui.NewVBox( true ):Append( ui.NewGrid( true ) 113 | :Append( bopen, 0, 0, 1, 1, 0 ) 114 | :Append( eopen, 1, 0, 1, 1, 1 ) 115 | :Append( bsave, 0, 1, 1, 1, 0 ) 116 | :Append( esave, 1, 1, 1, 1, 1 ) 117 | :Append( ui.NewGrid( true ) 118 | :Append( ui.NewButton( "Message Box" ):OnClicked( function() ui.MsgBox( window, "This is a normal message box.", "More detailed information can be shown here." ) end ), 0, 0 ) 119 | :Append( ui.NewButton( "Error Box" ):OnClicked( function() ui.MsgBox( window, "This message box describes an error.", "More detailed information can be shown here." ) end ), 1, 0 ), 0, 2, 2, 1, 0, ui.AlignCenter, ui.AlignStart ) ), true ) 120 | 121 | 122 | 123 | local areabox = ui.NewVBox( true ) 124 | local area = ui.NewArea( nil ) 125 | local fbutton = ui.NewFontButton() 126 | area.font = fbutton:Font() 127 | 128 | area.Draw = function( area, dc, rect ) 129 | local path = ui.Draw.Path( ui.Draw.FillMode.Winding ) 130 | path:NewFigure( 10 + rect.x, 10 + rect.y ) 131 | path:LineTo( 10 + rect.x, rect.y + rect.h - 10 ) 132 | path:LineTo( rect.x + rect.w - 10, rect.y + rect.h - 10 ) 133 | path:LineTo( rect.x + rect.w - 10, 10 + rect.y ) 134 | path:CloseFigure() 135 | path:End() 136 | dc:Stroke( path, ui.Draw.Brush():rgba( { g = 1, a = 0.5 } ), { join = ui.Draw.Line.Join.Round, thickness = 20 } ) 137 | dc:Fill( path, ui.Draw.Brush():linear( { { x = 0, y = 0 }, { x = rect.w, y = rect.h } }, { { pos = 0, b = 1, a = 0.5 }, { pos = 1, r = 1, a = 0.5 } } ) ) 138 | 139 | dc:Image( ui.NewImage( "examples/text-x-lua.png" ), 20, 20 ) 140 | 141 | dc:Transform( ui.Draw.Matrix.Identity():Translate( rect.w / 4, rect.h / 4 ) ) 142 | dc:Transform( ui.Draw.Matrix.Identity():Rotate( 0, 0, math.pi / 4 ) ) 143 | dc:Text( ui.Draw.TextLayout( "Hello World", area.font, -1 ):SetColour( 0, 15, {} ), 0, 0 ) 144 | end 145 | fbutton:OnChanged( function( fb ) area.font = fb:Font() area:QueueRedrawAll() end ) 146 | areabox:Append( fbutton ) 147 | areabox:Append( area, true ) 148 | 149 | 150 | local tab = ui.NewTab() 151 | tab:Append( "Basic Controls", basic, true ) 152 | tab:Append( "Numbers and Lists", lists, true ) 153 | tab:Append( "Data Choosers", choosers, true ) 154 | tab:Append( "Area", areabox, true ) 155 | window:SetChild( tab ) 156 | 157 | 158 | ui.ShouldQuit( function() 159 | window:Destroy() 160 | ui.Quit() 161 | end ) 162 | 163 | window:Show() 164 | ui.Main() 165 | -------------------------------------------------------------------------------- /examples/gtk3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdombroski/libui-lua/2a6457de656088e7610b98ce64bed6015995a274/examples/gtk3.png -------------------------------------------------------------------------------- /examples/text-x-lua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdombroski/libui-lua/2a6457de656088e7610b98ce64bed6015995a274/examples/text-x-lua.png -------------------------------------------------------------------------------- /examples/text-x-lua.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdombroski/libui-lua/2a6457de656088e7610b98ce64bed6015995a274/examples/windows.png -------------------------------------------------------------------------------- /image.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include "object.h" 3 | 4 | #include 5 | #include 6 | 7 | #define uiImageSignature 0x45363456 8 | 9 | 10 | static luaL_Reg image_members[]; 11 | 12 | 13 | int is_image( lua_State* L, int index ) 14 | { 15 | return is_object( L, index, uiImageSignature ); 16 | } 17 | 18 | 19 | uiImage* check_image( lua_State* L, int index ) 20 | { 21 | return (uiImage*) check_object( L, index, uiImageSignature ); 22 | } 23 | 24 | 25 | static int l_Load( lua_State* L ) 26 | { 27 | uiImage* i = (uiImage*) check_object( L, 1, uiImageSignature ); 28 | 29 | if( uiImageLoad( i, luaL_checkstring( L, 2 ) ) ) 30 | { 31 | lua_pushvalue( L, 1 ); 32 | return 1; 33 | } 34 | 35 | luaL_error( L, "libui: image could not be loaded." ); 36 | return 0; 37 | } 38 | 39 | static int l_Valid( lua_State* L ) 40 | { 41 | uiImage *i = (uiImage*) check_object( L, 1, uiImageSignature ); 42 | lua_pushboolean( L, uiImageValid( i ) ); 43 | return 1; 44 | } 45 | 46 | static int l_Size( lua_State* L ) 47 | { 48 | uiImage *i = (uiImage*) check_object( L, 1, uiImageSignature ); 49 | int width = -1, height = -1; 50 | uiImageSize( i, &width, &height ); 51 | lua_pushinteger( L, width ); 52 | lua_pushinteger( L, height ); 53 | return 2; 54 | } 55 | 56 | static int l_Resize( lua_State* L ) 57 | { 58 | uiImage *i = (uiImage*) check_object( L, 1, uiImageSignature ); 59 | uiImage *n = uiImageResize( i, luaL_checkinteger( L, 2 ), luaL_checkinteger( L, 3 ) ); 60 | object_create( L, n, uiImageSignature, image_members, 0 ); 61 | return 1; 62 | } 63 | 64 | static int l_Destroy( lua_State* L ) 65 | { 66 | uiImage *i = (uiImage*) check_object( L, 1, uiImageSignature ); 67 | uiImageDestroy( i ); 68 | return 0; 69 | } 70 | 71 | 72 | static luaL_Reg image_members[] = 73 | { 74 | { "Load", l_Load }, 75 | { "Valid", l_Valid }, 76 | { "Size", l_Size }, 77 | { "Resize", l_Resize }, 78 | { "__gc", l_Destroy }, 79 | { 0, 0 } 80 | }; 81 | 82 | int new_image( lua_State* L ) 83 | { 84 | uiImage* maybecopy = 0; 85 | if( lua_isuserdata( L, 1 ) ) 86 | { 87 | int s; 88 | void* p = get_object( L, 1, &s ); 89 | if( s == uiImageSignature ) 90 | { 91 | maybecopy = p; 92 | } 93 | } 94 | 95 | uiImage* i = uiNewImage( maybecopy ); 96 | 97 | if( lua_isstring( L, 1 ) ) 98 | { 99 | uiImageLoad( i, lua_tostring( L, 1 ) ); 100 | } 101 | 102 | object_create( L, i, uiImageSignature, image_members, 0 ); 103 | return 1; 104 | } 105 | 106 | luaL_Reg image_functions[] = 107 | { 108 | { "NewImage", new_image }, 109 | { 0, 0 } 110 | }; 111 | 112 | 113 | -------------------------------------------------------------------------------- /image.h: -------------------------------------------------------------------------------- 1 | #ifndef IMAGE_H 2 | #define IMAGE_H 3 | 4 | #include 5 | #include 6 | 7 | extern luaL_Reg image_functions[]; 8 | 9 | int is_image( lua_State* L, int index ); 10 | uiImage* check_image( lua_State* L, int index ); 11 | 12 | 13 | #endif // IMAGE_H 14 | 15 | -------------------------------------------------------------------------------- /libui-lua-git-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "libui-lua" 2 | version = "git-0" 3 | 4 | description = { 5 | summary = "Lua binding for libui"; 6 | detailed = [[Lua binding for libui: https://github.com/mdombroski/libui-lua]]; 7 | homepage = "https://github.com/mdombroski/libui-lua"; 8 | } 9 | 10 | source = { 11 | url = "git+https://github.com/mdombroski/libui-lua.git"; 12 | } 13 | 14 | dependencies = { 15 | "lua >= 5.1, < 5.4" 16 | } 17 | 18 | external_dependencies = { 19 | UI = { 20 | header = "ui.h"; 21 | library = "ui"; 22 | }; 23 | } 24 | 25 | build = { 26 | type = "builtin", 27 | modules = { 28 | libui = { 29 | sources = { "libui-lua.c", "lua-compat.c", "object.c", "callback.c", "control-common.c", "controls.c", "area.c", "draw.c", "image.c", "menu.c" }; 30 | libraries = "ui"; 31 | incdirs = { 32 | "$(UI_INCDIR)"; 33 | }; 34 | libdirs = { 35 | "$(UI_LIBDIR)"; 36 | }; 37 | }; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /libui-lua.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "object.h" 4 | #include "callback.h" 5 | #include "control-common.h" 6 | #include "menu.h" 7 | #include "controls.h" 8 | #include "image.h" 9 | #include "area.h" 10 | #include "draw.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #ifndef MODULE_API 17 | # ifdef _WIN32 18 | # define MODULE_API __declspec(dllexport) 19 | # else 20 | # define MODULE_API __attribute__((visibility("default"))) 21 | # endif 22 | #endif 23 | 24 | 25 | static uiInitOptions init_options; 26 | 27 | 28 | 29 | static int l_uiMain( lua_State* L ) 30 | { 31 | uiMain(); 32 | return 0; 33 | } 34 | 35 | static int l_uiQuit( lua_State* L ) 36 | { 37 | uiQuit(); 38 | return 0; 39 | } 40 | 41 | typedef struct timeout_data 42 | { 43 | lua_State* L; 44 | } timeout_data; 45 | 46 | static int invoke_timeout( void* data ) 47 | { 48 | timeout_data *td = (timeout_data *) data; 49 | lua_State* L = td->L; 50 | 51 | lua_pushlightuserdata( L, td ); 52 | lua_gettable( L, LUA_REGISTRYINDEX ); 53 | 54 | if (lua_isfunction( L, -1 ) ) 55 | { 56 | lua_call( L, 0, 1 ); 57 | 58 | int status = lua_toboolean( L, -1 ); 59 | lua_pop( L, 1 ); 60 | if (status) 61 | // reschedule 62 | return 1; 63 | } 64 | 65 | // delete timeout data 66 | lua_pushnil( L ); 67 | lua_settable( L, LUA_REGISTRYINDEX ); 68 | free( td ); 69 | 70 | // do not reschedule 71 | return 0; 72 | } 73 | 74 | static int l_uiTimeout( lua_State* L ) 75 | { 76 | int timeout = luaL_checkinteger( L, 1 ); 77 | luaL_checktype( L, 2, LUA_TFUNCTION ); 78 | 79 | timeout_data *data = (timeout_data *) malloc( sizeof(timeout_data) ); 80 | data->L = L; 81 | 82 | // REGISTRY[lightuserdata] = function 83 | lua_pushlightuserdata( L, data ); 84 | lua_pushvalue( L, 2 ); 85 | lua_settable( L, LUA_REGISTRYINDEX ); 86 | 87 | uiTimeout( timeout, invoke_timeout, data ); 88 | 89 | return 0; 90 | } 91 | 92 | static int l_uiQueueMain( lua_State* L ) 93 | { 94 | printf( "STUB uiQueueMain\n" ); 95 | return 0; 96 | } 97 | 98 | static int callback_uiShouldQuit( void* data ) 99 | { 100 | return invoke_callback( (lua_State*) data, &init_options, callback_ShouldQuit, 0 ); 101 | } 102 | 103 | static int l_uiOnShouldQuit( lua_State* L ) 104 | { 105 | register_callback( L, -1, &init_options, callback_ShouldQuit ); 106 | if( lua_isfunction( L, -1 ) ) 107 | uiOnShouldQuit( callback_uiShouldQuit, L ); 108 | 109 | return 0; 110 | } 111 | 112 | 113 | static int openfile( lua_State* L ) 114 | { 115 | char* f = uiOpenFile( (uiWindow*) check_object( L, 1, uiWindowSignature ) ); 116 | if( f ) 117 | { 118 | lua_pushstring( L, f ); 119 | uiFreeText( f ); 120 | } 121 | else 122 | { 123 | lua_pushnil( L ); 124 | } 125 | return 1; 126 | } 127 | 128 | static int savefile( lua_State* L ) 129 | { 130 | char* f = uiSaveFile( (uiWindow*) check_object( L, 1, uiWindowSignature ) ); 131 | if( f ) 132 | { 133 | lua_pushstring( L, f ); 134 | uiFreeText( f ); 135 | } 136 | else 137 | { 138 | lua_pushnil( L ); 139 | } 140 | return 1; 141 | } 142 | 143 | static int msgbox( lua_State* L ) 144 | { 145 | uiWindow* w = (uiWindow*) check_object( L, 1, uiWindowSignature ); 146 | uiMsgBox( w, luaL_checkstring( L, 2 ), luaL_checkstring( L, 3 ) ); 147 | return 0; 148 | } 149 | 150 | static int msgboxerror( lua_State* L ) 151 | { 152 | uiWindow* w = (uiWindow*) check_object( L, 1, uiWindowSignature ); 153 | uiMsgBoxError( w, luaL_checkstring( L, 2 ), luaL_checkstring( L, 3 ) ); 154 | return 0; 155 | } 156 | 157 | luaL_Reg ui_functions[] = 158 | { 159 | { "Main", l_uiMain }, 160 | { "Quit", l_uiQuit }, 161 | { "Timeout", l_uiTimeout }, 162 | { "QueueMain", l_uiQueueMain }, 163 | { "ShouldQuit", l_uiOnShouldQuit }, 164 | 165 | { "OpenFile", openfile }, 166 | { "SaveFile", savefile }, 167 | { "MsgBox", msgbox }, 168 | { "MsgBoxError", msgboxerror }, 169 | 170 | { 0, 0 } 171 | }; 172 | 173 | 174 | MODULE_API int luaopen_libui( lua_State* L ) 175 | { 176 | char const* err; 177 | 178 | memset( &init_options, 0, sizeof(init_options) ); 179 | err = uiInit( &init_options ); 180 | 181 | if( err ) 182 | { 183 | printf( "error\n" ); 184 | uiFreeInitError( err ); 185 | return 0; 186 | } 187 | 188 | luaL_newlib( L, ui_functions ); 189 | luaL_setfuncs( L, image_functions, 0 ); 190 | luaL_setfuncs( L, controls_functions, 0 ); 191 | luaL_setfuncs( L, menu_functions, 0 ); 192 | luaL_setfuncs( L, area_functions, 0 ); 193 | 194 | draw_init( L ); 195 | 196 | // these are the alignment/positioning enums for uiGrid 197 | lua_pushinteger( L, uiAlignFill ); 198 | lua_setfield( L, -2, "AlignFill" ); 199 | lua_pushinteger( L, uiAlignStart ); 200 | lua_setfield( L, -2, "AlignStart" ); 201 | lua_pushinteger( L, uiAlignCenter ); 202 | lua_setfield( L, -2, "AlignCenter" ); 203 | lua_pushinteger( L, uiAlignEnd ); 204 | lua_setfield( L, -2, "AlignEnd" ); 205 | lua_pushinteger( L, uiAtLeading ); 206 | lua_setfield( L, -2, "AtLeading" ); 207 | lua_pushinteger( L, uiAtTop ); 208 | lua_setfield( L, -2, "AtTop" ); 209 | lua_pushinteger( L, uiAtTrailing ); 210 | lua_setfield( L, -2, "AtTrailing" ); 211 | lua_pushinteger( L, uiAtBottom ); 212 | lua_setfield( L, -2, "AtBottom" ); 213 | 214 | return 1; 215 | } 216 | -------------------------------------------------------------------------------- /lua-compat.c: -------------------------------------------------------------------------------- 1 | #include "lua-compat.h" 2 | 3 | // implementing support for old Lua versions 4 | // See https://github.com/keplerproject/lua-compat-5.3/blob/master/c-api/compat-5.3.c 5 | 6 | // Functions not available in Lua 5.1 or 5.2 7 | #if LUA_VERSION_NUM < 503 8 | int lua_isinteger( lua_State *L, int index ) 9 | { 10 | if( lua_type( L, index ) == LUA_TNUMBER ) 11 | { 12 | lua_Number n = lua_tonumber( L, index ); 13 | lua_Integer i = lua_tointeger( L, index ); 14 | if( i == n ) 15 | return 1; 16 | } 17 | return 0; 18 | } 19 | 20 | 21 | static void _reverse ( lua_State *L, int a, int b ) 22 | { 23 | for( ; a < b; ++a, --b ) 24 | { 25 | lua_pushvalue( L, a ); 26 | lua_pushvalue( L, b ); 27 | lua_replace( L, a ); 28 | lua_replace( L, b ); 29 | } 30 | } 31 | 32 | 33 | void lua_rotate( lua_State *L, int idx, int n ) 34 | { 35 | int n_elems = 0; 36 | idx = lua_absindex( L, idx ); 37 | n_elems = lua_gettop( L ) - idx + 1; 38 | if( n < 0 ) 39 | { 40 | n += n_elems; 41 | } 42 | if( n > 0 && n < n_elems ) 43 | { 44 | luaL_checkstack( L, 2, "not enough stack slots available" ); 45 | n = n_elems - n; 46 | _reverse( L, idx, idx + n - 1 ); 47 | _reverse( L, idx + n, idx + n_elems - 1 ); 48 | _reverse( L, idx, idx + n_elems - 1 ); 49 | } 50 | } 51 | #endif 52 | 53 | 54 | // Functions not available in Lua 5.1 55 | #if LUA_VERSION_NUM < 502 56 | int lua_absindex( lua_State *L, int i ) 57 | { 58 | if( i < 0 && i > LUA_REGISTRYINDEX ) 59 | i += lua_gettop( L ) + 1; 60 | return i; 61 | } 62 | 63 | 64 | void lua_len( lua_State *L, int i ) 65 | { 66 | switch( lua_type( L, i ) ) 67 | { 68 | case LUA_TSTRING: 69 | lua_pushnumber( L, (lua_Integer) lua_objlen( L, i ) ); 70 | break; 71 | case LUA_TTABLE: 72 | if( !luaL_callmeta(L, i, "__len" ) ) 73 | lua_pushnumber( L, (lua_Integer) lua_objlen( L, i ) ); 74 | break; 75 | case LUA_TUSERDATA: 76 | if( luaL_callmeta( L, i, "__len" ) ) 77 | break; 78 | /* maybe fall through */ 79 | default: 80 | luaL_error( L, "attempt to get length of a %s value", 81 | lua_typename( L, lua_type( L, i ) ) ); 82 | } 83 | } 84 | 85 | 86 | // copied from Lua 5.3 source code 87 | void luaL_setfuncs( lua_State* L, luaL_Reg* l, int nup ) 88 | { 89 | luaL_checkstack(L, nup, "too many upvalues"); 90 | for (; l->name != NULL; l++) { /* fill the table with given functions */ 91 | int i; 92 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ 93 | lua_pushvalue(L, -nup); 94 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ 95 | lua_setfield(L, -(nup + 2), l->name); 96 | } 97 | lua_pop(L, nup); /* remove upvalues */ 98 | } 99 | #endif 100 | 101 | -------------------------------------------------------------------------------- /lua-compat.h: -------------------------------------------------------------------------------- 1 | #ifndef LUA_COMPAT_H 2 | #define LUA_COMPAT_H 3 | 4 | #include 5 | #include 6 | 7 | // implementing support for old Lua versions 8 | 9 | #if LUA_VERSION_NUM < 501 10 | #error Lua < 5.1 not supported 11 | #endif 12 | 13 | // Functions not available in Lua < 5.3 14 | #if LUA_VERSION_NUM < 503 15 | int lua_isinteger( lua_State* L, int idx ); 16 | void lua_rotate( lua_State* L, int idx, int n ); 17 | #endif 18 | 19 | // Functions not available in Lua < 5.2 20 | #if LUA_VERSION_NUM < 502 21 | int lua_absindex( lua_State *L, int i ); 22 | void lua_len( lua_State* L, int i ); 23 | void luaL_setfuncs( lua_State* L, luaL_Reg* l, int nup ); 24 | 25 | #define luaL_newlib(L,l) \ 26 | (lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1), luaL_setfuncs(L,l,0)) 27 | #endif 28 | 29 | #endif // LUA_COMPAT_H 30 | -------------------------------------------------------------------------------- /menu.c: -------------------------------------------------------------------------------- 1 | #include "menu.h" 2 | #include "object.h" 3 | #include "callback.h" 4 | 5 | #include 6 | 7 | // menus and items are not controls and do not have control signatures 8 | #define uiMenuSignature 0x54665434 9 | #define uiMenuItemSignature 0x295629A5 10 | 11 | 12 | static void callback_uiMenuItemOnClicked( uiMenuItem* i, uiWindow* w, void* d ) 13 | { 14 | lua_State* L = (lua_State*) d; 15 | if( L ) 16 | { 17 | object_copy( L, w ); 18 | invoke_callback( (lua_State*) d, i, callback_OnClicked, 1 ); 19 | } 20 | } 21 | 22 | DECLARE_ACTION( uiMenuItem, Enable ) 23 | DECLARE_ACTION( uiMenuItem, Disable ) 24 | DECLARE_GETTER( uiMenuItem, Checked, boolean ) 25 | DECLARE_SETTER( uiMenuItem, SetChecked, boolean ) 26 | DECLARE_CALLBACK_REGISTER( uiMenuItem, uiMenuItemSignature, OnClicked ) 27 | 28 | static luaL_Reg menuitem_functions[] = 29 | { 30 | { "Enable", l_uiMenuItemEnable }, 31 | { "Disable", l_uiMenuItemDisable }, 32 | { "Checked", l_uiMenuItemChecked }, 33 | { "SetChecked", l_uiMenuItemSetChecked }, 34 | { "OnClicked", l_uiMenuItemOnClicked }, 35 | { 0, 0 } 36 | }; 37 | 38 | 39 | static int l_uiMenuAppendItem( lua_State* L ) 40 | { 41 | uiMenu* m = (uiMenu*) check_object( L, 1, uiMenuSignature ); 42 | uiMenuItem* i = uiMenuAppendItem( m, luaL_checkstring( L, 2 ) ); 43 | object_create( L, i, uiMenuItemSignature, menuitem_functions, 0 ); 44 | return 1; 45 | } 46 | 47 | static int l_uiMenuAppendCheckItem( lua_State* L ) 48 | { 49 | uiMenu* m = (uiMenu*) check_object( L, 1, uiMenuSignature ); 50 | uiMenuItem* i = uiMenuAppendCheckItem( m, luaL_checkstring( L, 2 ) ); 51 | object_create( L, i, uiMenuItemSignature, menuitem_functions, 0 ); 52 | return 1; 53 | } 54 | 55 | static int l_uiMenuAppendQuitItem( lua_State* L ) 56 | { 57 | uiMenu* m = (uiMenu*) check_object( L, 1, uiMenuSignature ); 58 | uiMenuItem* i = uiMenuAppendQuitItem( m ); 59 | object_create( L, i, uiMenuItemSignature, menuitem_functions, 0 ); 60 | return 1; 61 | } 62 | 63 | static int l_uiMenuAppendPreferencesItem( lua_State* L ) 64 | { 65 | uiMenu* m = (uiMenu*) check_object( L, 1, uiMenuSignature ); 66 | uiMenuItem* i = uiMenuAppendPreferencesItem( m ); 67 | object_create( L, i, uiMenuItemSignature, menuitem_functions, 0 ); 68 | return 1; 69 | } 70 | 71 | static int l_uiMenuAppendAboutItem( lua_State* L ) 72 | { 73 | uiMenu* m = (uiMenu*) check_object( L, 1, uiMenuSignature ); 74 | uiMenuItem* i = uiMenuAppendAboutItem( m ); 75 | object_create( L, i, uiMenuItemSignature, menuitem_functions, 0 ); 76 | return 1; 77 | } 78 | 79 | DECLARE_ACTION( uiMenu, AppendSeparator ) 80 | 81 | static luaL_Reg _menu_functions[] = 82 | { 83 | { "AppendItem", l_uiMenuAppendItem }, 84 | { "AppendCheckItem", l_uiMenuAppendCheckItem }, 85 | { "AppendQuitItem", l_uiMenuAppendQuitItem }, 86 | { "AppendPreferencesItem", l_uiMenuAppendPreferencesItem }, 87 | { "AppendAboutItem", l_uiMenuAppendAboutItem }, 88 | { "AppendSeparator", l_uiMenuAppendSeparator }, 89 | { 0, 0 } 90 | }; 91 | 92 | static int new_menu( lua_State* L ) 93 | { 94 | void* m = uiNewMenu( luaL_optlstring( L, 1, "Menu", NULL ) ); 95 | object_create( L, m, uiMenuSignature, _menu_functions, 0 ); 96 | return 1; 97 | } 98 | 99 | 100 | luaL_Reg menu_functions[] = 101 | { 102 | { "NewMenu", new_menu }, 103 | { 0, 0 } 104 | }; 105 | -------------------------------------------------------------------------------- /menu.h: -------------------------------------------------------------------------------- 1 | #ifndef MENU_H 2 | #define MENU_H 3 | 4 | #include 5 | 6 | extern luaL_Reg menu_functions[]; 7 | 8 | #endif /* MENU_H */ 9 | 10 | -------------------------------------------------------------------------------- /object.c: -------------------------------------------------------------------------------- 1 | #include "object.h" 2 | 3 | #include 4 | 5 | 6 | int object_gc( lua_State* L ) 7 | { 8 | if( lua_type( L, 1 ) != LUA_TUSERDATA ) 9 | { 10 | luaL_error( L, "libui not a userdata" ); 11 | return 0; 12 | } 13 | 14 | int object_signature = 0; 15 | 16 | // fetch object signature from its metatable data 17 | lua_getmetatable( L, 1 ); 18 | if( lua_istable( L, -1 ) ) 19 | { 20 | lua_pushstring( L, "__libui_signature" ); 21 | lua_gettable( L, -2 ); 22 | if( lua_isinteger( L, -1 ) ) 23 | { 24 | object_signature = lua_tointeger( L, -1 ); 25 | } 26 | lua_pop( L, 1 ); 27 | } 28 | lua_pop( L, 1 ); 29 | 30 | if( object_signature == 0 ) 31 | { 32 | luaL_error( L, "libui not an object" ); 33 | return 0; 34 | } 35 | // if( object_signature == uiMenuSignature || object_signature == uiMenuItemSignature ) 36 | // { 37 | // can't delete anything from menus 38 | // return 0; 39 | // } 40 | 41 | // TODO maybe one day when libui gets an OnDestroy callback this can be implemented fully. 42 | 43 | return 0; 44 | } 45 | 46 | // NOTE: when calling object_create, the last argument MUST be 0 (just add it on the end) 47 | void* object_create( lua_State* L, void* object, int signature, ... ) 48 | { 49 | // userdata wrapper is a single pointer 50 | void** p = lua_newuserdata( L, sizeof(object) ); 51 | *p = object; 52 | 53 | // create a metatable 54 | lua_newtable( L ); 55 | 56 | // copy control signature to metatable 57 | lua_pushinteger( L, signature ); 58 | lua_setfield( L, -2, "__libui_signature" ); 59 | 60 | // allow objects to override the __gc metamethod 61 | lua_pushcfunction( L, object_gc ); 62 | lua_setfield( L, -2, "__gc" ); 63 | 64 | // variable list of meta functions 65 | va_list ap; 66 | va_start( ap, signature ); 67 | while( 1 ) 68 | { 69 | luaL_Reg* fn = va_arg( ap, luaL_Reg* ); 70 | if( fn ) 71 | luaL_setfuncs( L, fn, 0 ); 72 | else 73 | break; 74 | } 75 | va_end(ap); 76 | 77 | lua_pushvalue( L, -1 ); 78 | lua_setfield( L, -2, "__index" ); 79 | 80 | lua_pushvalue( L, -1 ); 81 | lua_setfield( L, -2, "__newindex" ); 82 | 83 | // create meta data table in registry 84 | lua_pushlightuserdata( L, object ); 85 | lua_newtable( L ); 86 | lua_pushvalue( L, -3 ); 87 | lua_setfield( L, -2, "meta" ); 88 | lua_settable( L, LUA_REGISTRYINDEX ); 89 | 90 | lua_setmetatable( L, -2 ); 91 | 92 | return object; 93 | } 94 | 95 | int object_copy( lua_State* L, void* object ) 96 | { 97 | // retreive meta table from registry 98 | lua_pushlightuserdata( L, object ); 99 | lua_gettable( L, LUA_REGISTRYINDEX ); 100 | 101 | // object not registered, can't continue 102 | if( ! lua_istable( L, -1 ) ) 103 | { 104 | lua_pop( L, 1 ); 105 | return 0; 106 | } 107 | 108 | // get function table, pop previous table 109 | lua_getfield( L, -1, "meta" ); 110 | lua_rotate( L, -2, 1 ); 111 | lua_pop( L, 1 ); 112 | 113 | // meta table not valid, can't continue 114 | if( ! lua_istable( L, -1 ) ) 115 | { 116 | lua_pop( L, 1 ); 117 | return 0; 118 | } 119 | 120 | void** p = lua_newuserdata( L, sizeof(object) ); 121 | *p = object; 122 | 123 | lua_rotate( L, -2, 1 ); 124 | lua_setmetatable( L, -2 ); 125 | 126 | return 1; 127 | } 128 | 129 | 130 | void* get_object( lua_State* L, int idx, int* signature ) 131 | { 132 | if( lua_type( L, idx ) != LUA_TUSERDATA ) 133 | { 134 | luaL_error( L, "libui not a userdata" ); 135 | return 0; 136 | } 137 | 138 | int object_signature = 0; 139 | 140 | // fetch object signature from its metatable data 141 | lua_getmetatable( L, idx ); 142 | if( lua_istable( L, -1 ) ) 143 | { 144 | lua_pushstring( L, "__libui_signature" ); 145 | lua_gettable( L, -2 ); 146 | if( lua_isinteger( L, -1 ) ) 147 | { 148 | object_signature = lua_tointeger( L, -1 ); 149 | } 150 | lua_pop( L, 1 ); 151 | } 152 | lua_pop( L, 1 ); 153 | 154 | void** p = lua_touserdata( L, idx ); 155 | if( p == NULL || *p == NULL ) 156 | { 157 | luaL_error( L, "libui object pointer invalid (NULL)" ); 158 | return 0; 159 | } 160 | 161 | void* o = *p; 162 | 163 | // check object is valid in registry 164 | lua_pushlightuserdata( L, o ); 165 | lua_gettable( L, LUA_REGISTRYINDEX ); 166 | if( lua_isnil( L, -1 ) ) 167 | { 168 | luaL_error( L, "libui object is not valid in registry (it might have been deleted)" ); 169 | return 0; 170 | } 171 | lua_pop( L, 1 ); 172 | 173 | if( signature ) 174 | { 175 | *signature = object_signature; 176 | } 177 | 178 | return o; 179 | } 180 | 181 | void* get_object_unsafe( lua_State* L, int idx ) 182 | { 183 | void** p = lua_touserdata( L, idx ); 184 | return *p; 185 | } 186 | 187 | void* check_object( lua_State* L, int idx, int signature ) 188 | { 189 | int s = 0; 190 | void* o = get_object( L, idx, &s ); 191 | 192 | if( s && s == signature ) 193 | { 194 | return o; 195 | } 196 | 197 | return 0; 198 | } 199 | 200 | 201 | int is_object( lua_State* L, int idx, int signature ) 202 | { 203 | if( lua_type( L, idx ) != LUA_TUSERDATA ) 204 | { 205 | // Not a userdata 206 | return 0; 207 | } 208 | 209 | int object_signature = 0; 210 | 211 | // fetch object signature from its metatable data 212 | lua_getmetatable( L, idx ); 213 | int e = lua_istable( L, -1 ); 214 | if( e ) 215 | { 216 | lua_pushstring( L, "__libui_signature" ); 217 | lua_gettable( L, -2 ); 218 | e = lua_isinteger( L, -1 ); 219 | if( e ) 220 | { 221 | object_signature = lua_tointeger( L, -1 ); 222 | } 223 | lua_pop( L, 1 ); 224 | 225 | if( !e ) 226 | { 227 | // libui object signature not found in meta table 228 | return 0; 229 | } 230 | } 231 | lua_pop( L, 1 ); 232 | 233 | if( !e ) 234 | { 235 | // no metatable present 236 | return 0; 237 | } 238 | 239 | void** p = lua_touserdata( L, idx ); 240 | if( p == NULL || *p == NULL ) 241 | { 242 | // pointer invalid 243 | return 0; 244 | } 245 | 246 | void* o = *p; 247 | 248 | // check object is valid in registry 249 | lua_pushlightuserdata( L, o ); 250 | lua_gettable( L, LUA_REGISTRYINDEX ); 251 | e = lua_isnil( L, -1 ); 252 | lua_pop( L, 1 ); 253 | 254 | if( e ) 255 | { 256 | // libui object is not valid in registry (it might have been deleted) 257 | return 0; 258 | } 259 | 260 | if( signature == 0 || signature == object_signature ) 261 | { 262 | return 1; 263 | } 264 | 265 | // signature mismatch 266 | return 0; 267 | } 268 | 269 | 270 | // get object userdata from registry, with a meta function 271 | void object_retreive_with_function( lua_State* L, void* obj, char const* metafunction ) 272 | { 273 | lua_pushlightuserdata( L, obj ); 274 | lua_gettable( L, LUA_REGISTRYINDEX ); 275 | 276 | // object not registered, can't continue 277 | if( ! lua_istable( L, -1 ) ) 278 | { 279 | lua_pop( L, 1 ); 280 | luaL_error( L, "Object is not registered" ); 281 | } 282 | 283 | // get function table, pop previous table 284 | lua_getfield( L, -1, "meta" ); 285 | lua_rotate( L, -2, 1 ); 286 | lua_pop( L, 1 ); 287 | 288 | // meta table not valid, can't continue 289 | if( ! lua_istable( L, -1 ) ) 290 | { 291 | lua_pop( L, 1 ); 292 | luaL_error( L, "Object meta table invalid" ); 293 | } 294 | 295 | // check that the function is valid in the caller 296 | lua_getfield( L, -1, metafunction ); 297 | 298 | // construct area object for use in function call 299 | lua_rotate( L, -2, 1 ); 300 | void** p = lua_newuserdata( L, sizeof(obj) ); 301 | *p = obj; 302 | lua_rotate( L, -2, 1 ); 303 | lua_setmetatable( L, -2 ); 304 | lua_rotate( L, -2, 1 ); 305 | 306 | // stack is now: function, object 307 | lua_rotate( L, -2, 1 ); 308 | } 309 | -------------------------------------------------------------------------------- /object.h: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_H 2 | #define OBJECT_H 3 | 4 | #include 5 | #include 6 | #include "lua-compat.h" 7 | 8 | // simplifies getters/setters 9 | #define luaL_checkboolean( L, i ) lua_toboolean( L, i ) 10 | typedef int integer; 11 | typedef int boolean; 12 | typedef double number; 13 | 14 | // TODO figure out how to free text in generic getters 15 | 16 | 17 | void* object_create( lua_State* L, void* object, int signature, ... ); 18 | int object_copy( lua_State* L, void* object ); 19 | void* get_object( lua_State* L, int idx, int* signature ); 20 | void* get_object_unsafe( lua_State* L, int idx ); 21 | void* check_object( lua_State* L, int idx, int signature ); 22 | int is_object( lua_State* L, int idx, int signature ); 23 | int object_gc( lua_State* L ); 24 | 25 | // get object userdata from registry, with a meta function 26 | // suitable for use with lua_call() 27 | void object_retreive_with_function( lua_State* L, void* obj, char const* metafunction ); 28 | 29 | 30 | 31 | #define DECLARE_SETTER( typename, action, type ) \ 32 | int l_ ## typename ## action( lua_State* L ) { \ 33 | typename ## action( (typename*) check_object( L, 1, typename ## Signature ), luaL_check ## type ( L, 2 ) ); \ 34 | lua_pushvalue( L, 1 ); \ 35 | return 1; \ 36 | } 37 | 38 | #define DECLARE_GETTER( typename, action, type ) \ 39 | int l_ ## typename ## action( lua_State* L ) { \ 40 | lua_push ## type ( L, typename ## action ( (typename*) check_object( L, 1, typename ## Signature ) ) ); \ 41 | return 1; \ 42 | } 43 | 44 | #define DECLARE_SETTER_2( typename, action, typea, typeb ) \ 45 | int l_ ## typename ## action( lua_State* L ) { \ 46 | typename ## action( (typename*) check_object( L, 1, typename ## Signature ), luaL_check ## typea ( L, 2 ), luaL_check ## typeb ( L, 3 ) ); \ 47 | lua_pushvalue( L, 1 ); \ 48 | return 1; \ 49 | } 50 | 51 | #define DECLARE_GETTER_2( typename, action, typea, typeb ) \ 52 | int l_ ## typename ## action( lua_State* L ) { \ 53 | typea a; \ 54 | typeb b; \ 55 | typename ## action ( (typename*) check_object( L, 1, typename ## Signature ), &a, &b ); \ 56 | lua_push ## typea ( L, a ); \ 57 | lua_push ## typeb ( L, b ); \ 58 | return 1; \ 59 | } 60 | 61 | #define DECLARE_ACTION( typename, action ) \ 62 | int l_ ## typename ## action( lua_State* L ) { \ 63 | typename ## action ( (typename*) check_object( L, 1, typename ## Signature ) ); \ 64 | lua_pushvalue( L, 1 ); \ 65 | return 1; \ 66 | } 67 | 68 | #endif /* OBJECT_H */ 69 | -------------------------------------------------------------------------------- /signatures.h: -------------------------------------------------------------------------------- 1 | // This header is a copy from libui upstream. 2 | // common/controlsigs.h 3 | // 24 april 2016 4 | 5 | #define uiAreaSignature 0x41726561 6 | #define uiBoxSignature 0x426F784C 7 | #define uiButtonSignature 0x42746F6E 8 | #define uiCheckboxSignature 0x43686B62 9 | #define uiColorButtonSignature 0x436F6C42 10 | #define uiComboboxSignature 0x436F6D62 11 | #define uiDateTimePickerSignature 0x44545069 12 | #define uiEditableComboboxSignature 0x45644362 13 | #define uiEntrySignature 0x456E7472 14 | #define uiFontButtonSignature 0x466F6E42 15 | #define uiFormSignature 0x466F726D 16 | #define uiGridSignature 0x47726964 17 | #define uiGroupSignature 0x47727062 18 | #define uiLabelSignature 0x4C61626C 19 | #define uiImageBoxSignature 0x4C616E45 20 | #define uiMultilineEntrySignature 0x4D6C6E45 21 | #define uiProgressBarSignature 0x50426172 22 | #define uiRadioButtonsSignature 0x5264696F 23 | #define uiSeparatorSignature 0x53657061 24 | #define uiSliderSignature 0x536C6964 25 | #define uiSpinboxSignature 0x5370696E 26 | #define uiTabSignature 0x54616273 27 | #define uiWindowSignature 0x57696E64 28 | --------------------------------------------------------------------------------