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