[Ipe-discuss] problem with the 'presentation' ipelet
Zhengdao Wang
zhengdao at iastate.edu
Sat Mar 10 21:51:15 CET 2012
I attached a current version that I am using, hoping that this will
solve the problem.
Zhengdao
-----Original Message-----
> From: Shengping Zhang <shengping.zhang at gmail.com>
> Date: Fri, 9 Mar 2012 18:53:41 -0800
> To: ipe-discuss at lists.science.uu.nl
> Subject: [Ipe-discuss] problem with the 'presentation' ipelet
>
> Hello,
>
> When I use the 'presentation' ipelet to add box around text. I can successfully do it for the first time. But when i want to add a box around another text, it fails. I need to reboot ipe and the can successfully do it. But if i want to continue to add box around other tex, i need to reboot ipe again.
>
> I use ipe 7.1.2 on Mac.
>
> Did anyone else meet the same problem? How to solve it?
>
> Thanks!
> --
> Best regards,
>
> Shengping Zhang
>
> ----------------------------------------------------------------
> Redwood Center for Theoretical Neuroscience
> University of California at Berkeley
> 567 Evans Hall, MC# 3198
> Berkeley, CA 94720-3198, United States
> School of Computer Science and Technology
> Harbin Institute of Technology
> 92 Xidazhi Street, Harbin 150001, China
> Phone: 510-502-8557 / +86-451-86416485
> http://redwood.berkeley.edu/spzhang/
> ----------------------------------------------------------------
>
>
>
> _______________________________________________
> Ipe-discuss mailing list
> Ipe-discuss at lists.science.uu.nl
> http://lists.science.uu.nl/mailman/listinfo/ipe-discuss
-------------- next part --------------
----------------------------------------------------------------------
-- presentation goodies for Ipe
--[[
SUMMARY
This ipelet adds a few goodies for presentation, including
1. Ability to create beamer-like boxes with/without header
2. Add a framed box for the selected objects (including text)
3. A function to deselect all selected on all pages
4. The boxes can be edited as text/path objects (press E)
5. A few items can be added to the style sheet to add preferred
symbolics for box colors etc. This has the benefit that this
preferences can be changed to affect all boxes (see below).
The design of these boxes is from Martin N?llenburg's presentation
example posted on the Ipe7 wiki page.
STYLESHEET (CHANGING PREFERRED SETTINGS)
Example style sheet to cascade with presentation.isy is as follows.
---- content of example.isy ---
<?xml version="1.0"?>
<!DOCTYPE ipestyle SYSTEM "ipe.dtd">
<ipestyle name="mine">
<color name="tab_header" value="0 0 0.5"/>
<color name="tab_body" value="0.827"/>
<color name="box_fill" value="0.827"/>
<color name="box_border" value="0 0 0"/>
<pen name="boxborder" value="2.4"/>
<preamble>
\usepackage{amsmath}
</preamble>
</ipestyle>
---- end content of example.isy ---
where:
tab_header= color of the tab header in a tabbed box
tab_body = color of the tab body in a tabbed box
box_fill = fill color a box
box_border= color of the box border
boxborder = linewidth of the box border
The preferred box mode (stroked/filled/strokedfilled) can be changed by
changing the hard-wired value (no stylesheet option) PREFERRED_BOX_MODE below
With the above style sheet, one can start an empty presentation using
ipe -sheet presentation -sheet /path/to/example.isy
SHORTCUT
Shortcuts to these functions can be changed as for other ipelets:
shortcuts.ipelet_x_presentation = "Key"
where x is the index (starting 1) of the sub-menu for the function
FILE/AUTHOR HISTORY
verion 0. Initial Release. Zhengdao Wang 2010
verion 1. add a line here if a change is made
LICENSE
This file can be distributed and modified under the terms of the GNU General
Public License as published by the Free Software Foundation; either version
3, or (at your option) any later version.
This file is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
--]]
----------------------------------------------------------------------
label = "Presentation"
about = [[
Presentation Goodies: Add boxes around objects, deselect all,
add tabbed/boxed text.
]]
V = ipe.Vector
indexOf=_G.indexOf
-- table storing the height of the first line box
Height={}
Spacing={}
Has_Height=nil
local c=10 -- corner size
local UNKNOWN=0
local TABBED_TEXT=1
local BOXED_TEXT=2
local BOXED_OTHER=3
local ROUND_CORNER=true -- true of false
local PREFERRED_BOX_MODE="filled" -- stroked, filled, strokedfilled
local BOX_DIALOG_SIZE={400,140}
-- initialize the Height table
local function init_spacing(model)
local p=model:page()
local xx=300
local iH={}
local sizes = model.doc:sheets():allNames("textsize")
for i,size in ipairs(sizes) do
obj=ipe.Text({textsize=size, minipage=true}, "ABC\n\nDEF", V(xx,xx), xx)
p:insert(nil, obj, nil, "alpha")
obj=ipe.Text({textsize=size, minipage=true}, "ABC", V(xx,xx), xx)
p:insert(nil, obj, nil, "alpha")
iH[#iH+1]=size
end
model.doc:runLatex()
for i=#sizes,1,-1 do
Height[iH[i]]=xx-p:bbox(#p):bottomLeft().y
p:remove(#p)
Spacing[iH[i]]=(xx-p:bbox(#p):bottomLeft().y)/2-Height[iH[i]]
p:remove(#p)
end
Has_Height=1
end
-- generate a path with given properties
local function path(model, shape, props)
local oldvalues={}
for k,v in pairs(props) do
oldvalues[k]=model[k]
model.attributes[k]=v
end
local obj = ipe.Path(model.attributes, shape)
for k,v in pairs(props) do
model.attributes[k]=oldvalues[k]
end
if props.pen then obj:set('pen', props.pen) end
obj:set('pathmode', props.pathmode, props.stroke, props.fill)
return obj
end
-- create a square box #shape=3
local function boxshape_square(v1, v2)
return { type="curve", closed=true;
{ type="segment"; v1, V(v1.x, v2.y) }, -- L
{ type="segment"; V(v1.x, v2.y), v2 }, -- T
{ type="segment"; v2, V(v2.x, v1.y) } } -- R
end
-- create a square box with a pointer #shape=6
local function boxshape_square_pointer(v1, v2, v3, v4, v5)
local dx=v2.x-v1.x
local dy=v2.y-v1.y
local v3=v3 or V(v1.x+.4*dx, v2.y)
local v4=v4 or V(v1.x+.6*dx,v2.y+.3*dy)
local v5=v5 or V(v1.x+.5*dx,v2.y)
return { type="curve", closed=true;
{ type="segment"; v1, V(v1.x, v2.y) }, -- L
{ type="segment"; V(v1.x, v2.y), v3}, -- T
{ type="segment"; v3, v4}, -- P
{ type="segment"; v4, v5}, --P
{ type="segment"; v5, v2}, -- T
{ type="segment"; v2, V(v2.x, v1.y) } } -- R
end
-- create a header box: round corner on topRight
local function boxshape_roundTR(v1, v2)
return { type="curve", closed=true;
{ type="segment"; v1, V(v1.x, v2.y) },
{ type="segment"; V(v1.x, v2.y), V(v2.x-c, v2.y) },
{ type="bezier"; V(v2.x-c, v2.y), V(v2.x-c/2, v2.y),
V(v2.x, v2.y-c/2), V(v2.x, v2.y-c) },
{ type="segment"; V(v2.x, v2.y-c), V(v2.x, v1.y) } }
end
-- create a body box: round corner on bottom Left
local function boxshape_roundLL(v1, v2)
return { type="curve", closed=true;
{ type="segment"; v2, V(v2.x, v1.y) },
{ type="segment"; V(v2.x, v1.y), V(v1.x+c, v1.y) },
{ type="bezier"; V(v1.x+c, v1.y), V(v1.x+c/2,v1.y),
V(v1.x, v1.y+c/2), V(v1.x, v1.y+c) },
{ type="segment"; V(v1.x, v1.y+c), V(v1.x, v2.y) } }
end
-- create a body box: 4 round corners #shape=8
local function boxshape_round(v1, v2)
return { type="curve", closed=true;
{ type="segment"; V(v2.x, v2.y-c), V(v2.x, v1.y+c) }, -- R
{ type="bezier"; V(v2.x,v1.y+c), V(v2.x, v1.y+c/2),
V(v2.x-c/2,v1.y), V(v2.x-c,v1.y)}, -- BR
{ type="segment"; V(v2.x-c, v1.y), V(v1.x+c, v1.y) }, -- B
{ type="bezier"; V(v1.x+c, v1.y), V(v1.x+c/2,v1.y),
V(v1.x, v1.y+c/2), V(v1.x, v1.y+c) }, -- BL
{ type="segment"; V(v1.x, v1.y+c), V(v1.x, v2.y-c) }, -- L
{ type="bezier"; V(v1.x, v2.y-c), V(v1.x,v2.y-c/2),
V(v1.x+c/2, v2.y), V(v1.x+c, v2.y) }, -- TL
{ type="segment"; V(v1.x+c, v2.y), V(v2.x-c, v2.y) }, -- T
{ type="bezier"; V(v2.x-c, v2.y), V(v2.x-c/2,v2.y),
V(v2.x, v2.y-c/2), V(v2.x, v2.y-c) }, -- TR
}
end
-- create a body box: 4 round corners, with pointer #shape=11
local function boxshape_round_pointer(v1, v2, v3, v4, v5)
local dx=v2.x-v1.x
local dy=v2.y-v1.y
local v3=v3 or V(v1.x+.4*dx, v2.y)
local v4=v4 or V(v1.x+.6*dx,v2.y+.3*dy)
local v5=v5 or V(v1.x+.5*dx,v2.y)
return { type="curve", closed=true;
{ type="segment"; V(v2.x, v2.y-c), V(v2.x, v1.y+c) }, -- R
{ type="bezier"; V(v2.x,v1.y+c), V(v2.x, v1.y+c/2),
V(v2.x-c/2,v1.y), V(v2.x-c,v1.y)}, -- BR
{ type="segment"; V(v2.x-c, v1.y), V(v1.x+c, v1.y) }, -- B
{ type="bezier"; V(v1.x+c, v1.y), V(v1.x+c/2,v1.y),
V(v1.x, v1.y+c/2), V(v1.x, v1.y+c) }, -- BL
{ type="segment"; V(v1.x, v1.y+c), V(v1.x, v2.y-c) }, -- L
{ type="bezier"; V(v1.x, v2.y-c), V(v1.x,v2.y-c/2),
V(v1.x+c/2, v2.y), V(v1.x+c, v2.y) }, -- TL
{ type="segment"; V(v1.x+c, v2.y), v3}, -- T
{ type="segment"; v3, v4}, -- P
{ type="segment"; v4, v5}, --P
{ type="segment"; v5, V(v2.x-c, v2.y)}, -- T
{ type="bezier"; V(v2.x-c, v2.y), V(v2.x-c/2,v2.y),
V(v2.x, v2.y-c/2), V(v2.x, v2.y-c) }, -- TR
}
end
-- parse the values from a group obj
local function parse_group_values(model,prim)
local fs = model.doc:sheets():find("layout").framesize
local p=model:page()
local bbox=p:bbox(prim)
local pos=V(bbox:bottomLeft().x, bbox:topRight().y)
local elements=p[prim]:elements()
if #elements==4 then
local hb,bb,ht,bt=elements[1],elements[2],elements[3],elements[4]
if hb:type()=="path" and bb:type()=="path" and
ht:type()=="text" and bt:type()=="text" then
local values={htext=ht:text(),
btext=bt:text(),
pinned=(p[prim]:get("pinned")=="horizontal"),
fwidth=string.format('%.2f',
(bbox:topRight().x-bbox:bottomLeft().x)/fs.x),
hcolor=hb:get("fill"),
bcolor=bb:get("fill"),
size=ht:get("textsize")}
return TABBED_TEXT,values,pos
end
else
local bb,bt=elements[1],elements[2]
if bb:type()=="path" and #bb:shape()==1 and
bb:shape()[1].closed==true and
(#bb:shape()[1]==3 or #bb:shape()[1]==8 or
#bb:shape()[1]==6 or #bb:shape()[1]==11) then
if bt:type()=="text" then
local values={btext=bt:text(),
pinned=(p[prim]:get("pinned")=="horizontal"),
size=bt:get("textsize"),
fwidth=string.format('%.2f',
(bbox:topRight().x-bbox:bottomLeft().x)/fs.x),
bcolor=bb:get("fill")}
if #bb:shape()[1]==6 then
pos=V(pos.x,bb:shape()[1][1][2].y)
elseif #bb:shape()[1]==11 then
pos=V(pos.x,bb:shape()[1][10][2].y)
end
return BOXED_TEXT,values,pos
else
return BOXED_OTHER
end
end
end
return UNKNOWN
end
-- Edit the values for the frame
local function edit_tabbed_values(model,values)
local d = ipeui.Dialog(model.ui:win(), "Create tabbed text")
local colors = model.doc:sheets():allNames("color")
local sizes = model.doc:sheets():allNames("textsize")
d:add("hlabel", "label", { label="Enter Header" }, 1, 1, 1, 1)
d:add("hcolor", "combo", colors, 1, 4)
d:add("htext", "input", { syntax="latex" }, 2, 1, 1, 4)
d:add("blabel", "label", { label="Enter Body"}, 3, 1, 1, 3)
d:add("bcolor", "combo", colors, 3, 4)
d:add("btext", "text", { syntax="latex" }, 4, 1, 1, 4)
d:add("size", "combo", sizes, 5, 1)
d:add("wlabel", "label", { label="width [0-1]"}, 5, 2, 1, 2)
d:add("fwidth", "input", {size=2}, 5, 3, 1, 1)
d:add("pinned", "checkbox", { label="pinned"}, 5, 4)
d:add("ok", "button", { label="&Ok", action="accept" }, 6, 4)
d:add("cancel", "button", { label="&Cancel", action="reject" }, 6, 3)
_G.addEditorField(d, "btext", 6, 2)
d:setStretch("row", 2, 1)
d:setStretch("column", 1, 1)
if indexOf("tab_header", colors) then
d:set("hcolor", indexOf("tab_header", colors))
else
d:set("hcolor", indexOf("darkblue", colors))
end
if indexOf("tab_body", colors) then
d:set("bcolor", indexOf("tab_body", colors))
else
d:set("bcolor", indexOf("lightgray", colors))
end
if values then
for k,v in pairs(values) do
if k=="hcolor" or k=="bcolor" then v=indexOf(v, colors) end
if k=="size" then v=indexOf(v, sizes) end
d:set(k, v)
end
end
local r = d:execute(prefs.editor_size)
if not r then return end
local newvalues={}
newvalues.htext=d:get("htext")
newvalues.btext=d:get("btext")
newvalues.pinned=d:get("pinned")
newvalues.fwidth=d:get("fwidth")
newvalues.size=sizes[d:get("size")]
newvalues.hcolor=colors[d:get("hcolor")]
newvalues.bcolor=colors[d:get("bcolor")]
if newvalues.fwidth=="" or tonumber(newvalues.fwidth)>.99 then
newvalues.pinned=true
end
return newvalues
end
-- measure the height a piece of given text
local function measure_height(model,text,size,width)
local p=model:page()
local obj= ipe.Text(model.attributes, text, V(0,0), width)
obj:set('textsize', size)
local layer=p:active(model.vno)
p:insert(nil, obj, nil, layer)
if not model.doc:runLatex() then
p:remove(#p)
return 100
end
local bbox=p:bbox(#p)
p:remove(#p)
return bbox:topRight().y-bbox:bottomLeft().y
end
-- Create boxed text
local function create_boxed(model,values, pos, prim)
local fs = model.doc:sheets():find("layout").framesize
local p = model:page()
local editmode=(prim~=nil)
local width fwidth=tonumber(values.fwidth)
if not fwidth or fwidth<0 or fwidth>1 then
width=fs.x
fwidth=1
else
width=fwidth*fs.x
end
-- spacing
local s=Spacing[values.size]
local h=Height[values.size]
if not s or not h then
init_spacing(model)
s=Spacing[values.size]
h=Height[values.size]
end
local bheight=measure_height(model,values.btext,values.size,width-2*s)
-- location
if not pos then
x1=fs.x/2-width/2
x2=fs.x/2+width/2
y2=fs.y/2
y1=y2-bheight-1.8*s
else
x1=pos.x
x2=x1+width
y2=pos.y
y1=y2-bheight-1.8*s
end
if fwidth>.99 then x1,x2=0,fs.x end
-- body text
pos=V(x1+s, y2-s)
local bt= ipe.Text(model.attributes, values.btext, pos, width-2*s)
bt:set('textsize', values.size)
-- body box
local shape2
if values.rounded then
shape2 = { boxshape_round(V(x1,y1), V(x2,y2)) }
else
shape2 = { boxshape_square(V(x1,y1), V(x2,y2)) }
end
local bb = path(model, shape2,
{pathmode='filled', fill=values.bcolor, stroke="white"})
-- group object
local elements={bb,bt}
local obj=ipe.Group(elements)
-- obj:setMatrix(p[prim]:matrix()) -- currently not working
if values.pinned then obj:set('pinned', 'horizontal') end
if editmode then
local t={original=p[prim]:clone(),
label="edit boxed text",
pno=model.pno,
vno=model.vno,
primary=prim,
final=obj }
t.undo = function (t, doc)
doc[t.pno]:replace(t.primary, t.original)
end
t.redo = function (t, doc)
doc[t.pno]:replace(t.primary, t.final)
end
model:register(t)
else
model:creation("create boxed text", obj)
-- model.doc:runLatex() -- may crash the thing
end
end
-- Create the requested object from values
local function create_tabbed(model,values, pos, prim)
local fs = model.doc:sheets():find("layout").framesize
local p = model:page()
local editmode=(prim~=nil)
local width fwidth=tonumber(values.fwidth)
if not fwidth or fwidth<0 or fwidth>1 then
width=fs.x
fwidth=1
else
width=fwidth*fs.x
end
-- spacing
local s=Spacing[values.size]
local h=Height[values.size]
if not s or not h then
init_spacing(model)
s=Spacing[values.size]
h=Height[values.size]
end
local bheight=measure_height(model,values.btext,values.size,width-2*s)
-- location
if not pos then
x1=fs.x/2-width/2
x2=fs.x/2+width/2
y2=fs.y/2
y1=y2-h-bheight-3.8*s
else
x1=pos.x
x2=x1+width
y2=pos.y
y1=y2-h-bheight-3.8*s
end
if fwidth>.99 then x1,x2=0,fs.x end
-- header text
pos=V(x1+s, y2-s)
local ht= ipe.Text(model.attributes, values.htext, pos, width-2*s)
ht:set('stroke', 'white')
ht:set('textsize', values.size)
-- body text
pos=V(x1+s, y2-s-h-2*s)
local bt= ipe.Text(model.attributes, values.btext, pos, width-2*s)
bt:set('textsize', values.size)
-- header box
local shape1 = { boxshape_roundTR(V(x1,y2-h-2*s), V(x2,y2)) }
local hb = path(model, shape1,
{pathmode='filled', fill=values.hcolor, stroke="white"})
hb:set('pathmode', 'filled', "white", values.hcolor)
-- body box
local shape2 = { boxshape_roundLL(V(x1,y1), V(x2,y2-h-2*s)) }
local bb = path(model, shape2,
{pathmode='filled', fill=values.bcolor, stroke="white"})
-- group object
local elements={hb,bb,ht,bt}
local obj=ipe.Group(elements)
if values.pinned then obj:set('pinned', 'horizontal') end
if editmode then
local t={original=p[prim]:clone(),
label="edit tabbed text",
pno=model.pno,
vno=model.vno,
primary=prim,
final=obj }
t.undo = function (t, doc)
doc[t.pno]:replace(t.primary, t.original)
end
t.redo = function (t, doc)
doc[t.pno]:replace(t.primary, t.final)
end
model:register(t)
else
model:creation("create tabbed text", obj)
-- model.doc:runLatex() -- may crash the thing
end
end
-- create the dialog for editing box properties
local function box_property_dialog(model)
local colors = model.doc:sheets():allNames("color")
local pens= model.doc:sheets():allNames("pen")
local pathmodes = {"stroked", "strokedfilled", "filled"}
local d = ipeui.Dialog(model.ui:win(), "Edit box properties")
d:add("rounded", "checkbox", { label="Round Corner"}, 1, 1)
d:add("pointer", "checkbox", { label="Pointer"}, 1, 2)
d:add("mlabel", "label", { label="Mode"}, 2, 1)
d:add("pathmode", "combo", pathmodes, 2, 2)
d:add("flabel", "label", { label="Fill Color" }, 3, 1)
d:add("fill", "combo", colors, 3, 2)
d:add("slabel", "label", { label="Stroke Color" }, 4, 1)
d:add("stroke", "combo", colors, 4, 2)
d:add("plabel", "label", { label="Line Width"}, 5, 1)
d:add("pen", "combo", pens, 5, 2)
d:add("cancel", "button", { label="&Cancel", action="reject" }, 6, 1)
d:add("ok", "button", { label="&Ok", action="accept" }, 6, 2)
d:setStretch("column", 2, 1)
return d
end
-- edit a box object
local function edit_box(model, prim)
local colors = model.doc:sheets():allNames("color")
local pens= model.doc:sheets():allNames("pen")
local pathmodes = {"stroked", "strokedfilled", "filled"}
local p=model:page()
local elements=p[prim]:elements()
local bb=elements[1]
local bbs=bb:shape()[1]
local d=box_property_dialog(model)
-- default values
d:set("rounded", #bbs>=7)
d:set("pathmode", indexOf(bb:get('pathmode'),pathmodes))
d:set("pointer", #bbs==6 or #bbs==11)
if indexOf(bb:get('stroke'),colors) then
d:set("stroke", indexOf(bb:get('stroke'),colors) )
elseif model.attributes.stroke then
d:set("stroke", indexOf(model.attributes.stroke,colors) )
end
if indexOf(bb:get('fill'),colors) then
d:set("fill", indexOf(bb:get('fill'),colors) )
elseif not model.attributes.fill then
d:set("fill", indexOf(model.attributes.fill,colors) )
end
if indexOf(bb:get('pen'),pens) then
d:set("pen", indexOf(bb:get('pen'),pens) )
elseif not model.attributes.pen then
d:set("pen", indexOf(model.attributes.pen,pens) )
end
local r = d:execute(BOX_DIALOG_SIZE)
if not r then return end
local pathmode=pathmodes[d:get("pathmode")]
local stroke=colors[d:get("stroke")]
local fill=colors[d:get("fill")]
local pen=pens[d:get("pen")]
local boxshape
if d:get('rounded') and d:get('pointer') then
boxshape=boxshape_round_pointer
elseif d:get('rounded') and not d:get('pointer') then
boxshape=boxshape_round
elseif not d:get('rounded') and d:get('pointer') then
boxshape=boxshape_square_pointer
else
boxshape=boxshape_square
end
-- v1=BL, v2=TR, v3=P1, v4=P2, v5=P3. Pointer=(P1,P2,P3)
local v1,v2,v3,v4,v5,shape
if #bbs==3 then
v1=bbs[1][1];v2=bbs[2][2]
shape={ boxshape(v1,v2) }
elseif #bb:shape()[1]==6 then
v1=bbs[1][1];v3=bbs[2][2]; v4=bbs[3][2]; v5=bbs[4][2];
v2=bbs[5][2];
shape={ boxshape(v1,v2,v3,v4,v5) }
elseif #bb:shape()[1]==8 then
v1=V(bbs[5][1].x,bbs[3][1].y)
v2=V(bbs[1][1].x,bbs[7][1].y)
shape={ boxshape(v1,v2) }
elseif #bb:shape()[1]==11 then
v1=V(bbs[5][1].x,bbs[3][1].y)
v2=V(bbs[1][1].x,bbs[7][1].y)
v3=bbs[7][2]; v4=bbs[8][2]; v5=bbs[9][2];
shape={ boxshape(v1,v2,v3,v4,v5) }
end
local obj = path(model, shape,
{pen=pen, pathmode=pathmode, stroke=stroke, fill=fill})
elements[1]=obj
local final = ipe.Group(elements)
final:setMatrix(p[prim]:matrix())
local t = { label="edit box", pno=model.pno, vno=model.vno,
layer=p:active(model.vno),
original=p[prim]:clone(),
primary=prim, final=final }
t.undo = function (t, doc)
doc[t.pno]:replace(t.primary, t.original)
end
t.redo = function (t, doc)
doc[t.pno]:replace(t.primary, t.final)
end
model:register(t)
end
-- Edit a group object
local function action_edit_group(model,prim,obj)
local otype,values,pos=parse_group_values(model,prim)
if otype==UNKNOWN then
model:warning("Cannot edit this object")
return
elseif otype==TABBED_TEXT then
local newvalues=edit_tabbed_values(model, values)
if not newvalues then return end
if newvalues.htext=="" then
newvalues.rounded=true
create_boxed(model,newvalues,pos,prim)
else
create_tabbed(model,newvalues,pos,prim)
end
elseif otype==BOXED_OTHER or otype==BOXED_TEXT then
edit_box(model,prim)
end
end
-- modify the global edit action
function _G.MODEL:action_edit()
local p = self:page()
local prim = p:primarySelection()
if not prim then self.ui:explain("no selection") return end
local obj = p[prim]
if obj:type() == "text" then
self:action_edit_text(prim, obj)
elseif obj:type() == "path" then
self:action_edit_path(prim, obj)
elseif obj:type() == "group" then
action_edit_group(self, prim, obj)
else
self:warning('cannot edit this object')
end
end
-- Run to create a new object
function tabbedboxed(model)
local values=edit_tabbed_values(model)
if not values then return end
if values.htext=="" then
values.rounded=true
create_boxed(model,values)
else
create_tabbed(model,values)
end
end
-- deselect all selected
function deselectAll(model)
local doc = model.doc
model.ui:finishTool() -- in case editing a path
for i,p in doc:pages() do
p:deselectAll()
end
end
-- box the selected objects
function boxit(model)
local p=model:page()
local box = ipe.Rect()
local elements={0}
for i,obj,sel,layer in p:objects() do
if sel then
box:add(p:bbox(i))
elements[#elements+1]=obj:clone()
end
end
if #elements==1 then
model.ui:explain('No selection to box')
return
end
local s=8
local layout = model.doc:sheets():find("layout")
local maxx=layout.framesize.x
local x1=box:bottomLeft().x-s
if x1 < 0 then x1 = 0 end
local y1=box:bottomLeft().y-s
local x2=box:topRight().x+s
if x2 > maxx then x2 = maxx end
local y2=box:topRight().y+s
local d=box_property_dialog(model)
local colors = model.doc:sheets():allNames("color")
local pens= model.doc:sheets():allNames("pen")
local pathmodes = {"stroked", "strokedfilled", "filled"}
-- default values
d:set("rounded", true)
d:set("pathmode", indexOf(PREFERRED_BOX_MODE,pathmodes))
if indexOf("box_border",colors) then
d:set("stroke", indexOf("box_border",colors))
elseif not model.attributes.fill then
d:set("stroke", indexOf(model.attributes.fill,colors) )
end
if indexOf("box_fill",colors) then
d:set("fill", indexOf("box_fill",colors))
elseif not model.attributes.fill then
d:set("fill", indexOf(model.attributes.fill,colors) )
end
if indexOf("boxborder",pens) then
d:set("pen", indexOf("boxborder",pens))
elseif not model.attributes.pen then
d:set("pen", indexOf(model.attributes.pen,pens) )
end
local r = d:execute(BOX_DIALOG_SIZE)
if not r then return end
local pathmode=pathmodes[d:get("pathmode")]
local stroke=colors[d:get("stroke")]
local fill=colors[d:get("fill")]
local pen=pens[d:get("pen")]
local boxshape
if d:get('rounded') and d:get('pointer') then
boxshape=boxshape_round_pointer
elseif d:get('rounded') and not d:get('pointer') then
boxshape=boxshape_round
elseif not d:get('rounded') and d:get('pointer') then
boxshape=boxshape_square_pointer
else
boxshape=boxshape_square
end
local shape = { boxshape(V(x1,y1), V(x2,y2)) }
local obj = path(model, shape,
{pen=pen, pathmode=pathmode, stroke=stroke, fill=fill})
elements[1]=obj
local final = ipe.Group(elements)
local t = { label="add box", pno=model.pno, vno=model.vno,
layer=p:active(model.vno), object=obj,
selection=model:selection(),
undo=_G.revertOriginal,
original=p:clone(),
final=final }
t.redo = function (t, doc)
local p = doc[t.pno]
for i = #t.selection,1,-1 do p:remove(t.selection[i]) end
p:insert(nil, t.final, 1, t.layer)
end
model:register(t)
end
--
-- set text object to minipage
function to_minipage(model)
set_text_minipage(model, true)
end
-- set text object to label
function to_label(model)
set_text_minipage(model, false)
end
-- set text object minipage property
function set_text_minipage(model, minipage)
local p = model:page()
local selection = model:selection()
local selected = {}
if p:hasSelection()==false then return end
local sel
local j=0
for _,i in ipairs(selection) do
j=j+1
if p[i]:type()~='text' then
model:warning("Not all text objects")
return
end
if j>1 then
model:warning("So far works only with one text object")
end
sel=i
end
local final = p[sel]:clone()
final:set('minipage', minipage)
p:deselectAll()
local t = { label="group",
pno = model.pno,
vno = model.vno,
original = p:clone(),
selection = selection,
layer = p:active(model.vno),
final = final,
undo = _G.revertOriginal,
}
t.redo = function (t, doc)
local p = doc[t.pno]
for i = #t.selection,1,-1 do p:remove(t.selection[i]) end
p:insert(nil, t.final, 1, t.layer)
end
model:register(t)
end
-- merge text objects into a single text object
function merge_text(model)
local p = model:page()
local selection = model:selection()
local selected = {}
local key = {}
local rank = {}
if p:hasSelection()==false then return end
for _,i in ipairs(selection) do
if p[i]:type()~='text' then
model:warning("Not all text objects")
return
end
selected[#selected+1]=i
key[#key+1]=p[i]:position().y
rank[#rank+1]=1
end
-- sort the selected elements
for i=2,#selected do
for j=1,i-1 do
if key[j]>key[i] then
rank[i]=rank[i]+1
else
rank[j]=rank[j]+1
end
end
end
local ptr={}
for j=1,#selected do ptr[rank[j]]=j end
-- concatenate the strings
local str=''
for j=1,#selected do str=str .. p[selected[ptr[j]]]:text() .. '\n' end
local final = p[ptr[1]]:clone()
final:setText(str)
p:deselectAll()
local t = { label="group",
pno = model.pno,
vno = model.vno,
original = p:clone(),
selection = selection,
layer = p:active(model.vno),
final = final,
undo = _G.revertOriginal,
}
t.redo = function (t, doc)
local p = doc[t.pno]
for i = #t.selection,1,-1 do p:remove(t.selection[i]) end
p:insert(nil, t.final, 1, t.layer)
end
model:register(t)
end
methods = {
{ label = "Box It", run=boxit},
{ label = "Tabbed/Boxed Text", run=tabbedboxed},
{ label = "Deselect All", run=deselectAll},
{ label = "Merge Text", run=merge_text},
{ label = "Convert to Minipage", run=to_minipage},
{ label = "Convert to Label", run=to_label},
}
More information about the Ipe-discuss
mailing list