1 // --------------------------------------------------------------------
2 // Canvas tools used from Lua
3 // --------------------------------------------------------------------
4 /*
5
6 This file is part of the extensible drawing editor Ipe.
7 Copyright (c) 1993-2020 Otfried Cheong
8
9 Ipe is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 As a special exception, you have permission to link Ipe with the
15 CGAL library and distribute executables, as long as you follow the
16 requirements of the Gnu General Public License in regard to all of
17 the software in the executable aside from CGAL.
18
19 Ipe is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
22 License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with Ipe; if not, you can find it at
26 "http://www.gnu.org/copyleft/gpl.html", or write to the Free
27 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28
29 */
30
31 #include "tools.h"
32
33 extern "C" {
34 #include <lua.h>
35 #include <lualib.h>
36 #include <lauxlib.h>
37 }
38
39 #include "ipecanvas.h"
40
41 #include "ipepainter.h"
42
43 #include "ipelua.h"
44
45 using namespace ipe;
46 using namespace ipelua;
47
48 // --------------------------------------------------------------------
49
IpeTransformTool(CanvasBase * canvas,Page * page,int view,TType type,bool withShift,lua_State * L0,int method)50 IpeTransformTool::IpeTransformTool(CanvasBase *canvas, Page *page, int view,
51 TType type, bool withShift,
52 lua_State *L0, int method)
53 : TransformTool(canvas, page, view, type, withShift)
54 {
55 L = L0;
56 iMethod = method;
57 }
58
~IpeTransformTool()59 IpeTransformTool::~IpeTransformTool()
60 {
61 luaL_unref(L, LUA_REGISTRYINDEX, iMethod);
62 }
63
report()64 void IpeTransformTool::report()
65 {
66 // call back to Lua to report final transformation
67 lua_rawgeti(L, LUA_REGISTRYINDEX, iMethod);
68 push_matrix(L, iTransform);
69 lua_callk(L, 1, 0, 0, nullptr);
70 }
71
72 // --------------------------------------------------------------------
73
push_modifiers(lua_State * L,int button)74 static void push_modifiers(lua_State *L, int button)
75 {
76 lua_createtable(L, 0, 4);
77 lua_pushboolean(L, (button & CanvasBase::EShift));
78 lua_setfield(L, -2, "shift");
79 lua_pushboolean(L, (button & CanvasBase::EControl));
80 lua_setfield(L, -2, "control");
81 lua_pushboolean(L, (button & CanvasBase::ECommand));
82 lua_setfield(L, -2, "command");
83 lua_pushboolean(L, (button & CanvasBase::EAlt));
84 lua_setfield(L, -2, "alt");
85 lua_pushboolean(L, (button & CanvasBase::EMeta));
86 lua_setfield(L, -2, "meta");
87 }
88
push_button(lua_State * L,int button)89 void push_button(lua_State *L, int button)
90 {
91 lua_pushinteger(L, (button & 0xff)); // button number
92 push_modifiers(L, button);
93 }
94
95 // --------------------------------------------------------------------
96
LuaTool(CanvasBase * canvas,lua_State * L0,int luatool)97 LuaTool::LuaTool(CanvasBase *canvas, lua_State *L0, int luatool)
98 : Tool(canvas)
99 {
100 L = L0;
101 iLuaTool = luatool;
102 iColor = Color(0, 0, 0);
103 }
104
~LuaTool()105 LuaTool::~LuaTool()
106 {
107 luaL_unref(L, LUA_REGISTRYINDEX, iLuaTool);
108 }
109
mouseButton(int button,bool press)110 void LuaTool::mouseButton(int button, bool press)
111 {
112 lua_rawgeti(L, LUA_REGISTRYINDEX, iLuaTool);
113 lua_getfield(L, -1, "mouseButton");
114 lua_pushvalue(L, -2); // model
115 lua_remove(L, -3);
116 push_button(L, button);
117 lua_pushboolean(L, press);
118 lua_callk(L, 4, 0, 0, nullptr);
119 }
120
mouseMove()121 void LuaTool::mouseMove()
122 {
123 lua_rawgeti(L, LUA_REGISTRYINDEX, iLuaTool);
124 lua_getfield(L, -1, "mouseMove");
125 lua_pushvalue(L, -2); // model
126 lua_remove(L, -3);
127 lua_callk(L, 1, 0, 0, nullptr);
128 }
129
key(String text,int modifiers)130 bool LuaTool::key(String text, int modifiers)
131 {
132 lua_rawgeti(L, LUA_REGISTRYINDEX, iLuaTool);
133 lua_getfield(L, -1, "key");
134 lua_pushvalue(L, -2); // model
135 lua_remove(L, -3);
136 push_string(L, text);
137 push_modifiers(L, modifiers);
138 lua_State *L0 = L; // need to save L since
139 lua_callk(L, 3, 1, 0, nullptr); // this may delete tool
140 bool used = lua_toboolean(L0, -1);
141 return used;
142 }
143
144 // --------------------------------------------------------------------
145
ShapeTool(CanvasBase * canvas,lua_State * L0,int luatool)146 ShapeTool::ShapeTool(CanvasBase *canvas, lua_State *L0, int luatool)
147 : LuaTool(canvas, L0, luatool)
148 {
149 iPen = 1.0;
150 iSnap = false;
151 iSkipLast = false;
152 }
153
draw(Painter & painter) const154 void ShapeTool::draw(Painter &painter) const
155 {
156 double z = 1.0 / iCanvas->zoom();
157 painter.setPen(Attribute(Fixed::fromDouble(iPen)));
158 painter.setStroke(Attribute(iColor));
159 painter.setLineCap(TLineCap::ERoundCap);
160 painter.setLineJoin(TLineJoin::ERoundJoin);
161 painter.newPath();
162 iShape.draw(painter);
163 painter.drawPath(EStrokedOnly);
164 painter.setStroke(Attribute(Color(0, 1000, 0)));
165 painter.setPen(Attribute(Fixed::fromDouble(1.0)));
166 painter.newPath();
167 iAuxShape.draw(painter);
168 painter.drawPath(EStrokedOnly);
169 for (int i = 0; i < size(iMarks); ++i) {
170 switch (iMarks[i].t) {
171 case EVertex:
172 painter.setFill(Attribute(Color(1000, 0, 1000)));
173 break;
174 case ECenter:
175 case ERadius:
176 painter.setFill(Attribute(Color(0, 0, 1000)));
177 break;
178 case ESplineCP:
179 painter.setFill(Attribute(Color(0, 0, 800)));
180 break;
181 case EMinor:
182 painter.setFill(Attribute(Color(0, 800, 0)));
183 break;
184 case ECurrent:
185 painter.setStroke(Attribute(Color(1000, 0, 0)));
186 break;
187 case EScissor:
188 painter.setFill(Attribute(Color(1000, 0, 0)));
189 break;
190 default:
191 break;
192 }
193 painter.pushMatrix();
194 painter.translate(iMarks[i].v);
195 painter.untransform(ETransformationsTranslations);
196 switch (iMarks[i].t) {
197 case EVertex:
198 case ECenter:
199 default:
200 painter.newPath();
201 painter.moveTo(Vector(6*z, 0));
202 painter.drawArc(Arc(Matrix(6*z, 0, 0, 6*z, 0, 0)));
203 painter.closePath();
204 painter.drawPath(EFilledOnly);
205 break;
206 case ECurrent:
207 painter.newPath();
208 painter.moveTo(Vector(9*z, 0));
209 painter.drawArc(Arc(Matrix(9*z, 0, 0, 9*z, 0, 0)));
210 painter.closePath();
211 painter.drawPath(EStrokedOnly);
212 break;
213 case ESplineCP:
214 case ERadius:
215 case EMinor:
216 painter.newPath();
217 painter.moveTo(Vector(-4*z, -4*z));
218 painter.lineTo(Vector(4*z, -4*z));
219 painter.lineTo(Vector(4*z, 4*z));
220 painter.lineTo(Vector(-4*z, 4*z));
221 painter.closePath();
222 painter.drawPath(EFilledOnly);
223 break;
224 case EScissor:
225 painter.newPath();
226 painter.moveTo(Vector(5*z, 0));
227 painter.lineTo(Vector(0, 5*z));
228 painter.lineTo(Vector(-5*z, 0));
229 painter.lineTo(Vector(0, -5*z));
230 painter.closePath();
231 painter.drawPath(EFilledOnly);
232 break;
233 }
234 painter.popMatrix();
235 }
236 }
237
setSnapping(bool snap,bool skipLast)238 void ShapeTool::setSnapping(bool snap, bool skipLast)
239 {
240 iSnap = snap;
241 iSkipLast = skipLast;
242 }
243
setShape(Shape shape,int which,double pen)244 void ShapeTool::setShape(Shape shape, int which, double pen)
245 {
246 if (which == 1)
247 iAuxShape = shape;
248 else
249 iShape = shape;
250 iPen = pen;
251 }
252
clearMarks()253 void ShapeTool::clearMarks()
254 {
255 iMarks.clear();
256 }
257
addMark(const Vector & v,TMarkType t)258 void ShapeTool::addMark(const Vector &v, TMarkType t)
259 {
260 SMark m;
261 m.v = v;
262 m.t = t;
263 iMarks.push_back(m);
264 }
265
snapVtx(const Vector & mouse,Vector & pos,double & bound,bool cp) const266 void ShapeTool::snapVtx(const Vector &mouse, Vector &pos,
267 double &bound, bool cp) const
268 {
269 if (!iSnap)
270 return;
271 Matrix m;
272 if (iSkipLast && iShape.countSubPaths() == 1 &&
273 iShape.subPath(0)->asCurve()) {
274 const Curve *c = iShape.subPath(0)->asCurve();
275 if (!cp)
276 c->segment(0).cp(0).snap(mouse, pos, bound);
277 // skip last vertex of curve
278 for (int i = 0; i < c->countSegments() - 1; ++i)
279 c->segment(i).snapVtx(mouse, m, pos, bound, cp);
280 } else
281 iShape.snapVtx(mouse, m, pos, bound, cp);
282 }
283
284 // --------------------------------------------------------------------
285
PasteTool(CanvasBase * canvas,lua_State * L0,int luatool,Object * obj)286 PasteTool::PasteTool(CanvasBase *canvas, lua_State *L0, int luatool,
287 Object *obj)
288 : LuaTool(canvas, L0, luatool)
289 {
290 iObject = obj;
291 }
292
~PasteTool()293 PasteTool::~PasteTool()
294 {
295 delete iObject;
296 }
297
draw(Painter & painter) const298 void PasteTool::draw(Painter &painter) const
299 {
300 painter.transform(iMatrix);
301 painter.setStroke(Attribute(iColor));
302 iObject->drawSimple(painter);
303 }
304
305 // --------------------------------------------------------------------
306