/** \file * \brief IUP binding for Lua 5. * * See Copyright Notice in "iup.h" */ #include #include #include #include "iup.h" #include "iup_str.h" #include "iup_object.h" #include #include #include "iuplua.h" #include "il.h" static int CopyUserData2String(lua_State *L) { void* udata = lua_touserdata(L, 1); size_t size = luaL_checkinteger(L, 2); char* str = malloc(size); memcpy(str, udata, size); /* buffer must contain the terminator */ lua_pushlstring(L, str, size - 1); /* len */ free(str); return 1; } static int CopyString2UserData(lua_State *L) { size_t len; const char* str = luaL_checklstring(L, 1, &len); void* udata = lua_touserdata(L, 2); size_t size = luaL_checkinteger(L, 3); if (len >= size) len = size-1; memcpy(udata, str, len); ((char*)udata)[len] = 0; return 0; } static int StringCompare(lua_State *L) { const char* str1 = luaL_optstring(L, 1, NULL); const char* str2 = luaL_optstring(L, 2, NULL); int casesensitive = (int)luaL_optinteger(L, 3, 0); int lexicographic = (int)luaL_optinteger(L, 4, 1); int ret = IupStringCompare(str1, str2, casesensitive, lexicographic); lua_pushinteger(L, ret); return 1; } static int StringChangeCase(lua_State *L) { int utf8 = IupGetInt(NULL, "UTF8MODE"); const char* str = luaL_checkstring(L, 1); char* dst_str = iupStrDup(str); const char* flag = luaL_checkstring(L, 2); int case_flag = IUP_CASE_UPPER; if (iupStrEqualNoCase(flag, "UPPER")) case_flag = IUP_CASE_UPPER; else if (iupStrEqualNoCase(flag, "LOWER")) case_flag = IUP_CASE_LOWER; else if (iupStrEqualNoCase(flag, "TOGGLE")) case_flag = IUP_CASE_TOGGLE; else if (iupStrEqualNoCase(flag, "TITLE")) case_flag = IUP_CASE_TITLE; iupStrChangeCase(dst_str, str, case_flag, utf8); lua_pushstring(L, dst_str); free(dst_str); return 1; } /******************************* Error Handling *****************************************/ static int show_error_continue_action(Ihandle* ih) { (void)ih; return IUP_CLOSE; } static int show_error_exit_action(Ihandle* ih) { if (ih) /* just to avoid a warning at return */ exit(EXIT_FAILURE); return IUP_DEFAULT; } static int show_error_copy_action(Ihandle* ih) { Ihandle* multi_text = IupGetDialogChild(ih, "TEXT"); IupSetAttribute(multi_text, "SELECTION", "ALL"); IupSetAttribute(multi_text, "CLIPBOARD", "COPY"); return IUP_DEFAULT; } IUPLUA_API void iuplua_show_error_message(const char *pname, const char* msg) { Ihandle *multi_text, *lbl, *copy, *button, *box, *dlg, *abort, *buttonbox; char* value = IupGetGlobal("LUA_ERROR_LABEL"); if (!pname) pname = "_@IUP_ERROR"; lbl = IupLabel("_@IUP_LUAERROR"); IupSetAttribute(lbl, "EXPAND", "HORIZONTAL"); if (value) IupSetStrAttribute(lbl, "TITLE", value); copy = IupButton("_@IUP_COPY", NULL); IupSetStrAttribute(copy, "TIP", "_@IUP_COPYTOCLIPBOARD"); IupSetStrAttribute(copy, "PADDING", IupGetGlobal("DEFAULTBUTTONPADDING")); IupSetCallback(copy, "ACTION", show_error_copy_action); button = IupButton("_@IUP_CONTINUE", NULL); IupSetStrAttribute(button, "PADDING", IupGetGlobal("DEFAULTBUTTONPADDING")); IupSetCallback(button, "ACTION", show_error_continue_action); abort = IupButton("_@IUP_EXIT", NULL); IupSetStrAttribute(abort, "PADDING", IupGetGlobal("DEFAULTBUTTONPADDING")); IupSetCallback(abort, "ACTION", show_error_exit_action); multi_text = IupMultiLine(NULL); IupSetAttribute(multi_text, "EXPAND", "YES"); IupSetAttribute(multi_text, "READONLY", "YES"); IupSetAttribute(multi_text, "FONT", "Courier, 12"); IupSetAttribute(multi_text, "VISIBLELINES", "10"); IupSetAttribute(multi_text, "VISIBLECOLUMNS", "50"); IupSetAttribute(multi_text, "NAME", "TEXT"); IupSetStrAttribute(multi_text, "VALUE", msg); buttonbox = IupHbox(copy, button, abort, NULL); IupSetAttribute(buttonbox, "GAP", "50"); IupSetAttribute(IupNormalizer(button, abort, NULL), "NORMALIZE", "HORIZONTAL"); box = IupVbox(lbl, multi_text, buttonbox, NULL); IupSetAttribute(box, "ALIGNMENT", "ACENTER"); IupSetAttribute(box, "NMARGIN", "10x10"); IupSetAttribute(box, "GAP", "10"); dlg = IupDialog(box); IupSetStrAttribute(dlg, "TITLE", pname); IupSetAttribute(dlg, "MINBOX", "NO"); IupSetAttribute(dlg, "MAXBOX", "NO"); IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON")); IupSetAttributeHandle(dlg, "DEFAULTESC", button); IupSetAttributeHandle(dlg, "DEFAULTENTER", button); IupSetAttributeHandle(dlg, "STARTFOCUS", button); IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT); IupDestroy(dlg); } static int il_error_message(lua_State *L) { const char* msg = lua_tostring(L, 1); iuplua_show_error_message(NULL, msg); return 0; } static void show_error(lua_State *L, const char *msg) { iuplua_push_name(L, "_ERRORMESSAGE"); if (lua_isnil(L, -1)) { /* Panic mode */ iuplua_show_error_message(NULL, msg); return; } lua_pushstring(L, msg); lua_call(L, 1, 0); /* iup._ERRORMESSAGE(msg) */ } /**********************************************************/ /* report, traceback and docall were adapted from "lua.c" */ static int report (lua_State *L, int status) { /* if there was an erro, and there is an error message on the stack */ if (status != LUA_OK && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error with no message)"; show_error(L, msg); lua_pop(L, 1); /* remove message */ } return status; } #if LUA_VERSION_NUM > 501 #if LUA_VERSION_NUM > 502 static int traceback (lua_State *L) { const char *msg = lua_tostring(L, 1); if (msg == NULL) { /* is error object not a string? */ if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ return 1; /* that is the message */ else msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1)); } luaL_traceback(L, L, msg, 1); /* append a standard traceback */ return 1; /* return the traceback */ } #else static int traceback(lua_State *L) { const char *msg = lua_tostring(L, 1); if (msg) luaL_traceback(L, L, msg, 1); else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ lua_pushliteral(L, "(no error message)"); } return 1; } #endif #else static int traceback(lua_State *L) { if (!lua_isstring(L, 1)) /* 'message' not a string? */ return 1; /* keep it intact */ lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ return 1; } #endif static void push_tracefunc(lua_State *L) { iuplua_get_env(L); lua_pushstring(L, "_TRACEBACK"); lua_gettable(L, -2); lua_remove(L, -2); /* remove global table from stack */ if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_pushcfunction(L, traceback); /* push traceback function */ } } static int docall (lua_State *L, int narg, int nret) { int status; int base = lua_gettop(L) - narg; /* function index */ push_tracefunc(L); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ status = lua_pcall(L, narg, nret, base); lua_remove(L, base); /* remove traceback function */ /* force a complete garbage collection in case of errors */ if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } /*************************************/ /* Utilities */ IUPLUA_SDK_API void iuplua_push_name(lua_State *L, const char* name) { /* push iup.name in stack */ iuplua_get_env(L); lua_pushstring(L, name); lua_gettable(L, -2); lua_remove(L, -2); /* remove global table from stack */ } IUPLUA_API int iuplua_dofile(lua_State *L, const char *filename) { int status = luaL_loadfile(L, filename); if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); else if (status == LUA_ERRFILE) { char *dir = getenv("IUPLUA_DIR"); if (dir) { char* full_name = iupStrFileMakeFileName(dir, filename); if (full_name) { /* remove the error string from the stack, and try again */ lua_remove(L, -1); status = luaL_loadfile(L, full_name); free(full_name); if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); } } } return report(L, status); } IUPLUA_API int iuplua_dostring(lua_State *L, const char *s, const char *chunk_name) { int status = luaL_loadbuffer(L, s, strlen(s), chunk_name); if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); return report(L, status); } IUPLUA_API int iuplua_dobuffer(lua_State *L, const char *s, int len, const char *chunk_name) { int status = luaL_loadbuffer(L, s, len, chunk_name); if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); return report(L, status); } static int il_dofile(lua_State *L) { int old_top = lua_gettop(L); const char* filename = luaL_checkstring(L, 1); int status = iuplua_dofile(L, filename); if (status == LUA_OK) { int top = lua_gettop(L); return top - old_top; } else return 0; } static int il_dostring(lua_State *L) { int old_top = lua_gettop(L); size_t size; const char* str = luaL_checklstring(L, 1, &size); int status = iuplua_dobuffer(L, str, (int)size, "=iup.dostring"); if (status == LUA_OK) { int top = lua_gettop(L); return top - old_top; } else return 0; } IUPLUA_SDK_API Ihandle *iuplua_checkihandleornil(lua_State *L, int pos) { if (lua_isnoneornil(L, pos)) return NULL; else return iuplua_checkihandle(L, pos); } IUPLUA_API int iuplua_isihandle(lua_State *L, int pos) { int ret = 0; if (lua_getmetatable(L, pos)) /* t2 = metatable(stack(pos)) */ { /* TODO: luaL_getmetatable(L, "iupHandle"); */ lua_pushstring(L, "iupHandle"); lua_gettable(L, LUA_REGISTRYINDEX); /* t = registry["iupHandle"] */ if (lua_rawequal(L, -2, -1)) /* check (t2==t)? */ ret = 1; lua_pop(L, 2); /* Pop registry["iuphandle"] and the metatable */ } return ret; } IUPLUA_API Ihandle* iuplua_checkihandle(lua_State *L, int pos) { Ihandle* *ih = (Ihandle**)luaL_checkudata(L, pos, "iupHandle"); if (!(*ih)) luaL_argerror(L, pos, "destroyed iupHandle"); if (!iupObjectCheck(*ih)) luaL_argerror(L, pos, "invalid Lua object, destroyed iupHandle in C but not in Lua"); return *ih; } #if 0 Ihandle* iuplua_checkihandle_OLD(lua_State *L, int pos) { Ihandle* ih = NULL; if (lua_getmetatable(L, pos)) /* t2 = metatable(stack(pos)) */ { /* TODO: luaL_getmetatable(L, "iupHandle"); */ lua_pushstring(L, "iupHandle"); lua_gettable(L, LUA_REGISTRYINDEX); /* t = registry["iupHandle"] */ if (lua_rawequal(L, -2, -1)) /* check (t2==t)? */ ih = *(Ihandle**)lua_touserdata(L, pos); lua_pop(L, 2); /* Pop registry["iupHandle"] and the metatable */ } if (!ih) { const char *msg = lua_pushfstring(L, "iupHandle expected, got %s", luaL_typename(L, pos)); luaL_argerror(L, pos, msg); } return ih; } #endif IUPLUA_SDK_API void iuplua_pushihandle_raw(lua_State *L, Ihandle *ih) { if (ih) { Ihandle** new_pointer = (Ihandle**)lua_newuserdata(L, sizeof(Ihandle*)); *new_pointer = ih; } else lua_pushnil(L); } IUPLUA_API void iuplua_pushihandle(lua_State *L, Ihandle *ih) { if (ih) { char* sref = IupGetAttribute(ih, "_IUPLUA_WIDGET_TABLE_REF"); if (!sref) { /* was not created in Lua */ iuplua_plugstate(L, ih); /* push iup.RegisterHandle */ iuplua_push_name(L, "RegisterHandle"); iuplua_pushihandle_raw(L, ih); lua_pushstring(L, IupGetClassName(ih)); lua_call(L, 2, 1); /* iup.RegisterHandle(ih, type) */ } else { /* already created in Lua */ iuplua_pushihandle_raw(L, ih); /* TODO: luaL_getmetatable(L, "iupHandle"); */ lua_pushstring(L, "iupHandle"); lua_gettable(L, LUA_REGISTRYINDEX); /* t = registry["iupHandle"] */ lua_setmetatable(L, -2); /* metatable(ih) = t */ } } else lua_pushnil(L); } static int il_destroy_cb(Ihandle* ih) { /* called from IupDestroy. */ char* sref = IupGetAttribute(ih, "_IUPLUA_WIDGET_TABLE_REF"); if (sref) { lua_State *L = iuplua_getstate(ih); int ref = atoi(sref); /* removes the Ihandle* reference from the lua object */ /* widget.ihandle = nil */ lua_rawgeti(L, LUA_REGISTRYINDEX, ref); /* push object */ lua_pushstring(L, "ihandle"); lua_pushnil(L); lua_settable(L, -3); lua_pop(L, 1); /* removes the association of the Ihandle* with the lua object */ luaL_unref(L, LUA_REGISTRYINDEX, ref); /* this is the complement of SetWidget */ IupSetAttribute(ih, "_IUPLUA_WIDGET_TABLE_REF", NULL); sref = IupGetAttribute(ih, "_IUPLUA_STATE_THREAD"); if (sref) { ref = atoi(sref); luaL_unref(L, LUA_REGISTRYINDEX, ref); IupSetAttribute(ih, "_IUPLUA_STATE_THREAD", NULL); } IupSetCallback(ih, "LDESTROY_CB", NULL); } return IUP_DEFAULT; } IUPLUA_SDK_API char** iuplua_checkstring_array(lua_State *L, int pos, int n) { int i; char **v; luaL_checktype(L, pos, LUA_TTABLE); if (n == -1) n = iuplua_getn(L, pos); else if (n != iuplua_getn(L, pos)) luaL_argerror(L, pos, "Invalid number of elements (n!=count)."); if (n<=0) luaL_argerror(L, pos, "Invalid number of elements (n<=0)."); v = (char **) malloc (n*sizeof(char *)); for(i=1; i<=n; i++) { lua_pushinteger(L,i); lua_gettable(L,pos); v[i-1] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } return v; } IUPLUA_SDK_API int* iuplua_checkint_array(lua_State *L, int pos, int n) { int i; int *v; luaL_checktype(L, pos, LUA_TTABLE); if (n == -1) n = iuplua_getn(L, pos); else if (n != iuplua_getn(L, pos)) luaL_argerror(L, pos, "Invalid number of elements (n!=count)."); if (n<=0) luaL_argerror(L, pos, "Invalid number of elements (n<=0)."); v = (int *) malloc (n*sizeof(int)); for(i=1; i<=n; i++) { lua_pushinteger(L,i); lua_gettable(L,pos); v[i - 1] = (int)lua_tointeger(L, -1); lua_pop(L, 1); } return v; } IUPLUA_SDK_API float* iuplua_checkfloat_array(lua_State *L, int pos, int n) { int i; float* v; luaL_checktype(L, pos, LUA_TTABLE); if (n == -1) n = iuplua_getn(L, pos); else if (n != iuplua_getn(L, pos)) luaL_argerror(L, pos, "Invalid number of elements (n!=count)."); if (n<=0) luaL_argerror(L, pos, "Invalid number of elements (n<=0)."); v = (float *) malloc (n*sizeof(float)); for(i=1; i<=n; i++) { lua_pushinteger(L,i); lua_gettable(L,pos); v[i-1] = (float)lua_tonumber(L, -1); lua_pop(L, 1); } return v; } IUPLUA_SDK_API double* iuplua_checkdouble_array(lua_State *L, int pos, int n) { int i; double* v; luaL_checktype(L, pos, LUA_TTABLE); if (n == -1) n = iuplua_getn(L, pos); else if (n != iuplua_getn(L, pos)) luaL_argerror(L, pos, "Invalid number of elements (n!=count)."); if (n <= 0) luaL_argerror(L, pos, "Invalid number of elements (n<=0)."); v = (double *)malloc(n*sizeof(double)); for (i = 1; i <= n; i++) { lua_pushinteger(L, i); lua_gettable(L, pos); v[i - 1] = (double)lua_tonumber(L, -1); lua_pop(L, 1); } return v; } IUPLUA_SDK_API unsigned char* iuplua_checkuchar_array(lua_State *L, int pos, int n) { int i; unsigned char *v; luaL_checktype(L, pos, LUA_TTABLE); if (n == -1) n = iuplua_getn(L, pos); else if (n != iuplua_getn(L, pos)) luaL_argerror(L, pos, "Invalid number of elements (n!=count)."); if (n<=0) luaL_argerror(L, pos, "Invalid number of elements (n<=0)."); v = (unsigned char *) malloc (n*sizeof(unsigned char)); for(i=1; i<=n; i++) { lua_pushinteger(L,i); lua_gettable(L,pos); v[i-1] = (unsigned char)lua_tointeger(L, -1); lua_pop(L, 1); } return v; } IUPLUA_SDK_API Ihandle ** iuplua_checkihandle_array(lua_State *L, int pos, int n) { int i; Ihandle **v; luaL_checktype(L, pos, LUA_TTABLE); if (n == -1) n = iuplua_getn(L, pos); else if (n != iuplua_getn(L, pos)) luaL_argerror(L, pos, "Invalid number of elements (n!=count)."); if (n<=0) luaL_argerror(L, pos, "Invalid number of elements (n<=0)."); v = (Ihandle **) malloc ((n+1)*sizeof(Ihandle *)); for (i=1; i<=n; i++) { lua_pushinteger(L,i); lua_gettable(L,pos); v[i-1] = iuplua_checkihandle(L, -1); lua_pop(L, 1); } v[i-1] = NULL; return v; } /*************************************/ /* used by callbacks */ IUPLUA_SDK_API void iuplua_plugstate(lua_State *L, Ihandle *ih) { IupSetAttribute(ih, "_IUPLUA_STATE_CONTEXT",(char *) L); if (IupGetGlobal("IUPLUA_THREADED")) { int ref; lua_pushthread(L); ref = luaL_ref(L, LUA_REGISTRYINDEX); /* keep ref for L, L maybe a thread */ IupSetInt(ih, "_IUPLUA_STATE_THREAD", ref); } } IUPLUA_SDK_API lua_State* iuplua_getstate(Ihandle *ih) { return (lua_State *) IupGetAttribute(ih, "_IUPLUA_STATE_CONTEXT"); } IUPLUA_SDK_API lua_State* iuplua_call_start(Ihandle *ih, const char* name) { lua_State *L = iuplua_getstate(ih); /* prepare to call iup.CallMethod(name, ih, ...) */ iuplua_push_name(L, "CallMethod"); lua_pushstring(L, name); iuplua_pushihandle(L, ih); /* here there was 3 value pushed on the stack, if this changes must update callback where LUA_MULTRET is used. */ return L; } static lua_State* iuplua_call_global_start(const char* name) { lua_State *L = (lua_State *) IupGetGlobal("_IUP_LUA_DEFAULT_STATE"); /* prepare to call iup.CallGlobalMethod(name, ...) */ iuplua_push_name(L, "CallGlobalMethod"); lua_pushstring(L, name); return L; } IUPLUA_SDK_API int iuplua_call(lua_State* L, int nargs) { int status = docall(L, nargs + 2, 1); /* always 1 result */ report(L, status); if (status != LUA_OK) return IUP_DEFAULT; else { int tmp = (int)lua_isnil(L, -1) ? IUP_DEFAULT : (int)lua_tointeger(L, -1); lua_pop(L, 1); /* remove the result */ return tmp; } } int iuplua_call_global(lua_State* L, int nargs) { return iuplua_call(L, nargs-1); /* remove the ih from the parameter count */ } IUPLUA_SDK_API char* iuplua_call_ret_s(lua_State *L, int nargs) { int status = docall(L, nargs + 2, 1); /* always 1 result */ report(L, status); if (status != LUA_OK) return NULL; else { char* tmp = lua_isnil(L, -1) ? NULL: (char*)lua_tostring(L,-1); lua_pop(L, 1); /* remove the result */ return tmp; } } IUPLUA_SDK_API double iuplua_call_ret_d(lua_State *L, int nargs) { int status = docall(L, nargs + 2, 1); /* always 1 result */ report(L, status); if (status != LUA_OK) return 0; else { double tmp = lua_isnil(L, -1) ? 0: (double)lua_tonumber(L,-1); lua_pop(L, 1); /* remove the result */ return tmp; } } IUPLUA_SDK_API int iuplua_call_raw(lua_State* L, int nargs, int nresults) { int status = docall(L, nargs, nresults); /* always n results, or LUA_MULTRET */ report(L, status); return status; } IUPLUA_SDK_API void iuplua_register_cb(lua_State *L, const char* name, lua_CFunction func, const char* type) { iuplua_push_name(L, "RegisterCallback"); lua_pushstring(L, name); lua_pushcfunction(L, func); lua_pushstring(L, type); lua_call(L, 3, 0); /* iup.RegisterCallback(name, func, type) */ } /* iup.SetCallback(ih, name, c_func, lua_func) */ static int SetCallback(lua_State *L) { Icallback c_func; Ihandle* ih = iuplua_checkihandle(L, 1); const char* name = luaL_checkstring(L, 2); if (!lua_iscfunction(L, 3)) luaL_argerror(L, 3, "Invalid function when set callback."); c_func = (Icallback)lua_tocfunction(L, 3); if (lua_isnil(L, 4)) /* lua_func is only used here to remove the callback */ IupSetCallback(ih, name, (Icallback)NULL); else IupSetCallback(ih, name, c_func); /* lua_func, when not nil, has always the same name of a C callback in lowercase */ return 0; } static int SetFunction(lua_State *L) { const char* name = luaL_checkstring(L, 1); if (lua_isnil(L, 2)) IupSetFunction(name, NULL); else { Icallback func; if (!lua_iscfunction(L, 2)) luaL_argerror(L, 2, "must be a C function"); func = (Icallback)lua_tocfunction(L, 2); IupSetFunction(name, func); } return 0; } /*************************************/ /* metatable */ /* iup.NewClass(class_name) Calls: iup.NewClass("iupHandle") -- this is an Ihandle* with enhancements iup.NewClass("iupWidget") -- this is a Lua object for control construction, see iup.WIDGET and iup.BOX */ static int NewClass(lua_State *L) { lua_newtable(L); /* push t */ lua_pushstring(L, "class"); /* push "class" */ lua_pushvalue(L, 1); /* push again the class_name to the stack, because settable will remove it */ lua_settable(L, -3); /* t.class = class_name */ lua_settable(L, LUA_REGISTRYINDEX); /* registry[class_name] = t */ return 0; } /* iup.SetClass(t, class_name) Calls: iup.SetClass(ih, "iupHandle") --Called only in iup.RegisterHandle and WIDGET.constructor iup.SetClass(widget, "iupWidget") --Called whenever a new control class is created. */ static int SetClass(lua_State *L) { lua_gettable(L, LUA_REGISTRYINDEX); /* t2 = registry[class_name] */ if (lua_isnil(L, -1)) { lua_pushstring(L, "Invalid class name."); lua_error(L); } lua_setmetatable(L, -2); /* metatable(t) = t2 */ return 0; } /* class_name = iup.GetClass(t) */ static int GetClass(lua_State *L) { if (lua_istable(L, 1) || lua_isuserdata(L, 1)) { lua_getmetatable(L, 1); /* t2 = metatable(t) */ if (lua_istable(L, -1)) { lua_pushstring(L, "class"); lua_gettable(L, -2); /* class_name = t2.class */ return 1; } } lua_pushnil(L); return 1; } /* iup.SetMethod(class_name, method, function) For ex: iup.SetMethod("iupHandle", "__index", ihandle_gettable) */ static int SetMethod(lua_State *L) { lua_pushvalue(L, 1); /* push class_name */ lua_gettable(L, LUA_REGISTRYINDEX); /* t = registry[class_name] */ if (lua_isnil(L, -1)) { lua_pushstring(L, "Invalid class name."); lua_error(L); } lua_pushvalue(L, -3); /* push method */ lua_pushvalue(L, -3); /* push function */ lua_settable(L, -3); /* t.method = function */ return 0; } static int IsContainer(lua_State *L) { Ihandle *ih = iuplua_checkihandle(L, 1); if (ih) { lua_pushboolean(L, ih->iclass->childtype != IUP_CHILDNONE); return 1; } return 0; } static int ihandle_tostring (lua_State *L) { Ihandle *ih = iuplua_checkihandle(L, 1); if (!ih) lua_pushstring (L, "(not an IUP handle)"); else lua_pushfstring (L, "IUP(%s): %p", IupGetClassName(ih), ih); return 1; } static int ihandle_compare(lua_State *L) { Ihandle *a = iuplua_checkihandle(L, 1); Ihandle *b = iuplua_checkihandle(L, 2); if(a == b) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; } /*************************************/ /* widget <-> Ihandle* */ /* local widget = iup.GetWidget(ih) */ static int GetWidget(lua_State *L) { /* Pushes a Lua object that is associated with an Ihandle* */ /* Used by the "__index" metamethod of the iupHandle */ Ihandle * ih = iuplua_checkihandle(L, 1); char* sref = IupGetAttribute(ih, "_IUPLUA_WIDGET_TABLE_REF"); if (!sref) lua_pushnil(L); else lua_rawgeti(L, LUA_REGISTRYINDEX, atoi(sref)); return 1; } /* iup.SetWidget(ih, widget) */ static int SetWidget(lua_State *L) { /* Saves the Lua object reference as an attribute, i.e. associates a Lua object with the Ihandle*. Used by the "iupWidget" constructor and by RegisterHandle */ Ihandle * ih = iuplua_checkihandle(L, 1); char* sref = IupGetAttribute(ih, "_IUPLUA_WIDGET_TABLE_REF"); if (!sref) { int ref = luaL_ref(L, LUA_REGISTRYINDEX); IupSetInt(ih, "_IUPLUA_WIDGET_TABLE_REF", ref); IupSetCallback(ih, "LDESTROY_CB", il_destroy_cb); } return 0; } /*************************************/ /* registration */ IUPLUA_SDK_API int iuplua_opencall_internal(lua_State * L) { int ret = 0; const char* s; iuplua_get_env(L); lua_pushliteral(L,"_IUPOPEN_CALL"); lua_gettable(L, -2); s = lua_tostring(L, -1); if (s && strcmp(s, "INTERNAL")==0) ret = 1; lua_pop(L, 2); /* remove global table and ._IUPOPEN_CALL from stack */ return ret; } /* iup[name] = func */ IUPLUA_SDK_API void iuplua_register(lua_State *L, lua_CFunction func, const char* name) { lua_pushcfunction(L, func); lua_setfield(L, -2, name); } /* iup[name] = s */ IUPLUA_SDK_API void iuplua_regstring(lua_State *L, const char* s, const char* name) { lua_pushstring(L, s); lua_setfield(L, -2, name); } /* global table */ static const char* iup_globaltable = "iup"; IUPLUA_SDK_API void iuplua_get_env(lua_State *L) { lua_getglobal(L, iup_globaltable); } IUPLUA_SDK_API void iuplua_register_lib(lua_State *L, const luaL_Reg* funcs) { #if LUA_VERSION_NUM < 502 luaL_register(L, iup_globaltable, funcs); #else iuplua_get_env(L); if (lua_istable(L, -1)) luaL_setfuncs(L, funcs, 0); else { if (!lua_isnil(L, -1)) luaL_error(L, "name conflict for module \"%s\"", iup_globaltable); lua_newtable(L); luaL_setfuncs(L, funcs, 0); lua_pushvalue(L, -1); lua_setglobal(L, iup_globaltable); } #endif } IUPLUA_SDK_API void iuplua_register_funcs(lua_State *L, const luaL_Reg* funcs) { #if LUA_VERSION_NUM < 502 luaL_register(L, NULL, funcs); #else luaL_setfuncs(L, funcs, 0); #endif } /***************************************************************************** * Common Callbacks * ****************************************************************************/ static int help_cb(Ihandle *self) { lua_State *L = iuplua_call_start(self, "help_cb"); return iuplua_call(L, 0); } static int getfocus_cb(Ihandle *self) { lua_State *L = iuplua_call_start(self, "getfocus_cb"); return iuplua_call(L, 0); } static int k_any(Ihandle *self, int c) { lua_State *L = iuplua_call_start(self, "k_any"); lua_pushinteger(L, c); return iuplua_call(L, 1); } static int killfocus_cb(Ihandle *self) { lua_State *L = iuplua_call_start(self, "killfocus_cb"); return iuplua_call(L, 0); } static int multitouch_cb(Ihandle *ih, int count, int* pid, int* px, int* py, int* pstate) { int i; lua_State *L = iuplua_call_start(ih, "multitouch_cb"); lua_pushinteger(L, count); lua_createtable(L, count, 0); for (i = 0; i < count; i++) { lua_pushinteger(L,i+1); lua_pushinteger(L,pid[i]); lua_settable(L,-3); } lua_createtable(L, count, 0); for (i = 0; i < count; i++) { lua_pushinteger(L,i+1); lua_pushinteger(L,px[i]); lua_settable(L,-3); } lua_createtable(L, count, 0); for (i = 0; i < count; i++) { lua_pushinteger(L,i+1); lua_pushinteger(L,py[i]); lua_settable(L,-3); } lua_createtable(L, count, 0); for (i = 0; i < count; i++) { lua_pushinteger(L,i+1); lua_pushinteger(L,pstate[i]); lua_settable(L,-3); } return iuplua_call(L, 5); } static int attribchanged_cb(Ihandle *self, char * p0) { lua_State *L = iuplua_call_start(self, "attribchanged_cb"); lua_pushstring(L, p0); return iuplua_call(L, 1); } static int layoutchanged_cb(Ihandle *self, Ihandle* elem) { lua_State *L = iuplua_call_start(self, "layoutchanged_cb"); iuplua_pushihandle(L, elem); return iuplua_call(L, 1); } static void entry_point(void) { lua_State *L = iuplua_call_global_start("entry_point"); iuplua_call_global(L, 0); } static void exit_cb(void) { lua_State *L = iuplua_call_global_start("exit_cb"); iuplua_call_global(L, 0); } static void globalwheel_cb(float delta, int x, int y, char* status) { lua_State *L = iuplua_call_global_start("globalwheel_cb"); lua_pushnumber(L, delta); lua_pushinteger(L, x); lua_pushinteger(L, y); lua_pushstring(L, status); iuplua_call_global(L, 4); } static void globalbutton_cb(int button, int pressed, int x, int y, char* status) { lua_State *L = iuplua_call_global_start("globalbutton_cb"); lua_pushinteger(L, button); lua_pushinteger(L, pressed); lua_pushinteger(L, x); lua_pushinteger(L, y); lua_pushstring(L, status); iuplua_call_global(L, 5); } static void globalmotion_cb(int x, int y, char* status) { lua_State *L = iuplua_call_global_start("globalmotion_cb"); lua_pushinteger(L, x); lua_pushinteger(L, y); lua_pushstring(L, status); iuplua_call_global(L, 3); } static void globalkeypress_cb(int key, int pressed) { lua_State *L = iuplua_call_global_start("globalkeypress_cb"); lua_pushinteger(L, key); lua_pushinteger(L, pressed); iuplua_call_global(L, 2); } static void globalctrlfunc_cb(int key) { lua_State *L = iuplua_call_global_start("globalctrlfunc_cb"); lua_pushinteger(L, key); iuplua_call_global(L, 1); } static int globalidle_cb(void) { lua_State *L = iuplua_call_global_start("idle_action"); return iuplua_call_global(L, 0); } static int idle_cb(void) { int ret = 0; lua_State *L = (lua_State *) IupGetGlobal("_IUP_LUA_DEFAULT_STATE"); lua_getglobal(L, "_IUP_LUA_IDLE_FUNC_"); lua_call(L, 0, 1); /* _IUP_LUA_IDLE_FUNC_() */ ret = (int)lua_tointeger(L, -1); lua_pop(L, 1); return ret; } static int SetIdle(lua_State *L) { if (lua_isnoneornil(L,1)) IupSetFunction("IDLE_ACTION", NULL); else { luaL_checktype(L, 1, LUA_TFUNCTION); lua_pushvalue(L,1); lua_setglobal(L, "_IUP_LUA_IDLE_FUNC_"); IupSetFunction("IDLE_ACTION", (Icallback)idle_cb); } return 0; } /***************************************************************************** * Iuplua bind functions * ****************************************************************************/ static int GetFromC(lua_State *L) { Ihandle *n; const char *a; if (!lua_istable(L, -1)) { lua_pushstring(L, "iup.GetFromC: wrong arguments to function"); lua_error(L); return 0; } lua_pushinteger(L, 1); lua_gettable(L, -2); if (!lua_isstring(L, -1)) { lua_pushstring(L, "iup.GetFromC: wrong arguments to function"); lua_error(L); return 0; } a = lua_tostring(L, -1); n = IupGetHandle((char*)a); if(n) iuplua_pushihandle(L, n); else lua_pushnil(L); return 1; } /***************************************************************************** * iupkey * ****************************************************************************/ static void register_key(char *name, int code, void* user_data) { lua_State *L = (lua_State*)user_data; lua_pushinteger(L, code); lua_setfield(L, -2, name); } /* from iupkey.c */ void iupKeyForEach(void (*func)(char *name, int code, void* user_data), void* user_data); IUPLUA_API int iupkey_open(lua_State *L) { (void)L; /* does nothing, kept for backward compatibility */ return 0; } /***************************************************************************** * iuplua_open * ****************************************************************************/ static int il_open(lua_State * L) { int ret, argc = 0; char **argv = NULL; lua_getglobal(L, "arg"); if (lua_istable(L, -1)) { int i; argc = iuplua_getn(L, -1); argv = malloc(sizeof(char*)*argc); for(i=1; i<=argc; i++) { lua_pushinteger(L,i); lua_gettable(L,-2); argv[i-1] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } } lua_pop(L, 1); ret = IupOpen(&argc, &argv); if (ret == IUP_ERROR) { if (argv) free(argv); lua_pushstring(L, "IupOpen: could not initialize"); lua_error(L); return 0; } if (argv) free(argv); lua_pushinteger(L, ret); return 1; } IUPLUA_API int iuplua_close(lua_State * L) { if (iuplua_opencall_internal(L)) IupClose(); return 0; /* nothing in stack */ } static void setinfo (lua_State *L) { /* global table is at the stack */ lua_pushliteral (L, IUP_COPYRIGHT); lua_setfield(L, -2, "_COPYRIGHT"); lua_pushliteral (L, IUP_DESCRIPTION); lua_setfield(L, -2, "_DESCRIPTION"); lua_pushliteral (L, IUP_NAME); lua_setfield(L, -2, "_NAME"); lua_pushstring (L, IupVersion()); lua_setfield(L, -2, "_VERSION"); lua_pushliteral (L, IUP_VERSION_DATE); lua_setfield(L, -2, "_VERSION_DATE"); lua_pushinteger (L, IupVersionNumber()); lua_setfield(L, -2, "_VERSION_NUMBER"); } IUPLUA_API int iuplua_open(lua_State * L) { int ret; struct luaL_Reg funcs[] = { {"key_open", iupkey_open}, {"Open", il_open}, {"Close", iuplua_close}, {"SetIdle", SetIdle}, {"GetFromC", GetFromC}, {"GetWidget", GetWidget}, {"SetWidget", SetWidget}, {"NewClass", NewClass}, {"SetClass", SetClass}, {"GetClass", GetClass}, {"IsContainer", IsContainer}, {"SetMethod", SetMethod}, {"SetCallback", SetCallback}, {"SetFunction", SetFunction}, {"ihandle_compare", ihandle_compare}, {"ihandle_tostring", ihandle_tostring}, {"_ERRORMESSAGE", il_error_message}, {"dostring", il_dostring}, {"dofile", il_dofile}, { "StringCompare", StringCompare }, { "StringChangeCase", StringChangeCase }, { "CopyUserData2String", CopyUserData2String }, { "CopyString2UserData", CopyString2UserData }, { NULL, NULL }, }; if (!il_open(L)) return 0; ret = (int)lua_tointeger(L, -1); /* retrieve IupOpen return value */ lua_pop(L, -1); /* Registers functions in iup namespace */ iuplua_register_lib(L, funcs); /* leave global table at the top of the stack */ iupluaapi_open(L); /* set version info */ setinfo(L); /* register if IupOpen was called here or from outside IupLua */ /* iup._IUPOPEN_CALL = EXTERNAL|INTERNAL */ if (ret == IUP_OPENED) lua_pushliteral (L, "EXTERNAL"); else lua_pushliteral (L, "INTERNAL"); lua_setfield(L, -2, "_IUPOPEN_CALL"); /* used by Idle in Lua */ IupSetGlobal("_IUP_LUA_DEFAULT_STATE", (char *) L); #ifdef IUPLUA_USELOH #include "iuplua.loh" #include "constants.loh" #else #ifdef IUPLUA_USELH #include "iuplua.lh" #include "constants.lh" #else iuplua_dofile(L, "iuplua.lua"); iuplua_dofile(L, "constants.lua"); #endif #endif /* Register the common callbacks */ iuplua_register_cb(L, "HELP_CB", (lua_CFunction)help_cb, NULL); iuplua_register_cb(L, "GETFOCUS_CB", (lua_CFunction)getfocus_cb, NULL); iuplua_register_cb(L, "K_ANY", (lua_CFunction)k_any, NULL); iuplua_register_cb(L, "KILLFOCUS_CB", (lua_CFunction)killfocus_cb, NULL); iuplua_register_cb(L, "MULTITOUCH_CB", (lua_CFunction)multitouch_cb, NULL); /* Register global callbacks */ iuplua_register_cb(L, "ENTRY_POINT", (lua_CFunction)entry_point, NULL); iuplua_register_cb(L, "EXIT_CB", (lua_CFunction)exit_cb, NULL); iuplua_register_cb(L, "GLOBALWHEEL_CB", (lua_CFunction)globalwheel_cb, NULL); iuplua_register_cb(L, "GLOBALBUTTON_CB", (lua_CFunction)globalbutton_cb, NULL); iuplua_register_cb(L, "GLOBALMOTION_CB", (lua_CFunction)globalmotion_cb, NULL); iuplua_register_cb(L, "GLOBALKEYPRESS_CB", (lua_CFunction)globalkeypress_cb, NULL); iuplua_register_cb(L, "GLOBALCTRLFUNC_CB", (lua_CFunction)globalctrlfunc_cb, NULL); iuplua_register_cb(L, "IDLE_ACTION", (lua_CFunction)globalidle_cb, NULL); /* Other callbacks */ iuplua_register_cb(L, "ATTRIBCHANGED_CB", (lua_CFunction)attribchanged_cb, NULL); iuplua_register_cb(L, "LAYOUTCHANGED_CB", (lua_CFunction)layoutchanged_cb, NULL); /* Register Keys */ iupKeyForEach(register_key, (void*)L); /* Iup Modules initialization */ iupbuttonlua_open(L); iupluadraw_open(L); /* must be before canvas */ iupcanvaslua_open(L); iupdialoglua_open(L); iupfilllua_open(L); iupframelua_open(L); iupfiledlglua_open(L); iuphboxlua_open(L); iupitemlua_open(L); iupimagelua_open(L); iuplabellua_open(L); iuplistlua_open(L); iupmenulua_open(L); iupmultilinelua_open(L); iupradiolua_open(L); iupseparatorlua_open(L); iupsubmenulua_open(L); iuptextlua_open(L); iuptogglelua_open(L); iupvboxlua_open(L); iupzboxlua_open(L); iuptimerlua_open(L); iupsboxlua_open(L); iupsplitlua_open(L); iupspinlua_open(L); iupspinboxlua_open(L); iupscrollboxlua_open(L); iupgridboxlua_open(L); iupmultiboxlua_open(L); iupexpanderlua_open(L); iuplinklua_open(L); iupcboxlua_open(L); iupdetachboxlua_open(L); iupbackgroundboxlua_open(L); iupgclua_open(L); iupgetparamlua_open(L); iupvallua_open(L); iuptabslua_open(L); iupfontdlglua_open(L); iupmessagedlglua_open(L); iupcolordlglua_open(L); iupimagergbalua_open(L); iupimagergblua_open(L); iupprogressbarlua_open(L); iupnormalizerlua_open(L); iupuserlua_open(L); iupthreadlua_open(L); iuptreelua_open(L); iupclipboardlua_open(L); iupprogressdlglua_open(L); iupflatlabellua_open(L); iupflatbuttonlua_open(L); iupflattogglelua_open(L); iupdropbuttonlua_open(L); iupflatframelua_open(L); iupflatseparatorlua_open(L); iupflatlistlua_open(L); iupflatvallua_open(L); iupflattreelua_open(L); iupspacelua_open(L); iupconfiglua_open(L); iupanimatedlabellua_open(L); iupcalendarlua_open(L); iupdatepicklua_open(L); iupflattabslua_open(L); iupflatscrollboxlua_open(L); iupgaugelua_open(L); iupdiallua_open(L); iupcolorbarlua_open(L); iupcolorbrowserlua_open(L); return 0; /* nothing in stack */ } /* obligatory to use require"iuplua" */ IUPLUA_SDK_API int luaopen_iuplua(lua_State* L) { return iuplua_open(L); }