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