summaryrefslogtreecommitdiff
path: root/iup/srclua5/iuplua.lua
blob: b0f644af40d60d1d381c251bb4d4183a7172da87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
-- This file is executed with the "iup" table already as the globalindex

------------------------------------------------------------------------------
-- Callback handler  
------------------------------------------------------------------------------

callbacks = {}

function iupCallMethod(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 RegisterCallback(name, func, type)
  if not callbacks[name] then callbacks[name] = {} end
  local cb = 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

iupNewClass("iup widget")
iupSetMethod("iup widget", "__index", widget_gettable)


local ihandle_gettable = function(handle, index)
  local INDEX = string.upper(index)
  if (callbacks[INDEX]) then 
   local object = iupGetWidget(handle)
   if (not object or type(object)~="table") then error("invalid iup handle") end
   return object[index]
  else
    local value = GetAttribute(handle, INDEX)
    if (not value) then
      local object = iupGetWidget(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 = 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 = iupGetWidget(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 = callbacks[INDEX]
    if (cb) then -- if a callback name
      local func = cb[1]
      if (not func) then
        func = cb[GetClassName(handle)]
      end
      iupSetCallback(handle, INDEX, func, value) -- register the pre-defined C callback
      object[index] = value -- store also in Lua
    elseif iupGetClass(value) == "iup handle" then -- if a iup handle
      local name = ihandle_setname(value)
      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
      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

iupNewClass("iup handle")
iupSetMethod("iup handle", "__index", ihandle_gettable)
iupSetMethod("iup handle", "__newindex", ihandle_settable)
iupSetMethod("iup handle", "__tostring", ihandle_tostring)
iupSetMethod("iup handle", "__eq", ihandle_compare) -- implemented in C


------------------------------------------------------------------------------
-- Utilities 
------------------------------------------------------------------------------

function ihandle_setname(v)  -- used also by radio and zbox
  local name = GetName(v)
  if not name then
    local autoname = string.format("_IUPLUA_NAME(%s)", tostring(v))
    SetHandle(autoname, v)
    return autoname
  end
  return name
end

function iupRegisterWidget(ctrl) -- called by all the controls initialization functions
  iup[ctrl.nick] = function(arg)
    return ctrl:constructor(arg)
  end
end

function RegisterHandle(handle, typename)

  iupSetClass(handle, "iup handle")
  
  local object = iupGetWidget(handle)
  if not object then

    local class = iup[string.upper(typename)]
    if not class then
      class = WIDGET
    end

    local object = { parent=class, handle=handle }
    iupSetClass(object, "iup widget")
    iupSetWidget(handle, object)
  end
  
  return handle
end

------------------------------------------------------------------------------
-- Widget class (top class) 
------------------------------------------------------------------------------

WIDGET = {
  callback = {}
}

function WIDGET.show(object)
  Show(object.handle)
end

function WIDGET.hide(object)
  Hide(object.handle)
end

function WIDGET.map(object)
  Map(object.handle)
end

function WIDGET.constructor(class, arg)
  local handle = class:createElement(arg)
  local object = { 
    parent = class,
    handle = handle
  }
  iupSetClass(handle, "iup handle")
  iupSetClass(object, "iup widget")
  iupSetWidget(handle, object)
  object:setAttributes(arg)
  return handle
end

function WIDGET.setAttributes(object, arg)
  local handle = object.handle
  for i,v in pairs(arg) do 
    if type(i) == "number" and iupGetClass(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
iupSetClass(WIDGET, "iup widget")


------------------------------------------------------------------------------
-- Box class (inherits from WIDGET) 
------------------------------------------------------------------------------

BOX = {
  parent = WIDGET
}

function BOX.setAttributes(object, arg)
  local handle = rawget(object, "handle")
  local n = #arg
  for i = 1, n do
    if iupGetClass(arg[i]) == "iup handle" then 
      Append(handle, arg[i]) 
    end
  end
  WIDGET.setAttributes(object, arg)
end

iupSetClass(BOX, "iup widget")


------------------------------------------------------------------------------
-- Compatibility functions.
------------------------------------------------------------------------------

error_message_popup = nil

function _ERRORMESSAGE(err,traceback)
  err = err..(traceback or "")
  if (error_message_popup) then
    error_message_popup.value = err
  else  
    local bt = button{title="Ok", size="60", action="error_message_popup = nil; return iup.CLOSE"}
    local ml = multiline{expand="YES", readonly="YES", value=err, size="300x150"}
    local vb = vbox{ml, bt; alignment="ACENTER", margin="10x10", gap="10"}
    local dg = dialog{vb; title="Error Message",defaultesc=bt,defaultenter=bt,startfocus=bt}
    error_message_popup = ml
    dg:popup(CENTER, CENTER)
    dg:destroy()
    error_message_popup = nil
  end
end

pack = function (...) return arg end

function protectedcall_(f, err)
  if not f then 
    _ERRORMESSAGE(err)
    return 
  end
  local ret = pack(pcall(f))
  if not ret[1] then 
    _ERRORMESSAGE(ret[2])
    return
  else  
    table.remove(ret, 1)
    return unpack(ret)
  end
end

function dostring(s) return protectedcall_(loadstring(s)) end
function dofile(f) return protectedcall_(loadfile(f)) end

function 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