warzone2100/lib/betawidget/betawidget.i

628 lines
15 KiB
OpenEdge ABL

%module betawidget
%{
extern "C" {
#include "widget.h"
#include "window.h"
#include "hBox.h"
#include "clipboard.h"
#include "spacer.h"
#include "textEntry.h"
#include "lua-wrap.h"
#include <assert.h>
}
#include <vector>
typedef struct
{
lua_State* L;
int table;
#ifndef NDEBUG
widget* self;
eventType type;
#endif
} lua_widget_callback;
static void createLuaCallbackTable(lua_State* const L)
{
// Create a table to hold the function and a weak table with additional data
lua_newtable(L); // callback = {}
lua_newtable(L); // weak = {}
// setmetatable(weak, { __mode = 'v' })
lua_newtable(L);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
// callback.weak = weak
lua_setfield(L, -2, "weak");
}
static bool callbackHandler(widget* const self, const event* const evt, int const handlerId, lua_widget_callback const * const callbackRef)
{
lua_State* const L = callbackRef->L;
const int stack_top = lua_gettop(L);
bool result;
assert(self == callbackRef->self);
assert(evt->type == callbackRef->type);
// callback.function(callback.weak.widget, evt, handlerId)
lua_getref(L, callbackRef->table);
lua_getfield(L, -1, "function");
lua_getfield(L, -2, "weak");
lua_getfield(L, -1, "widget");
lua_replace(L, -2);
lua_remove(L, -3);
assert(self == (widget const *)((swig_lua_userdata*)lua_touserdata(L, -1))->ptr);
swig_lua_userdata* const usr = (swig_lua_userdata*)lua_newuserdata(L, sizeof(*usr));
usr->ptr = (event* const)evt;
usr->type = SWIGTYPE_p__event;
usr->own = 0;
_SWIG_Lua_AddMetatable(L, SWIGTYPE_p__event);
lua_pushnumber(L, handlerId);
// return callback(self, evt, handlerId)
if (lua_pcall(L, 3, 1, 0) != 0)
return false;
if (lua_gettop(L) != (stack_top + 1))
// If no value got returned assume the event handler was succesfull
return true;
// Pop the result from the stack and return it
result = lua_toboolean(L, -1);
lua_pop(L, 1);
return result;
}
static bool callbackDestructor(widget* const self, const event* const evt, int const handlerId, lua_widget_callback* const callbackRef)
{
assert(self == callbackRef->self);
lua_unref(callbackRef->L, callbackRef->table);
free(callbackRef);
return true;
}
%}
%rename (getTime) widgetGetTime;
int widgetGetTime(void);
%rename (getClipboardText) widgetGetClipboardText;
%rename (setClipboardText) widgetSetClipboardText;
%typemap (newfree) char * "free($1);";
%newobject widgetGetClipboardText;
%include "clipboard.h"
typedef enum
{
SPACER_DIRECTION_HORIZONTAL,
SPACER_DIRECTION_VERTICAL
} spacerDirection;
typedef enum
{
LEFT,
CENTRE,
RIGHT
} hAlign;
typedef enum
{
TOP,
MIDDLE,
BOTTOM
} vAlign;
typedef enum
{
EVT_MOUSE_DOWN,
EVT_MOUSE_UP,
EVT_MOUSE_CLICK,
EVT_MOUSE_ENTER,
EVT_MOUSE_MOVE,
EVT_MOUSE_LEAVE,
EVT_KEY_DOWN,
EVT_KEY_UP,
EVT_TEXT,
EVT_DRAG_BEGIN,
EVT_DRAG_TRACK,
EVT_DRAG_END,
EVT_TIMER,
EVT_TIMER_SINGLE_SHOT,
EVT_TIMER_PERSISTENT,
EVT_TOOL_TIP_SHOW,
EVT_TOOL_TIP_HIDE,
EVT_RESIZE,
EVT_REPOSITION,
EVT_FOCUS,
EVT_BLUR,
EVT_DESTRUCT
} eventType;
%rename (event) _event;
typedef struct _event
{
int time;
eventType type;
};
typedef struct _point
{
float x;
float y;
} point;
typedef point size;
typedef enum
{
ANI_TYPE_TRANSLATE,
ANI_TYPE_ROTATE,
ANI_TYPE_SCALE,
ANI_TYPE_ALPHA,
} animationType;
struct animationFrame
{
animationType type;
int time;
union
{
_point translate;
float rotate;
_point scale;
float alpha;
} data;
};
%typemap (in) (int nframes, const animationFrame *frames) (std::vector<animationFrame> frameList)
{
if (!lua_istable(L, $input))
SWIG_fail_arg("addAnimation", $input, "table");
lua_getfield(L, LUA_GLOBALSINDEX, "ipairs");
lua_pushvalue(L, $input);
if (lua_pcall(L, 1, 3, 0) != 0)
goto fail;
for (;;)
{
animationFrame *frame = 0;
lua_pushvalue(L, -3);
lua_pushvalue(L, -3);
lua_pushvalue(L, -3);
if (lua_pcall(L, 2, 2, 0) != 0)
{
goto fail;
}
if (!SWIG_isptrtype(L, -1))
{
SWIG_fail_arg("addAnimation", -1, "animationFrame *");
}
if (!SWIG_IsOK(SWIG_ConvertPtr(L, -1, (void**)&frame, SWIGTYPE_p_animationFrame, 0)))
{
SWIG_fail_ptr("widget_addAnimation", -1, SWIGTYPE_p_animationFrame);
}
lua_pop(L, 1);
lua_replace(L, -2);
if (!frame)
break;
frameList.push_back(*frame);
}
lua_pop(L, 3);
$1 = frameList.size();
$2 = &frameList[0];
}
%typemap (in) (callback handler, callback destructor, void *userData)
{
lua_widget_callback* callbackRef;
static const int self_idx = 1;
_widget* self = 0;
if (!SWIG_isptrtype(L, self_idx))
SWIG_fail_arg("$symname", self_idx, "_widget *");
if (!lua_isfunction(L, $input))
SWIG_fail_arg("$symname", $input, "function");
if (!SWIG_IsOK(SWIG_ConvertPtr(L, self_idx, (void**)&self, SWIGTYPE_p__widget, 0)))
{
SWIG_fail_ptr("$symname", self_idx, SWIGTYPE_p__widget);
}
// Allocate a chunk of memory to place a reference to the function in
callbackRef = (lua_widget_callback*)malloc(sizeof(*callbackRef));
if (callbackRef == NULL)
{
lua_pushstring(L, "Error in $symname: Out of memory");
goto fail;
}
// Create a table to store the Lua callback info in
createLuaCallbackTable(L);
// callback.function = function
lua_pushvalue(L, $input);
lua_setfield(L, -2, "function");
// callback.weak.widget = self
lua_getfield(L, -1, "weak");
lua_pushvalue(L, self_idx);
lua_setfield(L, -2, "widget");
lua_pop(L, 1);
// Retrieve a reference to the callback table
callbackRef->L = L;
callbackRef->table = lua_ref(L, true);
$1 = (callback)callbackHandler;
$2 = (callback)callbackDestructor;
$3 = callbackRef;
#ifndef NDEBUG
callbackRef->self = self;
callbackRef->type = arg2;
#endif
}
%rename (widget) _widget;
struct _widget
{
const char * const id;
_point offset;
%extend
{
_widget(const char* id)
{
struct _widget * const self = (struct _widget*)malloc(sizeof(*self));
if (self == NULL)
return NULL;
widgetInit(self, id);
return self;
}
virtual ~_widget()
{
widgetDestroy(WIDGET($self));
}
virtual bool addChild(struct _widget *child)
{
return widgetAddChild(WIDGET($self), child);
}
virtual void removeChild(struct _widget *child)
{
return widgetRemoveChild(WIDGET($self), child);
}
virtual int addEventHandler(eventType type, callback handler, callback destructor, void *userData)
{
return widgetAddEventHandler($self, type, handler, destructor, userData);
}
virtual int addTimerEventHandler(eventType type, int interval, callback handler, callback destructor, void *userData)
{
return widgetAddTimerEventHandler($self, type, interval, handler, destructor, userData);
}
virtual void removeEventHandler(int id)
{
return widgetRemoveEventHandler(WIDGET($self), id);
}
virtual void focus()
{
return widgetFocus(WIDGET($self));
}
virtual void blur()
{
return widgetBlur(WIDGET($self));
}
virtual void acceptDrag()
{
return widgetAcceptDrag(WIDGET($self));
}
virtual void declineDrag()
{
return widgetDeclineDrag(WIDGET($self));
}
virtual int addAnimation(int nframes, const animationFrame *frames)
{
return widgetAddAnimation($self, nframes, frames);
}
virtual void enable()
{
return widgetEnable(WIDGET($self));
}
virtual void disable()
{
return widgetDisable(WIDGET($self));
}
virtual void show()
{
return widgetShow(WIDGET($self));
}
virtual void hide()
{
return widgetHide(WIDGET($self));
}
virtual size getMinSize()
{
return widgetGetMinSize(WIDGET($self));
}
virtual size getMaxSize()
{
return widgetGetMaxSize(WIDGET($self));
}
virtual void resize(int w, int h)
{
return widgetResize(WIDGET($self), w, h);
}
virtual void reposition(int x, int y)
{
return widgetReposition(WIDGET($self), x, y);
}
}
};
%rename (window) _window;
struct _window : public _widget
{
%extend
{
_window(const char* id, int width, int heigth)
{
struct _window * const self = (struct _window*)malloc(sizeof(*self));
if (self == NULL)
return NULL;
windowInit(self, id, width, heigth);
return self;
}
virtual ~_window()
{
widgetDestroy(WIDGET($self));
}
virtual void repositionFromScreen(hAlign hAlign, int xOffset, vAlign vAlign, int yOffset)
{
return windowRepositionFromScreen($self, hAlign, xOffset, vAlign, yOffset);
}
virtual void repositionFromAnchor(const struct _window *anchor, hAlign hAlign, int xOffset, vAlign vAlign, int yOffset)
{
return windowRepositionFromAnchor($self, anchor, hAlign, xOffset, vAlign, yOffset);
}
}
};
%rename (hBox) _hBox;
struct _hBox : public _widget
{
%extend
{
_hBox(const char* id)
{
return hBoxCreate(id);
}
virtual ~_hBox()
{
widgetDestroy(WIDGET($self));
}
virtual void setVAlign(vAlign v)
{
return hBoxSetVAlign($self, v);
}
}
};
%rename (spacer) _spacer;
struct _spacer : public _widget
{
%extend
{
_spacer(const char* id, spacerDirection direction)
{
return spacerCreate(id, direction);
}
virtual ~_spacer()
{
widgetDestroy(WIDGET($self));
}
}
};
%rename (textEntry) _textEntry;
struct _textEntry : public _widget
{
%extend
{
_textEntry(const char* id)
{
return textEntryCreate(id);
}
virtual ~_textEntry()
{
widgetDestroy(WIDGET($self));
}
virtual const char* getContents()
{
return textEntryGetContents($self);
}
virtual bool setContents(const char* contents)
{
return textEntrySetContents($self, contents);
}
}
};
%wrapper %{
static int lua_widget_destroy(lua_State* const L)
{
int args = 0;
_widget *self;
swig_lua_userdata* usr;
SWIG_check_num_args("destroy", 1, 1);
if (!SWIG_isptrtype(L, 1))
SWIG_fail_arg("destroy", 1, "_widget *");
if (!SWIG_IsOK(SWIG_ConvertPtr(L, 1, (void**)&self, SWIGTYPE_p__widget,0)))
{
SWIG_fail_ptr("widget_destroy", 1, SWIGTYPE_p__widget);
}
widgetDestroy(self);
/* FIXME: Setting SWIG's pointer to our widget to NULL. This is
* currently required because widgetDestroy() frees the memory
* at *self. This however causes *all* further operations (in
* Lua) on the "self" variable/object to cause segfaults.
*/
usr = (swig_lua_userdata*)lua_touserdata(L, 1);
usr->ptr = NULL;
return args;
fail:
lua_error(L);
return args;
}
static bool lua_inherits_From(swig_lua_class const * const clss, swig_lua_class const * const from)
{
int i;
if (clss == from)
return true;
for (i = 0; clss->bases[i]; ++i)
{
if (lua_inherits_From(clss->bases[i], from))
return true;
}
return false;
}
static void addLuaFuncToSwigBaseClass(lua_State* const L,
swig_lua_class const * const base,
swig_type_info const * const * const classes,
int const class_count,
const char * const name,
lua_CFunction const func)
{
int i;
for (i = 0; i < class_count; ++i)
{
swig_lua_class const * const clss = (swig_lua_class const *)classes[i]->clientdata;
if (clss
&& lua_inherits_From(clss, base))
{
SWIG_Lua_get_class_metatable(L, clss->name);
SWIG_Lua_get_table(L, ".fn"); /* find the .fn table */
SWIG_Lua_add_function(L, name, func);
lua_pop(L,1); /* tidy stack (remove table) */
lua_pop(L,1); /* tidy stack (remove class metatable) */
}
}
}
%}
%init %{
static swig_type_info const * const * const classes = swig_type_initial;
static int const class_count = sizeof(swig_type_initial) / sizeof(swig_type_initial[0]);
static const struct
{
swig_lua_class const * const base;
const char * const name;
lua_CFunction func;
} methods[] =
// Table of custom crafted virtual functions
{
{ &_wrap_class__widget, "destroy", lua_widget_destroy },
};
int i;
for (i = 0; i < sizeof(methods) / sizeof(methods[0]); ++i)
{
addLuaFuncToSwigBaseClass(L, methods[i].base, classes, class_count, methods[i].name, methods[i].func);
}
%}
%luacode {
function betawidget.animationScaleFrame(time, x, y)
local frame = betawidget.animationFrame()
frame.type = betawidget.ANI_TYPE_SCALE
frame.time = time
frame.data.scale.x = x
frame.data.scale.y = y
return frame
end
function betawidget.animationTranslateFrame(time, x, y)
local frame = betawidget.animationFrame()
frame.type = betawidget.ANI_TYPE_TRANSLATE
frame.time = time
frame.data.translate.x = x
frame.data.translate.y = y
return frame
end
function betawidget.animationRotateFrame(time, r)
local frame = betawidget.animationFrame()
frame.type = betawidget.ANI_TYPE_ROTATE
frame.time = time
frame.data.rotate = r
return frame
end
function betawidget.animationAlphaFrame(time, a)
local frame = betawidget.animationFrame()
frame.type = betawidget.ANI_TYPE_ALPHA
frame.time = time
frame.data.alpha = a
return frame
end
}