1 ----------------------------------------------------------------------
2 -- presentation goodies for Ipe
8 This ipelet adds a few goodies for presentation, including
9 1. Ability to create beamer-like boxes with/without header
10 2. Add a framed box for the selected objects (including text)
11 3. A function to deselect all selected on all pages
12 4. The boxes can be edited as text/path objects (press E)
13 5. A few items can be added to the style sheet to add preferred
14 symbolics for box colors etc. This has the benefit that this
15 preferences can be changed to affect all boxes (see below).
17 The design of these boxes is from Martin Nöllenburg's presentation
18 example posted on the Ipe7 wiki page.
20 STYLESHEET (CHANGING PREFERRED SETTINGS)
22 Example style sheet to cascade with presentation.isy is as follows.
24 ---- content of example.isy ---
25 example removed, not possible to upload this file to the ipe-wiki otherwise
26 ---- end content of example.isy ---
29 tab_header= color of the tab header in a tabbed box
30 tab_body = color of the tab body in a tabbed box
31 box_fill = fill color a box
32 box_border= color of the box border
33 boxborder = linewidth of the box border
35 The preferred box mode (stroked/filled/strokedfilled) can be changed by
36 changing the hard-wired value (no stylesheet option) PREFERRED_BOX_MODE below
38 With the above style sheet, one can start an empty presentation using
39 ipe -sheet presentation -sheet /path/to/example.isy
43 Shortcuts to these functions can be changed as for other ipelets:
44 shortcuts.ipelet_x_presentation = "Key"
45 where x is the index (starting 1) of the sub-menu for the function
49 version 0. Initial Release. Zhengdao Wang 2010
50 version 1. add a line here if a change is made
54 This file can be distributed and modified under the terms of the GNU General
55 Public License as published by the Free Software Foundation; either version
56 3, or (at your option) any later version.
58 This file is distributed in the hope that it will be useful, but WITHOUT ANY
59 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
60 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
65 ----------------------------------------------------------------------
67 label = "Presentation"
70 Presentation Goodies: Add boxes around objects, deselect all,
71 add tabbed/boxed text.
77 -- table storing the height of the first line box
82 local c=10 -- corner size
89 local PREFERRED_BOX_MODE="strokedfilled" -- or stroked or filled
91 local BOX_DIALOG_SIZE={400,140}
93 -- initialize the Height table
94 local function init_spacing(model)
98 local sizes = model.doc:sheets():allNames("textsize")
99 for i,size in ipairs(sizes) do
100 obj=ipe.Text({textsize=size, minipage=true}, "ABC\n\nDEF", V(xx,xx), xx)
101 local layer=p:active(model.vno)
102 p:insert(nil, obj, nil, layer)
103 obj=ipe.Text({textsize=size, minipage=true}, "ABC", V(xx,xx), xx)
104 p:insert(nil, obj, nil, layer)
109 Height[iH[i]]=xx-p:bbox(#p):bottomLeft().y
111 Spacing[iH[i]]=(xx-p:bbox(#p):bottomLeft().y)/2-Height[iH[i]]
117 -- generate a path with given properties
118 local function path(model, shape, props)
120 for k,v in pairs(props) do
121 oldvalues[k]=model.attributes[k]
122 model.attributes[k]=v
124 local obj = ipe.Path(model.attributes, shape)
125 for k,v in pairs(props) do
126 model.attributes[k]=oldvalues[k]
128 if props.pen then obj:set('pen', props.pen) end
129 obj:set('pathmode', props.pathmode, props.stroke, props.fill)
133 -- create a square box #shape=3
134 local function boxshape_square(v1, v2)
135 return { type="curve", closed=true;
136 { type="segment"; v1, V(v1.x, v2.y) }, -- L
137 { type="segment"; V(v1.x, v2.y), v2 }, -- T
138 { type="segment"; v2, V(v2.x, v1.y) } } -- R
141 -- create a square box with a pointer #shape=6
142 local function boxshape_square_pointer(v1, v2, v3, v4, v5)
145 local v3=v3 or V(v1.x+.4*dx, v2.y)
146 local v4=v4 or V(v1.x+.6*dx,v2.y+.3*dy)
147 local v5=v5 or V(v1.x+.5*dx,v2.y)
148 return { type="curve", closed=true;
149 { type="segment"; v1, V(v1.x, v2.y) }, -- L
150 { type="segment"; V(v1.x, v2.y), v3}, -- T
151 { type="segment"; v3, v4}, -- P
152 { type="segment"; v4, v5}, --P
153 { type="segment"; v5, v2}, -- T
154 { type="segment"; v2, V(v2.x, v1.y) } } -- R
157 -- create a header box: round corner on topRight
158 local function boxshape_roundTR(v1, v2)
159 return { type="curve", closed=true;
160 { type="segment"; v1, V(v1.x, v2.y) },
161 { type="segment"; V(v1.x, v2.y), V(v2.x-c, v2.y) },
162 { type="bezier"; V(v2.x-c, v2.y), V(v2.x-c/2, v2.y),
163 V(v2.x, v2.y-c/2), V(v2.x, v2.y-c) },
164 { type="segment"; V(v2.x, v2.y-c), V(v2.x, v1.y) } }
167 -- create a body box: round corner on bottom Left
168 local function boxshape_roundLL(v1, v2)
169 return { type="curve", closed=true;
170 { type="segment"; v2, V(v2.x, v1.y) },
171 { type="segment"; V(v2.x, v1.y), V(v1.x+c, v1.y) },
172 { type="bezier"; V(v1.x+c, v1.y), V(v1.x+c/2,v1.y),
173 V(v1.x, v1.y+c/2), V(v1.x, v1.y+c) },
174 { type="segment"; V(v1.x, v1.y+c), V(v1.x, v2.y) } }
177 -- create a body box: 4 round corners #shape=8
178 local function boxshape_round(v1, v2)
179 return { type="curve", closed=true;
180 { type="segment"; V(v2.x, v2.y-c), V(v2.x, v1.y+c) }, -- R
181 { type="bezier"; V(v2.x,v1.y+c), V(v2.x, v1.y+c/2),
182 V(v2.x-c/2,v1.y), V(v2.x-c,v1.y)}, -- BR
183 { type="segment"; V(v2.x-c, v1.y), V(v1.x+c, v1.y) }, -- B
184 { type="bezier"; V(v1.x+c, v1.y), V(v1.x+c/2,v1.y),
185 V(v1.x, v1.y+c/2), V(v1.x, v1.y+c) }, -- BL
186 { type="segment"; V(v1.x, v1.y+c), V(v1.x, v2.y-c) }, -- L
187 { type="bezier"; V(v1.x, v2.y-c), V(v1.x,v2.y-c/2),
188 V(v1.x+c/2, v2.y), V(v1.x+c, v2.y) }, -- TL
189 { type="segment"; V(v1.x+c, v2.y), V(v2.x-c, v2.y) }, -- T
190 { type="bezier"; V(v2.x-c, v2.y), V(v2.x-c/2,v2.y),
191 V(v2.x, v2.y-c/2), V(v2.x, v2.y-c) }, -- TR
195 -- create a body box: 4 round corners, with pointer #shape=11
196 local function boxshape_round_pointer(v1, v2, v3, v4, v5)
199 local v3=v3 or V(v1.x+.4*dx, v2.y)
200 local v4=v4 or V(v1.x+.6*dx,v2.y+.3*dy)
201 local v5=v5 or V(v1.x+.5*dx,v2.y)
202 return { type="curve", closed=true;
203 { type="segment"; V(v2.x, v2.y-c), V(v2.x, v1.y+c) }, -- R
204 { type="bezier"; V(v2.x,v1.y+c), V(v2.x, v1.y+c/2),
205 V(v2.x-c/2,v1.y), V(v2.x-c,v1.y)}, -- BR
206 { type="segment"; V(v2.x-c, v1.y), V(v1.x+c, v1.y) }, -- B
207 { type="bezier"; V(v1.x+c, v1.y), V(v1.x+c/2,v1.y),
208 V(v1.x, v1.y+c/2), V(v1.x, v1.y+c) }, -- BL
209 { type="segment"; V(v1.x, v1.y+c), V(v1.x, v2.y-c) }, -- L
210 { type="bezier"; V(v1.x, v2.y-c), V(v1.x,v2.y-c/2),
211 V(v1.x+c/2, v2.y), V(v1.x+c, v2.y) }, -- TL
212 { type="segment"; V(v1.x+c, v2.y), v3}, -- T
213 { type="segment"; v3, v4}, -- P
214 { type="segment"; v4, v5}, --P
215 { type="segment"; v5, V(v2.x-c, v2.y)}, -- T
216 { type="bezier"; V(v2.x-c, v2.y), V(v2.x-c/2,v2.y),
217 V(v2.x, v2.y-c/2), V(v2.x, v2.y-c) }, -- TR
221 -- parse the values from a group obj
222 local function parse_group_values(model,prim)
223 local fs = model.doc:sheets():find("layout").framesize
225 local bbox=p:bbox(prim)
226 local pos=V(bbox:bottomLeft().x, bbox:topRight().y)
228 local elements=p[prim]:elements()
230 local hb,bb,ht,bt=elements[1],elements[2],elements[3],elements[4]
231 if hb:type()=="path" and bb:type()=="path" and
232 ht:type()=="text" and bt:type()=="text" then
233 local values={htext=ht:text(),
235 pinned=(p[prim]:get("pinned")=="horizontal"),
236 fwidth=string.format('%.2f',
237 (bbox:topRight().x-bbox:bottomLeft().x)/fs.x),
238 hcolor=hb:get("fill"),
239 bcolor=bb:get("fill"),
240 size=ht:get("textsize")}
241 return TABBED_TEXT,values,pos
244 local bb,bt=elements[1],elements[2]
245 if bb:type()=="path" and #bb:shape()==1 and
246 bb:shape()[1].closed==true and
247 (#bb:shape()[1]==3 or #bb:shape()[1]==8 or
248 #bb:shape()[1]==6 or #bb:shape()[1]==11) then
249 if bt:type()=="text" then
250 local values={btext=bt:text(),
251 pinned=(p[prim]:get("pinned")=="horizontal"),
252 size=bt:get("textsize"),
253 fwidth=string.format('%.2f',
254 (bbox:topRight().x-bbox:bottomLeft().x)/fs.x),
255 bcolor=bb:get("fill")}
256 if #bb:shape()[1]==6 then
257 pos=V(pos.x,bb:shape()[1][1][2].y)
258 elseif #bb:shape()[1]==11 then
259 pos=V(pos.x,bb:shape()[1][10][2].y)
261 return BOXED_TEXT,values,pos
270 function mainWindow(model)
271 if model.ui.win == nil then
274 return model.ui:win()
278 -- Edit the values for the frame
279 local function edit_tabbed_values(model,values)
280 local d = ipeui.Dialog(mainWindow(model), "Create tabbed text")
281 local colors = model.doc:sheets():allNames("color")
282 local sizes = model.doc:sheets():allNames("textsize")
283 d:add("hlabel", "label", { label="Enter Header" }, 1, 1, 1, 1)
284 d:add("hcolor", "combo", colors, 1, 4)
285 d:add("htext", "input", { syntax="latex" }, 2, 1, 1, 4)
286 d:add("blabel", "label", { label="Enter Body"}, 3, 1, 1, 3)
287 d:add("bcolor", "combo", colors, 3, 4)
288 d:add("btext", "text", { syntax="latex" }, 4, 1, 1, 4)
289 d:add("size", "combo", sizes, 5, 1)
290 d:add("wlabel", "label", { label="width [0-1]"}, 5, 2, 1, 2)
291 d:add("fwidth", "input", {size=2}, 5, 3, 1, 1)
292 d:add("pinned", "checkbox", { label="pinned"}, 5, 4)
293 d:add("ok", "button", { label="&Ok", action="accept" }, 6, 4)
294 d:add("cancel", "button", { label="&Cancel", action="reject" }, 6, 3)
295 _G.addEditorField(d, "btext", 6, 2)
296 d:setStretch("row", 2, 1)
297 d:setStretch("column", 1, 1)
298 d:set("fwidth", "0.8")
301 if indexOf("tab_header", colors) then
302 d:set("hcolor", indexOf("tab_header", colors))
303 elseif indexOf("darkblue", colors) then
304 d:set("hcolor", indexOf("darkblue", colors))
306 d:set("hcolor", indexOf("black", colors))
309 if indexOf("tab_body", colors) then
310 d:set("bcolor", indexOf("tab_body", colors))
311 elseif indexOf("lightgray", colors) then
312 d:set("bcolor", indexOf("lightgray", colors))
314 d:set("bcolor", indexOf("white", colors))
318 for k,v in pairs(values) do
319 if k=="hcolor" or k=="bcolor" then v=indexOf(v, colors) end
320 if k=="size" then v=indexOf(v, sizes) end
325 local r = d:execute(prefs.editor_size)
326 if not r then return end
328 newvalues.htext=d:get("htext")
329 newvalues.btext=d:get("btext")
330 newvalues.pinned=d:get("pinned")
331 newvalues.fwidth=d:get("fwidth")
332 newvalues.size=sizes[d:get("size")]
333 newvalues.hcolor=colors[d:get("hcolor")]
334 newvalues.bcolor=colors[d:get("bcolor")]
335 -- if newvalues.fwidth=="" or tonumber(newvalues.fwidth)>.99 then
336 -- newvalues.pinned=true
341 -- measure the height a piece of given text
342 local function measure_height(model,text,size,width)
344 local obj= ipe.Text(model.attributes, text, V(0,0), width)
345 obj:set('textsize', size)
346 local layer=p:active(model.vno)
347 p:insert(nil, obj, nil, layer)
348 if not model.doc:runLatex() then
352 local bbox=p:bbox(#p)
354 return bbox:topRight().y-bbox:bottomLeft().y
358 local function create_boxed(model,values, pos, prim)
359 local fs = model.doc:sheets():find("layout").framesize
360 local p = model:page()
361 local editmode=(prim~=nil)
363 local width fwidth=tonumber(values.fwidth)
365 if not fwidth or fwidth<0 or fwidth>1 then
373 local s=Spacing[values.size]
374 local h=Height[values.size]
375 if not s or not h then
377 s=Spacing[values.size]
378 h=Height[values.size]
381 local bheight=measure_height(model,values.btext,values.size,width-2*s)
395 if fwidth>.99 then x1,x2=0,fs.x end
399 local bt= ipe.Text(model.attributes, values.btext, pos, width-2*s)
400 bt:set('textsize', values.size)
404 if values.rounded then
405 shape2 = { boxshape_round(V(x1,y1), V(x2,y2)) }
407 shape2 = { boxshape_square(V(x1,y1), V(x2,y2)) }
409 local bb = path(model, shape2,
410 {pathmode='filled', fill=values.bcolor, stroke="white"})
413 local elements={bb,bt}
414 local obj=ipe.Group(elements)
415 -- obj:setMatrix(p[prim]:matrix()) -- currently not working
416 if values.pinned then obj:set('pinned', 'horizontal') end
419 local t={original=p[prim]:clone(),
420 label="edit boxed text",
425 t.undo = function (t, doc)
426 doc[t.pno]:replace(t.primary, t.original)
428 t.redo = function (t, doc)
429 doc[t.pno]:replace(t.primary, t.final)
433 model:creation("create boxed text", obj)
434 -- model.doc:runLatex() -- may crash the thing
438 -- Create the requested object from values
439 local function create_tabbed(model,values, pos, prim)
440 local fs = model.doc:sheets():find("layout").framesize
441 local p = model:page()
442 local editmode=(prim~=nil)
444 local width fwidth=tonumber(values.fwidth)
446 if not fwidth or fwidth<0 or fwidth>1 then
454 local s=Spacing[values.size]
455 local h=Height[values.size]
456 if not s or not h then
458 s=Spacing[values.size]
459 h=Height[values.size]
462 local bheight=measure_height(model,values.btext,values.size,width-2*s)
469 y1=y2-h-bheight-3.8*s
474 y1=y2-h-bheight-3.8*s
476 if fwidth>.99 then x1,x2=0,fs.x end
480 local ht= ipe.Text(model.attributes, values.htext, pos, width-2*s)
481 ht:set('stroke', 'white')
482 ht:set('textsize', values.size)
485 pos=V(x1+s, y2-s-h-2*s)
486 local bt= ipe.Text(model.attributes, values.btext, pos, width-2*s)
487 bt:set('textsize', values.size)
490 local shape1 = { boxshape_roundTR(V(x1,y2-h-2*s), V(x2,y2)) }
491 local hb = path(model, shape1,
492 {pathmode='filled', fill=values.hcolor, stroke="white"})
493 hb:set('pathmode', 'filled', "white", values.hcolor)
496 local shape2 = { boxshape_roundLL(V(x1,y1), V(x2,y2-h-2*s)) }
497 local bb = path(model, shape2,
498 {pathmode='filled', fill=values.bcolor, stroke="white"})
501 local elements={hb,bb,ht,bt}
502 local obj=ipe.Group(elements)
503 if values.pinned then obj:set('pinned', 'horizontal') end
506 local t={original=p[prim]:clone(),
507 label="edit tabbed text",
512 t.undo = function (t, doc)
513 doc[t.pno]:replace(t.primary, t.original)
515 t.redo = function (t, doc)
516 doc[t.pno]:replace(t.primary, t.final)
520 model:creation("create tabbed text", obj)
521 -- model.doc:runLatex() -- may crash the thing
526 -- create the dialog for editing box properties
527 local function box_property_dialog(model)
528 local colors = model.doc:sheets():allNames("color")
529 local pens= model.doc:sheets():allNames("pen")
530 local pathmodes = {"stroked", "strokedfilled", "filled"}
531 local d = ipeui.Dialog(mainWindow(model), "Edit box properties")
533 d:add("rounded", "checkbox", { label="Round Corner"}, 1, 1, 1, 1)
534 d:add("pointer", "checkbox", { label="Pointer"}, 1, 2, 1, 1)
535 d:add("mlabel", "label", { label="Mode"}, 2, 1)
536 d:add("pathmode", "combo", pathmodes, 2, 2)
537 d:add("flabel", "label", { label="Fill Color" }, 3, 1)
538 d:add("fill", "combo", colors, 3, 2)
539 d:add("slabel", "label", { label="Stroke Color" }, 4, 1)
540 d:add("stroke", "combo", colors, 4, 2)
541 d:add("plabel", "label", { label="Line Width"}, 5, 1)
542 d:add("pen", "combo", pens, 5, 2)
543 d:add("cancel", "button", { label="&Cancel", action="reject" }, 6, 1)
544 d:add("ok", "button", { label="&Ok", action="accept" }, 6, 2)
545 d:setStretch("column", 2, 1)
550 local function edit_box(model, prim)
551 local colors = model.doc:sheets():allNames("color")
552 local pens= model.doc:sheets():allNames("pen")
553 local pathmodes = {"stroked", "strokedfilled", "filled"}
556 local elements=p[prim]:elements()
558 local bbs=bb:shape()[1]
560 local d=box_property_dialog(model)
563 d:set("rounded", #bbs>=7)
564 d:set("pathmode", indexOf(bb:get('pathmode'),pathmodes))
565 d:set("pointer", #bbs==6 or #bbs==11)
566 if indexOf(bb:get('stroke'),colors) then
567 d:set("stroke", indexOf(bb:get('stroke'),colors) )
568 elseif not model.attributes.stroke then
569 d:set("stroke", indexOf(model.attributes.stroke,colors) )
571 if indexOf(bb:get('fill'),colors) then
572 d:set("fill", indexOf(bb:get('fill'),colors) )
573 elseif not model.attributes.fill then
574 d:set("fill", indexOf(model.attributes.fill,colors) )
576 if indexOf(bb:get('pen'),pens) then
577 d:set("pen", indexOf(bb:get('pen'),pens) )
578 elseif not model.attributes.pen then
579 d:set("pen", indexOf(model.attributes.pen,pens) )
582 local r = d:execute(BOX_DIALOG_SIZE)
583 if not r then return end
584 local pathmode=pathmodes[d:get("pathmode")]
585 local stroke=colors[d:get("stroke")]
586 local fill=colors[d:get("fill")]
587 local pen=pens[d:get("pen")]
590 if d:get('rounded') and d:get('pointer') then
591 boxshape=boxshape_round_pointer
592 elseif d:get('rounded') and not d:get('pointer') then
593 boxshape=boxshape_round
594 elseif not d:get('rounded') and d:get('pointer') then
595 boxshape=boxshape_square_pointer
597 boxshape=boxshape_square
600 -- v1=BL, v2=TR, v3=P1, v4=P2, v5=P3. Pointer=(P1,P2,P3)
601 local v1,v2,v3,v4,v5,shape
603 v1=bbs[1][1];v2=bbs[2][2]
604 shape={ boxshape(v1,v2) }
605 elseif #bb:shape()[1]==6 then
606 v1=bbs[1][1];v3=bbs[2][2]; v4=bbs[3][2]; v5=bbs[4][2];
608 shape={ boxshape(v1,v2,v3,v4,v5) }
609 elseif #bb:shape()[1]==8 then
610 v1=V(bbs[5][1].x,bbs[3][1].y)
611 v2=V(bbs[1][1].x,bbs[7][1].y)
612 shape={ boxshape(v1,v2) }
613 elseif #bb:shape()[1]==11 then
614 v1=V(bbs[5][1].x,bbs[3][1].y)
615 v2=V(bbs[1][1].x,bbs[7][1].y)
616 v3=bbs[7][2]; v4=bbs[8][2]; v5=bbs[9][2];
617 shape={ boxshape(v1,v2,v3,v4,v5) }
620 local obj = path(model, shape,
621 {pen=pen, pathmode=pathmode, stroke=stroke, fill=fill})
624 local final = ipe.Group(elements)
625 final:setMatrix(p[prim]:matrix())
627 local t = { label="edit box", pno=model.pno, vno=model.vno,
628 layer=p:active(model.vno),
629 original=p[prim]:clone(),
630 primary=prim, final=final }
631 t.undo = function (t, doc)
632 doc[t.pno]:replace(t.primary, t.original)
634 t.redo = function (t, doc)
635 doc[t.pno]:replace(t.primary, t.final)
640 -- Edit a group object
641 local function action_edit_group(model,prim,obj)
642 local otype,values,pos=parse_group_values(model,prim)
643 if otype==UNKNOWN then
644 model:warning("Cannot edit this object")
646 elseif otype==TABBED_TEXT then
647 local newvalues=edit_tabbed_values(model, values)
648 if not newvalues then return end
649 if newvalues.htext=="" then
650 newvalues.rounded=true
651 create_boxed(model,newvalues,pos,prim)
653 create_tabbed(model,newvalues,pos,prim)
655 elseif otype==BOXED_OTHER or otype==BOXED_TEXT then
660 -- saving the old function
661 function _G.MODEL:presentation_backup_actinon_edit () end
662 _G.MODEL.presentation_backup_action_edit = _G.MODEL.action_edit
664 -- modify the global edit action
665 function _G.MODEL:action_edit()
666 local p = self:page()
667 local prim = p:primarySelection()
669 self:presentation_backup_action_edit()
673 if obj:type() == "group" then
674 action_edit_group(self, prim, obj)
676 self:presentation_backup_action_edit()
680 -- Run to create a new object
681 function tabbedboxed(model)
682 local values=edit_tabbed_values(model)
683 if not values then return end
684 if values.htext=="" then
686 create_boxed(model,values)
688 create_tabbed(model,values)
692 -- deselect all selected
693 function deselectAll(model)
694 local doc = model.doc
695 for i,p in doc:pages() do
700 -- box the selected objects
701 function boxit(model)
703 local box = ipe.Rect()
705 for i,obj,sel,layer in p:objects() do
708 elements[#elements+1]=obj:clone()
712 model.ui:explain('No selection to box')
716 local layout = model.doc:sheets():find("layout")
717 -- local maxx=layout.framesize.x
719 local x1=box:bottomLeft().x-s
720 -- if x1 < 0 then x1 = 0 end
721 local y1=box:bottomLeft().y-s
723 local x2=box:topRight().x+s
724 -- if x2 > maxx then x2 = maxx end
725 local y2=box:topRight().y+s
727 local d=box_property_dialog(model)
729 local colors = model.doc:sheets():allNames("color")
730 local pens= model.doc:sheets():allNames("pen")
731 local pathmodes = {"stroked", "strokedfilled", "filled"}
734 d:set("rounded", true)
736 d:set("pathmode", indexOf(PREFERRED_BOX_MODE,pathmodes))
738 if indexOf("box_border",colors) then
739 d:set("stroke", indexOf("box_border",colors))
740 elseif model.attributes.stroke then
741 d:set("stroke", indexOf(model.attributes.stroke,colors) )
744 if indexOf("box_fill",colors) then
745 d:set("fill", indexOf("box_fill",colors))
746 elseif model.attributes.fill then
747 d:set("fill", indexOf(model.attributes.fill,colors) )
750 if indexOf("boxborder",pens) then
751 d:set("pen", indexOf("boxborder",pens))
752 elseif model.attributes.pen then
753 d:set("pen", indexOf(model.attributes.pen,pens) )
756 local r = d:execute(BOX_DIALOG_SIZE)
758 if not r then return end
759 local pathmode=pathmodes[d:get("pathmode")]
760 local stroke=colors[d:get("stroke")]
761 local fill=colors[d:get("fill")]
762 local pen=pens[d:get("pen")]
765 if d:get('rounded') and d:get('pointer') then
766 boxshape=boxshape_round_pointer
767 elseif d:get('rounded') and not d:get('pointer') then
768 boxshape=boxshape_round
769 elseif not d:get('rounded') and d:get('pointer') then
770 boxshape=boxshape_square_pointer
772 boxshape=boxshape_square
775 local shape = { boxshape(V(x1,y1), V(x2,y2)) }
777 local obj = path(model, shape, {pen=pen, pathmode=pathmode, stroke=stroke, fill=fill})
780 local final = ipe.Group(elements)
782 local t = { label="add box", pno=model.pno, vno=model.vno,
783 layer=p:active(model.vno), object=obj,
784 selection=model:selection(),
785 undo=_G.revertOriginal,
788 t.redo = function (t, doc)
790 for i = #t.selection,1,-1 do p:remove(t.selection[i]) end
791 p:insert(nil, t.final, 1, t.layer)
797 { label = "Box It", run=boxit},
798 { label = "Tabbed/Boxed Text", run=tabbedboxed},
799 { label = "Deselect All", run=deselectAll},