summaryrefslogtreecommitdiff
path: root/iup/srclua5/iuplua.lua
blob: a58656f470609e2a631ba07ebd5dbe66256f3afd (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
286
-- This file is executed with the "iup" table already as the globalindex

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

iup.callbacks = {}

function iup.CallMethod(name, ...)
  local handle = ... -- always the handle
  local func = handle[name]
  if (not func) then
    return
  end
  
  if type(func) == "function" then
    return func(...)
  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(msg,traceback)
  msg = msg..(traceback or "")
  if (iup.error_message_popup) then
    iup.error_message_popup.value = msg
  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=msg, 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 {...} end

function iup.protectedcall(f, msg)
  if not f then 
    iup._ERRORMESSAGE(msg)
    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)   --must replace this by table.unpack when 5.1 is not supported
  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