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