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 #include<cmath>
27 #include <QAction>
28 #include <QMouseEvent>
29 #include "rs_actiondimlinear.h"
30 #include "rs_dimlinear.h"
31 
32 #include "rs_dialogfactory.h"
33 #include "rs_graphicview.h"
34 #include "rs_commandevent.h"
35 #include "rs_constructionline.h"
36 #include "rs_line.h"
37 #include "rs_coordinateevent.h"
38 #include "rs_math.h"
39 #include "rs_preview.h"
40 #include "rs_debug.h"
41 
42 /**
43  * Constructor.
44  *
45  * @param angle Initial angle in rad.
46  * @param fixedAngle true: The user can't change the angle.
47  *                   false: The user can change the angle in a option widget.
48  */
RS_ActionDimLinear(RS_EntityContainer & container,RS_GraphicView & graphicView,double angle,bool _fixedAngle,RS2::ActionType)49 RS_ActionDimLinear::RS_ActionDimLinear(RS_EntityContainer& container,
50                                        RS_GraphicView& graphicView,
51                                        double angle,
52 									   bool _fixedAngle, RS2::ActionType /*type*/)
53         :RS_ActionDimension("Draw linear dimensions",
54                     container, graphicView)
55 		,edata(new RS_DimLinearData(RS_Vector(0., 0.), RS_Vector(0., 0.), angle, 0.))
56 		,fixedAngle(_fixedAngle)
57 		,lastStatus(SetExtPoint1)
58 {
59 	//TODO: fix dim linear type logic: whether it's for linear only, or should cover horizontal/vertical dim types
60 	actionType=RS2::ActionDimLinear;
61 	reset();
62 }
63 
64 
65 
66 RS_ActionDimLinear::~RS_ActionDimLinear() = default;
67 
reset()68 void RS_ActionDimLinear::reset() {
69     RS_ActionDimension::reset();
70 
71 	edata.reset(new RS_DimLinearData(RS_Vector(false),
72                              RS_Vector(false),
73 							 (fixedAngle ? edata->angle : 0.0), 0.0)
74 				);
75 
76 	RS_DIALOGFACTORY->requestOptions(this, true, true);
77 }
78 
79 
80 
trigger()81 void RS_ActionDimLinear::trigger() {
82     RS_ActionDimension::trigger();
83 
84     preparePreview();
85 	RS_DimLinear* dim = new RS_DimLinear(container, *data, *edata);
86     dim->setLayerToActive();
87     dim->setPenToActive();
88     dim->update();
89     container->addEntity(dim);
90 
91     // upd. undo list:
92     if (document) {
93         document->startUndoCycle();
94         document->addUndoable(dim);
95         document->endUndoCycle();
96     }
97 
98     RS_Vector rz = graphicView->getRelativeZero();
99 	graphicView->redraw(RS2::RedrawDrawing);
100     graphicView->moveRelativeZero(rz);
101 
102     RS_DEBUG->print("RS_ActionDimLinear::trigger():"
103                     " dim added: %d", dim->getId());
104 }
105 
106 
preparePreview()107 void RS_ActionDimLinear::preparePreview() {
108 	RS_Vector dirV = RS_Vector::polar(100., edata->angle+M_PI_2);
109 
110     RS_ConstructionLine cl(
111         NULL,
112         RS_ConstructionLineData(
113 			edata->extensionPoint2,
114 			edata->extensionPoint2+dirV));
115 
116 	data->definitionPoint =
117 		cl.getNearestPointOnEntity(data->definitionPoint);
118 
119 }
120 
121 
122 
mouseMoveEvent(QMouseEvent * e)123 void RS_ActionDimLinear::mouseMoveEvent(QMouseEvent* e) {
124     RS_DEBUG->print("RS_ActionDimLinear::mouseMoveEvent begin");
125 
126     RS_Vector mouse = snapPoint(e);
127 
128     switch (getStatus()) {
129     case SetExtPoint1:
130         break;
131 
132     case SetExtPoint2:
133 		if (edata->extensionPoint1.valid) {
134             deletePreview();
135 			preview->addEntity(new RS_Line{preview.get(),
136 										   edata->extensionPoint1, mouse});
137             drawPreview();
138         }
139         break;
140 
141     case SetDefPoint:
142 		if (edata->extensionPoint1.valid && edata->extensionPoint2.valid) {
143             deletePreview();
144 			data->definitionPoint = mouse;
145 
146             preparePreview();
147 
148 			RS_DimLinear* dim = new RS_DimLinear(preview.get(), *data, *edata);
149             preview->addEntity(dim);
150             dim->update();
151             drawPreview();
152         }
153         break;
154     }
155 
156     RS_DEBUG->print("RS_ActionDimLinear::mouseMoveEvent end");
157 }
158 
159 
160 
mouseReleaseEvent(QMouseEvent * e)161 void RS_ActionDimLinear::mouseReleaseEvent(QMouseEvent* e) {
162     if (e->button()==Qt::LeftButton) {
163         RS_CoordinateEvent ce(snapPoint(e));
164         coordinateEvent(&ce);
165     } else if (e->button()==Qt::RightButton) {
166         deletePreview();
167         init(getStatus()-1);
168     }
169 }
170 
171 
172 
coordinateEvent(RS_CoordinateEvent * e)173 void RS_ActionDimLinear::coordinateEvent(RS_CoordinateEvent* e) {
174     if (e==NULL) {
175         return;
176     }
177 
178     RS_Vector pos = e->getCoordinate();
179 
180     switch (getStatus()) {
181     case SetExtPoint1:
182 		edata->extensionPoint1 = pos;
183         graphicView->moveRelativeZero(pos);
184         setStatus(SetExtPoint2);
185         break;
186 
187     case SetExtPoint2:
188 		edata->extensionPoint2 = pos;
189         graphicView->moveRelativeZero(pos);
190         setStatus(SetDefPoint);
191         break;
192 
193     case SetDefPoint:
194 		data->definitionPoint = pos;
195         trigger();
196         reset();
197         setStatus(SetExtPoint1);
198         break;
199 
200     default:
201         break;
202     }
203 }
204 
getAngle() const205 double RS_ActionDimLinear::getAngle() const{
206 	return edata->angle;
207 }
208 
setAngle(double a)209 void RS_ActionDimLinear::setAngle(double a) {
210 	edata->angle = a;
211 }
212 
hasFixedAngle() const213 bool RS_ActionDimLinear::hasFixedAngle() const{
214 	return fixedAngle;
215 }
216 
commandEvent(RS_CommandEvent * e)217 void RS_ActionDimLinear::commandEvent(RS_CommandEvent* e) {
218     QString c = e->getCommand().toLower();
219 
220 	if (checkCommand("help", c)) {
221 		RS_DIALOGFACTORY->commandMessage(msgAvailableCommands()
222 										 + getAvailableCommands().join(", "));
223 		return;
224 	}
225 
226     switch (getStatus()) {
227     case SetText:
228         setText(c);
229 		RS_DIALOGFACTORY->requestOptions(this, true, true);
230         graphicView->enableCoordinateInput();
231         setStatus(lastStatus);
232         break;
233 
234     case SetAngle: {
235             bool ok;
236             double a = RS_Math::eval(c, &ok);
237 			if (ok) {
238                 setAngle(RS_Math::deg2rad(a));
239             } else {
240 				RS_DIALOGFACTORY->commandMessage(tr("Not a valid expression"));
241             }
242 			RS_DIALOGFACTORY->requestOptions(this, true, true);
243             setStatus(lastStatus);
244         }
245         break;
246 
247     default:
248         lastStatus = (Status)getStatus();
249         deletePreview();
250         if (checkCommand("text", c)) {
251             graphicView->disableCoordinateInput();
252             setStatus(SetText);
253             return;
254         } else if (!fixedAngle && (checkCommand("angle", c))) {
255             setStatus(SetAngle);
256         }
257         break;
258     }
259 }
260 
261 
262 
getAvailableCommands()263 QStringList RS_ActionDimLinear::getAvailableCommands() {
264     QStringList cmd;
265 
266     switch (getStatus()) {
267     case SetExtPoint1:
268     case SetExtPoint2:
269     case SetDefPoint:
270         cmd += command("text");
271         if (!fixedAngle) {
272             cmd += command("angle");
273         }
274         break;
275 
276     default:
277         break;
278     }
279 
280     return cmd;
281 }
282 
283 
updateMouseButtonHints()284 void RS_ActionDimLinear::updateMouseButtonHints() {
285 	switch (getStatus()) {
286 	case SetExtPoint1:
287 		RS_DIALOGFACTORY->updateMouseWidget(
288 					tr("Specify first extension line origin"),
289 					tr("Cancel"));
290 		break;
291 	case SetExtPoint2:
292 		RS_DIALOGFACTORY->updateMouseWidget(
293 					tr("Specify second extension line origin"),
294 					tr("Back"));
295 		break;
296 	case SetDefPoint:
297 		RS_DIALOGFACTORY->updateMouseWidget(
298 					tr("Specify dimension line location"),
299 					tr("Back"));
300 		break;
301 	case SetText:
302 		RS_DIALOGFACTORY->updateMouseWidget(tr("Enter dimension text:"), "");
303 		break;
304 	case SetAngle:
305 		RS_DIALOGFACTORY->updateMouseWidget(
306 					tr("Enter dimension line angle:"), "");
307 		break;
308 	default:
309 		RS_DIALOGFACTORY->updateMouseWidget();
310 		break;
311 	}
312 }
313 
314 
315 
showOptions()316 void RS_ActionDimLinear::showOptions() {
317     RS_ActionInterface::showOptions();
318 
319 	RS_DIALOGFACTORY->requestOptions(this, true, true);
320 }
321 
322 
323 
hideOptions()324 void RS_ActionDimLinear::hideOptions() {
325     RS_ActionInterface::hideOptions();
326 
327 	RS_DIALOGFACTORY->requestOptions(this, false);
328 }
329 
330 
331 
332 // EOF
333