loadmodule "luaiup" loadmodule "luahandle" loadmodule "lualibs" 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 dalosp.canvas = { drawlink = function (self, src, dst, si, di) local cvdb = self.cvdb cvdb:Foreground(cd.BLACK) local x1, y1, x2, y2 x1 = self.origin.x + src.x + src.w x2 = self.origin.x + dst.x y1 = self.origin.y + src.y + si * src.h / (src.obj.noutputs + 1) y2 = self.origin.y + dst.y + di * src.h / (dst.obj.ninputs + 1) cvdb:Line(x1, cvdb:InvertYAxis(y1), x2, cvdb:InvertYAxis(y2)) end, draw = function (self) local cvdb = self.cvdb if not cvdb then return iup.DEFAULT end cvdb:Clear() for k, v in ipairs(self.objects) do v.obj:draw(cvdb, self.origin.x + v.x, self.origin.y + v.y, v.w, v.h) for oi = 1, v.obj.noutputs do local dest = v.obj.outputs[oi] if dest and dest.obj then self:drawlink(v, dest.obj, oi, dest.ind) end end end if self.stateful.linking then cvdb:Foreground(cd.BLACK) cvdb:Line(self.bx, cvdb:InvertYAxis(self.by), self.ox, cvdb:InvertYAxis(self.oy)) end cvdb:Flush() return iup.DEFAULT end, addobj = function (self, obj, x, y, w, h) table.insert(self.objects, { obj = obj, x = x, y = y, w = w, h = h }) self:draw() end, findobj = function (self, x, y) local obj, ind x = x - self.origin.x y = y - self.origin.y for k, v in ipairs(self.objects) do if v.x <= x and (v.x + v.w) >= x and v.y <= y and (v.y + v.h) >= y then obj, ind = v, k end end return obj, ind end, moveobj = function (self, obj, dx, dy) obj.x, obj.y = obj.x + dx, obj.y + dy self:draw() end, setobjplace = function (self, obj, x, y) obj.x, obj.y = x, y self:draw() end, panning = function (self, dx, dy) self.origin.x = self.origin.x + dx self.origin.y = self.origin.y + dy self:draw() end, focus_cb = function (self, focus) if focus == 0 then self:button_cb() end end, stypes = { INFO = 0, WARNING = 1, ERROR = 2, }, setstatus = function (self, stype, msg) -- todo: add a status line end, motion_cb = function (self, x, y, status) if self.stateful.panning then local ox, oy = self.ox, self.oy local dx, dy = x - ox, y - oy self:panning(dx, dy) self.ox, self.oy = x, y elseif self.stateful.leftbutton then local linking = self.stateful.linking self.stateful.dragging = true local got_error = false if self.stateful.leftclk and not self.stateful.linking then linking = self.stateful.leftclk 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.stateful.leftclk = nil linking = nil got_error = true end else linking = self.stateful.linking end if linking then self.ox, self.oy = x, y self:draw() elseif not got_error then -- todo: start selection square ? end elseif self.stateful.rghtbutton then if self.stateful.rghtclk and not self.stateful.moving then self.stateful.moving = self.stateful.rghtclk end self.stateful.dragging = true local moving = self.stateful.moving if moving then local ox, oy = self.ox, self.oy local dx, dy = x - ox, y - oy self:moveobj(moving, dx, dy) self.ox, self.oy = x, y else -- todo: show X menu end end end, createlink = function (self, src, dst) local oldsrc = src.obj.outputs[src.obj.curoutput] local olddst = dst.obj.inputs[dst.obj.curinput] if oldsrc then oldsrc.obj.obj.inputs[oldsrc.ind] = nil oldsrc.obj.obj:input_change(oldsrc.ind) end if olddst then olddst.obj.obj.outputs[olddst.ind] = nil 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 } dst.obj:input_change(dst.obj.curinput) 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 if not y then y = self.oy end if button == iup.BUTTON1 or not button then if pressed == 1 then self.stateful.leftbutton = true if self.stateful.rghtbutton then self.stateful.panning = true else local obj, ind = self:findobj(x, y) 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 else if not self.stateful.linking and self.stateful.leftclk and not self.stateful.dragging then self.stateful.leftclk.obj:activate() elseif self.stateful.linking then local dest = self:findobj(x,y) if not dest then -- just do nothing, huh... elseif dest == self.stateful.linking then self:setstatus(dalosp.canvas.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") else self:createlink(self.stateful.linking, dest) end self.stateful.linking = nil self:draw() end self.stateful.panning = nil self.stateful.linking = nil self.stateful.leftclk = nil self.stateful.leftbutton = nil if not self.stateful.rghtbutton then self.stateful.dragging = nil end end end if button == iup.BUTTON3 or not button then if pressed == 1 then self.stateful.rghtbutton = true if self.stateful.leftbutton then self.stateful.panning = true else local obj, ind = self:findobj(x, y) 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 else if not self.stateful.moving and self.stateful.rghtclk and not self.stateful.dragging then self.stateful.rghtclk.obj:configure() end self.stateful.panning = nil self.stateful.moving = nil self.stateful.rghtclk = nil self.stateful.rghtbutton = nil if not self.stateful.leftbutton then self.stateful.dragging = nil end end end end, wheel_cb = function (self, delta, x, y, status) local obj = self:findobj(x, y) if obj then if iup.isshift(status) then obj:change_curoutput(delta) elseif iup.isalt(status) then obj:change_quicksetting(delta) else obj:change_curinput(delta) end end self:draw() end, create = function (tab) tab.border = "No" tab.expand = "Yes" tab.shrink = "Yes" tab.minsize = "1x1" tab.rastersize = "1x1" local r = iup.canvas(tab) r.action = iupep.dbuffer.action r.draw = dalosp.canvas.draw r.resize_cb = iupep.dbuffer.resize_cb r.map_cb = iupep.dbuffer.map_cb r.unmap_cb = iupep.dbuffer.unmap_cb r.focus_cb = dalosp.canvas.focus_cb r.motion_cb = dalosp.canvas.motion_cb r.button_cb = dalosp.canvas.button_cb r.wheel_cb = dalosp.canvas.wheel_cb r.addobj = dalosp.canvas.addobj r.findobj = dalosp.canvas.findobj r.moveobj = dalosp.canvas.moveobj r.setobjplace = dalosp.canvas.setobjplace r.panning = dalosp.canvas.panning r.setstatus = dalosp.canvas.setstatus r.createlink = dalosp.canvas.createlink r.drawlink = dalosp.canvas.drawlink r.origin = { x = 0, y = 0 } r.stateful = {} r.objects = {} return r end, } dalosp.menu = { action_exit = function (self) return iup.CLOSE end, action_about = function (self) local dlg = iup.messagedlg { DialogType = "Information", 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.', } dlg:popup() return iup.DEFAULT end, create = function (tab) local item_exit = iup.item { title = "Exit" } item_exit.action = dalosp.menu.action_exit local item_about = iup.item { title = "About" } item_about.action = dalosp.menu.action_about local menu_file = iup.submenu { iup.menu { item_exit }, title = "File" } local menu_help = iup.submenu { iup.menu { item_about }, title = "Help" } return iup.menu { menu_file, menu_help } end, } dalosp.object = { 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 cv:Foreground(self.color) cv:Box(x1, x2, y1, y2) cv:Foreground(cd.BLACK) cv:Rect(x1, x2, y1, y2) cv:TextAlignment(cd.SOUTH) cv:Text(cx, y2, self.name) cv:TextAlignment(cd.NORTH) if self.ninputs >= 1 then cv:Text(x1, y1, self.curinput .. "/" .. self.ninputs) end if self.noutputs >= 1 then cv:Text(x2, y1, self.curoutput .. "/" .. self.noutputs) end if self.quicksetting then cv:Text(cx, y1, self.quicksetting) end end, default_activate = function (self) print "activate" end, default_configure = function (self) print "configure" end, change_curinput = function (self, delta) if self.ninputs <= 1 then return end self.curinput = self.curinput + delta if self.curinput > self.ninputs then self.curinput = self.ninputs end if self.curinput <= 0 then self.curinput = 1 end end, change_curoutput = function (self, delta) if self.ouputs <= 1 then return end self.curoutput = self.curoutput + delta if self.curoutput > self.noutputs then self.curoutput = self.noutputs end if self.curoutput <= 0 then self.curoutput = 1 end end, default_change_quicksetting = function (self, delta) end, default_getoutput = function (self, ind) return self.houtputs[ind] end, default_inputchange = function (self, ind) end, set_houtput = function (self, h, ind) if not ind then ind = 1 end self.houtputs[ind] = h end, create = function (dcanvas, tab, extra) if not tab then tab = {} end local obj = { draw = dalosp.object.default_draw, name = tab.name or "NoName", color = tab.color or cd.GRAY, ninputs = tab.ninputs or 0, noutputs = tab.noutputs or 0, inputs = {}, outputs = {}, curinput = 1, curoutput = 1, quicksetting = tab.quicksetting, otype = tab.otype or dalos.objtype.DUMMY, activate = tab.activate or dalosp.object.default_activate, configure = tab.configure or dalosp.object.default_configure, change_curinput = dalosp.object.change_curinput, change_curoutput = dalosp.object.change_curoutput, change_quicksetting = tab.change_quicksetting or dalosp.object.default_change_quicksetting, extra = extra, get_output = tab.getoutput or dalosp.object.default_getoutput, input_change = tab.input_change or dalosp.object.default_inputchange, set_houtput = dalosp.object.set_houtput, get_outputx = nil, houtputs = {}, } if tab.otype and not tab.c then if tab.otype == dalos.objtype.DUMMY then obj.color = cd.GRAY elseif tab.otype == dalos.objtype.HANDLE then obj.color = cd.CYAN elseif tab.otype == dalos.objtype.LUA_VIEWER then obj.color = cd.MAGENTA elseif tab.otype == dalos.objtype.LUA_FILTER then obj.color = cd.YELLOW else obj.color = cd.DARK_RED end end dcanvas:addobj(obj, tab.x or 0, tab.y or 0, tab.w or 50, tab.h or 50) return obj end, } dalos.canvas = dalosp.canvas.create dalos.menu = dalosp.menu.create dalos.object = dalosp.object.create dalos.objtype = { UNKNOWN = 0, DUMMY = 1, HANDLE = 2, LUA_FILTER = 3, LUA_VIEWER = 4, } ---------------- d = dalos.canvas {} m = dalos.menu {} b1 = Buffer(true) b1:write("Buffer 1 contents") b2 = Buffer(true) b2:write("Buffer 2 contents") function activate_hv(self) self.extra.hvdlg:show() end function input_change_hv(self, ind) self.extra.hv:updatehandle(self.inputs[ind].obj.obj:getoutput(self.inputs[ind].ind)) end extra = { hv = iupe.hexview { }, hvdlg = iup.dialog { iup.hbox{ iup.frame { hv }, iup.sbox { direction = "WEST", iupe.hexview_toolbox { hexview = hv, }, }, }, title = "Hexview" } } o1 = dalos.object(d, { y = 30, x = 10, noutputs = 1, name = "Buffer 1", otype = dalos.objtype.HANDLE }) o2 = dalos.object(d, { y = 30, x = 90, noutputs = 1, name = "Buffer 2", otype = dalos.objtype.HANDLE }) h = dalos.object(d, { y = 120, x = 50, ninputs = 1, name = "Hexview", otype = dalos.objtype.LUA_VIEWER, activate = activate_hv, input_change = input_change_hv }, extra) o1:set_houtput(b1) o2:set_houtput(b2) dlg = iup.dialog { d, title = "Dalos", menu = m } dlg:show() iup.MainLoop() dlg:hide()