cross platform gui lib for lua
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

301 lines
8.5 KiB

  1. /* lui.c
  2. *
  3. * lua binding to libui (https://github.com/andlabs/libui)
  4. *
  5. * Gunnar Zötl <gz@tset.de>, 2016
  6. * Released under MIT/X11 license. See file LICENSE for details.
  7. *
  8. * This file is included by lui.c
  9. */
  10. /* menuitem control *******************************************************/
  11. /*** Object
  12. * Name: menuitem
  13. * a single menu item, as returned by the menu:append*() methods. This is
  14. * not a control, so it does not have the standard control methods and
  15. * properties.
  16. */
  17. #define LUI_MENUITEM "lui_menuitem"
  18. #define lui_pushMenuitem(L) lui_pushObject(L, LUI_MENUITEM, 1)
  19. #define lui_checkMenuitem(L, pos) ((lui_object*)luaL_checkudata(L, pos, LUI_MENUITEM))
  20. /*** Property
  21. * Object: menuitem
  22. * Name: text
  23. * the text of the menu item, as passed into menu:append() or menu:appendcheckable().
  24. * The other menu:append*() methods fill this with default names. This is a read-only
  25. * property.
  26. *** Property
  27. * Object: menuitem
  28. * Name: enabled
  29. * true if the menuitem is / should be enabled, false if not. Default is true.
  30. *** Property
  31. * Object: menuitem
  32. * Name: checked
  33. * true if the checkable menu item is / should be checked, false if not.
  34. * Default is false.
  35. *** Property
  36. * Object: menuitem
  37. * Name: onclicked
  38. * a function <code>onclicked(menuitem, window)</code> that is called when
  39. * this menu item is clicked. Note that quit menuitems don't call their
  40. * onclicked handler, and checkable menu items call the handler after the
  41. * checked status has changed.
  42. */
  43. static int lui_menuitem__index(lua_State *L)
  44. {
  45. lui_object *lobj = lui_checkMenuitem(L, 1);
  46. const char *what = luaL_checkstring(L, 2);
  47. if (strcmp(what, "enabled") == 0) {
  48. if (lui_aux_getUservalue(L, 1, "enabled") == LUA_TNIL) {
  49. lua_pop(L, 1);
  50. lua_pushboolean(L, 1);
  51. }
  52. } else if (strcmp(what, "checked") == 0) {
  53. lua_pushboolean(L, uiMenuItemChecked(uiMenuItem(lobj->object)) != 0);
  54. } else if (strcmp(what, "text") == 0) {
  55. lui_aux_getUservalue(L, 1, "text");
  56. } else if (strcmp(what, "onclicked") == 0) {
  57. lui_objectGetHandler(L, "onclicked");
  58. } else {
  59. return lui_utility__index(L);
  60. }
  61. return 1;
  62. }
  63. static int lui_menuitem__newindex(lua_State *L)
  64. {
  65. lui_object *lobj = lui_checkMenuitem(L, 1);
  66. const char *what = luaL_checkstring(L, 2);
  67. if (strcmp(what, "enabled") == 0) {
  68. int enabled = lua_toboolean(L, 3);
  69. if (enabled) {
  70. uiMenuItemEnable(uiMenuItem(lobj->object));
  71. } else {
  72. uiMenuItemDisable(uiMenuItem(lobj->object));
  73. }
  74. lui_aux_setUservalue(L, 1, "enabled", enabled);
  75. } else if (strcmp(what, "checked") == 0) {
  76. int checked = lua_toboolean(L, 3);
  77. uiMenuItemSetChecked(uiMenuItem(lobj->object), checked);
  78. } else if (strcmp(what, "onclicked") == 0) {
  79. lui_objectSetHandler(L, "onclicked", 3);
  80. } else {
  81. return lui_multilineEntry__newindex(L);
  82. }
  83. return 0;
  84. }
  85. static int lui_menuitem__gc(lua_State *L)
  86. {
  87. lui_object *lobj = lui_checkMenuitem(L, 1);
  88. lobj->object = 0;
  89. /* nothing else to do here */
  90. return 0;
  91. }
  92. static void lui_menuitemOnClickedCallback(uiMenuItem *mi, uiWindow *win, void *data)
  93. {
  94. lua_State *L = (lua_State*) data;
  95. int top = lua_gettop(L);
  96. lui_findObject(L, uiControl(win));
  97. lui_objectHandlerCallback(L, uiControl(mi), "onclicked", top + 1, 1, 0);
  98. lua_settop(L, top);
  99. }
  100. static int lui_wrapMenuItem(lua_State *L, uiMenuItem *mi, const char *text, int nohandler)
  101. {
  102. lui_object *lobj = lui_pushMenuitem(L);
  103. lobj->object = mi;
  104. lua_pushstring(L, text);
  105. lui_aux_setUservalue(L, lua_gettop(L) - 1, "text", lua_gettop(L));
  106. lua_pop(L, 1);
  107. if (nohandler == 0) {
  108. uiMenuItemOnClicked(mi, lui_menuitemOnClickedCallback, L);
  109. lui_registerObject(L, -1);
  110. }
  111. return 1;
  112. }
  113. /* metamethods for menuitem */
  114. static const luaL_Reg lui_menuitem_meta[] = {
  115. {"__index", lui_menuitem__index},
  116. {"__newindex", lui_menuitem__newindex},
  117. {"__gc", lui_menuitem__gc},
  118. {0, 0}
  119. };
  120. /* menu control ***********************************************************/
  121. /*** Object
  122. * Name: menu
  123. * a menu for a window. All menus must be created before the window they
  124. * should be attached to. Once a window with menus has been created, you
  125. * can not create any more menus for other windows, and can safely drop the
  126. * reference to any created lui.menu's. This is not a control, so it does
  127. * not have the standard control methods and properties.
  128. */
  129. #define LUI_MENU "lui_menu"
  130. #define lui_pushMenu(L) lui_pushObject(L, LUI_MENU, 1)
  131. #define lui_checkMenu(L, pos) ((lui_object*)luaL_checkudata(L, pos, LUI_MENU))
  132. static int lui_menu__gc(lua_State *L)
  133. {
  134. lui_object *lobj = lui_checkMenu(L, 1);
  135. lobj->object = 0;
  136. return 0;
  137. }
  138. /*** Method
  139. * Object: menu
  140. * Name: append
  141. * Signature: menuitem = menu:append(text, menuitemproperties = nil)
  142. * append a standard item to a menu.
  143. */
  144. static int lui_menuAppend(lua_State *L)
  145. {
  146. lui_object *lobj = lui_checkMenu(L, 1);
  147. const char *name = luaL_checkstring(L, 2);
  148. int hastable = lui_aux_istable(L, 3);
  149. uiMenuItem *mi = uiMenuAppendItem(uiMenu(lobj->object), name);
  150. int res = lui_wrapMenuItem(L, mi, name, 0);
  151. if (hastable) { lui_aux_setFieldsFromTable(L, lua_gettop(L), 3); }
  152. return res;
  153. }
  154. /*** Method
  155. * Object: menu
  156. * Name: appendcheckable
  157. * Signature: menuitem = menu:appendcheckable(text, menuitemproperties = nil)
  158. * append a checkable item to a menu. Default status is unchecked.
  159. */
  160. static int lui_menuAppendCheckable(lua_State *L)
  161. {
  162. lui_object *lobj = lui_checkMenu(L, 1);
  163. const char *name = luaL_checkstring(L, 2);
  164. int hastable = lui_aux_istable(L, 3);
  165. uiMenuItem *mi = uiMenuAppendCheckItem(uiMenu(lobj->object), name);
  166. int res = lui_wrapMenuItem(L, mi, name, 0);
  167. if (hastable) { lui_aux_setFieldsFromTable(L, lua_gettop(L), 3); }
  168. return res;
  169. }
  170. /*** Method
  171. * Object: menu
  172. * Name: appendquit
  173. * Signature: menuitem = menu:appendquit(menuitemproperties = nil)
  174. * append a quit item to a menu. The text property for this item will be
  175. * "quit". quit menu items can not have an onclicked handler
  176. */
  177. static int lui_menuAppendQuit(lua_State *L)
  178. {
  179. lui_object *lobj = lui_checkMenu(L, 1);
  180. int hastable = lui_aux_istable(L, 2);
  181. uiMenuItem *mi = uiMenuAppendQuitItem(uiMenu(lobj->object));
  182. int res = lui_wrapMenuItem(L, mi, "quit", 1);
  183. if (hastable) { lui_aux_setFieldsFromTable(L, lua_gettop(L), 2); }
  184. return res;
  185. }
  186. /*** Method
  187. * Object: menu
  188. * Name: appendpreferences
  189. * Signature: menuitem = menu:appendpreferences(menuitemproperties = nil)
  190. * append a preferences item to a menu. The text property for this item will
  191. * be "preferences".
  192. */
  193. static int lui_menuAppendPreferences(lua_State *L)
  194. {
  195. lui_object *lobj = lui_checkMenu(L, 1);
  196. int hastable = lui_aux_istable(L, 2);
  197. uiMenuItem *mi = uiMenuAppendPreferencesItem(uiMenu(lobj->object));
  198. int res = lui_wrapMenuItem(L, mi, "preferences", 0);
  199. if (hastable) { lui_aux_setFieldsFromTable(L, lua_gettop(L), 2); }
  200. return res;
  201. }
  202. /*** Method
  203. * Object: menu
  204. * Name: appendabout
  205. * Signature: menuitem = menu:appendabout(menuitemproperties = nil)
  206. * append an about item to a menu. The text property for this item will be
  207. * "about".
  208. */
  209. static int lui_menuAppendAbout(lua_State *L)
  210. {
  211. lui_object *lobj = lui_checkMenu(L, 1);
  212. int hastable = lui_aux_istable(L, 2);
  213. uiMenuItem *mi = uiMenuAppendAboutItem(uiMenu(lobj->object));
  214. int res = lui_wrapMenuItem(L, mi, "about", 0);
  215. if (hastable) { lui_aux_setFieldsFromTable(L, lua_gettop(L), 2); }
  216. return res;
  217. }
  218. /*** Method
  219. * Object: menu
  220. * Name: appendseparator
  221. * Signature: menuitem = menu:appendseparator()
  222. * append a separator to a menu.
  223. */
  224. static int lui_menuAppendSeparator(lua_State *L)
  225. {
  226. lui_object *lobj = lui_checkMenu(L, 1);
  227. uiMenuAppendSeparator(uiMenu(lobj->object));
  228. return 0;
  229. }
  230. /*** Constructor
  231. * Object: menu
  232. * Name: menu
  233. * Signature: menu = lui.menu(title)
  234. * create a new menu with title.
  235. */
  236. static int lui_newMenu(lua_State *L)
  237. {
  238. const char *title = luaL_checkstring(L, 1);
  239. lui_object *lobj = lui_pushMenu(L);
  240. lobj->object = uiNewMenu(title);
  241. return 1;
  242. }
  243. /* metamethods for menus */
  244. static const luaL_Reg lui_menu_meta[] = {
  245. {"__gc", lui_menu__gc},
  246. {0, 0}
  247. };
  248. /* methods for menus */
  249. static const luaL_Reg lui_menu_methods[] = {
  250. {"append", lui_menuAppend},
  251. {"appendcheckable", lui_menuAppendCheckable},
  252. {"appendquit", lui_menuAppendQuit},
  253. {"appendpreferences", lui_menuAppendPreferences},
  254. {"appendabout", lui_menuAppendAbout},
  255. {"appendseparator", lui_menuAppendSeparator},
  256. {0, 0}
  257. };
  258. /* menu function list table
  259. */
  260. static const struct luaL_Reg lui_menu_funcs [] ={
  261. {"menu", lui_newMenu},
  262. {0, 0}
  263. };
  264. static int lui_init_menu(lua_State *L)
  265. {
  266. luaL_setfuncs(L, lui_menu_funcs, 0);
  267. /* these are not controls! */
  268. lui_add_utility_type(L, LUI_MENUITEM, 0, lui_menuitem_meta);
  269. lui_add_utility_type(L, LUI_MENU, lui_menu_methods, lui_menu_meta);
  270. return 1;
  271. }