1480 lines
38 KiB
C
1480 lines
38 KiB
C
|
/** \file
|
||
|
* \brief IUP binding for Lua 5.
|
||
|
*
|
||
|
* See Copyright Notice in "iup.h"
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "iup.h"
|
||
|
#include "iup_str.h"
|
||
|
#include "iup_object.h"
|
||
|
|
||
|
#include <lua.h>
|
||
|
#include <lauxlib.h>
|
||
|
|
||
|
#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 <global table>._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);
|
||
|
}
|
||
|
|