1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26 
27 #include <QAction>
28 #include <QMouseEvent>
29 #include "rs_actiondrawspline.h"
30 
31 #include "rs_spline.h"
32 #include "rs_dialogfactory.h"
33 #include "rs_graphicview.h"
34 #include "rs_commands.h"
35 #include "rs_commandevent.h"
36 #include "rs_point.h"
37 #include "rs_coordinateevent.h"
38 #include "rs_preview.h"
39 #include "rs_debug.h"
40 
41 struct RS_ActionDrawSpline::Points {
42 
43 	/**
44 	 * Spline data defined so far.
45 	 */
46 	RS_SplineData data;
47 	/**
48 	 * Polyline entity we're working on.
49 	 */
50 	RS_Spline* spline{nullptr};
51 	/**
52 	 * Point history (for undo)
53 	 */
54 		QList<RS_Vector> history;
55 
56 	/**
57 	 * Bulge history (for undo)
58 	 */
59 		//QList<double> bHistory;
60 };
61 
RS_ActionDrawSpline(RS_EntityContainer & container,RS_GraphicView & graphicView)62 RS_ActionDrawSpline::RS_ActionDrawSpline(RS_EntityContainer& container,
63 										 RS_GraphicView& graphicView)
64 	:RS_PreviewActionInterface("Draw splines",
65 							   container, graphicView)
66 	,pPoints(new Points{})
67 {
68 	actionType=RS2::ActionDrawSpline;
69 	reset();
70 }
71 
72 RS_ActionDrawSpline::~RS_ActionDrawSpline() = default;
73 
reset()74 void RS_ActionDrawSpline::reset() {
75 	pPoints->spline = nullptr;
76 	pPoints->history.clear();
77 }
78 
79 
80 
init(int status)81 void RS_ActionDrawSpline::init(int status) {
82     RS_PreviewActionInterface::init(status);
83 
84     reset();
85 }
86 
87 
88 
trigger()89 void RS_ActionDrawSpline::trigger() {
90     RS_PreviewActionInterface::trigger();
91 
92 		if (!pPoints->spline) {
93                 return;
94         }
95 
96         // add the entity
97     //RS_Spline* spline = new RS_Spline(container, data);
98 	pPoints->spline->setLayerToActive();
99 	pPoints->spline->setPenToActive();
100 	pPoints->spline->update();
101 	container->addEntity(pPoints->spline);
102 
103     // upd. undo list:
104     if (document) {
105         document->startUndoCycle();
106 		document->addUndoable(pPoints->spline);
107         document->endUndoCycle();
108     }
109 
110         // upd view
111         RS_Vector r = graphicView->getRelativeZero();
112         graphicView->redraw(RS2::RedrawDrawing);
113     graphicView->moveRelativeZero(r);
114     RS_DEBUG->print("RS_ActionDrawSpline::trigger(): spline added: %d",
115 					pPoints->spline->getId());
116 
117 		pPoints->spline = nullptr;
118     //history.clear();
119 }
120 
mouseMoveEvent(QMouseEvent * e)121 void RS_ActionDrawSpline::mouseMoveEvent(QMouseEvent* e) {
122     RS_DEBUG->print("RS_ActionDrawSpline::mouseMoveEvent begin");
123 
124     RS_Vector mouse = snapPoint(e);
125 	if (getStatus()==SetNextPoint && pPoints->spline /*&& point.valid*/) {
126         deletePreview();
127 
128 				RS_Spline* tmpSpline = static_cast<RS_Spline*>(pPoints->spline->clone());
129                 tmpSpline->addControlPoint(mouse);
130                 tmpSpline->update();
131                 preview->addEntity(tmpSpline);
132 
133 				auto cpts = tmpSpline->getControlPoints();
134 				for (const RS_Vector& vp: cpts) {
135 						preview->addEntity(new RS_Point(preview.get(), RS_PointData(vp)));
136                 }
137         drawPreview();
138     }
139 
140     RS_DEBUG->print("RS_ActionDrawSpline::mouseMoveEvent end");
141 }
142 
143 
144 
mouseReleaseEvent(QMouseEvent * e)145 void RS_ActionDrawSpline::mouseReleaseEvent(QMouseEvent* e) {
146     if (e->button()==Qt::LeftButton) {
147         RS_CoordinateEvent ce(snapPoint(e));
148         coordinateEvent(&ce);
149     } else if (e->button()==Qt::RightButton) {
150 				if (getStatus()==SetNextPoint &&
151 						pPoints->spline &&
152 						pPoints->spline->getNumberOfControlPoints()>=pPoints->spline->getDegree()+1) {
153                         trigger();
154                 }
155         deletePreview();
156         init(getStatus()-1);
157     }
158 }
159 
160 
161 
coordinateEvent(RS_CoordinateEvent * e)162 void RS_ActionDrawSpline::coordinateEvent(RS_CoordinateEvent* e) {
163 	if (!e) return;
164 
165     RS_Vector mouse = e->getCoordinate();
166 
167     switch (getStatus()) {
168     case SetStartpoint:
169                 //data.startpoint = mouse;
170         //point = mouse;
171 		pPoints->history.clear();
172 		pPoints->history.append(mouse);
173 				if (!pPoints->spline) {
174 						pPoints->spline = new RS_Spline(container, pPoints->data);
175 						pPoints->spline->addControlPoint(mouse);
176                 }
177         //bHistory.clear();
178         //bHistory.append(new double(0.0));
179         //start = mouse;
180         setStatus(SetNextPoint);
181         graphicView->moveRelativeZero(mouse);
182         updateMouseButtonHints();
183         break;
184 
185     case SetNextPoint:
186         graphicView->moveRelativeZero(mouse);
187         //point = mouse;
188 		pPoints->history.append(mouse);
189         //bHistory.append(new double(0.0));
190 				if (pPoints->spline) {
191                         //graphicView->deleteEntity(spline);
192 						pPoints->spline->addControlPoint(mouse);
193                         //spline->setEndpoint(mouse);
194                         //if (spline->count()==1) {
195                         //spline->setLayerToActive();
196                         //spline->setPenToActive();
197                                 //container->addEntity(spline);
198                         //}
199                         deletePreview();
200                         //graphicView->drawEntity(spline);
201                         drawSnapper();
202                 }
203         //trigger();
204         //data.startpoint = data.endpoint;
205         updateMouseButtonHints();
206         //graphicView->moveRelativeZero(mouse);
207         break;
208 
209     default:
210         break;
211     }
212 }
213 
214 
215 
commandEvent(RS_CommandEvent * e)216 void RS_ActionDrawSpline::commandEvent(RS_CommandEvent* e) {
217     QString c = e->getCommand().toLower();
218 
219     switch (getStatus()) {
220     case SetStartpoint:
221         if (checkCommand("help", c)) {
222             RS_DIALOGFACTORY->commandMessage(msgAvailableCommands()
223                                              + getAvailableCommands().join(", "));
224             return;
225         }
226         break;
227 
228     case SetNextPoint:
229         /*if (checkCommand("close", c)) {
230             close();
231             updateMouseButtonHints();
232             return;
233         }*/
234 
235         if (checkCommand("undo", c)) {
236             undo();
237             updateMouseButtonHints();
238             return;
239         }
240         break;
241 
242     default:
243         break;
244     }
245 }
246 
247 
248 
getAvailableCommands()249 QStringList RS_ActionDrawSpline::getAvailableCommands() {
250     QStringList cmd;
251 
252     switch (getStatus()) {
253     case SetStartpoint:
254         break;
255     case SetNextPoint:
256 		if (pPoints->history.size()>=2) {
257             cmd += command("undo");
258 		}else if (pPoints->history.size()>=3) {
259             cmd += command("close");
260         }
261         break;
262     default:
263         break;
264     }
265 
266     return cmd;
267 }
268 
269 
270 
updateMouseButtonHints()271 void RS_ActionDrawSpline::updateMouseButtonHints() {
272     switch (getStatus()) {
273     case SetStartpoint:
274         RS_DIALOGFACTORY->updateMouseWidget(tr("Specify first control point"),
275                                             tr("Cancel"));
276         break;
277     case SetNextPoint: {
278             QString msg = "";
279 
280 			if (pPoints->history.size()>=3) {
281                 msg += RS_COMMANDS->command("close");
282                 msg += "/";
283             }
284 			if (pPoints->history.size()>=2) {
285 				msg += RS_COMMANDS->command("undo");
286                 RS_DIALOGFACTORY->updateMouseWidget(
287                     tr("Specify next control point or [%1]").arg(msg),
288                     tr("Back"));
289             } else {
290                 RS_DIALOGFACTORY->updateMouseWidget(
291                     tr("Specify next control point"),
292                     tr("Back"));
293             }
294         }
295         break;
296     default:
297         RS_DIALOGFACTORY->updateMouseWidget();
298         break;
299     }
300 }
301 
302 
showOptions()303 void RS_ActionDrawSpline::showOptions() {
304     RS_ActionInterface::showOptions();
305 
306     RS_DIALOGFACTORY->requestOptions(this, true);
307 }
308 
309 
310 
hideOptions()311 void RS_ActionDrawSpline::hideOptions() {
312     RS_ActionInterface::hideOptions();
313 
314     RS_DIALOGFACTORY->requestOptions(this, false);
315 }
316 
317 
updateMouseCursor()318 void RS_ActionDrawSpline::updateMouseCursor() {
319     graphicView->setMouseCursor(RS2::CadCursor);
320 }
321 
322 /*
323 void RS_ActionDrawSpline::close() {
324     if (history.count()>2 && start.valid) {
325         //data.endpoint = start;
326         //trigger();
327                 if (spline) {
328                         RS_CoordinateEvent e(spline->getStartpoint());
329                         coordinateEvent(&e);
330                 }
331                 trigger();
332         setStatus(SetStartpoint);
333         graphicView->moveRelativeZero(start);
334     } else {
335         RS_DIALOGFACTORY->commandMessage(
336             tr("Cannot close sequence of lines: "
337                "Not enough entities defined yet."));
338     }
339 }
340 */
341 
undo()342 void RS_ActionDrawSpline::undo() {
343 	if (pPoints->history.size()>1) {
344 		pPoints->history.removeLast();
345         //bHistory.removeLast();
346         deletePreview();
347         //graphicView->setCurrentAction(
348         //    new RS_ActionEditUndo(true, *container, *graphicView));
349 				if (!pPoints->history.isEmpty()) {
350                 //point = *history.last();
351                 }
352 				if (pPoints->spline) {
353 						pPoints->spline->removeLastControlPoint();
354 						if (!pPoints->history.isEmpty()) {
355 							RS_Vector v = pPoints->history.last();
356                             graphicView->moveRelativeZero(v);
357                         }
358                         graphicView->redraw(RS2::RedrawDrawing);
359 
360                 }
361     } else {
362         RS_DIALOGFACTORY->commandMessage(
363             tr("Cannot undo: "
364                "Not enough entities defined yet."));
365     }
366 }
367 
368 
setDegree(int deg)369 void RS_ActionDrawSpline::setDegree(int deg) {
370 		pPoints->data.degree = deg;
371 		if (pPoints->spline) {
372 				pPoints->spline->setDegree(deg);
373         }
374 }
375 
getDegree()376 int RS_ActionDrawSpline::getDegree() {
377 		return pPoints->data.degree;
378 }
379 
setClosed(bool c)380 void RS_ActionDrawSpline::setClosed(bool c) {
381 		pPoints->data.closed = c;
382 		if (pPoints->spline) {
383 				pPoints->spline->setClosed(c);
384         }
385 }
386 
isClosed()387 bool RS_ActionDrawSpline::isClosed() {
388 		return pPoints->data.closed;
389 }
390 
391 // EOF
392