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