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