decorator in a usable state
[Misc/ipe.git] / ipelets / decorator / decorator.lua
diff --git a/ipelets/decorator/decorator.lua b/ipelets/decorator/decorator.lua
new file mode 100644 (file)
index 0000000..8797c8b
--- /dev/null
@@ -0,0 +1,97 @@
+
+-- return a table of names associated with decorator symbols
+function decorator_names(model)
+   local sheets = model.doc:sheets()
+   local symbols = sheets:allNames("symbol")
+   local res = {}
+   for _, name in pairs(symbols) do
+      if name:find("deco/") == 1 then
+        res[#res + 1] = name
+      end
+   end
+   return res
+end
+
+-- Decorate something given by its bounding box with a given deco
+-- object, which needs to be a path.
+function decorate(model, bbox, deco)
+   if (deco:type() ~= "path") then
+      model.ui:explain("The decoration needs to be a path.")
+      return
+   end
+
+   local shape = deco:shape()
+   for _,path in pairs(shape) do
+      for _,subpath in ipairs(path) do  
+        -- move all points
+        for i,point in ipairs(subpath) do
+           subpath[i] = translation(bbox, point) * point
+        end
+
+        -- for acs, the center must be translated separately
+        if (subpath["type"] == "arc") then
+           local arc = subpath["arc"]
+           local arc_pos = arc:matrix():translation()
+           subpath["arc"] = translation(bbox, arc_pos) * arc
+        end
+      end
+   end
+   -- update model
+   deco:setShape(shape)
+   model:creation("create", deco)
+end
+
+-- The translation matrix that should be applied to a given point when
+-- doing the decoration.
+function translation(bbox, point)
+   local dx = 0
+   local dy = 0
+   if (point.x > 0) then
+      dx = dx + bbox:width()
+   end
+   if (point.y > 0) then
+      dy = dy + bbox:height()
+   end
+   dx = dx + bbox:left()
+   dy = dy + bbox:bottom()
+   return ipe.Translation(dx, dy)
+end
+
+function mainWindow(model)
+   if model.ui.win == nil then
+      return model.ui
+   else
+      return model.ui:win()
+   end
+end
+
+function run_decorator(model)
+   -- get bbox of primary selection
+   local p = model:page()
+   local prim = p:primarySelection()
+   if not prim then
+      model.ui:explain("An object must be selected.")
+      return
+   end
+   local bbox = p:bbox(prim)
+
+   -- create decorator object
+   local dialog = ipeui.Dialog(mainWindow(model), "Select a decorator.")
+   local decorators = decorator_names(model)
+   dialog:add("deco", "combo", decorators, 1, 1, 1, 2)
+   dialog:add("ok", "button", { label="&Ok", action="accept" }, 2, 2)
+   dialog:add("cancel", "button", { label="&Cancel", action="reject" }, 2, 1)
+   local r = dialog:execute()
+   if not r then return end
+   local deco_name = decorators[dialog:get("deco")]
+   local symbol = model.doc:sheets():find("symbol", deco_name)
+   local deco = symbol:clone()
+
+   -- run the decoration
+   decorate(model, bbox, deco)
+end
+
+label = "Decorator"
+methods = {
+  { label = "Decorate", run=run_decorator},
+}