diff options
-rw-r--r-- | 12-em-cross.tga | bin | 0 -> 462 bytes | |||
-rw-r--r-- | 12-em-down.tga | bin | 0 -> 356 bytes | |||
-rw-r--r-- | 12-em-plus.tga | bin | 0 -> 342 bytes | |||
-rw-r--r-- | 12-em-up.tga | bin | 0 -> 334 bytes | |||
-rw-r--r-- | dalos-binaryops.lua | 114 | ||||
-rw-r--r-- | dalos-buffer.lua | 30 | ||||
-rw-r--r-- | dalos-cd.lua | 49 | ||||
-rw-r--r-- | dalos-framebuffer.lua | 396 | ||||
-rw-r--r-- | dalos-hexview.lua | 197 | ||||
-rw-r--r-- | dalos-input.lua | 44 | ||||
-rw-r--r-- | dalos-limiter.lua | 60 | ||||
-rw-r--r-- | dalos-luafilter.lua | 174 | ||||
-rw-r--r-- | dalos-luahandle.lua | 52 | ||||
-rw-r--r-- | dalos-struct.lua | 601 | ||||
-rw-r--r-- | dalos-tee.lua | 50 | ||||
-rw-r--r-- | dalos-textbuffer.lua | 35 | ||||
-rw-r--r-- | dalos-textview.lua | 53 | ||||
-rw-r--r-- | dalos.lua | 797 | ||||
-rw-r--r-- | iupe-dbuffer.lua | 4 | ||||
-rw-r--r-- | iupe-hexview.lua | 57 |
20 files changed, 2490 insertions, 223 deletions
diff --git a/12-em-cross.tga b/12-em-cross.tga Binary files differnew file mode 100644 index 0000000..06f0531 --- /dev/null +++ b/12-em-cross.tga diff --git a/12-em-down.tga b/12-em-down.tga Binary files differnew file mode 100644 index 0000000..3416152 --- /dev/null +++ b/12-em-down.tga diff --git a/12-em-plus.tga b/12-em-plus.tga Binary files differnew file mode 100644 index 0000000..337e3c5 --- /dev/null +++ b/12-em-plus.tga diff --git a/12-em-up.tga b/12-em-up.tga Binary files differnew file mode 100644 index 0000000..2ca9149 --- /dev/null +++ b/12-em-up.tga diff --git a/dalos-binaryops.lua b/dalos-binaryops.lua new file mode 100644 index 0000000..e4c6ed9 --- /dev/null +++ b/dalos-binaryops.lua @@ -0,0 +1,114 @@ +dalosp.binaryops = { + operations = { + XOR = 0, + AND = 1, + OR = 2, + ADD = 3, + SUB = 4, + }, + + opnames = { + [0] = "XOR", + [1] = "AND", + [2] = "OR", + [3] = "ADD", + [4] = "SUB", + }, + + configure = function (self) + local accept, operation, maximize = iup.GetParam(self.name .. " configuration", nil, [[ +Operation: %l|xor|and|or|add|sub|{Binary operation that's going to occur} +Maximize: %b[No,Yes]{Check if you want to maximize the output} +]], self.op or 0, self.maximize and 1 or 0) + if accept then + self.extra.op = operation + self.extra.maximize = maximize == 1 + self:input_change() + end + end, + + get_settings = function (self) + return { op = self.extra.op, maximize = self.extra.maximize } + end, + + input_change = function (self, ind) + local h1 = self:get_linked_input(1) + local h2 = self:get_linked_input(2) + local op = self.extra.op or dalosp.binaryops.operations.XOR + if h1 and h2 then + self.color = cd.GREEN + local obj = { + h1 = h1, + h2 = h2, + op = op, + maximize = self.extra.maximize, + offset = 0, + size = self.extra.maximize and math.max(h1:getsize(), h2:getsize()) or math.min(h1:getsize(), h2:getsize()), + getname = function () return self.name end, + do_read = function (self, count) + self.h1:seek(self.offset) + self.h2:seek(self.offset) + + local t1, r1 = self.h1:read(count) + local t2, r2 = self.h2:read(count) + local r = self.maximize and math.max(r1, r2) or math.min(r1, r2) + self.offset = self.offset + r + if r == 0 then self.got_eof = true return 0 end + local t = {} + local op + if self.op == dalosp.binaryops.operations.XOR then + op = bit.bxor + elseif self.op == dalosp.binaryops.operations.AND then + op = bit.band + elseif self.op == dalosp.binaryops.operations.OR then + op = bit.bor + elseif self.op == dalosp.binaryops.operations.ADD then + op = function(a, b) return a + b end + elseif self.op == dalosp.binaryops.operations.SUB then + op = function(a, b) return a - b end + end + for i = 0, r - 1 do + t[i] = bit.band(op(t1[i % r1], t2[i % r2]), 255) + end + return r, t + end, + } + self:set_houtput(dalos.luahandle(obj)) + self.dcanvas:draw() + else + self.color = cd.YELLOW + self:set_houtput(nil) + self.dcanvas:draw() + end + end, + + draw = function (self, cv, x, y, w, h) + dalosp.object.default_draw(self, cv, x, y, w, h) + local cx, cy = x + w / 2, cv:InvertYAxis(y + h / 2) + local op = self.extra.op or dalosp.binaryops.operations.XOR + cv:TextAlignment(cd.CENTER) + cv:Foreground(cd.BLACK) + cv:Text(cx, cy, dalosp.binaryops.opnames[op]) + end, + + create = function (d, tab, settings) + tab.ninputs = 2 + tab.noutputs = 1 + tab.otype = dalos.objtype.LUA_FILTER + tab.configure = dalosp.binaryops.configure + tab.input_change = dalosp.binaryops.input_change + tab.default_name = "Binary Ops" + tab.draw = dalosp.binaryops.draw + tab.get_settings = dalosp.binaryops.get_settings + tab.ntype = "Binary Ops" + local extra = { } + if settings then extra.op = settings.op extra.maximize = settings.maximize end + + local obj = dalos.object(d, tab, extra) + + return obj + end, +} + +dalos.binaryops = dalosp.binaryops.create +dalos:register_obj("Binary Ops", dalos.binaryops, "Basic Filters") diff --git a/dalos-buffer.lua b/dalos-buffer.lua new file mode 100644 index 0000000..3743f46 --- /dev/null +++ b/dalos-buffer.lua @@ -0,0 +1,30 @@ +dalosp.buffer = { + input_change = function (self, ind) + local h = self:get_linked_input(1) + if h then + self.color = cd.GREEN + local b = Buffer(true) + b:copyfrom(self:get_linked_input(1)) + self:set_houtput(b) + else + self:set_houtput(nil) + self.color = cd.YELLOW + end + self.dcanvas:draw() + end, + + create = function (d, tab, settings) + tab.ninputs = 1 + tab.noutputs = 1 + tab.otype = dalos.objtype.LUA_FILTER + tab.default_name = "Buffer" + tab.input_change = dalosp.buffer.input_change + tab.ntype = "Buffer" + local obj = dalos.object(d, tab, extra) + + return obj + end, +} + +dalos.buffer = dalosp.buffer.create +dalos:register_obj("Buffer", dalos.buffer, "Basic Filters") diff --git a/dalos-cd.lua b/dalos-cd.lua new file mode 100644 index 0000000..cb0b6a7 --- /dev/null +++ b/dalos-cd.lua @@ -0,0 +1,49 @@ +loadmodule "luacd" + +dalosp.cd = { + get_settings = function (self) + return { filename = self.extra.filename } + end, + + configure = function (self) + local drives_list = self.extra.drives_list + local list = "" + for i, v in ipairs(drives_list) do + list = list .. v .. "|" + end + local s, id = iup.GetParam("CD drive", nil, "CD drive: %l|" .. list .. "\n", 0) + + if s then + self.extra.filename = "cd:" .. drives_list[id + 1] + local s, v = pcall(cdabstract, self.extra.filename) + if s then + self:set_houtput(v) + return + end + end + self:set_houtput(nil) + end, + + create = function (d, tab, settings) + tab.ninputs = 0 + tab.noutputs = 1 + tab.otype = dalos.objtype.HANDLE + tab.configure = dalosp.cd.configure + tab.default_name = "CD" + tab.ntype = "CD" + tab.get_settings = dalosp.cd.get_settings + local extra = { drives_list = cdprobe() } + if settings then extra.filename = settings.filename end + local obj = dalos.object(d, tab, extra) + + if extra.filename then + local s, v = pcall(cdabstract, extra.filename) + if s then obj:set_houtput(v) end + end + + return obj + end, +} + +dalos.cd = dalosp.cd.create +dalos:register_obj("CD", dalos.cd, "Basic Inputs") diff --git a/dalos-framebuffer.lua b/dalos-framebuffer.lua new file mode 100644 index 0000000..27e183c --- /dev/null +++ b/dalos-framebuffer.lua @@ -0,0 +1,396 @@ +load "iupe-dbuffer.lua" + +dalosp.framebuffer = { + get_settings = function (self) + local extra = self.extra + return { + width = extra.width, + height = extra.height, + bpp = extra.bpp, + zoom = extra.zoom, + ppdir = extra.ppdir, + flipx = extra.flipx, + flipy = extra.flipy, + } + end, + + input_change = function (self, ind) + local h = self:get_linked_input(ind) + if ind == 2 then + if h then + local cfg, s = h:readfile() + s, cfg = pcall(loadstring, "local cfg = " .. cfg .. "\nreturn cfg\n") + if s then + self:apply_config(cfg) + self.extra.fb:prepare() + self.extra.fb:draw() + end + end + return + end + + if h then h.getnextbyte = dalosp.framebuffer.getnextbyte end + self:apply_config{} + self.extra.fb:prepare() + self.extra.fb:draw() + end, + + activate = function (self) + self.extra.dlg:show() + end, + + configure = function (self) + local extra = self.extra + invert_lookup = { + [1] = 0, + [2] = 1, + [4] = 2, + [8] = 3, + [24] = 4, + [32] = 5, + } + lookup = { + [0] = 1, + [1] = 2, + [2] = 4, + [3] = 8, + [4] = 24, + [5] = 32, + } + local owidth, oheight, obpp, oppdir, oflipx, oflipy = extra.width, extra.height, extra.bpp, extra.ppdir, not not extra.flipx, not not extra.flipy + local cb = function (dlg, pi) + if pi < 0 then return end + local width, height, bpp, dir + width = iup.GetParamParam(dlg, 1).value + 0 + height = iup.GetParamParam(dlg, 2).value + 0 + bpp = iup.GetParamParam(dlg, 3).value + 0 + dir = iup.GetParamParam(dlg, 4).value + 0 + flipx = (iup.GetParamParam(dlg, 5).value + 0) ~= 0 + flipy = (iup.GetParamParam(dlg, 6).value + 0) ~= 0 + self:apply_config{ width = width, height = height, bpp = lookup[bpp], dir = dir, flipx = flipx, flipy = flipy } + self.extra.fb:prepare() + self.extra.fb:draw() + end + local s, nname = iup.GetParam(self.name .. " configuration", cb, [[ +New name: %s +Width: %i +Height: %i +Bpp: %l|1 bpp|2 bpp|4 bpp|8 bpp|24 bpp|32 bpp| +Packed Pixels: %l|Little Endian|Big Endian| +Flip X axis: %b +Flip Y axis: %b +]], self.name, owidth, oheight, invert_lookup[obpp], oppdir, oflipx and 1 or 0, oflipy and 1 or 0) + if not s then + self:apply_config{ width = owidth, height = oheight, bpp = obpp, ppdir = oppdir, flipx = oflipx, flipy = oflipy } + self.extra.fb:prepare() + self.extra.fb:draw() + else + self.name = nname + end + end, + + apply_config = function (self, cfg) + local extra = self.extra + local fb = extra.fb + local h = self:get_linked_input(1) + if cfg.width then extra.width = cfg.width end + if cfg.height then extra.height = cfg.height end + if cfg.bpp then extra.bpp = cfg.bpp end + if cfg.ppdir then extra.ppdir = cfg.ppdir end + if cfg.flipx then extra.flipx = cfg.flipx end + if cfg.flipy then extra.flipy = cfg.flipy end + if cfg.zoom then extra.zoom = cfg.zoom end + local zoom = 2 ^ extra.zoom + local posx = fb.posx + local posy = fb.posy + local dx = fb.dx + 0 + local dy = fb.dy + 0 + local fw = math.floor(extra.width * zoom) + local fh = math.floor(extra.height * zoom) + if dx >= (fb.xmax - fb.xmin) then posx = math.floor((fw - dx) / 2) end + if dy >= (fb.ymax - fb.ymin) then posy = math.floor((fh - dy) / 2) end + fb.xmax = fw + fb.ymax = fh + cfg = { + h = h, + width = extra.width, + height = extra.height, + bpp = extra.bpp, + ppdir = extra.ppdir, + flipx = extra.flipx, + flipy = extra.flipy, + zoom = zoom, + x = -posx, + y = -posy, + fw = fw, + fh = fh, + } + fb.cfg = cfg + local cvwidth, cvheight = fb.width or 0, fb.height or 0 + cvwidth, cvheight = cvwidth + 0, cvheight + 0 + end, + + getnextbyte = function (h) + return h:tell() ~= h:getsize() and h:readU8() or 0 + end, + + getbit = function (cfg) + local rc + local h = cfg.h + local stateful = cfg.stateful + if cfg.bpp >= 8 then return end + stateful = cfg.stateful + if not stateful or bit.band(stateful, 0x7f) == 0 then + stateful = h:getnextbyte() * 2 + 1 + else + stateful = stateful * 2 + end + cfg.stateful = stateful + return bit.band(bit.rshift(stateful, 8), 1) + end, + + getnextpixel = function (cfg) + local rc + local r, g, b + local h = cfg.h + local getbit = function() return dalosp.framebuffer.getbit(cfg) end + if cfg.bpp == 1 then + rc = getbit() * 255 + r, g, b = rc, rc, rc + elseif cfg.bpp == 2 then + rc = getbit() * 2 + rc = (rc + getbit()) * 255 / 3 + r, g, b = rc, rc, rc + elseif cfg.bpp == 4 then + rc = getbit() * 8 + rc = rc + getbit() * 4 + rc = rc + getbit() * 2 + rc = (rc + getbit()) * 255 / 15 + r, g, b = rc, rc, rc + elseif cfg.bpp == 8 then + rc = h:getnextbyte() + r, g, b = rc, rc, rc + elseif cfg.bpp == 24 then + r = h:getnextbyte() + g = h:getnextbyte() + b = h:getnextbyte() + elseif cfg.bpp == 32 then + r = h:getnextbyte() + g = h:getnextbyte() + b = h:getnextbyte() + h:getnextbyte() + end + return r, g, b + end, + + prepare = function (self) + local cfg = self.cfg + local h = cfg.h + local width = cfg.width + local height = cfg.height + local bpp = cfg.bpp + local ppdir = cfg.ppdir + local flipx = cfg.flipx + local flipy = not cfg.flipy + local cim = im.ImageCreate(width, height, im.RGB, im.BYTE) + self.cim = cim + cim:Clear() + if not h then return iup.DEFAULT end + local getnextpixel = self.getnextpixel + + h:seek(0) + cfg.stateful = 0 + local r, g, b = cim[0], cim[1], cim[2] + + for y = 0, height - 1 do + for x = 0, width - 1 do + local px, py = flipx and width - x - 1 or x, flipy and height - y - 1 or y + r[py][px], g[py][px], b[py][px] = getnextpixel(cfg) + end + end + + return iup.DEFAULT + end, + + draw = function (self) + local cvdb = self.cvdb + if not cvdb then return iup.DEFAULT end + cvdb:Clear() + local cim = self.cim + local cfg = self.cfg + cim:cdCanvasPutImageRect(cvdb, cfg.x, cvdb:InvertYAxis(cfg.y + cfg.fh), cfg.fw, cfg.fh, 0, 0, 0, 0) + cvdb:Flush() + end, + + resize_cb = function (self, width, height) + self.dx = width + self.dy = height + self.posx = self.posx + self.posy = self.posy + iupep.dbuffer.resize_cb(self, width, height) + self.obj:apply_config{} + self:draw() + end, + + fimg2canvas = function (self, ix, iy) + local cfg = self.cfg + local cx, cy + return ix + cfg.x, iy + cfg.y + end, + + canvas2fimg = function (self, cx, cy) + local cfg = self.cfg + return cx - cfg.x, cy - cfg.y + end, + + img2canvas = function (self, ix, iy) + local cfg = self.cfg + return math.floor(ix * cfg.zoom + cfg.x), math.floor(iy * cfg.zoom + cfg.y) + end, + + canvas2img = function (self, cx, cy) + local cfg = self.cfg + return math.floor((cx - cfg.x) / cfg.zoom), math.floor((cy - cfg.y) / cfg.zoom) + end, + + scroll_cb = function (self, op, posx, posy) + self:resize_cb(self.width, self.height) + end, + + wheel_cb = function (self, delta, x, y, status) + local ox, oy = self:canvas2img(x, y) + local opx, opy = self.cfg.x, self.cfg.y + self.obj:apply_config { zoom = self.obj.extra.zoom + (delta / 10) } + local nx, ny = self:img2canvas(ox, oy) + local dx, dy = ox - nx, oy - ny + self.posx, self.posy = -opx - dx, -opy - dy + self:resize_cb(self.width, self.height) + end, + + motion_cb = function (self, x, y) + local ox, oy = self:canvas2img(x, y) + local nx, ny = self:img2canvas(ox, oy) + end, + + create = function (d, tab, settings) + tab.ninputs = 2 + tab.noutputs = 0 + tab.otype = dalos.objtype.LUA_VIEWER + tab.activate = dalosp.framebuffer.activate + tab.configure = dalosp.framebuffer.configure + tab.input_change = dalosp.framebuffer.input_change + tab.default_name = "Framebuffer" + tab.ntype = "Framebuffer" + tab.get_settings = dalosp.framebuffer.get_settings + local extra = { + width = settings.width or 256, + height = settings.height or 256, + bpp = settings.bpp or 32, + ppdir = settings.dir or 0, + flipx = settings.flipx, + flipy = settings.flipy, + zoom = settings.zoom or 0, + } + + local obj = dalos.object(d, tab, extra) + + obj.apply_config = dalosp.framebuffer.apply_config + + local fb = iup.canvas { + expand = "Yes", + font = "Courier, 8", + action = iupep.dbuffer.action, + map_cb = iupep.dbuffer.map_cb, + unmap_cb = iupep.dbuffer.unmap_cb, + resize_cb = dalosp.framebuffer.resize_cb, + motion_cb = dalosp.framebuffer.motion_cb, + draw = dalosp.framebuffer.draw, + scroll_cb = dalosp.framebuffer.scroll_cb, + wheel_cb = dalosp.framebuffer.wheel_cb, + prepare = dalosp.framebuffer.prepare, + img2canvas = dalosp.framebuffer.img2canvas, + canvas2img = dalosp.framebuffer.canvas2img, + fimg2canvas = dalosp.framebuffer.img2canvas, + canvas2fimg = dalosp.framebuffer.canvas2img, + getnextpixel = dalosp.framebuffer.getnextpixel, + rastersize = extra.width .. "x" .. extra.height, + scrollbar = "Yes", + dx = 1, + dy = 1, + linex = 1, + liney = 1, + xmax = 0, + ymax = 0, + xautohide = "No", + yautohide = "No", + obj = obj, + } + local dlg = iup.dialog { + iup.vbox { + fb, + iup.hbox { + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -4 } fb:resize_cb(fb.width, fb.height) end, + title = "1:16", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -3 } fb:resize_cb(fb.width, fb.height) end, + title = "1:8", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -2 } fb:resize_cb(fb.width, fb.height) end, + title = "1:4", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -1 } fb:resize_cb(fb.width, fb.height) end, + title = "1:2", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 0 } fb:resize_cb(fb.width, fb.height) end, + title = "1:1", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 1 } fb:resize_cb(fb.width, fb.height) end, + title = "2:1", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 2 } fb:resize_cb(fb.width, fb.height) end, + title = "4:1", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 3 } fb:resize_cb(fb.width, fb.height) end, + title = "8:1", + }, + iup.fill{}, + iup.button { + action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 4 } fb:resize_cb(fb.width, fb.height) end, + title = "16:1", + }, + iup.fill{}, + }, + }, + size = "320x200", + title = obj.name, + shrink = "Yes", + } + extra.dlg = dlg + extra.fb = fb + + obj:apply_config{} + fb:prepare() + fb:draw() + + return obj + end, +} + +dalos.framebuffer = dalosp.framebuffer.create +dalos:register_obj("Framebuffer", dalos.framebuffer, "Basic Viewers") diff --git a/dalos-hexview.lua b/dalos-hexview.lua new file mode 100644 index 0000000..b59993a --- /dev/null +++ b/dalos-hexview.lua @@ -0,0 +1,197 @@ +load "iupe-hexview.lua" +load "iupe-hexview-toolbox.lua" + +dalosp.hexview = { + activate = function (self) + self.extra.hvdlg:show() + end, + + input_change = function (self, ind) + local extra = self.extra + local hv = extra.hv + local h = self:get_linked_input(ind) + if not h then + self.color = cd.YELLOW + hv:updatehandle(nil) + self.dcanvas:draw() + return + end + if not h:canread() or not h:canseek() then + self.color = cd.RED + hv:updatehandle(nil) + self.dcanvas:draw() + return + end + self.color = cd.GREEN + for i = 1, 12 do + self:set_houtput(nil, i) + self.oldcursors[i] = -1 + end + hv:updatehandle(h) + self.dcanvas:draw() + end, + + configure = function (self) + local s, newname, gsx, gsy, dgsx, dgsy, dl, ml = + iup.GetParam(self.name .. " properties", nil, [[ +Name: %s +Gridsize X: %i +Gridsize Y: %i +Default gridsize X: %i +Default gridsize Y: %i +Lines: %i +Marker lengths: %b +]], + self.name, self.extra.hv.gridsize.x, self.extra.hv.gridsize.y, iupep.hexview.gridsize.x, iupep.hexview.gridsize.y, + self.extra.hv.displaylines, self.extra.hv.showmarkerslengths and 1 or 0) + if not s then return end + self.name = newname + self.extra.hv.gridsize.x = gsx + self.extra.hv.gridsize.y = gsy + iupep.hexview.gridsize.x = dgsx + iupep.hexview.gridsize.y = dgsy + self.extra.hv.displaylines = dl + self.extra.hv.showmarkerslengths = ml == 1 + end, + + get_settings = function (self) + local hv = self.extra.hv + local r = { + mcursor = hv.mcursor + 0, + kcursor = hv.kcursor + 0, + markers = {}, + filecursor = hv.filecursor + 0, + displaylines = hv.displaylines + 0, + gridsize = hv.gridsize, + showmarkerslengths = hv.showmarkerslengths, + } + for i = 1, 10 do + r.markers[i] = hv.markers[i] + 0 + end + return r + end, + + output_change = function (self, ind) + self.extra.hv.markerslengths[ind] = 0 + self.watchees[ind] = self.outputs[ind] and true or false + self:set_houtput(nil, ind) + self.oldcursors[ind] = -1 + self:dalos_hv_cb(self.extra.hv) + end, + + update_houtput = function (self, ind, cursor) + local hv = self.extra.hv + local h = self:get_linked_input(1) + local maxsize = h and h:getsize() or -1 + cursor = cursor + 0 + if cursor >= 0 and h and self.watchees[ind] then + if cursor >= maxsize then + self:set_houtput(nil, ind) + return + end + h:seek(cursor) + local obj = { + h = h, + hvo = self, + ind = ind, + origin = cursor, + size = maxsize - cursor, + getname = function (self) return self.hvo.name .. ":" .. self.ind end, + getmodif = function (self) return self.h:getmodif() end, + do_seek = function (self) + self.h:seek(self.offset + self.origin) + self:post_read() + end, + do_read = function (self, count, userdata) + return self.h:read(count, userdata) + end, + post_read = function (self, count) + local ol = hv.markerslengths[ind] + local nl = self.offset + if nl > ol then + hv.markerslengths[ind] = nl + if hv.showmarkerslengths then + hv:draw() + end + end + end, + } + self:set_houtput(dalos.luahandle(obj), ind) + end + end, + + dalos_hv_cb = function (self, hv, reset) + local m + for i = 1, 10 do + m = hv.markers[i] + if m and self.oldcursors[i] ~= m then + self:update_houtput(i, m) + self.oldcursors[i] = m + end + end + + m = hv.kcursor + if m and self.oldcursors[11] ~= m then + self:update_houtput(11, m) + self.oldcursors[11] = m + end + + m = hv.mcursor + if m and self.oldcursors[12] ~= m then + self:update_houtput(12, m) + self.oldcursors[12] = m + end + end, + + create = function (d, tab, settings) + tab.otype = dalos.objtype.LUA_FILTER + tab.activate = dalosp.hexview.activate + tab.input_change = dalosp.hexview.input_change + tab.output_change = dalosp.hexview.output_change + tab.configure = dalosp.hexview.configure + tab.get_settings = dalosp.hexview.get_settings + tab.ninputs = 1 + tab.noutputs = 12 + tab.default_name = "Hexview" + tab.ntype = "Hexview" + + local extra = { } + + local obj = dalos.object(d, tab, extra) + + local hv = iupe.hexview { } + local hvtb = iupe.hexview_toolbox { hexview = hv } + local hvdlg = iup.dialog { iup.hbox { iup.frame { hv }, iup.sbox { direction = "WEST", hvtb } }, title = obj.name, size = "500x", shrink = "Yes" } + + extra.hv = hv + extra.hvtb = hvtb + extra.hvdlg = hvdlg + + obj.oldcursors = { } + obj.watchees = { } + obj.update_houtput = dalosp.hexview.update_houtput + for i = 1, 12 do obj.oldcursors[i] = -1 end + + if settings then + if settings.markers then + for i = 1, 10 do + if settings.markers[i] then hv.markers[i] = settings.markers[i] end + end + end + if settings.mcursor then hv.mcursor = settings.mcursor end + if settings.kcursor then hv.kcursor = settings.kcursor end + if settings.filecursor then hv.filecursor = settings.filecursor end + if settings.displaylines then hv.displaylines = settings.displaylines end + if settings.gridsize then hv.gridsize.x, hv.gridsize.y = settings.gridsize.x, settings.gridsize.y end + if settings.showmarkerslengths then hv.showmarkerslengths = settings.showmarkerslengths end + end + + hv:registercb(dalosp.hexview.dalos_hv_cb, obj) + obj.dalos_hv_cb = dalosp.hexview.dalos_hv_cb + + return obj + end, +} + +dalos.hexview = dalosp.hexview.create +dalos:register_obj("Hexview", dalos.hexview, "Basic Viewers") diff --git a/dalos-input.lua b/dalos-input.lua new file mode 100644 index 0000000..bf37b9d --- /dev/null +++ b/dalos-input.lua @@ -0,0 +1,44 @@ +dalosp.input = { + get_settings = function (self) + return { filename = self.extra.filename } + end, + + configure = function (self) + local dlg = iup.filedlg { + dialogtype = "Open", + file = self.extra.filename, + } + iup.Popup(dlg) + if dlg.status ~= -1 then + local s, v = pcall(Input, dlg.value) + if s then + self:set_houtput(v) + return + end + end + self:set_houtput(nil) + end, + + create = function (d, tab, settings) + tab.ninputs = 0 + tab.noutputs = 1 + tab.otype = dalos.objtype.HANDLE + tab.configure = dalosp.input.configure + tab.default_name = "Input" + tab.ntype = "Input" + tab.get_settings = dalosp.input.get_settings + local extra = { } + if settings then extra.filename = settings.filename end + local obj = dalos.object(d, tab, extra) + + if extra.filename then + local s, v = pcall(Input, extra.filename) + if s then obj:set_houtput(v) end + end + + return obj + end, +} + +dalos.input = dalosp.input.create +dalos:register_obj("Input", dalos.input, "Basic Inputs") diff --git a/dalos-limiter.lua b/dalos-limiter.lua new file mode 100644 index 0000000..5643f30 --- /dev/null +++ b/dalos-limiter.lua @@ -0,0 +1,60 @@ +dalosp.limiter = { + configure = function (self) + local accept, limit = iup.GetParam(self.name .. " configuration", nil, [[ +Limit: %i{The actual size this limiter is going to produce} +]], self.op or 0, self.maximize and 1 or 0) + if accept then + self.extra.limit = limit + self:input_change() + end + end, + + get_settings = function (self) + return { limit = self.extra.limit } + end, + + input_change = function (self, ind) + local h = self:get_linked_input(1) + if h then + self.color = cd.GREEN + local obj = { + h = h, + size = math.min(h:getsize(), self.extra.limit), + getname = function () return self.name end, + do_read = function (self, count, userdata) + return self.h:read(count, userdata) + end, + do_seek = function (self) + self.h:seek(self.offset, SEEK_SET) + end, + } + self:set_houtput(dalos.luahandle(obj)) + self.dcanvas:draw() + else + self.color = cd.YELLOW + self:set_houtput(nil) + self.dcanvas:draw() + end + end, + + create = function (d, tab, settings) + tab.ninputs = 1 + tab.noutputs = 1 + tab.otype = dalos.objtype.LUA_FILTER + tab.configure = dalosp.limiter.configure + tab.input_change = dalosp.limiter.input_change + tab.default_name = "Limiter" + tab.ntype = "Limiter" + tab.get_settings = dalosp.limiter.get_settings + local extra = { } + if not settings then settings = {} end + extra.limit = settings.limit or 0 + + local obj = dalos.object(d, tab, extra) + + return obj + end, +} + +dalos.limiter = dalosp.limiter.create +dalos:register_obj("Limiter", dalos.limiter, "Basic Filters") diff --git a/dalos-luafilter.lua b/dalos-luafilter.lua new file mode 100644 index 0000000..312aff7 --- /dev/null +++ b/dalos-luafilter.lua @@ -0,0 +1,174 @@ +dalosp.luafilter = { + templates = {}, + + default_code = [[ +-- available globals: + +-- ninputs, noutputs: numbers + +-- get_input(ind): handle +-- del_output(ind): nil +-- new_output(ind): nil +-- set_color(c) : nil + +function activate() +end + +function read(ind, count, userdata, offset) +end + +function seek(ind, offset) +end + +function input_change(ind) +end +]], + + get_settings = function (self) + return { ninputs = self.ninputs, noutputs = self.noutputs, code = self.extra.code } + end, + + run_in_localenv = function (self, f, ...) + local localenv = self.extra.localenv + local metatable = getmetatable(_G) + if not metatable then metatable = {} end + local oldni, oldi = metatable.__newindex, metatable.__index + metatable.__newindex = function (table, key, value) + localenv[key] = value + end + metatable.__index = function (table, key) + local l = localenv[key] + if l then return localenv[key] end + return rawget(_G, key) + end + setmetatable(_G, metatable) + + if type(f) ~= "function" then f = localenv[f] end + local rets = { true } + if f then rets = { pcall(f, ...) } end + + metatable.__newindex, metatable.__index = oldni, oldi + setmetatable(_G, metatable) + + if not rets[1] then error(rets[2]) end + table.remove(rets, 1) + return unpack(rets) + end, + + load_code = function (self, code) + self.extra.localenv = { + ninputs = self.ninputs + 0, + noutputs = self.noutputs + 0, + get_input = function(ind) return self:get_linked_input(ind) end, + del_output = function(ind) self:set_houtput(nil, ind) end, + new_output = function(ind, size, name) + self:set_houtput(dalos.luahandle{ + size = size, + getname = function () + return name + end, + do_read = function (lh, count, userdata) + return self:run_in_localenv("read", ind, count, userdata, lh.offset) + end, + do_seek = function (lh) + return self:run_in_localenv("seek", ind, lh.offset) + end, + }, ind) + end, + set_color = function(c) self.color = c self:draw() end, + } + if code and code ~= "" then + local f = loadstring(code) + if f then self:run_in_localenv(f) end + end + end, + + input_change = function (self, ind) + self:run_in_localenv("input_change", ind) + end, + + load_template = function (self) + local dlg = iup.filedlg { + dialogtype = "Open", + filter = "*.dtpl", + } + iup.Popup(dlg) + if dlg.status == -1 then return end + + local s, v = pcall(Input, dlg.value) + if not s then error("Problem loading file " .. dlg.value) end + local f = preload(v) + v:destroy() + if not f then error("Syntax error loading file " .. dlg.value) end + local data, otype, tname = f() + if otype ~= "Lua Filter" then error("Wrong template type: " .. otype) end + + self:apply_template(data.template) + end, + + gen_template = function (self) + return { code = self.extra.close } + end, + + apply_template = function (self, data) + self.extra.code = data.code + end, + + configure = function (self) + local okay = false + local text = iup.text { multiline = "Yes", font = "Courier", expand = "Yes", value = self.extra.code } + local bok = iup.button { title = "Ok", action = function () okay = true return iup.CLOSE end } + local bimport = iup.button { title = "Import", action = function() self:load_template() return iup.CLOSE end } + local bexport = iup.button { title = "Export", action = function() self:save_template(self:gen_template()) end } + local busetpl = iup.button { title = "Use Template", action = function() self:use_template(dalosp.luafilter.templates) end } + local bcancel = iup.button { title = "Cancel", action = function () okay = false return iup.CLOSE end } + local dlg = iup.dialog { iup.vbox { text, iup.hbox { bok, bimport, bexport, busetpl, iup.fill{}, bcancel, normalizesize = "Horizontal" } }, title = "Code for " .. self.name, size = "600x300" } + local r = dlg:popup() +-- if r ~= iup.NOERROR then return end + local newcode = text.value + if newcode and okay then + self.extra.code = newcode + self:load_code(newcode) + end + end, + + activate = function (self) + self:run_in_localenv "activate" + end, + + create = function (d, tab, settings) + tab.ninputs = settings and settings.ninputs + tab.noutputs = settings and settings.noutputs + tab.otype = dalos.objtype.LUA_FILTER + tab.configure = dalosp.luafilter.configure + tab.activate = dalosp.luafilter.activate + tab.input_change = dalosp.luafilter.input_change + tab.default_name = "Lua Filter" + tab.get_settings = dalosp.luafilter.get_settings + tab.ntype = "Lua Filter" + tab.gen_template = dalosp.luafilter.gen_template + tab.apply_template = dalosp.luafilter.apply_template + local extra = { localenv = {} } + extra.code = settings and settings.code + if not extra.code or extra.code == "" then extra.code = dalosp.luafilter.default_code end + local s = true + while not s and not tab.ninputs or not tab.noutputs do + s, tab.ninputs, tab.noutputs = iup.GetParam("Lua Filter", nil, "Inputs number: %i\nOutputs number: %i\n", 1, 1) + end + + local obj = dalos.object(d, tab, extra) + + obj.load_code = dalosp.luafilter.load_code + obj.run_in_localenv = dalosp.luafilter.run_in_localenv + obj:load_code(extra.code) + + return obj + end, + + register_template = function (data, tname) + dalosp.luafilters.templates[tname] = data + end, +} + +dalos.luafilter = dalosp.luafilter.create +dalos:register_obj("Lua Filter", dalos.luafilter, "Programmable", dalosp.luafilter.register_template) diff --git a/dalos-luahandle.lua b/dalos-luahandle.lua new file mode 100644 index 0000000..d3615fc --- /dev/null +++ b/dalos-luahandle.lua @@ -0,0 +1,52 @@ +dalosp.luahandle = { + create = function (tab) + local obj = { + offset = 0, + canread = function (self) return true end, + canwrite = function (self) return false end, + canseek = function (self) return true end, + canwatch = function (self) return false end, + tell = function (self) return self.offset end, + getsize = function (self) return self.size end, + getmodif = function (self) return 0 end, + flush = function (self) return true end, + seek = function (self, offset, wheel) + if wheel == SEEK_SET then + self.offset = offset + elseif wheel == SEEK_CUR then + self.offset = self.offset + offset + elseif wheel == SEEK_END then + self.offset = self.size + offset + else + error "Unknown wheel" + end + if self.offset < 0 then self.offset = 0 end + if self.offset >= self.size then self.offset = self.size end + if self.do_seek then self:do_seek() end + return self.offset + end, + read = function (self, userdata, count) + count = math.min(count, self.size - self.offset) + + if count == 0 then + if self.got_eof then self.lh:close() end + self.got_eof = true + return 0 + end + + self.got_eof = false + + local r, t = self:do_read(count, userdata) + self.offset = self.offset + r + if self.post_read then self:post_read(r) end + return r, t + end, + } + for k, v in pairs(tab) do obj[k] = v end + local newh = HandleLua(obj) + obj.lh = newh + return newh + end, +} + +dalos.luahandle = dalosp.luahandle.create diff --git a/dalos-struct.lua b/dalos-struct.lua new file mode 100644 index 0000000..5f157ef --- /dev/null +++ b/dalos-struct.lua @@ -0,0 +1,601 @@ +local function imLoadImage(fname) + local f = im.FileOpen(fname) + local r = f:LoadImage() + f:Close() + return r +end + +dalosp.struct = { + templates = {}, + + 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) + return { entries = self.extra.entries } + end, + + configure = function (self) + self.cfg_dlg:show() + end, + + activate = function (self) + self.act_dlg:show() + end, + + input_change = function (self, ind) + if ind == 1 then self:update_values() end + if ind == 2 then + local h = self:get_linked_input(2) + self:auto_template(dalosp.struct.templates, h:readstring()) + end + end, + + offset = function (self, lin) + local cache = self.extra.cache + return cache[lin] + end, + + read_value = function (self, h, t, flags, size) + local v + + if t == "int8" then + return h:read8() + elseif t == "uint8" then + return h:readU8() + elseif t == "int16" then + return h:read16() + elseif t == "uint16" then + return h:readU16() + elseif t == "int32" then + return h:read32() + elseif t == "uint32" then + return h:readU32() + elseif t == "int64" then + return h:read64() + elseif t == "uint64" then + return h:readU64() + elseif t == "float" then + return h:readFloat() + elseif t == "double" then + return h:readDouble() + elseif t == "asciiz" then + v = "" + local b + repeat + b = h:readU8() + if b ~= 0 then v = v .. string.char(b) end + until b == 0 + return v + elseif t == "nascii" then + return h:readstring(size) + end + + return 0 + end, + + update_values = function (self) + local h = self:get_linked_input(1) + self.extra.values = {} + self.extra.values_by_name = {} + if h and h:getsize() >= self.extra.size then + h:seek(0) + local v, s, t + for e, f in ipairs(self.extra.entries) do + s = f.size + if not tonumber(s) then + s = self.extra.values_by_name[s] + end + t = dalosp.struct.types[f.type] + if t == "asciiz" or t == "nascii" or s == 1 then + v = self:read_value(h, t, f.flags, s) + else + v = {} + for i = 1, f.size do + v[i] = self:read_value(h, t, f.flags, s) + end + end + self.extra.values[e] = v + self.extra.values_by_name[f.name] = v + end + self:output_selected() + self:output_struct() + else + self:set_houtput(nil, 1) + self:set_houtput(nil, 2) + end + end, + + output_selected = function (self) + local selected = self.extra.selected + local cache = self.extra.cache + local cursor = selected and cache[selected] or -1 + local h = self:get_linked_input(1) + if h and selected and selected > 0 and cursor >= 0 then + local field = self.extra.entries[selected].name + local maxsize = (cache[selected + 1] or self.extra.size) - cursor + h:seek(cursor) + local obj = { + h = h, + str = self, + origin = cursor, + field = field, + size = maxsize - cursor, + getname = function (self) return self.str.name .. ":" .. self.field end, + getmodif = function (self) return self.h:getmodif() end, + do_seek = function (self) + self.h:seek(self.offset + self.origin) + end, + do_read = function (self, count, userdata) + return self.h:read(count, userdata) + end, + } + self:set_houtput(dalos.luahandle(obj), 1) + local b = Buffer(true) + b:write(field .. "\n") + self:set_houtput(b, 3) + else + self:set_houtput(nil, 1) + self:set_houtput(nil, 3) + end + end, + + output_struct = function (self) + local b = Buffer(true) + dumpvars(b, self.extra.values_by_name, "data") + self:set_houtput(b, 2) + 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 + self:update_values() + self.act_dlg.mx.numlin = #entries + self.act_dlg.mx.numlin_visible = #entries + self.act_dlg.mx.redraw = "All" + 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 = "L" .. (lin - 1) + mx.redraw = "L" .. lin + 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 = "L" .. lin + mx.redraw = "L" .. (lin + 1) + end, + + gen_template = function (self) + return self:get_settings() + end, + + apply_template = function (self, data) + self.extra.entries = data.entries + self:cacheoffset() + end, + + get_field_value = function (self, lin) + local v = self.extra.values[lin] + if type(v) == "table" then + local r = nil + for k, sv in ipairs(v) do + if not r then + r = sv + else + r = r .. ", " .. sv + end + end + + return "[" .. (r or " ") .."]" + else + return v or "" + end + 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) + elseif col == 11 then + -- edit flags + 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" + elseif col == 11 then + return "Flags" + 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 + local off = self.struct:offset(lin) + if off == -1 then return "" end + return off + elseif col == 11 then + -- flags + 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 + self.struct:output_selected() + self.struct:output_struct() + 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 = newval + self.struct:cacheoffset() + elseif col == 8 then + -- enum + elseif col == 9 then + -- value check + end + self.struct.act_dlg.mx.redraw = "All" + 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 + local newval = self.value + if update == 0 then return iup.DEFAULT end + if col == 5 then + if not self.struct:isunique(newval) then return iup.IGNORE end + elseif col == 6 then + -- do a check on the dropdown ? I don't think so + elseif col == 7 then + if not tonumber(newval) and self.struct:isunique(newval) then return iup.IGNORE end + 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, + + act_value_cb = function (self, lin, col) + if lin == 0 then if col == 1 then return "Field" elseif col == 2 then return "Value" end end + if col == 0 then return nil end + + local entry = self.struct.extra.entries[lin] + + if col == 1 then + return entry.name + else + return self.struct:get_field_value(lin) + end + end, + + act_click_cb = function (self, lin, col, status) + self.struct.extra.selected = lin + self.struct:output_selected() + end, + + create = function (d, tab, settings) + tab.ninputs = 2 + tab.noutputs = 3 + 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.gen_template = dalosp.struct.gen_template + tab.apply_template = dalosp.struct.apply_template + 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 + local entries = settings.entries or {} + extra.entries = entries + + 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.get_field_value = dalosp.struct.get_field_value + obj.update_values = dalosp.struct.update_values + obj.read_value = dalosp.struct.read_value + obj.output_selected = dalosp.struct.output_selected + obj.output_struct = dalosp.struct.output_struct + + local cmx = iup.matrix { + numcol = 11, + numcol_visible = 11, + usetitlesize = "Yes", + rasterwidth1 = 12, + rasterwidth2 = 12, + rasterwidth3 = 12, + rasterwidth4 = 12, + rasterwidth5 = 120, + rasterwidth6 = 80, + rasterwidth7 = 80, + rasterwidth8 = 80, + rasterwidth9 = 120, + rasterwidth10 = 40, + rasterwidth11 = 60, + resizematrix = "Yes", + readonly = "No", + struct = obj, + 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, + } + local amx = iup.matrix { + numcol = 2, + numcol_visible = 2, + usetitlesize = "Yes", + rasterwidth1 = 120, + rasterwidth2 = 120, + readonly = "Yes", + resizematrix = "Yes", + struct = obj, + value_cb = dalosp.struct.act_value_cb, + click_cb = dalosp.struct.act_click_cb, + } + 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.button { + title = "Import", + action = function() obj:load_template() return iup.CLOSE end, + }, + iup.button { + title = "Export", + action = function() obj:save_template(self:gen_template()) end, + }, + iup.button { + title = "Use Template", + action = function() obj:use_template(dalsop.struct.templates) end, + }, + iup.button { + title = "Change name", + action = function() local s, n = iup.GetParam("Change name", nil, "Name: %s\n", obj.name) if s then obj.name = n end end + }, + iup.fill {}, + iup.button { + title = "Close", + action = function() return iup.CLOSE end, + }, + }, + }, + + size = "500x220", + mx = cmx, + lsize = lsize, + title = obj.name .. " configuration", + } + + obj.act_dlg = iup.dialog { + amx, + size = "250x120", + mx = amx, + title = obj.name, + } + + if entries then + obj.cfg_dlg.mx.numlin = #entries + obj.cfg_dlg.mx.numlin_visible = #entries + obj.act_dlg.mx.numlin = #entries + obj.act_dlg.mx.numlin_visible = #entries + end + obj:cacheoffset() + + return obj + end, + + register_template = function (data, tname) + dalosp.struct.templates[tname] = data + end, +} + +dalos.struct = dalosp.struct.create +dalos:register_obj("Struct", dalos.struct, "Programmable", dalosp.struct.register_template) diff --git a/dalos-tee.lua b/dalos-tee.lua new file mode 100644 index 0000000..b5193c0 --- /dev/null +++ b/dalos-tee.lua @@ -0,0 +1,50 @@ +dalosp.tee = { + NTEE = 16, + + set_out = function (self, h, ind) + local name = h:getname() + local obj = { + h = h, + size = h:getsize(), + getname = function () return name end, + do_read = function (self, count, userdata) + self.h:seek(self.offset, SEEK_SET) + return self.h:read(count, userdata) + end, + } + self:set_houtput(dalos.luahandle(obj), ind) + end, + + input_change = function (self, ind) + local h = self:get_linked_input(1) + if h then + self.color = cd.GREEN + for ind = 1, 16 do self:set_out(h, ind) end + self.dcanvas:draw() + else + self.color = cd.YELLOW + for i = 1, dalosp.tee.NTEE do + self:set_houtput(nil, i) + end + self.dcanvas:draw() + end + end, + + create = function (d, tab, settings) + tab.ninputs = 1 + tab.noutputs = dalosp.tee.NTEE + tab.otype = dalos.objtype.LUA_FILTER + tab.input_change = dalosp.tee.input_change + tab.default_name = "Tee" + tab.ntype = "Tee" + + local obj = dalos.object(d, tab) + + obj.set_out = dalosp.tee.set_out + + return obj + end, +} + +dalos.tee = dalosp.tee.create +dalos:register_obj("Tee", dalos.tee, "Basic Filters") diff --git a/dalos-textbuffer.lua b/dalos-textbuffer.lua new file mode 100644 index 0000000..2bda77f --- /dev/null +++ b/dalos-textbuffer.lua @@ -0,0 +1,35 @@ +dalosp.textbuffer = { + get_settings = function (self) + return { text = self.extra.text } + end, + + activate = function (self) + local text = self.extra.text or "" + text = iup.GetText(self.name, text) + if text then + self.extra.text = text + local b = Buffer(true) + b:write(text) + self:set_houtput(b) + end + end, + + create = function (d, tab, settings) + tab.ninputs = 0 + tab.noutputs = 1 + tab.otype = dalos.objtype.HANDLE + tab.activate = dalosp.textbuffer.activate + tab.default_name = "Text Buffer" + tab.ntype = "Text Buffer" + tab.get_settings = dalosp.textbuffer.get_settings + local extra = { } + if settings then extra.text = settings.text end + + local obj = dalos.object(d, tab, extra) + + return obj + end, +} + +dalos.textbuffer = dalosp.textbuffer.create +dalos:register_obj("Text Buffer", dalos.textbuffer, "Basic Inputs") diff --git a/dalos-textview.lua b/dalos-textview.lua new file mode 100644 index 0000000..2bd0be5 --- /dev/null +++ b/dalos-textview.lua @@ -0,0 +1,53 @@ +dalosp.textview = { + get_settings = function (self) + return { } + end, + + input_change = function (self) + local h = self:get_linked_input(1) + + if h then + self.extra.txt.value = h:readfile() + else + self.extra.txt.value = "" + end + end, + + activate = function (self) + self.extra.dlg:show() + end, + + create = function (d, tab, settings) + tab.ninputs = 1 + tab.noutputs = 0 + tab.otype = dalos.objtype.LUA_VIEWER + tab.activate = dalosp.textview.activate + tab.input_change = dalosp.textview.input_change + tab.default_name = "Text View" + tab.ntype = "Text View" + tab.get_settings = dalosp.textview.get_settings + local extra = { } + + local obj = dalos.object(d, tab, extra) + + local txt = iup.text { + multiline = "Yes", + readonly = "Yes", + expand = "Yes", + font = "Courier, 8" + } + local dlg = iup.dialog { + txt, + size = "320x200", + title = obj.name, + shrink = "Yes", + } + extra.dlg = dlg + extra.txt = txt + + return obj + end, +} + +dalos.textview = dalosp.textview.create +dalos:register_obj("Text View", dalos.textview, "Basic Viewers") @@ -2,22 +2,62 @@ loadmodule "luaiup" loadmodule "luahandle" loadmodule "lualibs" +--[[
+load "indent.lua" + +function testIndenter(i) + local lib = IndentationLib + local str = "" + local inp = Input "dalos.lua" + str = inp:readfile() + + local colorTable = lib.defaultColorTable + print(lib.indentCode(str, 4, colorTable, i)) +end + +testIndenter() +]]-- + load "iupe-dbuffer.lua" -load "iupe-hexview.lua" -load "iupe-hexview-toolbox.lua" load "iupe-tview.lua" if not dalosp then dalosp = {} end if not dalos then dalos = {} end -dalos.objects = {} +dalos.objectstypes = {} +dalos.objectstypes_by_name = {} + +dalosp.NORTH = 1 +dalosp.SOUTH = 2 +dalosp.WEST = 3 +dalosp.EAST = 4 +dalosp.cross = { } -function dalos:register_obj(name, constructor) - table.insert(self.objects, { name = name, constructor = constructor }) - if self.activemenu then - self.activemenu:update_objects() +dalos.version = { MAJOR = 0, MINOR = 1, suffix = "alpha" } +dalos.version.string = dalos.version.MAJOR .. "." .. dalos.version.MINOR .. dalos.version.suffix + +function dalos:register_obj(name, constructor, category, registertemplate) + if self.objectstypes_by_name[name] then + error("An object type of that name already exists: " .. name) + end + table.insert(self.objectstypes, { name = name, constructor = constructor, counter = 1, category = category, registertemplate = registertemplate }) + self.objectstypes_by_name[name] = #self.objectstypes + if self.active_menu then + self.active_menu:update_objects() end end +function dalos:clean() + local d = dalos.active_canvas + for k, v in ipairs(d.objects) do + for ind = 1, v.obj.noutputs do + d:destroylink(v, ind) + end + end + + while #d.objects ~= 0 do table.remove(d.objects) end + d.objects = {} +end + dalosp.canvas = { DARK_WHITE = cd.EncodeColor(224, 224, 224), BEZIER_CTRL_LEN = 40, @@ -85,6 +125,30 @@ dalosp.canvas = { cv:Line(x1, iy(y1), x2, iy(y1)) cv:Line(x1 + 1, iy(y1 + 1), x2 - 1, iy(y1 + 1)) cv:Line(x1 + 2, iy(y1 + 2), x2 - 2, iy(y1 + 2)) + + local f, st, si = cv:GetFont() + cv:Font("Helvetica", cd.PLAIN, 10) + + cv:Foreground(cd.BLACK) + cv:TextOrientation(0) + if dalosp.cross.north then + cv:TextAlignment(cd.NORTH) + cv:Text(x, iy(y1 + 3), dalosp.cross.north.name) + end + cv:TextAlignment(cd.SOUTH) + if dalosp.cross.south then + cv:Text(x, iy(y2 - 3), dalosp.cross.south.name) + end + if dalosp.cross.west then + cv:TextOrientation(270) + cv:Text(x1 + 3, iy(y), dalosp.cross.west.name) + end + if dalosp.cross.east then + cv:TextOrientation(90) + cv:Text(x2 - 3, iy(y), dalosp.cross.east.name) + end + + cv:Font(f, st, si) end, draw = function (self) @@ -120,6 +184,18 @@ dalosp.canvas = { self:draw() end, + delobj = function (self, ind) + local obj = self.objects[ind] + for i = 1, obj.obj.noutputs do + self:destroylink(obj, i) + end + for i = 1, obj.obj.ninputs do + self:destroylink_dst(obj, i) + end + table.remove(self.objects, ind) + self:draw() + end, + findobj = function (self, x, y) local obj, ind @@ -152,7 +228,7 @@ dalosp.canvas = { end, focus_cb = function (self, focus) - if focus == 0 then self:button_cb() end + if focus == 0 and (self.stateful.rghtbutton or self.stateful.leftbutton) then self:button_cb() end end, stypes = { @@ -162,10 +238,20 @@ dalosp.canvas = { }, setstatus = function (self, stype, msg) - -- todo: add a status line + local s = dalos.active_status + if not s then return end + if stype == dalos.stypes.INFO then + s.square.bgcolor = "0 255 0" + elseif stype == dalos.stypes.WARNING then + s.square.bgcolor = "255 255 0" + elseif stype == dalos.stypes.ERROR then + s.square.bgcolor = "255 0 0" + end + s.label.title = msg end, motion_cb = function (self, x, y, status) + self.stateful.mousepos = { x = x, y = y } if self.stateful.panning then local ox, oy = self.ox, self.oy local dx, dy = x - ox, y - oy @@ -183,7 +269,7 @@ dalosp.canvas = { if linking.obj.noutputs >= 1 then self.stateful.linking = linking else - self:setstatus(dalosp.canvas.stypes.ERROR, "Can't link: origin object doesn't have any output") + self:setstatus(dalos.stypes.ERROR, "Can't link: origin object doesn't have any output") self.stateful.leftclk = nil linking = nil got_error = true @@ -213,9 +299,11 @@ dalosp.canvas = { end end, - createlink = function (self, src, dst) - local oldsrc = src.obj.outputs[src.obj.curoutput] - local olddst = dst.obj.inputs[dst.obj.curinput] + createlink = function (self, src, dst, srcind, dstind) + if not srcind then srcind = src.obj.curoutput end + if not dstind then dstind = dst.obj.curinput end + local oldsrc = src.obj.outputs[srcind] + local olddst = dst.obj.inputs[dstind] if oldsrc then oldsrc.obj.obj.inputs[oldsrc.ind] = nil oldsrc.obj.obj:input_change(oldsrc.ind) @@ -224,23 +312,36 @@ dalosp.canvas = { olddst.obj.obj.outputs[olddst.ind] = nil olddst.obj.obj:output_change(olddst.ind) end - src.obj.outputs[src.obj.curoutput] = { obj = dst, ind = dst.obj.curinput } - dst.obj.inputs[dst.obj.curinput] = { obj = src, ind = src.obj.curoutput } - src.obj:output_change(src.obj.curoutput) - dst.obj:input_change(dst.obj.curinput) + src.obj.outputs[src.obj.curoutput] = { obj = dst, ind = dstind } + dst.obj.inputs[dst.obj.curinput] = { obj = src, ind = srcind } + src.obj:output_change(srcind) + dst.obj:input_change(dstind) end, - destroylink = function (self, src) - local oldsrc = src.obj.outputs[src.obj.curoutput] + destroylink = function (self, src, ind) + if not ind then ind = src.obj.curoutput end + local oldsrc = src.obj.outputs[ind] if oldsrc then - src.obj.outputs[src.obj.curoutput] = nil - src.obj:output_change(src.obj.curoutput) + src.obj.outputs[ind] = nil + src.obj:output_change(ind) oldsrc.obj.obj.inputs[oldsrc.ind] = nil oldsrc.obj.obj:input_change(oldsrc.ind) end end, + destroylink_dst = function (self, dst, ind) + if not ind then ind = dst.obj.curinput end + local olddst = dst.obj.inputs[ind] + if olddst then + dst.obj.inputs[ind] = nil + dst.obj:input_change(ind) + + olddst.obj.obj.outputs[olddst.ind] = nil + olddst.obj.obj:output_change(olddst.ind) + end + end, + button_cb = function (self, button, pressed, x, y, status) if not pressed then pressed = 0 end if not x then x = self.ox end @@ -256,23 +357,25 @@ dalosp.canvas = { self.stateful.leftclk = obj table.remove(self.objects, ind) table.insert(self.objects, obj) - self.ox, self.oy = x, y - self.bx, self.by = x, y - self:draw() end + self.ox, self.oy = x, y + self.bx, self.by = x, y + self:draw() end else if not self.stateful.linking and self.stateful.leftclk and not self.stateful.dragging then + self.stateful.leftbutton = nil self.stateful.leftclk.obj:activate() elseif self.stateful.linking then local dest = self:findobj(x,y) if not dest then self:destroylink(self.stateful.linking) elseif dest == self.stateful.linking then - self:setstatus(dalosp.canvas.stypes.ERROR, "Can't link: origin is the same as destination") + self:setstatus(dalos.stypes.ERROR, "Can't link: origin is the same as destination") elseif dest.obj.ninputs <= 0 then - self:setstatus(dalosp.canvas.stypes.ERROR, "Can't link: destination has no input") + self:setstatus(dalos.stypes.ERROR, "Can't link: destination has no input") else + self:setstatus(dalos.stypes.INFO, "Linking '" .. self.stateful.linking.obj.name .. "' and '" .. dest.obj.name .. "'") self:createlink(self.stateful.linking, dest) end self.stateful.linking = nil @@ -297,22 +400,38 @@ dalosp.canvas = { self.stateful.rghtclk = obj table.remove(self.objects, ind) table.insert(self.objects, obj) - self.ox, self.oy = x, y - self.bx, self.by = x, y - self:draw() end + self.ox, self.oy = x, y + self.bx, self.by = x, y + self:draw() end else if not self.stateful.moving and self.stateful.rghtclk and not self.stateful.dragging then + self.stateful.rghtbutton = nil self.stateful.rghtclk.obj:configure() self:draw() elseif self.menu.x then - -- activate X menu operation + local dx, dy = x - self.menu.x, y - self.menu.y + local obj + if math.abs(dx) > math.abs(dy) then + if dx < 0 then + obj = dalosp.cross.west + else + obj = dalosp.cross.east + end + else + if dy < 0 then + obj = dalosp.cross.north + else + obj = dalosp.cross.south + end + end + if obj then dalosp.menu.add_object(self, obj, self.menu.x, self.menu.y) end self.menu.x = nil self.menu.y = nil self:draw() elseif self.stateful.moving then - -- check for the trash can + -- dropped somewhere... do something useful here ? end self.stateful.panning = nil self.stateful.moving = nil @@ -326,6 +445,9 @@ dalosp.canvas = { wheel_cb = function (self, delta, x, y, status) local obj = self:findobj(x, y) + delta = -delta + if delta > 0 then delta = math.floor(delta + 0.5) else delta = -math.floor(-delta + 0.5) end + if obj then if iup.isshift(status) then obj.obj:change_curoutput(delta) @@ -339,10 +461,22 @@ dalosp.canvas = { self:draw() end, + keypress_cb = function (self, c, press) + if press ~= 1 then return end + local obj, ind = self:findobj(self.stateful.mousepos.x, self.stateful.mousepos.y) + if c == iup.K_cS then + if obj then self:delobj(ind) end + elseif c == iup.K_n then + if not obj then return end + local s, newname = iup.GetParam("Renaming", nil, "Set name: %s\n", obj.obj.name) + if s and newname then obj.obj.name = newname end + self:draw() + end + end, + create = function (tab) tab.border = "No" tab.expand = "Yes" - tab.shrink = "Yes" tab.minsize = "1x1" tab.rastersize = "1x1" local r = iup.canvas(tab) @@ -355,7 +489,9 @@ dalosp.canvas = { r.motion_cb = dalosp.canvas.motion_cb r.button_cb = dalosp.canvas.button_cb r.wheel_cb = dalosp.canvas.wheel_cb + r.keypress_cb = dalosp.canvas.keypress_cb r.addobj = dalosp.canvas.addobj + r.delobj = dalosp.canvas.delobj r.findobj = dalosp.canvas.findobj r.moveobj = dalosp.canvas.moveobj r.setobjplace = dalosp.canvas.setobjplace @@ -363,6 +499,7 @@ dalosp.canvas = { r.setstatus = dalosp.canvas.setstatus r.createlink = dalosp.canvas.createlink r.destroylink = dalosp.canvas.destroylink + r.destroylink_dst = dalosp.canvas.destroylink_dst r.drawlink = dalosp.canvas.drawlink r.drawxmenu = dalosp.canvas.drawxmenu r.origin = { x = 0, y = 0 } @@ -378,6 +515,172 @@ dalosp.canvas = { } dalosp.menu = { + action_new = function (self) + local d = dalos.active_canvas + dalos:clean() + + d:setstatus(dalos.stypes.INFO, "Workspace cleaned") + end, + + action_load = function (self) + local dlg = iup.filedlg { + dialogtype = "Open", + filter = "*.dalos" + } + iup.Popup(dlg) + if dlg.status == -1 then return end + + local s, v = pcall(Input, dlg.value) + if not s then error("Problem loading file " .. dlg.value) end + local f = preload(v) + v:destroy() + if not f then error("Syntax error loading file " .. dlg.value) end + local data = f() + local tlup = dalos.objectstypes_by_name + local ot = dalos.objectstypes + local d = dalos.active_canvas + local lup = {} + for k, v in ipairs(data.objects) do + if not tlup[v.ntype] then error("Object " .. v.ntype .. " isn't declared") end + end + if data.imports then + for i, v in ipairs(data.imports) do + dalosp.menu.load_file(v) + end + end + dalos:clean() + for k, v in ipairs(data.objects) do + local tab = { x = v.x, y = v.y, name = v.name } + local o = ot[tlup[v.ntype]].constructor(d, tab, v.settings) + for iobj, obj in ipairs(d.objects) do + if obj.obj == o then + lup[iobj] = obj + end + end + end + for k, v in ipairs(data.links) do + if not lup[v.src] then error("Can't find object for id src " .. v.src) end + if not lup[v.dst] then error("Can't find object for id dst " .. v.dst) end + d:createlink(lup[v.src], lup[v.dst], v.isrc, v.idst) + end + if data.cross then + dalosp.cross = {} + if data.cross.north then dalosp.cross.north = tlup[data.cross.north] end + if data.cross.south then dalosp.cross.south = tlup[data.cross.south] end + if data.cross.west then dalosp.cross.west = tlup[data.cross.west] end + if data.cross.east then dalosp.cross.east = tlup[data.cross.east] end + end + + d:setstatus(dalos.stypes.INFO, "Properly loaded") + end, + + action_save = function(self) + local s_obj = { } + if not dalos.active_canvas then return end + local d = dalos.active_canvas + for i, v in ipairs(d.objects) do + s_obj[i] = { x = v.x, y = v.y, name = v.obj.name, ntype = v.obj.ntype, settings = v.obj:get_settings(), lookup = v } + end + local s_links = { } + for iobj, obj in ipairs(d.objects) do + for iout, out in pairs(obj.obj.outputs) do + for ilookup, lobj in ipairs(s_obj) do + if lobj.lookup == out.obj then + table.insert(s_links, { src = iobj, dst = ilookup, isrc = iout, idst = out.ind }) + end + end + end + end + for i, v in ipairs(s_obj) do + v.lookup = nil + end + local s_cross = { } + if dalosp.cross.north then s_cross.north = dalosp.cross.north.name end + if dalosp.cross.sorth then s_cross.sorth = dalosp.cross.sorth.name end + if dalosp.cross.west then s_cross.west = dalosp.cross.west.name end + if dalosp.cross.east then s_cross.east = dalosp.cross.east.name end + local save = { objects = s_obj, links = s_links, cross = s_cross, imports = dalosp.imports } + local dlg = iup.filedlg { + dialogtype = "Save", + dalos = "*.dalos", + } + iup.Popup(dlg) + if dlg.status ~= -1 then + local s, v = pcall(Output, dlg.value) + if s then + v:write "---- Dalos save\nlocal " + dumpvars(v, dalos.version, "version") + v:write "if dalos.version.MAJOR < version.MAJOR or dalos.version.MAJOR == version.MAJOR and dalos.version.MINOR < version.MINOR then error 'Dalos version too old for this save.' end\n\nlocal " + dumpvars(v, save, "save") + v:write "return save" + v:destroy() + else + error("Failed opening " .. dlg.value .. " for writing") + end + end + + d:setstatus(dalos.stypes.INFO, "Properly saved") + end, + + load_file = function (file) + local s, v = pcall(load, file) + if not s then return end + if not dalosp.imports then dalosp.imports = {} end + for i, v in ipairs(dalosp.imports) do + if v == file then return end + end + table.insert(dalosp.imports, file) + end, + + action_import = function (self) + local dlg = iup.filedlg { + dialogtype = "Open", + filter = "*.lua", + } + iup.Popup(dlg) + if dlg.status == -1 then return end + + local d = dalos.active_canvas + dalosp.menu.load_file(dlg.value) + d:setstatus(dalos.stypes.INFO, "Properly imported") + end, + + action_reload = function (self) + if not dalosp.imports then return end + + for i, v in ipairs(dalosp.imports) do + pcall(load, v) + end + d:setstatus(dalos.stypes.INFO, "Properly reloaded all imported files") + end, + + action_load_template = function (self) + local dlg = iup.filedlg { + dialogtype = "Open", + filter = "*.dtpl", + } + iup.Popup(dlg) + if dlg.status == -1 then return end + + local s, v = pcall(Input, dlg.value) + if not s then error("Problem loading file " .. dlg.value) end + local f = preload(v) + v:destroy() + if not f then error("Syntax error loading file " .. dlg.value) end + local t = f() + local data, otype, tname = t.data, t.otype, t.tname + + local tobj = dalos.objectstypes_by_name[otype] + if not tobj then error("Unknown template object type: " .. otype) end + tobj = dalos.objectstypes[tobj] + + dalos:register_obj(otype .. "::" .. tname, function(d, tab) tobj.constructor(d, tab, data) end, "Template") + if tobj.registertemplate then tobj.registertemplate(data, tname) end + local d = dalos.active_canvas + + d:setstatus(dalos.stypes.INFO, "Template properly loaded") + end, + action_exit = function (self) return iup.CLOSE end, @@ -388,21 +691,51 @@ dalosp.menu = { ButtonDefault = "1", Buttons = "OK", Title = "About", - Value = 'DALOS (c) 2009-2010 Nicolas "Pixel" Noble.\nThis is free software with ABSOLUTELY NO WARRANTY.\nPlease look at the COPYRIGHT file for details.', + Value = 'DALOS ' .. dalos.version.string .. ' (c) 2009-2010 Nicolas "Pixel" Noble.\nThis is free software with ABSOLUTELY NO WARRANTY.\nPlease look at the COPYRIGHT file for details.', } dlg:popup() return iup.DEFAULT end, update_objects = function (self) - if dalos.dlg then - local newmenu = dalos.menu {} + local d = dalos.active_canvas + if d and d.dialog then + local newmenu = dalos.menu(dalos.active_canvas) -- copy anything from self to newmenu ? *shrug* - dalos.dlg.menu = newmenu + d.dialog.menu = newmenu end end, - create = function (tab) + add_object = function (canvas, object, x, y) + object.constructor(canvas, { counter = object.counter, x = (x or 25) + 0, y = (y or 25) + 0}, {}) + object.counter = object.counter + 1 + end, + + set_cross = function (canvas, object, dir) + if dir == dalosp.NORTH then + dalosp.cross.north = object + elseif dir == dalosp.SOUTH then + dalosp.cross.south = object + elseif dir == dalosp.EAST then + dalosp.cross.east = object + elseif dir == dalosp.WEST then + dalosp.cross.west = object + end + end, + + create = function (canvas, tab) + local item_new = iup.item { title = "New" } + item_new.action = dalosp.menu.action_new + local item_load = iup.item { title = "Load workspace" } + item_load.action = dalosp.menu.action_load + local item_save = iup.item { title = "Save workspace" } + item_save.action = dalosp.menu.action_save + local item_import = iup.item { title = "Import Lua file" } + item_import.action = dalosp.menu.action_import + local item_reload = iup.item { title = "Reload all" } + item_reload.action = dalosp.menu.action_reload + local item_load_template = iup.item { title = "Load Template" } + item_load_template.action = dalosp.menu.action_load_template local item_exit = iup.item { title = "Exit" } item_exit.action = dalosp.menu.action_exit local item_about = iup.item { title = "About" } @@ -412,22 +745,62 @@ dalosp.menu = { local east_menu = { radio = "1" } local west_menu = { radio = "1" } local south_menu = { radio = "1" } - if type(dalos.objects) == "table" then - local item - for k, v in ipairs(dalos.objects) do - item = iup.item { title = v.name } - table.insert(add_menu, item) - item = iup.item { title = v.name } - table.insert(north_menu, item) - item = iup.item { title = v.name } - table.insert(east_menu, item) - item = iup.item { title = v.name } - table.insert(west_menu, item) - item = iup.item { title = v.name } - table.insert(south_menu, item) + local item + local add_submenus = { } + local north_submenus = { } + local east_submenus = { } + local west_submenus = { } + local south_submenus = { } + local category + local add_smenu, north_smenu, east_smenu, west_smenu, south_smenu + local categories = {} + for k, v in ipairs(dalos.objectstypes) do + category = v.category + if category then + if not add_submenus[category] then + add_submenus[category] = { } + north_submenus[category] = { } + south_submenus[category] = { } + east_submenus[category] = { } + west_submenus[category] = { } + table.insert(categories, 1, category) + end + add_smenu = add_submenus[category] + north_smenu = north_submenus[category] + east_smenu = east_submenus[category] + west_smenu = west_submenus[category] + south_smenu = south_submenus[category] + else + add_smenu = add_menu + north_smenu = north_menu + east_smenu = east_menu + west_smenu = west_menu + south_smenu = south_menu end + item = iup.item { title = v.name } + item.action = function (self) dalosp.menu.add_object(canvas, v) end + table.insert(add_smenu, item) + item = iup.item { title = v.name } + item.action = function (self) dalosp.menu.set_cross(canvas, v, dalosp.NORTH) end + table.insert(north_smenu, item) + item = iup.item { title = v.name } + item.action = function (self) dalosp.menu.set_cross(canvas, v, dalosp.EAST) end + table.insert(east_smenu, item) + item = iup.item { title = v.name } + item.action = function (self) dalosp.menu.set_cross(canvas, v, dalosp.WEST) end + table.insert(west_smenu, item) + item = iup.item { title = v.name } + item.action = function (self) dalosp.menu.set_cross(canvas, v, dalosp.SOUTH) end + table.insert(south_smenu, item) + end + for i, v in ipairs(categories) do + table.insert(add_menu, 1, iup.submenu { iup.menu(add_submenus[v]), title = v }) + table.insert(north_menu, 1, iup.submenu { iup.menu(north_submenus[v]), title = v }) + table.insert(south_menu, 1, iup.submenu { iup.menu(south_submenus[v]), title = v }) + table.insert(east_menu, 1, iup.submenu { iup.menu(east_submenus[v]), title = v }) + table.insert(west_menu, 1, iup.submenu { iup.menu(west_submenus[v]), title = v }) end - local menu_file = iup.submenu { iup.menu { item_exit }, title = "File" } + local menu_file = iup.submenu { iup.menu { item_new, item_load, item_save, iup.separator {}, item_import, item_reload, iup.separator {}, item_load_template, iup.separator {}, item_exit }, title = "File" } local menu_add = iup.submenu { iup.menu(add_menu), title = "Add" } local menu_cross = iup.submenu { iup.menu { iup.submenu { iup.menu(north_menu), title = "North" }, @@ -447,7 +820,59 @@ dalosp.menu = { } dalosp.object = { - default_draw = function (self, cv, x, y, w, h ) + use_template = function (self, templates) + local ttpllst = {} + for n, v in pairs(templates) do + table.insert(ttpllst, n) + end + if #ttpllst == 0 then + local dlg = iup.messagedlg { + dialogtype = "Warning", + title = "No template", + value = "There's no template to use.\nPlease load templates from the main menu first.", + } + dlg:popup() + return iup.DEFAULT + end + table.sort(ttpllst) + local tpllst = "|" + for i, n in ipairs(ttpllst) do + tpllst = tpllst .. n .. "|" + end + local s, tind = iup.GetParam("Use Template", nil, "Template: %i" .. tpllst .. "\n", 0) + if not s then return iup.DEFAULT end + self:apply_template(templates[ttpllst[tind]]) + end, + + auto_template = function (self, templates, name) + for n, v in pairs(templates) do + if n == name then + self:apply_template(v) + end + end + end, + + load_template = function (self) + local dlg = iup.filedlg { + dialogtype = "Open", + filter = "*.dtpl", + } + iup.Popup(dlg) + if (dlg.status + 0) == -1 then return end + + local s, v = pcall(Input, dlg.value) + if not s then error("Problem loading file " .. dlg.value) end + local f = preload(v) + v:destroy() + if not f then error("Syntax error loading file " .. dlg.value) end + local t = f() + local data, otype, tname = t.data, t.otype, t.tname + if otype ~= self.ntype then error("Wrong template type: " .. otype) end + + self:apply_template(data.template) + end, + + default_draw = function (self, cv, x, y, w, h) local x1, x2, y1, y2 = x, x + w, y, y + h y1, y2 = cv:InvertYAxis(y2), cv:InvertYAxis(y1) local cx, cy = (x1 + x2) / 2, (y1 + y2) / 2 @@ -481,11 +906,13 @@ dalosp.object = { end, default_activate = function (self) - print "activate" + print "default activate" end, default_configure = function (self) - print "configure" + local s, n = iup.GetParam("Change name", nil, "Name: %s\n", self.name) + + if s then self.name = n end end, change_curinput = function (self, delta) @@ -524,10 +951,44 @@ dalosp.object = { end end, + default_get_settings = function (self) + return {} + end, + + save_template = function (self, template) + if not template then template = self:gen_template() end + local dlg = iup.filedlg { + dialogtype = "Save", + filter = "*.dtpl", + } + iup.Popup(dlg) + if dlg.status == -1 then return end + local s, name, v + s, name = iup.GetParam("Export template", nil, "Template name: %s\n", "") + if not s then return end + s, v = pcall(Output, dlg.value) + if s then + v:write "---- Dalos template\nlocal " + dumpvars(v, dalos.version, "version") + v:write "if dalos.version.MAJOR < version.MAJOR or dalos.version.MAJOR == version.MAJOR and dalos.version.MINOR < version.MINOR then error 'Dalos version too old for this save.' end\n\nlocal " + dumpvars(v, template, "template") + v:write("return { data = template, otype = '" .. self.ntype .. "', tname = '" .. name .. "' }\n") + v:destroy() + else + error("Failed opening " .. dlg.value .. " for writing") + end + end, + create = function (dcanvas, tab, extra) if not tab then tab = {} end + if not tab.name then + tab.name = tab.default_name + if tab.counter then + tab.name = tab.name .. " " .. tab.counter + end + end local obj = { - draw = dalosp.object.default_draw, + draw = tab.draw or dalosp.object.default_draw, name = tab.name or "NoName", color = tab.color or cd.GRAY, ninputs = tab.ninputs or 0, @@ -536,6 +997,7 @@ dalosp.object = { outputs = {}, curinput = 1, curoutput = 1, + ntype = tab.ntype, quicksetting = tab.quicksetting, otype = tab.otype or dalos.objtype.DUMMY, activate = tab.activate or dalosp.object.default_activate, @@ -548,8 +1010,15 @@ dalosp.object = { input_change = tab.input_change or dalosp.object.default_inputchange, output_change = tab.output_change or dalosp.object.default_outputchange, set_houtput = dalosp.object.set_houtput, + get_settings = tab.get_settings or dalosp.object.default_get_settings, houtputs = {}, get_linked_input = dalosp.object.get_linked_input, + save_template = dalosp.object.save_template, + load_template = dalosp.object.load_template, + use_template = dalosp.object.use_template, + auto_template = dalosp.object.auto_template, + apply_template = tab.apply_template, + gen_template = tab.gen_template, dcanvas = dcanvas, } @@ -573,9 +1042,36 @@ dalosp.object = { end, } +dalosp.status = { + create = function () + local r + + local s_square = iup.canvas { size = "10x", expand = "Vertical", border = "No", bgcolor = "0 255 0", } + local s_label = iup.label { expand = "Horizontal" } + + r = iup.frame { + iup.hbox { + s_square, + iup.label { separator = "Vertical" }, + s_label, + }, + expand = "Horizontal", + } + + r.square = s_square + r.label = s_label + + dalos.active_status = r + + return r + end, +} + dalos.canvas = dalosp.canvas.create dalos.menu = dalosp.menu.create dalos.object = dalosp.object.create +dalos.status = dalosp.status.create +dalos.stypes = dalosp.canvas.stypes dalos.objtype = { UNKNOWN = 0, @@ -587,172 +1083,41 @@ dalos.objtype = { ---------------- -dalosp.hexview = { - activate = function (self) - self.extra.hvdlg:show() - end, - - input_change = function (self, ind) - local extra = self.extra - local hv = extra.hv - local h = self:get_linked_input(ind) - if not h then - self.color = cd.YELLOW - hv:updatehandle(nil) - self.dcanvas:draw() - return - end - if not h:canread() or not h:canseek() then - self.color = cd.RED - hv:updatehandle(nil) - self.dcanvas:draw() - return - end - self.color = cd.GREEN - for i = 1, 12 do - self:set_houtput(nil, i) - self.oldcursors[i] = -1 - end - hv:updatehandle(h) - self.dcanvas:draw() - end, - - configure = function (self) - end, - - output_change = function (self, ind) - self.watchees[ind] = self.outputs[ind] and true or false - end, - - update_houtput = function (self, ind, cursor) - local h = self:get_linked_input(1) - if h and self.watchees[ind] then - local obj = { - h = h, - hvo = self, - ind = ind, - origin = cursor, - offset = 0, - size = h:getsize() - cursor, - canread = function (self) return true end, - canwrite = function (self) return false end, - canseek = function (self) return true end, - canwatch = function (self) return self.h:canwatch() end, - getname = function (self) return self.hvo.name .. ":" .. self.ind end, - tell = function (self) return self.offset end, - getsize = function (self) return self.size end, - getmodif = function (self) return self.hvo:getmodif() end, - flush = function (self) return self.hvo:flush() end, - seek = function (self, offset, wheel) - if wheel == SEEK_SET then - self.offset = offset - elseif wheel == SEEK_CUR then - self.offset = self.offset + offset - elseif wheel == SEEK_END then - self.offset = self.size + offset - else - error "Unknown wheel" - end - self.h:seek(self.offset + self.origin) - return self.offset - end, - read = function (self, userdata, count) - count = math.min(count, self.size - self.offset) - - if count == 0 then - if self.got_eof then self.lh:close() end - self.got_eof = true - return 0 - end - - self.got_eof = false - - local r = self.h:read(count, userdata) - self.offset = self.offset + r - if r == 0 then self.got_eof = true end - return r - end, - } - local newh = HandleLua(obj) - obj.lh = newh - self:set_houtput(newh, ind) - end - end, - - dalos_hv_cb = function (self, hv, reset) - local m - for i = 1, 10 do - m = hv.markers[i] - if self.oldcursors[i] ~= m then - self:update_houtput(i, m) - self.oldcursors[i] = m - end - end - - m = hv.kcursor - if self.oldcursors[11] ~= m then - self:update_houtput(11, m) - self.oldcursors[11] = m - end - - m = hv.mcursor - if self.oldcursors[12] ~= m then - self:update_houtput(12, m) - self.oldcursors[12] = m - end - end, - - create = function (d, tab) - if not tab.name then tab.name = "Hexview" end - tab.otype = dalos.objtype.LUA_FILTER - tab.activate = dalosp.hexview.activate - tab.input_change = dalosp.hexview.input_change - tab.output_change = dalosp.hexview.output_change - tab.configure = dalosp.hexview.configure - tab.ninputs = 1 - tab.noutputs = 12 - - local hv = iupe.hexview { } - local hvtb = iupe.hexview_toolbox { hexview = hv } - local hvdlg = iup.dialog { iup.hbox { iup.frame { hv }, iup.sbox { direction = "WEST", hvtb } }, title = tab.name } - - local obj = dalos.object(d, tab, { hv = hv, hvtb = hvtb, hvdlg = hvdlg }) - obj.oldcursors = { } - obj.watchees = { } - obj.update_houtput = dalosp.hexview.update_houtput - for i = 1, 12 do obj.oldcursors[i] = -1 end - - hv:registercb(dalosp.hexview.dalos_hv_cb, obj) - - return obj - end, -} - -dalos.hexview = dalosp.hexview.create -dalos:register_obj("Hexview", dalos.hexview) +load "dalos-luahandle.lua" +load "dalos-hexview.lua" +load "dalos-binaryops.lua" +load "dalos-limiter.lua" +load "dalos-textbuffer.lua" +load "dalos-input.lua" +load "dalos-tee.lua" +load "dalos-buffer.lua" +load "dalos-luafilter.lua" +load "dalos-struct.lua" +load "dalos-textview.lua" +load "dalos-cd.lua" +load "dalos-framebuffer.lua" ---------------- -d = dalos.canvas {} -m = dalos.menu {} - -b1 = Buffer(true) -b1:write("Buffer 1 contents") -b2 = Buffer(true) -b2:write("Buffer 2 contents") +function dalos:main() + local d, m, s + + d = self.canvas {} + m = self.menu(d) + s = self.status() -o1 = dalos.object(d, { y = 30, x = 10, noutputs = 1, name = "Buffer 1", otype = dalos.objtype.HANDLE }) -o2 = dalos.object(d, { y = 120, x = 10, noutputs = 1, name = "Buffer 2", otype = dalos.objtype.HANDLE }) -h1 = dalos.hexview(d, { y = 60, x = 100, name = "Hexview 1" }) -h2 = dalos.hexview(d, { y = 60, x = 200, name = "Hexview 2" }) + dlg = iup.dialog { iup.vbox { d, s }, title = "Dalos", menu = m, size = "400x250", shrink = "Yes", } -o1:set_houtput(b1) -o2:set_houtput(b2) + d.dialog = dlg -dlg = iup.dialog { d, title = "Dalos", menu = m } + d:setstatus(dalos.stypes.INFO, "Dalos version " .. dalos.version.string .. " started") + + local old_error = error + error = function(...) d:setstatus(dalos.stypes.ERROR, "Got a Lua error") old_error(...) end -dalos.dialog = dlg + dlg:show() + iup.MainLoop() + dlg:hide() +end -dlg:show() -iup.MainLoop() -dlg:hide() +if not archive_main then dalos:main() end diff --git a/iupe-dbuffer.lua b/iupe-dbuffer.lua index 4321206..8c1412f 100644 --- a/iupe-dbuffer.lua +++ b/iupe-dbuffer.lua @@ -4,6 +4,8 @@ loadmodule "lualibs" if not iupep then iupep = {} end +if not iupep.dbuffer then + iupep.dbuffer = { map_cb = function (self) self.cv = cd.CreateCanvas(cd.IUP, self) @@ -41,3 +43,5 @@ iupep.dbuffer = { return iup.DEFAULT end, } + +end diff --git a/iupe-hexview.lua b/iupe-hexview.lua index 0567cd0..a6817d9 100644 --- a/iupe-hexview.lua +++ b/iupe-hexview.lua @@ -34,6 +34,8 @@ markercolors = { } iupep.hexview = { + gridsize = { x = 8, y = 14 }, + printgrid = function (self, msg, y, x) local cvdb = self.cvdb if not x then x = self.textcursor.x end @@ -116,14 +118,24 @@ iupep.hexview = { self:colorgrid(cursorcolors.GREEN, 2, kline, kcolumn * 3 + 10) self:colorgrid(cursorcolors.GREEN, 1, kline, kcolumn + 12 + columns * 3) - local marker + local marker, len, mlen for i = 0, 10 do - marker = self.markers[i] - if marker ~= -1 then + marker = self.markers[i] or -1 + marker = marker - filecursor + mlen = self.markerslengths[i] + if marker >= 0 and self.showmarkerslengths and mlen and mlen > 0 then + len = math.min(mlen, nbbytes - marker) + elseif marker >= 0 and marker < nbbytes then + len = 1 + else + len = 0 + end + for j = 1, len do mline = math.floor(marker / columns) mcolumn = marker % columns self:colorgrid(markercolors[i], 2, mline, mcolumn * 3 + 10) self:colorgrid(markercolors[i], 1, mline, mcolumn + 12 + columns * 3) + marker = marker + 1 end end @@ -340,6 +352,36 @@ iupep.hexview = { elseif c == iup.K_m0 then kaction = true self.markers[10] = kcursor + elseif c == iup.K_c1 then + kaction = true + self.markers[1] = nil + elseif c == iup.K_c2 then + kaction = true + self.markers[2] = nil + elseif c == iup.K_c3 then + kaction = true + self.markers[3] = nil + elseif c == iup.K_c4 then + kaction = true + self.markers[4] = nil + elseif c == iup.K_c5 then + kaction = true + self.markers[5] = nil + elseif c == iup.K_c6 then + kaction = true + self.markers[6] = nil + elseif c == iup.K_c7 then + kaction = true + self.markers[7] = nil + elseif c == iup.K_c8 then + kaction = true + self.markers[8] = nil + elseif c == iup.K_c9 then + kaction = true + self.markers[9] = nil + elseif c == iup.K_c0 then + kaction = true + self.markers[10] = nil elseif c == iup.K_SP then kaction = true end @@ -491,7 +533,7 @@ iupep.hexview = { end, updategridsize = function (self, gridsize) - self.gridsize = gridsize or { x = 8, y = 14 } + self.gridsize = gridsize or iupep.hexview.gridsize self:resize_cb(self.width, self.height) end, @@ -509,7 +551,6 @@ iupep.hexview = { tab.gridsize = nil tab.cursor = "TEXT" tab.expand = "Yes" - tab.shrink = "Yes" tab.border = "No" tab.minsize = "0x0" tab.size = "0x0" @@ -544,9 +585,11 @@ iupep.hexview = { r.filesize = handle and handle:getsize() or 0 r.mcursor = -1 r.markers = {} - r.displaylines = -1 + r.markerslengths = {} + r.showmarkerslengths = false + r.displaylines = 0 for i = 0, 10 do r.markers[i] = -1 end - r.gridsize = gridsize or { x = 8, y = 14 } + r.gridsize = gridsize or iupep.hexview.gridsize r.textcursor = { x = 0, y = 0 } return r end, |