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-tview.lua" if not dalosp then dalosp = {} end if not dalos then dalos = {} end dalos.objectstypes = {} dalos.objectstypes_by_name = {} dalosp.NORTH = 1 dalosp.SOUTH = 2 dalosp.WEST = 3 dalosp.EAST = 4 dalosp.cross = { } 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, drawlink = function (self, src, dst, si, di) local cv = self.cvdb local iy = function (y) return cv:InvertYAxis(y) end local ctrl_len = dalosp.canvas.BEZIER_CTRL_LEN cv: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) x1, x2, y1, y2 = math.floor(x1 + 0.5), math.floor(x2 + 0.5), math.floor(y1 + 0.5), math.floor(y2 + 0.5) cv:Begin(cd.BEZIER) cv:Vertex(x1, iy(y1)) cv:Vertex(x1 + ctrl_len, iy(y1)) cv:Vertex(x2 - ctrl_len, iy(y2)) cv:Vertex(x2, iy(y2)) cv:End() end, XMENUWIDTH = 100, drawxmenu = function (self, x, y) local cv = self.cvdb local width = dalosp.canvas.XMENUWIDTH local x1, x2, y1, y2 = x - width / 2, x + width / 2, y - width / 2, y + width / 2 x1, x2, y1, y2 = math.floor(x1 + 0.5), math.floor(x2 + 0.5), math.floor(y1 + 0.5), math.floor(y2 + 0.5) local iy = function (y) return cv:InvertYAxis(y) end local cx1, cx2, cy1, cy2 = x - 5, x + 5, y - 5, y + 5 cv:Foreground(dalosp.canvas.DARK_WHITE) cv:Box(x1, x2, iy(y2), iy(y1)) cv:Foreground(cd.GRAY) cv:Line(x1, iy(y1), x2, iy(y2)) cv:Line(x1, iy(y2), x2, iy(y1)) cv:Line(x1 + 1, iy(y1), x2, iy(y2 - 1)) cv:Line(x1, iy(y2 - 1), x2 - 1, iy(y1)) cv:Foreground(cd.WHITE) cv:Line(x1, iy(y1 + 1), x2 - 1, iy(y2)) cv:Line(x1 + 1, iy(y2), x2, iy(y1 + 1)) cv:Line(x1, iy(y1 + 2), x2 - 2, iy(y2)) cv:Line(x1 + 2, iy(y2), x2, iy(y1 + 2)) cv:Foreground(dalosp.canvas.DARK_WHITE) cv:Sector(x, iy(y), 10, 10, 0, 360) cv:Foreground(cd.GRAY) cv:Arc(x, iy(y), 10, 10, 0, 360) cv:Foreground(cd.WHITE) cv:Arc(x + 1, iy(y + 1), 10, 10, 0, 360) cv:Foreground(cd.GRAY) cv:Line(x1, iy(y2), x2, iy(y2)) cv:Line(x1 + 1, iy(y2 - 1), x2 - 1, iy(y2 - 1)) cv:Line(x1 + 2, iy(y2 - 2), x2 - 2, iy(y2 - 2)) cv:Line(x2, iy(y1), x2, iy(y2)) cv:Line(x2 - 1, iy(y1 + 1), x2 - 1, iy(y2 - 1)) cv:Line(x2 - 2, iy(y1 + 2), x2 - 2, iy(y2 - 2)) cv:Foreground(cd.WHITE) cv:Line(x1, iy(y1), x1, iy(y2)) cv:Line(x1 + 1, iy(y1 + 1), x1 + 1, iy(y2 - 1)) cv:Line(x1 + 2, iy(y1 + 2), x1 + 2, iy(y2 - 2)) 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) local cvdb = self.cvdb if not cvdb then return iup.DEFAULT end cvdb:Background(dalosp.canvas.DARK_WHITE) 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 if self.menu.x then self:drawxmenu(self.menu.x, self.menu.y) 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, 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 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 and (self.stateful.rghtbutton or self.stateful.leftbutton) then self:button_cb() end end, stypes = { INFO = 0, WARNING = 1, ERROR = 2, }, setstatus = function (self, stype, msg) 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 if self.stateful.linking then self.bx, self.by = self.bx + dx, self.by + dy end 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(dalos.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 elseif not self.menu.x then self.menu.x, self.menu.y = x, y self:draw() end end end, 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) end if olddst then olddst.obj.obj.outputs[olddst.ind] = nil olddst.obj.obj:output_change(olddst.ind) end 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, ind) if not ind then ind = src.obj.curoutput end local oldsrc = src.obj.outputs[ind] if oldsrc then 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 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) if obj then self.stateful.leftclk = obj table.remove(self.objects, ind) table.insert(self.objects, obj) 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(dalos.stypes.ERROR, "Can't link: origin is the same as destination") elseif dest.obj.ninputs <= 0 then 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 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) if obj then self.stateful.rghtclk = obj table.remove(self.objects, ind) table.insert(self.objects, obj) 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 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 -- dropped somewhere... do something useful here ? 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) 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) elseif iup.isalt(status) then obj.obj:change_quicksetting(delta) else obj.obj:change_curinput(delta) end end 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.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.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 r.panning = dalosp.canvas.panning 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 } r.menu = { } r.stateful = {} r.objects = {} dalos.active_canvas = r return r end, } 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, action_about = function (self) local dlg = iup.messagedlg { DialogType = "Information", ButtonDefault = "1", Buttons = "OK", Title = "About", 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) 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* d.dialog.menu = newmenu end end, 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" } item_about.action = dalosp.menu.action_about local add_menu = { } local north_menu = { radio = "1" } local east_menu = { radio = "1" } local west_menu = { radio = "1" } local south_menu = { radio = "1" } 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_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" }, iup.submenu { iup.menu(east_menu), title = "East" }, iup.submenu { iup.menu(west_menu), title = "West" }, iup.submenu { iup.menu(south_menu), title = "South" }, }, title = "Cross", } local menu_help = iup.submenu { iup.menu { item_about }, title = "Help" } local r = iup.menu { menu_file, menu_add, menu_cross, menu_help } r.update_objects = dalosp.menu.update_objects r.add_menu = add_menu dalos.active_menu = r return r end, } dalosp.object = { 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 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, get_linked_input = function (self, ind) local ni = self.inputs[ind] if ni then local ii = ni.ind local io = ni.obj return io.obj:get_output(ii) else return nil end end, default_activate = function (self) print "default activate" end, default_configure = function (self) 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) 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.noutputs <= 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, default_outputchange = function (self, ind) end, set_houtput = function (self, h, ind) if not ind then ind = 1 end self.houtputs[ind] = h local obj = self.outputs[ind] if obj then obj.obj.obj:input_change(obj.ind) 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 = tab.draw or 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, ntype = tab.ntype, 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, 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, } 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, } 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, DUMMY = 1, HANDLE = 2, LUA_FILTER = 3, LUA_VIEWER = 4, } ---------------- 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" load "dalos-isoviewer.lua" ---------------- function dalos:main() local d, m, s d = self.canvas {} m = self.menu(d) s = self.status() dlg = iup.dialog { iup.vbox { d, s }, title = "Dalos", menu = m, size = "400x250", shrink = "Yes", } d.dialog = dlg 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 dlg:show() iup.MainLoop() dlg:hide() end if not archive_main then dalos:main() end