-- This file is executed with the "iup" table already as the globalindex ------------------------------------------------------------------------------ -- Callback handler ------------------------------------------------------------------------------ iup.callbacks = {} function iup.CallMethod(name, ...) local handle = arg[1] -- always the handle local func = handle[name] if (not func) then return end if type(func) == "function" then return func(unpack(arg)) elseif type(func) == "string" then local temp = self self = handle local result = iup.dostring(func) self = temp return result else return iup.ERROR end end function iup.RegisterCallback(name, func, type) if not iup.callbacks[name] then iup.callbacks[name] = {} end local cb = iup.callbacks[name] if type then cb[type] = func else cb[1] = func end end ------------------------------------------------------------------------------ -- Meta Methods ------------------------------------------------------------------------------ local widget_gettable = function(object, index) local p = object local v while 1 do v = rawget(p, index) if v then return v end p = rawget(p, "parent") if not p then return nil end end end iup.NewClass("iup widget") iup.SetMethod("iup widget", "__index", widget_gettable) local ihandle_gettable = function(handle, index) local INDEX = string.upper(index) if (iup.callbacks[INDEX]) then local object = iup.GetWidget(handle) if (not object or type(object)~="table") then error("invalid iup handle") end return object[index] else local value = iup.GetAttribute(handle, INDEX) if (not value) then local object = iup.GetWidget(handle) if (not object or type(object)~="table") then error("invalid iup handle") end return object[index] elseif type(value)== "number" or type(value) == "string" then local ih = iup.GetHandle(value) if ih then return ih else return value end else return value end end end local ihandle_settable = function(handle, index, value) local ti = type(index) local tv = type(value) local object = iup.GetWidget(handle) if (not object or type(object)~="table") then error("invalid iup handle") end if ti == "number" or ti == "string" then -- check if a valid C name local INDEX = string.upper(index) local cb = iup.callbacks[INDEX] if (cb) then -- if a callback name local func = cb[1] if (not func) then func = cb[iup.GetClassName(handle)] end iup.SetCallback(handle, INDEX, func, value) -- register the pre-defined C callback object[index] = value -- store also in Lua elseif iup.GetClass(value) == "iup handle" then -- if a iup handle local name = iup.SetHandleName(value) iup.SetAttribute(handle, INDEX, name) object[index] = nil -- if there was something in Lua remove it elseif tv == "string" or tv == "number" or tv == "nil" then -- if a common value iup.SetAttribute(handle, INDEX, value) object[index] = nil -- if there was something in Lua remove it else object[index] = value -- store also in Lua end else object[index] = value -- store also in Lua end end iup.NewClass("iup handle") iup.SetMethod("iup handle", "__index", ihandle_gettable) iup.SetMethod("iup handle", "__newindex", ihandle_settable) iup.SetMethod("iup handle", "__tostring", iup.ihandle_tostring) -- implemented in C iup.SetMethod("iup handle", "__eq", iup.ihandle_compare) -- implemented in C ------------------------------------------------------------------------------ -- Utilities ------------------------------------------------------------------------------ function iup.SetHandleName(v) -- used also by radio and zbox local name = iup.GetName(v) if not name then local autoname = string.format("_IUPLUA_NAME(%s)", tostring(v)) iup.SetHandle(autoname, v) return autoname end return name end function iup.RegisterWidget(ctrl) -- called by all the controls initialization functions iup[ctrl.nick] = function(param) if (not ctrl.constructor) then print(ctrl.nick) end return ctrl:constructor(param) end end function iup.RegisterHandle(handle, typename) iup.SetClass(handle, "iup handle") local object = iup.GetWidget(handle) if not object then local class = iup[string.upper(typename)] if not class then class = WIDGET end local object = { parent=class, handle=handle } iup.SetClass(object, "iup widget") iup.SetWidget(handle, object) end return handle end ------------------------------------------------------------------------------ -- Widget class (top class) ------------------------------------------------------------------------------ iup.WIDGET = { callback = {} } function iup.WIDGET.show(object) iup.Show(object.handle) end function iup.WIDGET.hide(object) iup.Hide(object.handle) end function iup.WIDGET.map(object) iup.Map(object.handle) end function iup.WIDGET.constructor(class, param) local handle = class:createElement(param) local object = { parent = class, handle = handle } iup.SetClass(handle, "iup handle") iup.SetClass(object, "iup widget") iup.SetWidget(handle, object) object:setAttributes(param) return handle end function iup.WIDGET.setAttributes(object, param) local handle = object.handle for i,v in pairs(param) do if type(i) == "number" and iup.GetClass(v) == "iup handle" then -- We should not set this or other elements (such as iuptext) -- will erroneosly inherit it rawset(object, i, v) else -- this will call settable metamethod handle[i] = v end end end -- all the objects in the hierarchy must be "iup widget" -- Must repeat this call for every new widget iup.SetClass(iup.WIDGET, "iup widget") ------------------------------------------------------------------------------ -- Box class (inherits from WIDGET) ------------------------------------------------------------------------------ iup.BOX = { parent = iup.WIDGET } function iup.BOX.setAttributes(object, param) local handle = rawget(object, "handle") local n = #param for i = 1, n do if iup.GetClass(param[i]) == "iup handle" then iup.Append(handle, param[i]) end end iup.WIDGET.setAttributes(object, param) end iup.SetClass(iup.BOX, "iup widget") ------------------------------------------------------------------------------ -- Compatibility functions. ------------------------------------------------------------------------------ iup.error_message_popup = nil function iup._ERRORMESSAGE(err,traceback) err = err..(traceback or "") if (iup.error_message_popup) then iup.error_message_popup.value = err else local bt = iup.button{title="Ok", size="60", action="iup.error_message_popup = nil; return iup.CLOSE"} local ml = iup.multiline{expand="YES", readonly="YES", value=err, size="300x150"} local vb = iup.vbox{ml, bt; alignment="ACENTER", margin="10x10", gap="10"} local dg = iup.dialog{vb; title="Error Message",defaultesc=bt,defaultenter=bt,startfocus=bt} iup.error_message_popup = ml dg:popup(CENTER, CENTER) dg:destroy() iup.error_message_popup = nil end end iup.pack = function (...) return arg end function iup.protectedcall_(f, err) if not f then iup._ERRORMESSAGE(err) return end local ret = iup.pack(pcall(f)) if not ret[1] then iup._ERRORMESSAGE(ret[2]) return else table.remove(ret, 1) return unpack(ret) end end function iup.dostring(s) return iup.protectedcall_(loadstring(s)) end function iup.dofile(f) return iup.protectedcall_(loadfile(f)) end function iup.RGB(r, g, b) return string.format("%d %d %d", 255*r, 255*g, 255*b) end -- This will allow both names to be used in the same application -- also will allow static linking to work with require if _G.package then _G.package.loaded["iuplua"] = iup _G.package.loaded["iuplua51"] = iup iup._M = iup iup._PACKAGE = "iuplua" end