local function imLoadImage(fname) local f = im.FileOpen(fname) local r = f:LoadImage() f:Close() return r end dalosp.struct = { images = { up = imLoadImage "12-em-up.tga", down = imLoadImage "12-em-down.tga", cross = imLoadImage "12-em-cross.tga", plus = imLoadImage "12-em-plus.tga", }, types = { "int8", "uint8", "int16", "uint16", "int32", "uint32", "int64", "uint64", "float", "double", "nascii", "asciiz", }, rtypes = { int8 = 1, uint8 = 2, int16 = 3, uint16 = 4, int32 = 5, uint32 = 6, int64 = 7, uint64 = 8, float = 9, double = 10, nascii = 11, asciiz = 12, }, typessizes = { 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 1, -1, }, get_settings = function (self) end, configure = function (self) self.cfg_dlg:popup() end, activate = function (self) self.actv_dlg:show() end, input_change = function (self) end, offset = function (self, lin) local cache = self.extra.cache return cache[lin] end, cacheoffset = function (self) local entries = self.extra.entries self.extra.cache = {} local cache = self.extra.cache local offset = 0 local got_var = false local ssize local vsize for i, v in ipairs(entries) do ssize = dalosp.struct.typessizes[v.type] vsize = ssize == -1 or type(v.size) ~= "number" if vsize then got_var = true end if got_var then cache[i] = -1 else cache[i] = offset end if not vsize then offset = offset + ssize * v.size end end self.extra.size = offset if self.cfg_dlg then self.cfg_dlg.mx.redraw = "C10" self.cfg_dlg.lsize.title = offset end end, isunique = function (self, name) for _, v in ipairs(self.extra.entries) do if name == v.name then return false end end return true end, getunique = function (self, lin) local newname = "Field" .. lin local base_newname = newname local i = 1 while not self:isunique(newname) do newname = base_newname .. "." .. i i = i + 1 end return newname end, insert_line = function (self, lin) if not lin then lin = (#self.extra.entries + 1) end local name = self:getunique(lin) table.insert(self.extra.entries, lin, { name = name, type = 1, size = 1 }) self:cacheoffset() local mx = self.cfg_dlg.mx mx.numlin = mx.numlin + 1 mx.numlin_visible = mx.numlin_visible + 1 end, remove_line = function (self, lin) table.remove(self.extra.entries, lin) self:cacheoffset() local mx = self.cfg_dlg.mx mx.numlin = mx.numlin - 1 mx.numlin_visible = mx.numlin_visible - 1 end, line_up = function (self, lin) if lin == 1 then return iup.DEFAULT end local entries = self.extra.entries local old_lin = entries[lin] table.remove(entries, lin) table.insert(entries, lin - 1, old_lin) self:cacheoffset() local mx = self.cfg_dlg.mx mx.redraw = "All" end, line_down = function (self, lin) local entries = self.extra.entries if lin == #entries then return iup.DEFAULT end local old_lin = entries[lin] table.remove(entries, lin) table.insert(entries, lin + 1, old_lin) self:cacheoffset() local mx = self.cfg_dlg.mx mx.redraw = "All" end, cfg_draw_cb = function (self, lin, col, x1, x2, y1, y2, cv) if col == 1 then dalosp.struct.images.plus:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) return iup.DEFAULT elseif col == 2 and lin ~= 0 then dalosp.struct.images.cross:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) return iup.DEFAULT elseif col == 3 and lin ~= 0 and lin ~= 1 then dalosp.struct.images.up:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) return iup.DEFAULT elseif col == 4 and lin ~= 0 and lin ~= #self.struct.extra.entries then dalosp.struct.images.down:cdCanvasPutImageRect(cv, x1 + 3, y2 + 5, 12, 12, 0, 12, 0, 12) return iup.DEFAULT end return iup.IGNORE end, cfg_click_cb = function (self, lin, col, status) if col == 1 and lin == 0 then return self.struct:insert_line() end if lin == 0 then return iup.DEFAULT end if col == 1 then self.struct:insert_line(lin) elseif col == 2 then self.struct:remove_line(lin) elseif col == 3 then self.struct:line_up(lin) elseif col == 4 then self.struct:line_down(lin) end end, cfg_value_cb = function (self, lin, col) if lin == 0 then if col == 5 then return "Name" elseif col == 6 then return "Type" elseif col == 7 then return "Size" elseif col == 8 then return "Enum" elseif col == 9 then return "Value Check" elseif col == 10 then return "Offset" end return "" end local entries = self.struct.extra.entries if col == 5 then return entries[lin].name elseif col == 6 then return dalosp.struct.types[entries[lin].type] elseif col == 7 then return entries[lin].size elseif col == 10 then return self.struct:offset(lin) end return "" end, cfg_value_edit_cb = function (self, lin, col, newval) local entries = self.struct.extra.entries if col == 5 then entries[lin].name = newval elseif col == 6 then entries[lin].type = dalosp.struct.rtypes[newval] self.struct:cacheoffset() elseif col == 7 then local nnewval = tonumber(newval) if nnewval then newval = nnewval end entries[lin].size = nnewval self.struct:cacheoffset() elseif col == 8 then -- enum elseif col == 9 then -- value check end end, cfg_dropcheck_cb = function (self, lin, col) return col == 6 and iup.DEFAULT or iup.IGNORE end, cfg_edition_cb = function (self, lin, col, mode, update) if mode == 1 then return (col >= 5 and col <= 7) and iup.DEFAULT or iup.IGNORE else if update == 0 then return iup.DEFAULT end if col == 5 then -- lookup duplicates in names elseif col == 6 then -- do a check on the dropdown ? I don't think so elseif col == 7 then -- do a check on the size; can be the name of another field elseif col == 8 then -- enum elseif col == 9 then -- value check end return iup.DEFAULT end end, cfg_drop_cb = function (self, drop, lin, col) if col ~= 6 then return iup.IGNORE end for i, v in ipairs(dalosp.struct.types) do drop[i] = v end drop.value = self.previousvalue drop.visible_items = 15 return iup.DEFAULT end, create = function (d, tab, settings) tab.ninputs = 1 tab.noutputs = 1 tab.otype = dalos.objtype.LUA_VIEWER tab.configure = dalosp.struct.configure tab.activate = dalosp.struct.activate tab.input_change = dalosp.struct.input_change tab.get_settings = dalosp.struct.get_settings tab.draw = function (self, cv, x, y, w, h) dalosp.object.default_draw(self, cv, x, y, w, h) end tab.default_name = "Struct" tab.ntype = "Struct" local extra = { } if not settings then settings = {} end extra.entries = settings.entries or {} local obj = dalos.object(d, tab, extra) obj.insert_line = dalosp.struct.insert_line obj.remove_line = dalosp.struct.remove_line obj.line_up = dalosp.struct.line_up obj.line_down = dalosp.struct.line_down obj.offset = dalosp.struct.offset obj.cacheoffset = dalosp.struct.cacheoffset obj.isunique = dalosp.struct.isunique obj.getunique = dalosp.struct.getunique obj:cacheoffset() local cmx = iup.matrix { numcol = 10, numcol_visible = 10, usetitlesize = "Yes", rasterwidth1 = 12, rasterwidth2 = 12, rasterwidth3 = 12, rasterwidth4 = 12, rasterwidth5 = 120, rasterwidth6 = 80, rasterwidth7 = 80, rasterwidth8 = 80, rasterwidth9 = 120, rasterwidth10 = 40, resizematrix = "Yes", readonly = "No", draw_cb = dalosp.struct.cfg_draw_cb, value_cb = dalosp.struct.cfg_value_cb, value_edit_cb = dalosp.struct.cfg_value_edit_cb, dropcheck_cb = dalosp.struct.cfg_dropcheck_cb, drop_cb = dalosp.struct.cfg_drop_cb, edition_cb = dalosp.struct.cfg_edition_cb, click_cb = dalosp.struct.cfg_click_cb, struct = obj, } local amx = iup.matrix { numcol = 2, numcol_visible = 2, usetitlesize = "Yes", rasterwidth1 = 120, rasterwidth2 = 120, struct = obj, } local lsize = iup.label { title = "0", expand = "Horizontal", } obj.cfg_dlg = iup.dialog { iup.vbox { iup.hbox { iup.label { title = "Struct size: " }, lsize, }, cmx, iup.hbox { iup.fill {}, iup.button { title = "Ok", action = function (self) return iup.CLOSE end }, iup.fill {}, }, }, size = "450x220", mx = cmx, lsize = lsize } obj.actv_dlg = iup.dialog { amx, } return obj end, } dalos.struct = dalosp.struct.create dalos:register_obj("Struct", dalos.struct, "Programmable")