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 <QRegExp>
28 #include <QAction>
29 #include <QMouseEvent>
30 #include "rs_eventhandler.h"
31 #include "rs_actioninterface.h"
32 #include "rs_dialogfactory.h"
33 #include "rs_commandevent.h"
34 #include "rs_coordinateevent.h"
35 #include "rs_commands.h"
36 #include "rs_math.h"
37 #include "rs_snapper.h"
38 #include "rs_debug.h"
39
40 /**
41 * Constructor.
42 */
RS_EventHandler(QObject * parent)43 RS_EventHandler::RS_EventHandler(QObject* parent) : QObject(parent)
44 {
45 connect(parent, SIGNAL(relative_zero_changed(const RS_Vector&)),
46 this, SLOT(setRelativeZero(const RS_Vector&)));
47 }
48
49 /**
50 * Destructor.
51 */
~RS_EventHandler()52 RS_EventHandler::~RS_EventHandler() {
53 RS_DEBUG->print("RS_EventHandler::~RS_EventHandler");
54 delete defaultAction;
55 defaultAction = nullptr;
56
57 RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..");
58 for(auto a: currentActions){
59 delete a;
60 }
61 currentActions.clear();
62 RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: Deleting all actions..: OK");
63 RS_DEBUG->print("RS_EventHandler::~RS_EventHandler: OK");
64 }
65
66
67 /**
68 * Go back in current action.
69 */
back()70 void RS_EventHandler::back() {
71 QMouseEvent e(QEvent::MouseButtonRelease, QPoint(0,0),
72 Qt::RightButton, Qt::RightButton,Qt::NoModifier);
73 mouseReleaseEvent(&e);
74 if (!hasAction() && q_action)
75 {
76 q_action->setChecked(false);
77 q_action = nullptr;
78 }
79 }
80
81
82
83 /**
84 * Go enter pressed event for current action.
85 */
enter()86 void RS_EventHandler::enter() {
87 QKeyEvent e(QEvent::KeyPress, Qt::Key_Enter, 0);
88 keyPressEvent(&e);
89 }
90
91
92 /**
93 * Called by QG_GraphicView
94 */
mousePressEvent(QMouseEvent * e)95 void RS_EventHandler::mousePressEvent(QMouseEvent* e) {
96 if(hasAction()){
97 currentActions.last()->mousePressEvent(e);
98 e->accept();
99 } else {
100 if (defaultAction) {
101 defaultAction->mousePressEvent(e);
102 e->accept();
103 } else {
104 RS_DEBUG->print("currently no action defined");
105 e->ignore();
106 }
107 }
108 }
109
110
111
112 /**
113 * Called by QG_GraphicView
114 */
mouseReleaseEvent(QMouseEvent * e)115 void RS_EventHandler::mouseReleaseEvent(QMouseEvent* e) {
116 if(hasAction()){
117 // if (actionIndex>=0 && currentActions[actionIndex] &&
118 // !currentActions[actionIndex]->isFinished()) {
119 RS_DEBUG->print("call action %s",
120 currentActions.last()->getName().toLatin1().data());
121
122 currentActions.last()->mouseReleaseEvent(e);
123
124 // Clean up actions - one might be finished now
125 cleanUp();
126 e->accept();
127 } else {
128 if (defaultAction) {
129 defaultAction->mouseReleaseEvent(e);
130 } else {
131 e->ignore();
132 }
133 }
134 }
135
136
137
138 /**
139 * Called by QG_GraphicView
140 */
mouseMoveEvent(QMouseEvent * e)141 void RS_EventHandler::mouseMoveEvent(QMouseEvent* e)
142 {
143 if(hasAction())
144 currentActions.last()->mouseMoveEvent(e);
145
146 else if (defaultAction)
147 defaultAction->mouseMoveEvent(e);
148 }
149
150 /**
151 * Called by QG_GraphicView
152 */
mouseLeaveEvent()153 void RS_EventHandler::mouseLeaveEvent() {
154
155 if(hasAction()){
156 currentActions.last()->suspend();
157 } else {
158 if (defaultAction) {
159 defaultAction->suspend();
160 }
161 //RS_DEBUG->print("currently no action defined");
162 }
163 }
164
165
166
167 /**
168 * Called by QG_GraphicView
169 */
mouseEnterEvent()170 void RS_EventHandler::mouseEnterEvent() {
171
172 if(hasAction()){
173 currentActions.last()->resume();
174 } else {
175 if (defaultAction) {
176 defaultAction->resume();
177 }
178 }
179 }
180
181
182
183 /**
184 * Called by QG_GraphicView
185 */
keyPressEvent(QKeyEvent * e)186 void RS_EventHandler::keyPressEvent(QKeyEvent* e) {
187
188 if(hasAction()){
189 currentActions.last()->keyPressEvent(e);
190 } else {
191 if (defaultAction) {
192 defaultAction->keyPressEvent(e);
193 }
194 else {
195 e->ignore();
196 }
197
198 //RS_DEBUG->print("currently no action defined");
199 }
200 }
201
202
203
204 /**
205 * Called by QG_GraphicView
206 */
keyReleaseEvent(QKeyEvent * e)207 void RS_EventHandler::keyReleaseEvent(QKeyEvent* e) {
208
209 if(hasAction()){
210 currentActions.last()->keyReleaseEvent(e);
211 } else {
212 if (defaultAction) {
213 defaultAction->keyReleaseEvent(e);
214 }
215 else {
216 e->ignore();
217 }
218 //RS_DEBUG->print("currently no action defined");
219 }
220 }
221
222 /**
223 * Handles command line events.
224 */
commandEvent(RS_CommandEvent * e)225 void RS_EventHandler::commandEvent(RS_CommandEvent* e) {
226 RS_DEBUG->print("RS_EventHandler::commandEvent");
227 QString cmd = e->getCommand();
228
229 if (coordinateInputEnabled) {
230 if (!e->isAccepted()) {
231
232 if(hasAction()){
233 // handle absolute cartesian coordinate input:
234 if (cmd.contains(',') && cmd.at(0)!='@') {
235
236 int commaPos = cmd.indexOf(',');
237 RS_DEBUG->print("RS_EventHandler::commandEvent: 001");
238 bool ok1, ok2;
239 RS_DEBUG->print("RS_EventHandler::commandEvent: 002");
240 double x = RS_Math::eval(cmd.left(commaPos), &ok1);
241 RS_DEBUG->print("RS_EventHandler::commandEvent: 003a");
242 double y = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
243 RS_DEBUG->print("RS_EventHandler::commandEvent: 004");
244
245 if (ok1 && ok2) {
246 RS_DEBUG->print("RS_EventHandler::commandEvent: 005");
247 RS_CoordinateEvent ce(RS_Vector(x,y));
248 RS_DEBUG->print("RS_EventHandler::commandEvent: 006");
249 currentActions.last()->coordinateEvent(&ce);
250 } else
251 RS_DIALOGFACTORY->commandMessage(
252 "Expression Syntax Error");
253 e->accept();
254 }
255
256 // handle relative cartesian coordinate input:
257 if (!e->isAccepted()) {
258 if (cmd.contains(',') && cmd.at(0)=='@') {
259 int commaPos = cmd.indexOf(',');
260 bool ok1, ok2;
261 double x = RS_Math::eval(cmd.mid(1, commaPos-1), &ok1);
262 double y = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
263
264 if (ok1 && ok2) {
265 RS_CoordinateEvent ce(RS_Vector(x,y) + relative_zero);
266
267 currentActions.last()->coordinateEvent(&ce);
268 // currentActions[actionIndex]->coordinateEvent(&ce);
269 } else
270 RS_DIALOGFACTORY->commandMessage(
271 "Expression Syntax Error");
272 e->accept();
273 }
274 }
275
276 // handle absolute polar coordinate input:
277 if (!e->isAccepted()) {
278 if (cmd.contains('<') && cmd.at(0)!='@') {
279 int commaPos = cmd.indexOf('<');
280 bool ok1, ok2;
281 double r = RS_Math::eval(cmd.left(commaPos), &ok1);
282 double a = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
283
284 if (ok1 && ok2) {
285 RS_Vector pos{
286 RS_Vector::polar(r,RS_Math::deg2rad(a))};
287 RS_CoordinateEvent ce(pos);
288 currentActions.last()->coordinateEvent(&ce);
289 } else
290 RS_DIALOGFACTORY->commandMessage(
291 "Expression Syntax Error");
292 e->accept();
293 }
294 }
295
296 // handle relative polar coordinate input:
297 if (!e->isAccepted()) {
298 if (cmd.contains('<') && cmd.at(0)=='@') {
299 int commaPos = cmd.indexOf('<');
300 bool ok1, ok2;
301 double r = RS_Math::eval(cmd.mid(1, commaPos-1), &ok1);
302 double a = RS_Math::eval(cmd.mid(commaPos+1), &ok2);
303
304 if (ok1 && ok2) {
305 RS_Vector pos = RS_Vector::polar(r,RS_Math::deg2rad(a));
306 RS_CoordinateEvent ce(pos + relative_zero);
307 currentActions.last()->coordinateEvent(&ce);
308 } else
309 RS_DIALOGFACTORY->commandMessage(
310 "Expression Syntax Error");
311 e->accept();
312 }
313 }
314
315 // send command event directly to current action:
316 if (!e->isAccepted()) {
317 // std::cout<<"RS_EventHandler::commandEvent(RS_CommandEvent* e): sending cmd("<<qPrintable(e->getCommand()) <<") to action: "<<currentActions.last()->rtti()<<std::endl;
318 currentActions.last()->commandEvent(e);
319 }
320 }else{
321 //send the command to default action
322 if (defaultAction) {
323 defaultAction->commandEvent(e);
324 }
325 }
326 // do not accept command here. Actions themselves should be responsible to accept commands
327 // e->accept();
328 }
329 }
330
331 RS_DEBUG->print("RS_EventHandler::commandEvent: OK");
332 }
333
334
335
336 /**
337 * Enables coordinate input in the command line.
338 */
enableCoordinateInput()339 void RS_EventHandler::enableCoordinateInput() {
340 coordinateInputEnabled = true;
341 }
342
343
344
345 /**
346 * Enables coordinate input in the command line.
347 */
disableCoordinateInput()348 void RS_EventHandler::disableCoordinateInput() {
349 coordinateInputEnabled = false;
350 }
351
352
353
354 /**
355 * @return Current action.
356 */
getCurrentAction()357 RS_ActionInterface* RS_EventHandler::getCurrentAction(){
358 if(hasAction()){
359 return currentActions.last();
360 } else {
361 return defaultAction;
362 }
363 }
364
365
366
367 /**
368 * @return The current default action.
369 */
getDefaultAction() const370 RS_ActionInterface* RS_EventHandler::getDefaultAction() const{
371 return defaultAction;
372 }
373
374
375
376 /**
377 * Sets the default action.
378 */
setDefaultAction(RS_ActionInterface * action)379 void RS_EventHandler::setDefaultAction(RS_ActionInterface* action) {
380 if (defaultAction) {
381 defaultAction->finish();
382 delete defaultAction;
383 // defaultAction = NULL;
384 }
385
386 defaultAction = action;
387 }
388
389
390
391 /**
392 * Sets the current action.
393 */
setCurrentAction(RS_ActionInterface * action)394 void RS_EventHandler::setCurrentAction(RS_ActionInterface* action) {
395 RS_DEBUG->print("RS_EventHandler::setCurrentAction");
396 if (action==NULL) {
397 return;
398 }
399
400 // Predecessor of the new action or NULL:
401 RS_ActionInterface* predecessor = NULL;
402
403 // Suspend current action:
404 if(hasAction()){
405 predecessor = currentActions.last();
406 predecessor->suspend();
407 predecessor->hideOptions();
408 }
409 else {
410 if (defaultAction) {
411 predecessor = defaultAction;
412 predecessor->suspend();
413 predecessor->hideOptions();
414 }
415 }
416
417 // // Forget about the oldest action and make space for the new action:
418 // if (actionIndex==RS_MAXACTIONS-1) {
419 // // delete oldest action if necessary (usually never happens):
420 // if (currentActions[0]) {
421 // currentActions[0]->finish();
422 // delete currentActions[0];
423 // currentActions[0] = NULL;
424 // }
425 // // Move up actionstack (optimize):
426 // for (int i=0; i<RS_MAXACTIONS-1; ++i) {
427 // currentActions[i] = currentActions[i+1];
428 // }
429 // } else if (actionIndex<RS_MAXACTIONS-1) {
430 // actionIndex++;
431 // }
432
433 // Set current action:
434 currentActions.push_back(action);
435 RS_DEBUG->print("RS_EventHandler::setCurrentAction: current action is: %s",
436 currentActions.last()->getName().toLatin1().data());
437
438 // Initialisation of our new action:
439 RS_DEBUG->print("RS_EventHandler::setCurrentAction: init current action");
440 action->init();
441 // ## new:
442 if (action->isFinished()==false) {
443 RS_DEBUG->print("RS_EventHandler::setCurrentAction: show options");
444 currentActions.last()->showOptions();
445 RS_DEBUG->print("RS_EventHandler::setCurrentAction: set predecessor");
446 action->setPredecessor(predecessor);
447 }
448
449 RS_DEBUG->print("RS_EventHandler::setCurrentAction: cleaning up..");
450 cleanUp();
451
452 RS_DEBUG->print("RS_EventHandler::setCurrentAction: debugging actions");
453 debugActions();
454 RS_DEBUG->print("RS_GraphicView::setCurrentAction: OK");
455 if (q_action)
456 q_action->setChecked(true);
457 }
458
459
460
461 /**
462 * Kills all running selection actions. Called when a selection action
463 * is launched to reduce confusion.
464 */
killSelectActions()465 void RS_EventHandler::killSelectActions() {
466
467 for (auto it=currentActions.begin();it != currentActions.end();){
468 if ((*it)->rtti()==RS2::ActionSelectSingle ||
469 (*it)->rtti()==RS2::ActionSelectContour ||
470 (*it)->rtti()==RS2::ActionSelectWindow ||
471 (*it)->rtti()==RS2::ActionSelectIntersected ||
472 (*it)->rtti()==RS2::ActionSelectLayer) {
473 if( ! (*it)->isFinished()){
474 (*it)->finish();
475 }
476 delete *it;
477 it= currentActions.erase(it);
478 }else{
479 it++;
480 }
481 }
482 }
483
484
485
486 /**
487 * Kills all running actions. Called when a window is closed.
488 */
killAllActions()489 void RS_EventHandler::killAllActions()
490 {
491 RS_DEBUG->print(__FILE__ ": %s: line %d: begin\n", __func__, __LINE__);
492
493 if (q_action)
494 {
495 q_action->setChecked(false);
496 q_action = nullptr;
497 }
498
499 for(auto p: currentActions)
500 {
501 if (!p->isFinished())
502 {
503 p->finish();
504 }
505 }
506
507 if (!defaultAction->isFinished())
508 {
509 defaultAction->finish();
510 }
511
512 RS_DEBUG->print(__FILE__ ": %s: line %d: begin\n", __func__, __LINE__);
513 defaultAction->init(0);
514 }
515
516
517
518 /**
519 * @return true if the action is within currentActions
520 */
isValid(RS_ActionInterface * action) const521 bool RS_EventHandler::isValid(RS_ActionInterface* action) const{
522 return currentActions.indexOf(action) >= 0;
523 }
524
525 /**
526 * @return true if there is at least one action in the action stack.
527 */
hasAction()528 bool RS_EventHandler::hasAction()
529 {
530 foreach (RS_ActionInterface* a, currentActions)
531 {
532 if(!a->isFinished())
533 return true;
534 }
535 return false;
536 }
537
538
539
540 /**
541 * Garbage collector for actions.
542 */
cleanUp()543 void RS_EventHandler::cleanUp() {
544 RS_DEBUG->print("RS_EventHandler::cleanUp");
545
546 for (auto it=currentActions.begin(); it != currentActions.end();)
547 {
548 if( (*it)->isFinished())
549 {
550 delete *it;
551 it= currentActions.erase(it);
552 }else{
553 ++it;
554 }
555 }
556 if(hasAction()){
557 currentActions.last()->resume();
558 currentActions.last()->showOptions();
559 } else {
560 if (defaultAction) {
561 defaultAction->resume();
562 defaultAction->showOptions();
563 }
564 }
565 RS_DEBUG->print("RS_EventHandler::cleanUp: OK");
566 }
567
568
569
570 /**
571 * Sets the snap mode for all currently active actions.
572 */
setSnapMode(RS_SnapMode sm)573 void RS_EventHandler::setSnapMode(RS_SnapMode sm) {
574 for(auto a: currentActions){
575 if( ! a->isFinished()){
576 a->setSnapMode(sm);
577 }
578 }
579
580 if (defaultAction) {
581 defaultAction->setSnapMode(sm);
582 }
583 }
584
585
586 /**
587 * Sets the snap restriction for all currently active actions.
588 */
setSnapRestriction(RS2::SnapRestriction sr)589 void RS_EventHandler::setSnapRestriction(RS2::SnapRestriction sr) {
590
591 for(auto a: currentActions){
592 if( ! a->isFinished()){
593 a->setSnapRestriction(sr);
594 }
595 }
596
597 if (defaultAction) {
598 defaultAction->setSnapRestriction(sr);
599 }
600 }
601
602
debugActions() const603 void RS_EventHandler::debugActions() const{
604 // std::cout<<"action queue size=:"<<currentActions.size()<<std::endl;
605 RS_DEBUG->print("---");
606 for(int i=0;i<currentActions.size();++i){
607
608 if (i == currentActions.size() - 1 ) {
609 RS_DEBUG->print("Current");
610 }
611 RS_DEBUG->print("Action %03d: %s [%s]",
612 i, currentActions.at(i)->getName().toLatin1().data(),
613 currentActions.at(i)->isFinished() ? "finished" : "active");
614 }
615 }
616
setQAction(QAction * action)617 void RS_EventHandler::setQAction(QAction* action)
618 {
619 if (q_action)
620 {
621 q_action->setChecked(false);
622 killAllActions();
623 }
624 q_action = action;
625 }
626
setRelativeZero(const RS_Vector & point)627 void RS_EventHandler::setRelativeZero(const RS_Vector& point)
628 {
629 relative_zero = point;
630 }
631
inSelectionMode()632 bool RS_EventHandler::inSelectionMode()
633 {
634 switch (getCurrentAction()->rtti())
635 {
636 case RS2::ActionDefault:
637 case RS2::ActionSelectSingle:
638 case RS2::ActionSelectWindow:
639 case RS2::ActionDeselectWindow:
640 case RS2::ActionSelectContour:
641 case RS2::ActionSelectIntersected:
642 case RS2::ActionDeselectIntersected:
643 case RS2::ActionSelectLayer:
644 return true;
645 default:
646 return false;
647 }
648 }
649
650 // EOF
651