]> Shamusworld >> Repos - architektonas/blob - src/mainapp/graphicview.cpp
5b633b2b3a56af1859772b16f4941bf5ac659f10
[architektonas] / src / mainapp / graphicview.cpp
1 // graphicview.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 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  06/16/2010  Created this file. :-)
15 //
16
17 #include "graphicview.h"
18
19 #include "dialogfactory.h"
20 #include "drawing.h"
21 #include "eventhandler.h"
22 #include "grid.h"
23 #include "linetypepattern.h"
24 #include "paintinterface.h"
25 #include "settings.h"
26 #include "text.h"
27 #include "units.h"
28
29 /**
30  * Constructor.
31  */
32 GraphicView::GraphicView(): background(), foreground()
33 {
34         drawingMode = RS2::ModeFull;
35         printing = false;
36         deleteMode = false;
37         factor = Vector(1.0, 1.0);
38         offsetX = 0;
39         offsetY = 0;
40         previousFactor = Vector(1.0, 1.0);
41         previousOffsetX = 0;
42         previousOffsetY = 0;
43         container = NULL;
44         eventHandler = new EventHandler(this);
45         gridColor = Qt::gray;
46         metaGridColor = Color(64, 64, 64);
47         grid = new Grid(this);
48         updateEnabled = 0;
49         zoomFrozen = false;
50         draftMode = false;
51         painter = NULL;
52
53         borderLeft = 0;
54         borderTop = 0;
55         borderRight = 0;
56         borderBottom = 0;
57
58         relativeZero = Vector(false);
59         relativeZeroLocked = false;
60
61         mx = my = 0;
62
63         defaultSnapMode = RS2::SnapFree;
64         defaultSnapRes = RS2::RestrictNothing;
65
66         settings.beginGroup("Appearance");
67         setBackground(QColor(settings.value("BackgroundColor", "#000000").toString()));
68         setGridColor(QColor(settings.value("GridColor", "#7F7F7F").toString()));
69         setMetaGridColor(QColor(settings.value("MetaGridColor", "#3F3F3F").toString()));
70         setSelectedColor(QColor(settings.value("SelectedColor", "#A54747").toString()));
71         setHighlightedColor(QColor(settings.value("HighlightedColor", "#739373").toString()));
72         settings.endGroup();
73
74         printPreview = false;
75
76         simulationSpeed = 100;
77         simulationSmooth = false;
78         simulationRapid = false;
79         simulationRunning = false;
80
81         // Snapper settings...
82         snapEntity = NULL;
83         snapSpot = Vector(false);
84         snapCoord = Vector(false);
85         snapperVisible = false;
86         snapDistance = 1.0;
87
88         settings.beginGroup("Snap");
89         snapRange = settings.value("Range", 20).toInt();
90         settings.endGroup();
91         settings.beginGroup("Appearance");
92         showCrosshairs = settings.value("ShowCrosshairs", true).toBool();
93         settings.endGroup();
94
95         // Sanity check for snapRange
96         if (snapRange < 2)
97                 snapRange = 20;
98 }
99
100 /**
101  * Destructor.
102  */
103 GraphicView::~GraphicView()
104 {
105         delete grid;
106 }
107
108 /**
109  * Must be called by any derrived class in the destructor.
110  */
111 void GraphicView::cleanUp()
112 {
113         delete eventHandler;
114 }
115
116 /**
117  * @return Pointer to the graphic entity if the entity container
118  * connected to this view is a graphic and valid.
119  * NULL otherwise.
120  */
121 Drawing * GraphicView::getGraphic()
122 {
123         if (container && container->rtti() == RS2::EntityGraphic)
124                 return (Drawing *)container;
125
126         return NULL;
127 }
128
129 /**
130  * Sets the drawing mode.
131  */
132 void GraphicView::setDrawingMode(RS2::DrawingMode m)
133 {
134         drawingMode = m;
135 }
136
137 /**
138  * @return Current drawing mode.
139  */
140 RS2::DrawingMode GraphicView::getDrawingMode()
141 {
142         return drawingMode;
143 }
144
145 /**
146  * Activates or deactivates the delete mode.
147  */
148 void GraphicView::setDeleteMode(bool m)
149 {
150         deleteMode = m;
151 }
152
153 /**
154  * @reval true Deleting instead of drawing.
155  *        false Normal drawing mode.
156  */
157 bool GraphicView::getDeleteMode()
158 {
159         return deleteMode;
160 }
161
162 /** This virtual method must be overwritten and is then
163         called whenever the view changed */
164 void GraphicView::adjustOffsetControls()
165 {
166 }
167
168 /** This virtual method must be overwritten and is then
169         called whenever the view changed */
170 void GraphicView::adjustZoomControls()
171 {
172 }
173
174 /**
175  * Sets the background color. Note that applying the background
176  * color for the widget is up to the implementing class.
177  */
178 void GraphicView::setBackground(const Color & bg)
179 {
180         background = bg;
181
182         // bright background:
183         if (bg.red() + bg.green() + bg.blue() > 380)
184 //              foreground = Qt::black;
185                 foreground = Color(0, 0, 0);
186         else
187 //              foreground = Qt::white;
188                 foreground = Color(255, 255, 255);
189 }
190
191 /**
192  * @return Current background color.
193  */
194 Color GraphicView::getBackground()
195 {
196         return background;
197 }
198
199 /**
200  * @return Current foreground color.
201  */
202 Color GraphicView::getForeground()
203 {
204         return foreground;
205 }
206
207 /**
208  * Sets the grid color.
209  */
210 void GraphicView::setGridColor(const Color & c)
211 {
212         gridColor = c;
213 }
214
215 /**
216  * Sets the meta grid color.
217  */
218 void GraphicView::setMetaGridColor(const Color & c)
219 {
220         metaGridColor = c;
221 }
222
223 /**
224  * Sets the selection color.
225  */
226 void GraphicView::setSelectedColor(const Color & c)
227 {
228         selectedColor = c;
229 }
230
231 /**
232  * Sets the highlight color.
233  */
234 void GraphicView::setHighlightedColor(const Color & c)
235 {
236         highlightedColor = c;
237 }
238
239 /**
240  * This virtual method can be overwritten to set the mouse
241  * cursor to the given type.
242  */
243 void GraphicView::setMouseCursor(RS2::CursorType /*c*/)
244 {
245 }
246
247 EntityContainer * GraphicView::getContainer()
248 {
249         return container;
250 }
251
252 void GraphicView::setFactor(double f)
253 {
254         setFactorX(f);
255         setFactorY(f);
256 }
257
258 Vector GraphicView::getFactor()
259 {
260         return factor;
261 }
262
263 /**
264  * Sets the offset of the graphic.
265  */
266 void GraphicView::setOffset(int ox, int oy)
267 {
268         setOffsetX(ox);
269         setOffsetY(oy);
270 }
271
272 void GraphicView::setOffsetX(int ox)
273 {
274         offsetX = ox;
275 }
276
277 void GraphicView::setOffsetY(int oy)
278 {
279         offsetY = oy;
280 }
281
282 int GraphicView::getOffsetX()
283 {
284         return offsetX;
285 }
286
287 int GraphicView::getOffsetY()
288 {
289         return offsetY;
290 }
291
292 /**
293  * Sets a fixed border in pixel around the graphic. This border
294  * specifies how far the user can scroll outside the graphic
295  * area.
296  */
297 void GraphicView::setBorders(int left, int top, int right, int bottom)
298 {
299         borderLeft = left;
300         borderTop = top;
301         borderRight = right;
302         borderBottom = bottom;
303 }
304
305 int GraphicView::getBorderLeft()
306 {
307         return borderLeft;
308 }
309
310 int GraphicView::getBorderTop()
311 {
312         return borderTop;
313 }
314
315 int GraphicView::getBorderRight()
316 {
317         return borderRight;
318 }
319
320 int GraphicView::getBorderBottom()
321 {
322         return borderBottom;
323 }
324
325 void GraphicView::disableUpdate()
326 {
327         updateEnabled--;
328 }
329
330 void GraphicView::enableUpdate()
331 {
332         updateEnabled++;
333 }
334
335 bool GraphicView::isUpdateEnabled()
336 {
337         return (updateEnabled == 0);
338 }
339
340 void GraphicView::freezeZoom(bool freeze)
341 {
342         zoomFrozen = freeze;
343 }
344
345 bool GraphicView::isZoomFrozen()
346 {
347         return zoomFrozen;
348 }
349
350 /**
351  * Sets the pointer to the graphic which contains the entities
352  * which are visualized by this widget.
353  */
354 void GraphicView::setContainer(EntityContainer * container)
355 {
356         this->container = container;
357 }
358
359 /**
360  * Sets the zoom factor in X for this visualization of the graphic.
361  */
362 void GraphicView::setFactorX(double f)
363 {
364         if (!zoomFrozen)
365                 factor.x = fabs(f);
366 }
367
368 /**
369  * Sets the zoom factor in Y for this visualization of the graphic.
370  */
371 void GraphicView::setFactorY(double f)
372 {
373         if (!zoomFrozen)
374                 factor.y = fabs(f);
375 }
376
377 /**
378  * @return true if the grid is switched on.
379  */
380 bool GraphicView::isGridOn()
381 {
382         if (container)
383         {
384                 Drawing * d = container->getGraphic();
385
386                 if (d)
387                         return d->isGridOn();
388         }
389
390         return true;
391 }
392
393 /**
394  * Centers the drawing in x-direction.
395  */
396 void GraphicView::centerOffsetX()
397 {
398         if (container != NULL && !zoomFrozen)
399                 offsetX = (int)(((getWidth() - borderLeft - borderRight)
400                         - (container->getSize().x * factor.x)) / 2.0
401                         - (container->getMin().x * factor.x)) + borderLeft;
402 }
403
404 /**
405  * Centers the drawing in y-direction.
406  */
407 void GraphicView::centerOffsetY()
408 {
409         if (container != NULL && !zoomFrozen)
410                 offsetY = (int)((getHeight() - borderTop - borderBottom
411                         - (container->getSize().y * factor.y)) / 2.0
412                         - (container->getMin().y * factor.y)) + borderBottom;
413 }
414
415 /**
416  * Centers the given coordinate in the view in x-direction.
417  */
418 void GraphicView::centerX(double v)
419 {
420         if (!zoomFrozen)
421                 offsetX = (int)((v * factor.x) - (double)(getWidth() - borderLeft - borderRight) / 2.0);
422 }
423
424 /**
425  * Centers the given coordinate in the view in y-direction.
426  */
427 void GraphicView::centerY(double v)
428 {
429     if (!zoomFrozen)
430         offsetY = (int)((v * factor.y) - (double)(getHeight() - borderTop - borderBottom) / 2.0);
431 }
432
433 void GraphicView::updateView()
434 {
435         static int running = 0;
436         running++;
437
438         if (running < 100)
439         {
440                 adjustZoomControls();
441                 adjustOffsetControls();
442         }
443
444         running--;
445
446         if (running == 0)
447                 redraw();
448 }
449
450 /**
451  * @return Current action or NULL.
452  */
453 ActionInterface * GraphicView::getDefaultAction()
454 {
455         if (eventHandler != NULL)
456                 return eventHandler->getDefaultAction();
457         else
458                 return NULL;
459 }
460
461 /**
462  * Sets the default action of the event handler.
463  */
464 void GraphicView::setDefaultAction(ActionInterface * action)
465 {
466     if (eventHandler)
467         eventHandler->setDefaultAction(action);
468 }
469
470 /**
471  * @return Current action or NULL.
472  */
473 ActionInterface * GraphicView::getCurrentAction()
474 {
475         if (eventHandler)
476                 return eventHandler->getCurrentAction();
477         else
478                 return NULL;
479 }
480
481 /**
482  * Sets the current action of the event handler.
483  */
484 void GraphicView::setCurrentAction(ActionInterface * action)
485 {
486         DEBUG->print("GraphicView::setCurrentAction");
487
488         if (eventHandler)
489                 eventHandler->setCurrentAction(action);
490
491         DEBUG->print("GraphicView::setCurrentAction: OK");
492 }
493
494 /**
495  * Kills all running selection actions. Called when a selection action
496  * is launched to reduce confusion.
497  */
498 void GraphicView::killSelectActions()
499 {
500         if (eventHandler)
501                 eventHandler->killSelectActions();
502 }
503
504 /**
505  * Kills all running actions.
506  */
507 void GraphicView::killAllActions()
508 {
509         if (eventHandler)
510                 eventHandler->killAllActions();
511 }
512
513 /**
514  * Go back in menu or current action.
515  */
516 void GraphicView::back()
517 {
518         if (eventHandler && eventHandler->hasAction())
519                 eventHandler->back();
520         else if (DIALOGFACTORY)
521                 DIALOGFACTORY->requestPreviousMenu();
522 }
523
524 /**
525  * Go forward with the current action.
526  */
527 void GraphicView::enter()
528 {
529         if (eventHandler && eventHandler->hasAction())
530                 eventHandler->enter();
531 }
532
533 /**
534  * Called by the actual GUI class which implements the GraphicView
535  * interface to notify qcadlib about mouse events.
536  */
537 void GraphicView::mousePressEvent(QMouseEvent * e)
538 {
539         if (eventHandler)
540                 eventHandler->mousePressEvent(e);
541 }
542
543 /**
544  * Called by the actual GUI class which implements the GraphicView
545  * interface to notify qcadlib about mouse events.
546  */
547 void GraphicView::mouseReleaseEvent(QMouseEvent * e)
548 {
549         DEBUG->print("GraphicView::mouseReleaseEvent");
550
551         if (!eventHandler)
552                 return;
553
554         if (e->button() != Qt::RightButton || eventHandler->hasAction())
555         {
556                 eventHandler->mouseReleaseEvent(e);
557         }
558         else
559         {
560                 back();
561                 e->accept();
562         }
563
564         DEBUG->print("GraphicView::mouseReleaseEvent: OK");
565 }
566
567 /**
568  * Called by the actual GUI class which implements the GraphicView
569  * interface to notify qcadlib about mouse events.
570  */
571 void GraphicView::mouseMoveEvent(QMouseEvent * e)
572 {
573         DEBUG->print("GraphicView::mouseMoveEvent begin");
574
575         Drawing * graphic = NULL;
576
577         if (container->rtti() == RS2::EntityGraphic)
578                 graphic = (Drawing *)container;
579
580         DEBUG->print("GraphicView::mouseMoveEvent 001");
581
582         if (e)
583         {
584                 mx = e->x();
585                 my = e->y();
586         }
587
588         DEBUG->print("GraphicView::mouseMoveEvent 002");
589
590         if (eventHandler)
591                 eventHandler->mouseMoveEvent(e);
592
593         DEBUG->print("GraphicView::mouseMoveEvent 003");
594
595         if (!eventHandler || !eventHandler->hasAction() && graphic)
596         {
597                 Vector mouse = toGraph(Vector(mx, my));
598                 Vector relMouse = mouse - getRelativeZero();
599
600                 if (DIALOGFACTORY)
601                         DIALOGFACTORY->updateCoordinateWidget(mouse, relMouse);
602         }
603
604         DEBUG->print("GraphicView::mouseMoveEvent end");
605 }
606
607 /**
608  * Called by the actual GUI class which implements the GraphicView
609  * interface to notify qcadlib about mouse events.
610  */
611 void GraphicView::mouseLeaveEvent()
612 {
613         if (eventHandler)
614                 eventHandler->mouseLeaveEvent();
615 }
616
617 /**
618  * Called by the actual GUI class which implements the GraphicView
619  * interface to notify qcadlib about mouse events.
620  */
621 void GraphicView::mouseEnterEvent()
622 {
623         if (eventHandler)
624                 eventHandler->mouseEnterEvent();
625 }
626
627 /**
628  * Called by the actual GUI class which implements the GraphicView
629  * interface to notify qcadlib about key events.
630  */
631 void GraphicView::keyPressEvent(QKeyEvent * e)
632 {
633         if (eventHandler)
634                 eventHandler->keyPressEvent(e);
635 }
636
637 /**
638  * Called by the actual GUI class which implements the GraphicView
639  * interface to notify qcadlib about key events.
640  */
641 void GraphicView::keyReleaseEvent(QKeyEvent * e)
642 {
643         if (eventHandler)
644                 eventHandler->keyReleaseEvent(e);
645 }
646
647 /**
648  * Called by the actual GUI class which implements a command line.
649  */
650 void GraphicView::commandEvent(CommandEvent * e)
651 {
652         if (eventHandler)
653                 eventHandler->commandEvent(e);
654 }
655
656 /**
657  * Enables coordinate input in the command line.
658  */
659 void GraphicView::enableCoordinateInput()
660 {
661         if (eventHandler)
662                 eventHandler->enableCoordinateInput();
663 }
664
665 /**
666  * Disables coordinate input in the command line.
667  */
668 void GraphicView::disableCoordinateInput()
669 {
670         if (eventHandler)
671                 eventHandler->disableCoordinateInput();
672 }
673
674 /**
675  * zooms in by factor f
676  */
677 void GraphicView::zoomIn(double f, const Vector & center)
678 {
679         if (f < 1.0e-6)
680         {
681                 DEBUG->print(Debug::D_WARNING, "GraphicView::zoomIn: invalid factor");
682                 return;
683         }
684
685         if (simulationRunning)
686                 return;
687
688         Vector c = center;
689         if (c.valid == false)
690                 c = toGraph(Vector(getWidth() / 2, getHeight() / 2));
691
692         zoomWindow(toGraph(Vector(0, 0)).scale(c, Vector(1.0 / f, 1.0 / f)),
693                 toGraph(Vector(getWidth(), getHeight())).scale(c, Vector(1.0 / f, 1.0 / f)));
694 }
695
696 /**
697  * zooms in by factor f in x
698  */
699 void GraphicView::zoomInX(double f)
700 {
701         if (simulationRunning)
702                 return;
703
704         factor.x *= f;
705         offsetX = (int)((offsetX - getWidth() / 2) * f) + getWidth() / 2;
706         adjustOffsetControls();
707         adjustZoomControls();
708         updateGrid();
709         redraw();
710 }
711
712 /**
713  * zooms in by factor f in y
714  */
715 void GraphicView::zoomInY(double f)
716 {
717         if (simulationRunning)
718                 return;
719
720         factor.y *= f;
721         offsetY = (int)((offsetY - getHeight() / 2) * f)+getHeight() / 2;
722         adjustOffsetControls();
723         adjustZoomControls();
724         updateGrid();
725         redraw();
726 }
727
728 /**
729  * zooms out by factor f
730  */
731 void GraphicView::zoomOut(double f, const Vector & center)
732 {
733         if (f < 1.0e-6)
734         {
735                 DEBUG->print(Debug::D_WARNING,
736                         "GraphicView::zoomOut: invalid factor");
737                 return;
738         }
739
740         if (simulationRunning)
741                 return;
742
743         zoomIn(1/f, center);
744 }
745
746 /**
747  * zooms out by factor f in x
748  */
749 void GraphicView::zoomOutX(double f)
750 {
751         if (f < 1.0e-6)
752         {
753                 DEBUG->print(Debug::D_WARNING,
754                         "GraphicView::zoomOutX: invalid factor");
755                 return;
756         }
757
758         if (simulationRunning)
759                 return;
760
761         factor.x /= f;
762         offsetX = (int)(offsetX / f);
763         adjustOffsetControls();
764         adjustZoomControls();
765         updateGrid();
766         redraw();
767 }
768
769 /**
770  * zooms out by factor of y
771  */
772 void GraphicView::zoomOutY(double f)
773 {
774         if (f < 1.0e-6)
775         {
776                 DEBUG->print(Debug::D_WARNING, "GraphicView::zoomOutY: invalid factor");
777                 return;
778         }
779
780         if (simulationRunning)
781                 return;
782
783         factor.y /= f;
784         offsetY = (int)(offsetY / f);
785         adjustOffsetControls();
786         adjustZoomControls();
787         updateGrid();
788         redraw();
789 }
790
791 /**
792  * performs autozoom
793  *
794  * @param axis include axis in zoom
795  * @param keepAspectRatio true: keep aspect ratio 1:1
796  *                        false: factors in x and y are stretched to the max
797  */
798 void GraphicView::zoomAuto(bool axis, bool keepAspectRatio)
799 {
800         DEBUG->print("GraphicView::zoomAuto");
801
802         if (simulationRunning)
803                 return;
804
805         saveView();
806
807         if (container != NULL)
808         {
809                 container->calculateBorders();
810
811                 double sx, sy;
812                 if (axis)
813                 {
814                         sx = std::max(container->getMax().x, 0.0) - std::min(container->getMin().x, 0.0);
815                         sy = std::max(container->getMax().y, 0.0) - std::min(container->getMin().y, 0.0);
816                 }
817                 else
818                 {
819                         sx = container->getSize().x;
820                         sy = container->getSize().y;
821                 }
822
823                 double fx, fy;
824
825                 if (sx > RS_TOLERANCE)
826                         fx = (getWidth() - borderLeft - borderRight) / sx;
827                 else
828                         fx = 1.0;
829
830                 if (sy > RS_TOLERANCE)
831                         fy = (getHeight() - borderTop - borderBottom) / sy;
832                 else
833                         fy = 1.0;
834
835                 DEBUG->print("f: %f/%f", fx, fy);
836
837                 if (keepAspectRatio)
838                         fx = fy = std::min(fx, fy);
839
840                 DEBUG->print("f: %f/%f", fx, fy);
841
842                 if (fx < RS_TOLERANCE)
843                         fx = fy = 1.0;
844
845                 setFactorX(fx);
846                 setFactorY(fy);
847
848                 DEBUG->print("f: %f/%f", fx, fy);
849
850                 DEBUG->print("adjustOffsetControls");
851                 adjustOffsetControls();
852                 DEBUG->print("adjustZoomControls");
853                 adjustZoomControls();
854                 DEBUG->print("centerOffsetX");
855                 centerOffsetX();
856                 DEBUG->print("centerOffsetY");
857                 centerOffsetY();
858                 DEBUG->print("updateGrid");
859                 updateGrid();
860                 redraw();
861         }
862
863         DEBUG->print("GraphicView::zoomAuto OK");
864 }
865
866 /**
867  * Shows previous view.
868  */
869 void GraphicView::zoomPrevious()
870 {
871         DEBUG->print("GraphicView::zoomPrevious");
872
873         if (simulationRunning)
874                 return;
875
876         if (container)
877                 restoreView();
878 }
879
880 /**
881  * Saves the current view as previous view to which we can
882  * switch back later with @see restoreView().
883  */
884 void GraphicView::saveView()
885 {
886         previousOffsetX = offsetX;
887         previousOffsetY = offsetY;
888         previousFactor = factor;
889 }
890
891 /**
892  * Restores the view previously saved with
893  * @see saveView().
894  */
895 void GraphicView::restoreView()
896 {
897         int pox = previousOffsetX;
898         int poy = previousOffsetY;
899         Vector pf = previousFactor;
900
901         saveView();
902
903         offsetX = pox;
904         offsetY = poy;
905         factor = pf;
906
907         adjustOffsetControls();
908         adjustZoomControls();
909         updateGrid();
910         redraw();
911 }
912
913 /**
914  * performs autozoom in y only
915  *
916  * @param axis include axis in zoom
917  */
918 void GraphicView::zoomAutoY(bool axis)
919 {
920         if (simulationRunning)
921                 return;
922
923         if (container != NULL)
924         {
925                 double visibleHeight = 0.0;
926                 double minY = RS_MAXDOUBLE;
927                 double maxY = RS_MINDOUBLE;
928                 bool noChange = false;
929
930                 for(Entity * e=container->firstEntity(RS2::ResolveNone);
931                         e!=NULL; e = container->nextEntity(RS2::ResolveNone))
932                 {
933                         if (e->rtti() == RS2::EntityLine)
934                         {
935                                 Line * l = (Line *)e;
936                                 double x1, x2;
937                                 x1 = toGuiX(l->getStartpoint().x);
938                                 x2 = toGuiX(l->getEndpoint().x);
939
940                                 if ((x1 > 0.0 && x1 < (double)getWidth())
941                                         || (x2 > 0.0 && x2 < (double)getWidth()))
942                                 {
943                                         minY = std::min(minY, l->getStartpoint().y);
944                                         minY = std::min(minY, l->getEndpoint().y);
945                                         maxY = std::max(maxY, l->getStartpoint().y);
946                                         maxY = std::max(maxY, l->getEndpoint().y);
947                                 }
948                         }
949                 }
950
951                 if (axis)
952                         visibleHeight = std::max(maxY, 0.0) - std::min(minY, 0.0);
953                 else
954                         visibleHeight = maxY - minY;
955
956                 if (visibleHeight < 1.0)
957                         noChange = true;
958
959                 double fy = 1.0;
960
961                 if (visibleHeight > 1.0e-6)
962                 {
963                         fy = (getHeight() - borderTop - borderBottom) / visibleHeight;
964
965                         if (factor.y < 0.000001)
966                                 noChange = true;
967                 }
968
969                 if (noChange == false)
970                 {
971                         setFactorY(fy);
972                         //centerOffsetY();
973                         offsetY = (int)((getHeight() - borderTop - borderBottom - (visibleHeight * factor.y)) / 2.0
974                                 - (minY * factor.y)) + borderBottom;
975                         adjustOffsetControls();
976                         adjustZoomControls();
977                         updateGrid();
978                 }
979
980                 DEBUG->print("Auto zoom y ok");
981         }
982 }
983
984 /**
985  * Zooms the area given by v1 and v2.
986  *
987  * @param keepAspectRatio true: keeps the aspect ratio 1:1
988  *                        false: zooms exactly the selected range to the
989  *                               current graphic view
990  */
991 void GraphicView::zoomWindow(Vector v1, Vector v2, bool keepAspectRatio)
992 {
993         if (simulationRunning)
994                 return;
995
996         saveView();
997
998         double zoomX = 480.0;    // Zoom for X-Axis
999         double zoomY = 640.0;    // Zoom for Y-Axis   (Set smaller one)
1000         double dum;            // Dummy for switching values
1001         int zoomBorder = 0;
1002
1003         // Switch left/right and top/bottom is necessary:
1004         if (v1.x > v2.x)
1005         {
1006                 dum = v1.x;
1007                 v1.x = v2.x;
1008                 v2.x = dum;
1009         }
1010
1011         if (v1.y > v2.y)
1012         {
1013                 dum = v1.y;
1014                 v1.y = v2.y;
1015                 v2.y = dum;
1016         }
1017
1018         // Get zoom in X and zoom in Y:
1019         if (v2.x - v1.x > 1.0e-6)
1020                 zoomX = getWidth() / (v2.x - v1.x);
1021
1022         if (v2.y - v1.y > 1.0e-6)
1023                 zoomY = getHeight() / (v2.y - v1.y);
1024
1025         // Take smaller zoom:
1026         if (keepAspectRatio)
1027         {
1028                 if (zoomX < zoomY)
1029                 {
1030                         if (getWidth() != 0)
1031                         {
1032                                 zoomX = zoomY = ((double)(getWidth() - 2 * zoomBorder)) /
1033                                                                 (double)getWidth() * zoomX;
1034                         }
1035                 }
1036                 else
1037                 {
1038                         if (getHeight() != 0)
1039                         {
1040                                 zoomX = zoomY = ((double)(getHeight() - 2 * zoomBorder)) /
1041                                                                 (double)getHeight() * zoomY;
1042                         }
1043                 }
1044         }
1045
1046         if (zoomX < 0.0)
1047                 zoomX *= -1;
1048
1049         if (zoomY < 0.0)
1050                 zoomY *= -1;
1051
1052         // Borders in pixel after zoom
1053         int pixLeft   = (int)(v1.x * zoomX);
1054         int pixTop    = (int)(v2.y * zoomY);
1055         int pixRight  = (int)(v2.x * zoomX);
1056         int pixBottom = (int)(v1.y * zoomY);
1057
1058         // Set new offset for zero point:
1059         offsetX = - pixLeft + (getWidth() - pixRight + pixLeft) / 2;
1060         offsetY = - pixTop + (getHeight() - pixBottom + pixTop) / 2;
1061         factor.x = zoomX;
1062         factor.y = zoomY;
1063
1064         adjustOffsetControls();
1065         adjustZoomControls();
1066         updateGrid();
1067         redraw();
1068 }
1069
1070 /**
1071  * Centers the point v1.
1072  */
1073 void GraphicView::zoomPan(int dx, int dy)
1074 {
1075         if (simulationRunning)
1076                 return;
1077
1078         offsetX += dx;
1079         offsetY -= dy;
1080
1081         disableUpdate();
1082         adjustOffsetControls();
1083         updateGrid();
1084         enableUpdate();
1085         redraw();
1086 }
1087
1088 /**
1089  * Scrolls in the given direction.
1090  */
1091 void GraphicView::zoomScroll(RS2::Direction direction)
1092 {
1093         if (simulationRunning)
1094                 return;
1095
1096         switch (direction)
1097         {
1098         case RS2::Up:
1099                 offsetY -= 50;
1100                 break;
1101         case RS2::Down:
1102                 offsetY += 50;
1103                 break;
1104         case RS2::Right:
1105                 offsetX += 50;
1106                 break;
1107         case RS2::Left:
1108                 offsetX -= 50;
1109                 break;
1110         }
1111
1112         adjustOffsetControls();
1113         adjustZoomControls();
1114         updateGrid();
1115         redraw();
1116 }
1117
1118 /**
1119  * Zooms to page extends.
1120  */
1121 void GraphicView::zoomPage()
1122 {
1123         DEBUG->print("GraphicView::zoomPage");
1124
1125         if (container == NULL)
1126                 return;
1127
1128         if (simulationRunning)
1129                 return;
1130
1131         Drawing * graphic = container->getGraphic();
1132
1133         if (graphic == NULL)
1134                 return;
1135
1136         Vector s = graphic->getPaperSize();
1137         Vector pinsbase = graphic->getPaperInsertionBase();
1138
1139         double fx, fy;
1140
1141         if (s.x > RS_TOLERANCE)
1142                 fx = (getWidth() - borderLeft - borderRight) / s.x;
1143         else
1144                 fx = 1.0;
1145
1146         if (s.y > RS_TOLERANCE)
1147                 fy = (getHeight() - borderTop - borderBottom) / s.y;
1148         else
1149                 fy = 1.0;
1150
1151         DEBUG->print("f: %f/%f", fx, fy);
1152
1153         fx = fy = std::min(fx, fy);
1154
1155         DEBUG->print("f: %f/%f", fx, fy);
1156
1157         if (fx < RS_TOLERANCE)
1158                 fx = fy = 1.0;
1159
1160         setFactorX(fx);
1161         setFactorY(fy);
1162
1163         DEBUG->print("f: %f/%f", fx, fy);
1164
1165         centerOffsetX();
1166         centerOffsetY();
1167         adjustOffsetControls();
1168         adjustZoomControls();
1169         updateGrid();
1170         redraw();
1171 }
1172
1173 /**
1174  * Draws the entities within the given range.
1175  */
1176 void GraphicView::drawWindow(Vector v1, Vector v2)
1177 {
1178         DEBUG->print("GraphicView::drawWindow() begin");
1179
1180         if (simulationRunning)
1181                 return;
1182
1183         if (container)
1184         {
1185                 for(Entity * se=container->firstEntity(RS2::ResolveNone); se!=NULL;
1186                         se=container->nextEntity(RS2::ResolveNone))
1187                 {
1188                         if (se->isInWindow(v1, v2))
1189                                 drawEntity(se);
1190                 }
1191         }
1192
1193         DEBUG->print("GraphicView::drawWindow() end");
1194 }
1195
1196 /**
1197  * Draws the entities. If painter is NULL a new painter will
1198  * be created and destroyed. [NB: Not any more, we don't let the programmer try
1199  * to outsmart the toolkit anymore. :-P
1200  */
1201 void GraphicView::drawIt()
1202 {
1203         if (!isUpdateEnabled())
1204 //{
1205 //printf("GraphicView::drawIt(): isUpdateEnabled() == false!\n");
1206                 return;
1207 //}
1208
1209         if (simulationRunning)
1210 //{
1211 //printf("GraphicView::drawIt(): simulationRunning == true!\n");
1212                 return;
1213 //}
1214
1215         settings.beginGroup("Appearance");
1216         draftMode = settings.value("DraftMode", false).toBool();
1217         settings.endGroup();
1218
1219         if (!painter)
1220 //      {
1221 //printf("GraphicView::drawIt(): painter == NULL!\n");
1222                 return;
1223 //      }
1224
1225         painter->erase();
1226
1227         // drawing paper border:
1228         if (isPrintPreview())
1229                 drawPaper();
1230         // drawing meta grid:
1231         else
1232                 drawMetaGrid();
1233
1234         // drawing entities:
1235 //#warning "!!! This looks like a bug, no match for 'drawEntity(Entity *, bool) !!!"
1236 // and indeed it *is* a bug... true is converted to 1.0 here. Dumb, dumb, dumb.
1237         drawEntity(container);//, true);
1238
1239         // drawing zero points:
1240         if (!isPrintPreview())
1241         {
1242                 drawAbsoluteZero();
1243                 drawRelativeZero();
1244         }
1245
1246         // drawing grid:
1247         if (!isPrintPreview())
1248                 drawGrid();
1249 }
1250
1251 /**
1252  * Sets the pen of the painter object to the suitable pen for the given
1253  * entity.
1254  */
1255 void GraphicView::setPenForEntity(Entity * e)
1256 {
1257         if (drawingMode == RS2::ModePreview /*|| draftMode==true*/)
1258                 return;
1259
1260         if (!painter || painter->isPreviewMode())
1261                 return;
1262
1263         // set color of entity
1264         // Getting pen from entity (or layer)
1265         Pen pen = e->getPen(true);
1266
1267         int w = pen.getWidth();
1268
1269         if (w < 0)
1270                 w = 0;
1271
1272         // scale pen width:
1273         if (!draftMode)
1274         {
1275                 double uf = 1.0;  // unit factor
1276                 double wf = 1.0;  // width factor
1277                 Drawing * graphic = container->getGraphic();
1278
1279                 if (graphic)
1280                 {
1281                         uf = Units::convert(1.0, RS2::Millimeter, graphic->getUnit());
1282
1283                         if ((isPrinting() || isPrintPreview()) && graphic->getPaperScale() > 1.0e-6)
1284                                 wf = 1.0 / graphic->getPaperScale();
1285                 }
1286
1287                 pen.setScreenWidth(toGuiDX(w / 100.0 * uf * wf));
1288         }
1289         else
1290         {
1291                 //pen.setWidth(RS2::Width00);
1292                 pen.setScreenWidth(0);
1293         }
1294
1295         // prevent drawing with 1-width which is slow:
1296         if (Math::round(pen.getScreenWidth()) == 1)
1297                 pen.setScreenWidth(0.0);
1298
1299         // prevent background color on background drawing:
1300         if (pen.getColor().stripFlags() == background.stripFlags())
1301                 pen.setColor(foreground);
1302
1303         // this entity is selected:
1304         if (e->isSelected())
1305         {
1306                 pen.setLineType(RS2::DotLine);
1307                 //pen.setColor(Color(0xa5,0x47,0x47));
1308                 pen.setColor(selectedColor);
1309         }
1310
1311         // this entity is highlighted:
1312         if (e->isHighlighted())
1313         {
1314                 //pen.setColor(Color(0x73, 0x93, 0x73));
1315                 pen.setColor(highlightedColor);
1316         }
1317
1318         // deleting not drawing:
1319         if (getDeleteMode())
1320                 pen.setColor(background);
1321
1322         painter->setPen(pen);
1323 }
1324
1325 /**
1326  * Draws an entity. Might be recusively called e.g. for polylines.
1327  * If the class wide painter is NULL a new painter will be created
1328  * and destroyed afterwards.
1329  *
1330  * @param patternOffset Offset of line pattern (used for connected
1331  *        lines e.g. in splines).
1332  * @param db Double buffering on (recommended) / off
1333  */
1334 void GraphicView::drawEntity(Entity * e, double patternOffset, bool db)
1335 {
1336         //DEBUG->print("GraphicView::drawEntity() begin");
1337
1338         // update is diabled:
1339         if (!isUpdateEnabled())
1340                 return;
1341
1342         // given entity is NULL:
1343         if (!e)
1344                 return;
1345
1346         // entity is not visible:
1347         if (!e->isVisible())
1348                 return;
1349
1350         // test if the entity is in the viewport
1351         if (!e->isContainer() && !isPrinting()
1352                 && (!painter || !painter->isPreviewMode())
1353                 && (toGuiX(e->getMax().x) < 0 || toGuiX(e->getMin().x) > getWidth()
1354                 || toGuiY(e->getMin().y) < 0 || toGuiY(e->getMax().y) > getHeight()))
1355 //{
1356 //printf("GraphicView::drawEntity(): Bailing out of big test!!!\n");
1357                 return;
1358 //}
1359
1360         //drawRecursion++;
1361         //DEBUG->print("recursion 1: %d", drawRecursion);
1362
1363         // set pen (color):
1364         setPenForEntity(e);
1365
1366         //DEBUG->print("draw plain");
1367         if (draftMode)
1368         {
1369                 // large texts as rectangles:
1370                 if (e->rtti() == RS2::EntityText)
1371                 {
1372                         if (toGuiDX(((Text *)e)->getHeight()) < 4 || e->countDeep() > 100)
1373                                 painter->drawRect(toGui(e->getMin()), toGui(e->getMax()));
1374                         else
1375                                 drawEntityPlain(e, patternOffset);
1376                 }
1377                 // all images as rectangles:
1378                 else if (e->rtti() == RS2::EntityImage)
1379                         painter->drawRect(toGui(e->getMin()), toGui(e->getMax()));
1380                 // hide hatches:
1381                 else if (e->rtti() == RS2::EntityHatch)
1382                 {
1383                         // nothing
1384                 }
1385                 else
1386                         drawEntityPlain(e, patternOffset);
1387         }
1388         else
1389                 drawEntityPlain(e, patternOffset);
1390
1391         // draw reference points:
1392         if (e->isSelected())
1393         {
1394                 if (!e->isParentSelected())
1395                 {
1396                         VectorSolutions s = e->getRefPoints();
1397
1398                         for(int i=0; i<s.getNumber(); ++i)
1399                         {
1400                                 int sz = -1;
1401                                 Color col = Color(0, 0, 255);
1402
1403                                 if (e->rtti() == RS2::EntityPolyline)
1404                                 {
1405                                         if (i == 0 || i == s.getNumber() - 1)
1406                                         {
1407                                                 if (i == 0)
1408                                                 {
1409                                                         sz = 4;
1410 //                                                      col = QColor(0, 64, 255);
1411                                                         col = Color(0, 64, 255);
1412                                                 }
1413                                                 else
1414                                                 {
1415                                                         sz = 3;
1416 //                                                      col = QColor(0, 0, 128);
1417                                                         col = Color(0, 0, 128);
1418                                                 }
1419                                         }
1420                                 }
1421
1422                                 if (getDeleteMode())
1423                                         painter->drawHandle(toGui(s.get(i)), background, sz);
1424                                 else
1425                                         painter->drawHandle(toGui(s.get(i)), col, sz);
1426                         }
1427                 }
1428         }
1429
1430         //DEBUG->print("draw plain OK");
1431         //DEBUG->print("GraphicView::drawEntity() end");
1432 }
1433
1434 /**
1435  * Draws an entity.
1436  * The painter must be initialized and all the attributes (pen) must be set.
1437  */
1438 void GraphicView::drawEntityPlain(Entity * e, double patternOffset/*= 0.0*/)
1439 {
1440 //Problems can still occur here when passing in a deleted object... It won't be
1441 //NULL, but it will cause a segfault here...
1442         if (!e)
1443 //{
1444 //printf("GraphicView::drawEntityPlain(): Entity passed in is NULL!\n");
1445                 return;
1446 //}
1447
1448 //printf("GraphicView::drawEntityPlain(): Passing in painter=%08X, view=%08X\n", painter, this);
1449         e->draw(painter, this, patternOffset);
1450 }
1451
1452 /**
1453  * Simulates this drawing in slow motion.
1454  */
1455 void GraphicView::simulateIt()
1456 {
1457         if (simulationRunning)
1458                 return;
1459
1460         simulationRunning = true;
1461         simulationLast = Vector(0.0, 0.0);
1462
1463         painter->erase();
1464
1465         // drawing paper border:
1466         if (isPrintPreview())
1467                 drawPaper();
1468
1469         // drawing meta grid:
1470         if (!isPrintPreview())
1471                 drawMetaGrid();
1472
1473         // drawing grid:
1474         if (!isPrintPreview())
1475                 drawGrid();
1476
1477         // drawing entities:
1478         Pen pen(foreground, RS2::Width00, RS2::SolidLine);
1479         simulateEntity(container, pen);
1480
1481         // drawing zero points:
1482         if (!isPrintPreview())
1483         {
1484                 drawAbsoluteZero();
1485                 drawRelativeZero();
1486         }
1487
1488         simulationRunning = false;
1489 }
1490
1491 /**
1492  * Simulates the given entity.
1493  *
1494  * @param smooth If true, the entity will be drawn slowly (pixel by pixel).
1495  */
1496 void GraphicView::simulateEntity(Entity * e, const Pen & pen)
1497 {
1498         if (!painter || !e)
1499                 return;
1500
1501         if (e->isContainer())
1502         {
1503                 EntityContainer * ec = (EntityContainer *)e;
1504
1505                 for(Entity * en=ec->firstEntity(RS2::ResolveNone);
1506                         en!=NULL; en=ec->nextEntity(RS2::ResolveNone))
1507                 {
1508                         if (en->isVisible() && en->isUndone() == false)
1509                         {
1510                                 // draw rapid move:
1511                                 if (en->isAtomic() && simulationRapid)
1512                                 {
1513                                         Vector sp = ((AtomicEntity *)en)->getStartpoint();
1514
1515                                         if (sp.distanceTo(simulationLast) > 1.0e-4)
1516                                         {
1517                                                 Pen rpen(Color(0, 0, 255), RS2::Width00, RS2::SolidLine);
1518                                                 Line rapidLine(NULL, LineData(simulationLast, sp));
1519                                                 simulateEntity(&rapidLine, rpen);
1520                                         }
1521                                 }
1522
1523                                 if (en->isHighlighted())
1524                                 {
1525                                         Pen hpen(highlightedColor, RS2::Width00, RS2::SolidLine);
1526                                         simulateEntity(en, hpen);
1527                                 }
1528                                 else
1529                                         simulateEntity(en, pen);
1530
1531                                 if (en->isAtomic())
1532                                         simulationLast = ((AtomicEntity *)en)->getEndpoint();
1533
1534                                 if (!simulationSmooth)
1535                                         simulationDelay(true);
1536                         }
1537                 }
1538         }
1539         else
1540         {
1541                 if (simulationSmooth)
1542                 {
1543                         switch (e->rtti())
1544                         {
1545                         case RS2::EntityLine:
1546                         {
1547                                 Line * line = (Line *)e;
1548                                 drawLineSmooth(toGui(line->getStartpoint()), toGui(line->getEndpoint()), pen);
1549                                         //simulationSpeed);
1550                         }
1551                                 break;
1552
1553                         case RS2::EntityArc:
1554                         {
1555                                 Arc * arc = (Arc *)e;
1556                                 drawArcSmooth(toGui(arc->getCenter()), toGuiDX(arc->getRadius()),
1557                                         arc->getAngle1(), arc->getAngle2(), arc->isReversed(), pen);
1558                         }
1559                                 break;
1560
1561                         case RS2::EntityCircle:
1562                         {
1563                                 Circle * circle = (Circle *)e;
1564                                 drawArcSmooth(toGui(circle->getCenter()), toGuiDX(circle->getRadius()),
1565                                         0.0, 2.0 * M_PI, false, pen);
1566                         }
1567                                 break;
1568
1569                         default:
1570                                 break;
1571                         }
1572                 }
1573                 else
1574                 {
1575                         painter->setPen(pen);
1576                         drawEntityPlain(e);
1577                 }
1578         }
1579 }
1580
1581 /**
1582  * Delay for slow motion simulation.
1583  *
1584  * @param step true: stepping mode (entity by entity simulation). adds a delay.
1585  */
1586 void GraphicView::simulationDelay(bool step)
1587 {
1588         int delay;
1589         settings.beginGroup("CAM");
1590         double fact = settings.value("SimulationFactor", 12000.0).toDouble();
1591         settings.endGroup();
1592
1593         // simulationSpeed: 0..100
1594
1595 #ifdef __APPLE__
1596         delay = (int)(((1.0 / (simulationSpeed + 1.0)) * fact) - (fact / 100.0));
1597         if (step)
1598                 delay *= 16;
1599
1600         //usleep(delay);
1601         static int call = 0;
1602
1603         if (call >= (fact - delay) / 1000)
1604         {
1605                 call = 0;
1606                 for(int i=0; i<delay; ++i)
1607                         RS_APP->processEvents(10);
1608         }
1609         else
1610                 call++;
1611 #else
1612         delay = (int)(((1.0 / (simulationSpeed + 1.0)) * fact) - (fact / 100.0));
1613
1614         if (step)
1615         {
1616                 delay *= 16;
1617         }
1618
1619         for(int i=0; i<delay; ++i)
1620         {
1621 #warning "Qt3->4 conversion: commented out problem line... !!! FIX !!!"
1622 //        RS_APP->processEvents(10);
1623         }
1624 #endif
1625 }
1626
1627 /**
1628  * Draws a line slowly from (x1, y1) to (x2, y2). This is used for simulation only.
1629  */
1630 void GraphicView::drawLineSmooth(const Vector & p1, const Vector & p2, const Pen & pen)
1631 {
1632         double alpha = p1.angleTo(p2);
1633         double xStep, yStep;
1634         bool  xIsOne;
1635
1636         if (Math::cmpDouble(alpha, 0.0) || Math::cmpDouble(alpha, 2 * M_PI))
1637         {
1638                 xStep = 1.0;
1639                 yStep = 0.0;
1640                 xIsOne = true;
1641         }
1642         else if (Math::cmpDouble(alpha, M_PI / 2.0))
1643         {
1644                 xStep = 0.0;
1645                 yStep = 1.0;
1646                 xIsOne = false;
1647         }
1648         else if (Math::cmpDouble(alpha, M_PI))
1649         {
1650                 xStep = -1.0;
1651                 yStep = 0.0;
1652                 xIsOne = true;
1653         }
1654         else if (Math::cmpDouble(alpha, M_PI / 2.0 * 3.0))
1655         {
1656                 xStep = 0.0;
1657                 yStep = -1.0;
1658                 xIsOne = false;
1659         }
1660         else if (fabs(p2.x - p1.x) > fabs(p2.y - p1.y))
1661         {
1662                 if (p2.x > p1.x)
1663                         xStep = 1.0;
1664                 else
1665                         xStep = -1.0;
1666
1667                 yStep = tan(alpha) * xStep;
1668                 xIsOne = true;
1669         }
1670         else
1671         {
1672                 if (p2.y > p1.y)
1673                         yStep = 1.0;
1674                 else
1675                         yStep = -1.0;
1676
1677                 xStep = yStep / tan(alpha);
1678                 xIsOne = false;
1679         }
1680
1681         double lx = p1.x;
1682         double ly = p1.y;
1683
1684         do
1685         {
1686                 if (lx >= 0.0 && lx <= (double)getWidth() && ly >= 0.0 && ly <= (double)getHeight())
1687                 {
1688                         painter->setPen(pen);
1689                         painter->drawGridPoint(Vector(lx, ly));
1690
1691                         simulationDelay();
1692                 }
1693
1694                 lx += xStep;
1695                 ly += yStep;
1696
1697         }
1698         while ((xIsOne && ((lx >= p1.x && lx <= p2.x) || (lx >= p2.x && lx <= p1.x)))
1699                 || (!xIsOne && ((ly >= p1.y && ly <= p2.y) || (ly >= p2.y && ly <= p1.y))));
1700 }
1701
1702 void GraphicView::drawArcSmooth(const Vector & center, double radius, double a1, double a2, bool rev,
1703         const Pen & pen)
1704 {
1705         if (radius <= 1.4)
1706         {
1707                 painter->setPen(pen);
1708                 painter->drawGridPoint(center);
1709         }
1710         else
1711         {
1712                 int ix1 = Math::round(center.x + cos(a1) * radius);
1713                 int iy1 = Math::round(center.y - sin(a1) * radius);
1714                 int ix2 = Math::round(center.x + cos(a2) * radius);
1715                 int iy2 = Math::round(center.y - sin(a2) * radius);
1716                 int k2x = 0;            // Next point on circle
1717                 int k2y = 0;            //
1718                 int k1x = ix1;          // Prev point on circle
1719                 int k1y = iy1;          //
1720                 double aStep;          // Angle Step (rad)
1721                 double a;              // Actual Angle (rad)
1722                 double a2cp = a2;      // Copy of a2
1723
1724                 if (1.0 / (radius * factor.x) <= 1.0)
1725                         aStep = asin(1.0 / (radius * factor.x));
1726                 else
1727                         aStep = 0.01;
1728
1729                 if (aStep < 0.01)
1730                         aStep = 0.01;
1731
1732                 if (!rev)
1733                 {
1734                         // Arc Counterclockwise:
1735                         //
1736                         if (a1 > a2cp - 0.01)
1737                                 a2cp += 2 * M_PI;
1738
1739                         for(a=a1+aStep; a<=a2cp; a+=aStep)
1740                         {
1741                                 k2x = Math::round(center.x+cos(a)*radius);
1742                                 k2y = Math::round(center.y-sin(a)*radius);
1743                                 painter->setPen(pen);
1744
1745                                 if ((k2x >= 0 && k2x <= painter->getWidth()
1746                                         && k2y >= 0 && k2y <= painter->getHeight())
1747                                         || (k1x >= 0 && k1x <= painter->getWidth()
1748                                         && k1y >= 0 && k1y <= painter->getHeight()))
1749                                 {
1750                                         painter->drawLine(Vector(k1x, k1y), Vector(k2x, k2y));
1751                                         simulationDelay();
1752                                 }
1753
1754                                 k1x = k2x;
1755                                 k1y = k2y;
1756                         }
1757
1758                         painter->setPen(pen);
1759                         painter->drawLine(Vector(k2x, k2y), Vector(ix2, iy2));
1760                 }
1761                 else
1762                 {
1763                         // Arc Clockwise:
1764                         //
1765                         if (a1 < a2cp + 0.01)
1766                                 a2cp -= 2 * M_PI;
1767
1768                         for(a=a1-aStep; a>=a2cp; a-=aStep)
1769                         {
1770                                 k2x = Math::round(center.x + cos(a) * radius);
1771                                 k2y = Math::round(center.y - sin(a) * radius);
1772                                 painter->setPen(pen);
1773
1774                                 if ((k2x >=0 && k2x <= painter->getWidth()
1775                                         && k2y >= 0 && k2y <= painter->getHeight())
1776                                         || (k1x >= 0 && k1x <= painter->getWidth()
1777                                         && k1y >= 0 && k1y <= painter->getHeight()))
1778                                 {
1779                                         painter->drawLine(Vector(k1x, k1y), Vector(k2x, k2y));
1780                                         simulationDelay();
1781                                 }
1782
1783                                 k1x = k2x;
1784                                 k1y = k2y;
1785                         }
1786
1787                         painter->setPen(pen);
1788                         painter->drawLine(Vector(k2x, k2y), Vector(ix2, iy2));
1789                 }
1790         }
1791 }
1792
1793 /**
1794  * @return Pointer to the static pattern struct that belongs to the
1795  * given pattern type or NULL.
1796  */
1797 LineTypePattern * GraphicView::getPattern(RS2::LineType t)
1798 {
1799         switch (t)
1800         {
1801         case RS2::SolidLine:
1802                 return &patternSolidLine;
1803                 break;
1804
1805         case RS2::DotLine:
1806                 return &patternDotLine;
1807                 break;
1808         case RS2::DotLine2:
1809                 return &patternDotLine2;
1810                 break;
1811         case RS2::DotLineX2:
1812                 return &patternDotLineX2;
1813                 break;
1814
1815         case RS2::DashLine:
1816                 return &patternDashLine;
1817                 break;
1818         case RS2::DashLine2:
1819                 return &patternDashLine2;
1820                 break;
1821         case RS2::DashLineX2:
1822                 return &patternDashLineX2;
1823                 break;
1824
1825         case RS2::DashDotLine:
1826                 return &patternDashDotLine;
1827                 break;
1828         case RS2::DashDotLine2:
1829                 return &patternDashDotLine2;
1830                 break;
1831         case RS2::DashDotLineX2:
1832                 return &patternDashDotLineX2;
1833                 break;
1834
1835         case RS2::DivideLine:
1836                 return &patternDivideLine;
1837                 break;
1838         case RS2::DivideLine2:
1839                 return &patternDivideLine2;
1840                 break;
1841         case RS2::DivideLineX2:
1842                 return &patternDivideLineX2;
1843                 break;
1844
1845         case RS2::CenterLine:
1846                 return &patternCenterLine;
1847                 break;
1848         case RS2::CenterLine2:
1849                 return &patternCenterLine2;
1850                 break;
1851         case RS2::CenterLineX2:
1852                 return &patternCenterLineX2;
1853                 break;
1854
1855         case RS2::BorderLine:
1856                 return &patternBorderLine;
1857                 break;
1858         case RS2::BorderLine2:
1859                 return &patternBorderLine2;
1860                 break;
1861         case RS2::BorderLineX2:
1862                 return &patternBorderLineX2;
1863                 break;
1864
1865         case RS2::LineByLayer:
1866                 return &patternBlockLine;
1867                 break;
1868         case RS2::LineByBlock:
1869                 return &patternBlockLine;
1870                 break;
1871         default:
1872                 break;
1873         }
1874
1875         return NULL;
1876 }
1877
1878 /**
1879  * This virtual method can be overwritten to draw the absolute
1880  * zero. It's called from within drawIt(). The default implemetation
1881  * draws a simple red round zero point.
1882  *
1883  * Actually, we have to rework the rendering code because the way that QCad did
1884  * it was wrong on so many levels... Part of that is making sure the rendering
1885  * path is 100% clear!
1886  *
1887  * @see drawIt()
1888  */
1889 void GraphicView::drawAbsoluteZero()
1890 {
1891         if (!painter)
1892                 return;
1893
1894         int zr = 20;
1895
1896 //      Pen p(Qt::red, RS2::Width00, RS2::SolidLine);
1897 //Using Qt::red doesn't seem to work here...
1898 //It's because Qt colors and Color are not 100% compatible...
1899         Pen p(Color(255, 0, 0), RS2::Width00, RS2::SolidLine);
1900         painter->setPen(p);
1901
1902         painter->drawLine(Vector(toGuiX(0.0) - zr, toGuiY(0.0)),
1903                 Vector(toGuiX(0.0) + zr, toGuiY(0.0)));
1904
1905         painter->drawLine(Vector(toGuiX(0.0), toGuiY(0.0) - zr),
1906                 Vector(toGuiX(0.0), toGuiY(0.0) + zr));
1907 }
1908
1909 /**
1910  * This virtual method can be overwritten to draw the relative
1911  * zero point. It's called from within drawIt(). The default implemetation
1912  * draws a simple red round zero point.
1913  *
1914  * @see drawIt()
1915  */
1916 void GraphicView::drawRelativeZero()
1917 {
1918         if (!relativeZero.valid || !painter)
1919 #if 1
1920                 return;
1921 #else
1922         {
1923                 if (!relativeZero.valid)
1924                         printf("GraphicView::drawRelativeZero(): relativeZero is NOT valid!!!\n");
1925
1926                 if (!painter)
1927                         printf("GraphicView::drawRelativeZero(): painter is NOT valid!!!\n");
1928
1929                 return;
1930         }
1931 #endif
1932
1933 //Using Qt::red doesn't seem to work here...
1934         Pen p(Color(255, 0, 0), RS2::Width00, RS2::SolidLine);
1935         painter->setPen(p);
1936 //This doesn't work--this is NOT a QPainter!
1937 //      painter->setBrush(Qt::NoBrush);
1938 //      painter->setBackgroundMode(Qt::TransparentMode);        // will that do it???
1939         painter->disableBrush();
1940 //      painter->setXORMode();
1941
1942         int zr = 5;
1943
1944         painter->drawLine(Vector(toGuiX(relativeZero.x) - zr, toGuiY(relativeZero.y)),
1945                 Vector(toGuiX(relativeZero.x) + zr, toGuiY(relativeZero.y)));
1946         painter->drawLine(Vector(toGuiX(relativeZero.x), toGuiY(relativeZero.y) - zr),
1947                 Vector(toGuiX(relativeZero.x), toGuiY(relativeZero.y) + zr));
1948         painter->drawCircle(toGui(relativeZero), zr);
1949 //      painter->setNormalMode();
1950 }
1951
1952 /**
1953  * Draws the paper border (for print previews).
1954  *
1955  * @see drawIt()
1956  */
1957 void GraphicView::drawPaper()
1958 {
1959         if (!container)
1960                 return;
1961
1962         Drawing * graphic = container->getGraphic();
1963
1964         if (!graphic)
1965                 return;
1966
1967         if (graphic->getPaperScale() < 1.0e-6)
1968                 return;
1969
1970         if (!painter)
1971                 return;
1972
1973         // draw paper:
1974         painter->setPen(Pen(Qt::gray));
1975
1976         Vector pinsbase = graphic->getPaperInsertionBase();
1977         Vector size = graphic->getPaperSize();
1978         double scale = graphic->getPaperScale();
1979
1980         Vector v1 = toGui((Vector(0, 0) - pinsbase) / scale);
1981         Vector v2 = toGui((size - pinsbase) / scale);
1982
1983         // gray background:
1984         painter->fillRect(0,0, getWidth(), getHeight(), Color(200, 200, 200));
1985
1986         // shadow
1987         painter->fillRect((int)(v1.x) + 6, (int)(v1.y) + 6,
1988                 (int)((v2.x - v1.x)), (int)((v2.y - v1.y)), Color(64, 64, 64));
1989
1990         // border:
1991         painter->fillRect((int)(v1.x), (int)(v1.y),
1992                 (int)((v2.x - v1.x)), (int)((v2.y - v1.y)), Color(64, 64, 64));
1993
1994         // paper
1995         painter->fillRect((int)(v1.x) + 1, (int)(v1.y) - 1,
1996                 (int)((v2.x - v1.x)) - 2, (int)((v2.y - v1.y)) + 2, Color(255, 255, 255));
1997 }
1998
1999 /**
2000  * Draws the grid.
2001  *
2002  * @see drawIt()
2003  */
2004 void GraphicView::drawGrid()
2005 {
2006         if (!grid || isGridOn() == false)
2007 //      {
2008 //              printf("GraphicView::drawGrid(): Aborting: grid=%08X, isGridOn=%s\n", grid, (isGridOn() ? "true" : "false"));
2009                 return;
2010 //      }
2011
2012         // draw grid:
2013         painter->setPen(gridColor);
2014
2015 //Problem here: pts is NULL!
2016         Vector * pts = grid->getPoints();
2017
2018         if (pts)
2019         {
2020                 for(int i=0; i<grid->count(); ++i)
2021                         painter->drawGridPoint(toGui(pts[i]));
2022         }
2023 //      else
2024 //              printf("GraphicView::drawGrid(): pts == NULL!\n");
2025
2026         // draw grid info:
2027         QString info = grid->getInfo();
2028         updateGridStatusWidget(info);
2029 }
2030
2031 /**
2032  * Draws the meta grid.
2033  *
2034  * @see drawIt()
2035  */
2036 void GraphicView::drawMetaGrid()
2037 {
2038         if (!grid || isGridOn() == false)
2039                 return;
2040
2041         if (!painter)
2042                 return;
2043
2044         Pen pen(metaGridColor, RS2::Width00, RS2::DotLine);
2045         painter->setPen(pen);
2046
2047         // draw meta grid:
2048         double * mx = grid->getMetaX();
2049         double * my = grid->getMetaY();
2050
2051         if (mx)
2052         {
2053                 for(int i=0; i<grid->countMetaX(); ++i)
2054                         painter->drawLine(Vector(toGuiX(mx[i]), 0), Vector(toGuiX(mx[i]), getHeight()));
2055         }
2056
2057         if (my)
2058         {
2059                 for(int i=0; i<grid->countMetaY(); ++i)
2060                         painter->drawLine(Vector(0, toGuiY(my[i])), Vector(getWidth(), toGuiY(my[i])));
2061         }
2062 }
2063
2064 /**
2065  * Updates the grid if there is one.
2066  */
2067 void GraphicView::updateGrid()
2068 {
2069         if (grid)
2070                 grid->update();
2071 }
2072
2073 Grid * GraphicView::getGrid()
2074 {
2075         return grid;
2076 }
2077
2078 void GraphicView::updateGridStatusWidget(const QString & /*text*/)
2079 {
2080 }
2081
2082 RS2::SnapMode GraphicView::getDefaultSnapMode()
2083 {
2084         return defaultSnapMode;
2085 }
2086
2087 RS2::SnapRestriction GraphicView::getSnapRestriction()
2088 {
2089         return defaultSnapRes;
2090 }
2091
2092 /**
2093  * Sets the default snap mode used by newly created actions.
2094  */
2095 void GraphicView::setDefaultSnapMode(RS2::SnapMode sm)
2096 {
2097         defaultSnapMode = sm;
2098
2099         if (eventHandler)
2100                 eventHandler->setSnapMode(sm);
2101
2102         //OK, the above sets the snap mode in the snapper that's derived from
2103         //the RS_ActionInterface and Snapper. So the following should fix
2104         //us up, hm notwithstanding. [and it does. :-)]
2105         //hm.
2106         snapper.setSnapMode(sm);
2107 }
2108
2109 /**
2110  * Sets a snap restriction (e.g. orthogonal).
2111  */
2112 void GraphicView::setSnapRestriction(RS2::SnapRestriction sr)
2113 {
2114         defaultSnapRes = sr;
2115
2116         if (eventHandler != NULL)
2117                 eventHandler->setSnapRestriction(sr);
2118 }
2119
2120 /**
2121  * Translates a vector in real coordinates to a vector in screen coordinates.
2122  */
2123 Vector GraphicView::toGui(Vector v)
2124 {
2125         return Vector(toGuiX(v.x), toGuiY(v.y), 0.0);
2126 }
2127
2128 /**
2129  * Translates a real coordinate in X to a screen coordinate X.
2130  * @param visible Pointer to a boolean which will contain true
2131  * after the call if the coordinate is within the visible range.
2132  */
2133 double GraphicView::toGuiX(double x, bool * visible/*= NULL*/)
2134 {
2135         if (visible != NULL)
2136         {
2137                 double res = x * factor.x + offsetX;
2138
2139                 if (res > 0.0 && res < getWidth())
2140                         *visible = true;
2141                 else
2142                         *visible = false;
2143         }
2144
2145         return x * factor.x + offsetX;
2146 }
2147
2148 /**
2149  * Translates a real coordinate in Y to a screen coordinate Y.
2150  */
2151 double GraphicView::toGuiY(double y)
2152 {
2153         return -y * factor.y + getHeight() - offsetY;
2154 }
2155
2156 /**
2157  * Translates a real coordinate distance to a screen coordinate distance.
2158  */
2159 double GraphicView::toGuiDX(double d)
2160 {
2161         return d * factor.x;
2162 }
2163
2164 /**
2165  * Translates a real coordinate distance to a screen coordinate distance.
2166  */
2167 double GraphicView::toGuiDY(double d)
2168 {
2169         return d * factor.y;
2170 }
2171
2172 /**
2173  * Translates a vector in screen coordinates to a vector in real coordinates.
2174  */
2175 Vector GraphicView::toGraph(Vector v)
2176 {
2177         return Vector(toGraphX(Math::round(v.x)), toGraphY(Math::round(v.y)), 0.0);
2178 }
2179
2180 /**
2181  * Translates two screen coordinates to a vector in real coordinates.
2182  */
2183 Vector GraphicView::toGraph(int x, int y)
2184 {
2185         return Vector(toGraphX(x), toGraphY(y), 0.0);
2186 }
2187
2188 /**
2189  * Translates a screen coordinate in X to a real coordinate X.
2190  */
2191 double GraphicView::toGraphX(int x)
2192 {
2193         return (x - offsetX) / factor.x;
2194 }
2195
2196 /**
2197  * Translates a screen coordinate in Y to a real coordinate Y.
2198  */
2199 double GraphicView::toGraphY(int y)
2200 {
2201         return -(y - getHeight() + offsetY) / factor.y;
2202 }
2203
2204 /**
2205  * Translates a screen coordinate distance to a real coordinate distance.
2206  */
2207 double GraphicView::toGraphDX(int d)
2208 {
2209         return d / factor.x;
2210 }
2211
2212 /**
2213  * Translates a screen coordinate distance to a real coordinate distance.
2214  */
2215 double GraphicView::toGraphDY(int d)
2216 {
2217         return d / factor.y;
2218 }
2219
2220 /**
2221  * (Un-)Locks the position of the relative zero.
2222  *
2223  * @param lock true: lock, false: unlock
2224  */
2225 void GraphicView::lockRelativeZero(bool lock)
2226 {
2227         relativeZeroLocked = lock;
2228 }
2229
2230 /**
2231  * @return true if the position of the realtive zero point is
2232  * locked.
2233  */
2234 bool GraphicView::isRelativeZeroLocked()
2235 {
2236         return relativeZeroLocked;
2237 }
2238
2239 /**
2240  * @return Relative zero coordinate.
2241  */
2242 Vector GraphicView::getRelativeZero()
2243 {
2244         return relativeZero;
2245 }
2246
2247 /**
2248  * Sets the relative zero coordinate (if not locked)
2249  * without deleting / drawing the point.
2250  */
2251 void GraphicView::setRelativeZero(const Vector & pos)
2252 {
2253         if (!relativeZeroLocked)
2254                 relativeZero = pos;
2255 }
2256
2257 /**
2258  * Sets the relative zero coordinate, deletes the old position
2259  * on the screen and draws the new one.
2260  */
2261 void GraphicView::moveRelativeZero(const Vector & pos)
2262 {
2263         setRelativeZero(pos);
2264 }
2265
2266 EventHandler * GraphicView::getEventHandler()
2267 {
2268         return eventHandler;
2269 }
2270
2271 /**
2272  * Enables or disables print preview.
2273  */
2274 void GraphicView::setPrintPreview(bool pv)
2275 {
2276         printPreview = pv;
2277 }
2278
2279 /**
2280  * @retval true This is a print preview graphic view.
2281  * @retval false Otherwise.
2282  */
2283 bool GraphicView::isPrintPreview()
2284 {
2285         return printPreview;
2286 }
2287
2288 /**
2289  * Enables or disables printing.
2290  */
2291 void GraphicView::setPrinting(bool p)
2292 {
2293         printing = p;
2294 }
2295
2296 /**
2297  * @retval true This is a a graphic view for printing.
2298  * @retval false Otherwise.
2299  */
2300 bool GraphicView::isPrinting()
2301 {
2302         return printing;
2303 }
2304
2305 /**
2306  * @retval true Draft mode is on for this view (all lines with 1 pixel / no style scaling).
2307  * @retval false Otherwise.
2308  */
2309 bool GraphicView::isDraftMode()
2310 {
2311         return draftMode;
2312 }
2313
2314 /**
2315  * Sets the simulation speed in percentage.
2316  */
2317 void GraphicView::setSimulationSpeed(int s)
2318 {
2319         simulationSpeed = s;
2320 }
2321
2322 /**
2323  * @return the simulation speed in percentage.
2324  */
2325 int GraphicView::getSimulationSpeed()
2326 {
2327         return simulationSpeed;
2328 }
2329
2330 /**
2331  * Sets the simulation smooth mode.
2332  */
2333 void GraphicView::setSimulationSmooth(bool s)
2334 {
2335         simulationSmooth = s;
2336 }
2337 /**
2338  * Sets the simulation rapid mode.
2339  */
2340 void GraphicView::setSimulationRapid(bool r)
2341 {
2342         simulationRapid = r;
2343 }
2344
2345 /**
2346  * @return the simulation rapid mode.
2347  */
2348 bool GraphicView::getSimulationRapid()
2349 {
2350         return simulationRapid;
2351 }
2352
2353 /**
2354  * Catches an entity which is close to the given position 'pos'.
2355  *
2356  * @param pos A graphic coordinate.
2357  * @param level The level of resolving for iterating through the entity
2358  *        container
2359  * @return Pointer to the entity or NULL.
2360  */
2361 Entity * GraphicView::CatchEntity(const Vector & pos, RS2::ResolveLevel level)
2362 {
2363         DEBUG->print("GraphicView::CatchEntity");
2364
2365         // Set default distance for points inside solids
2366         double dist = toGraphDX(snapRange) * 0.9;
2367         Entity * entity = container->getNearestEntity(pos, &dist, level);
2368
2369         // DEBUGGING INFO
2370         int idx = -1;
2371
2372         if (entity && entity->getParent())
2373                 idx = entity->getParent()->findEntity(entity);
2374         // END DEBUGGING INFO
2375
2376         if (entity && dist <= toGraphDX(snapRange))
2377         {
2378                 // Highlight:
2379                 DEBUG->print("GraphicView::CatchEntity: found: idx=%d", idx);
2380                 return entity;
2381         }
2382
2383         DEBUG->print("GraphicView::CatchEntity: not found");
2384         return NULL;
2385 }
2386
2387 /**
2388  * Catches an entity which is close to the mouse cursor.
2389  *
2390  * @param e A mouse event.
2391  * @param level The level of resolving for iterating through the entity
2392  *              container
2393  * @return Pointer to the entity or NULL.
2394  */
2395 Entity * GraphicView::CatchEntity(QMouseEvent * e, RS2::ResolveLevel level)
2396 {
2397         return CatchEntity(Vector(toGraphX(e->x()), toGraphY(e->y())), level);
2398 }
2399
2400 /**
2401  * Snap to a coordinate in the drawing using the current snap mode.
2402  *
2403  * @param e A mouse event.
2404  * @return The coordinates of the point or an invalid vector.
2405  */
2406 Vector GraphicView::SnapPoint(QMouseEvent * e)
2407 {
2408         DEBUG->print("GraphicView::SnapPoint");
2409         /*Vector*/ snapSpot = Vector(false);
2410
2411         if (!e)
2412         {
2413                 DEBUG->print(Debug::D_WARNING, "GraphicView::SnapPoint: QMouseEvent is NULL");
2414                 return snapSpot;
2415         }
2416
2417         Vector mouseCoord = toGraph(e->x(), e->y());
2418
2419 //      switch (snapMode)
2420         switch (defaultSnapMode)
2421         {
2422         case RS2::SnapFree:
2423 //              snapSpot = snapFree(mouseCoord);
2424                 snapEntity = NULL;
2425                 snapSpot = mouseCoord;
2426                 break;
2427
2428         case RS2::SnapEndpoint:
2429 //              snapSpot = snapEndpoint(mouseCoord);
2430                 snapSpot = container->getNearestEndpoint(mouseCoord, NULL);
2431                 break;
2432
2433         case RS2::SnapGrid:
2434                 snapSpot = SnapGrid(mouseCoord);
2435                 break;
2436
2437         case RS2::SnapOnEntity:
2438 //              snapSpot = snapOnEntity(mouseCoord);
2439                 snapSpot = container->getNearestPointOnEntity(mouseCoord, true, NULL, &snapEntity);
2440                 break;
2441
2442         case RS2::SnapCenter:
2443 //              snapSpot = snapCenter(mouseCoord);
2444                 snapSpot = container->getNearestCenter(mouseCoord, NULL);
2445                 break;
2446
2447         case RS2::SnapMiddle:
2448 //              snapSpot = snapMiddle(mouseCoord);
2449                 snapSpot = container->getNearestMiddle(mouseCoord, NULL);
2450                 break;
2451
2452         case RS2::SnapDist:
2453 //              snapSpot = snapDist(mouseCoord);
2454                 snapSpot = container->getNearestDist(snapDistance, mouseCoord, NULL);
2455                 break;
2456
2457         case RS2::SnapIntersection:
2458 //              snapSpot = snapIntersection(mouseCoord);
2459                 snapSpot = container->getNearestIntersection(mouseCoord, NULL);
2460                 break;
2461
2462         default:
2463                 break;
2464         }
2465
2466         // This is declared here because I really, really hate extraneous braces in
2467         // my switch statements. :-P
2468         Vector relZero = getRelativeZero();
2469         Vector restrictX = Vector(relZero.x, snapSpot.y);
2470         Vector restrictY = Vector(snapSpot.x, relZero.y);
2471 //      Vector snapCoord;
2472         // Handle snap restrictions that can be activated in addition to the ones above:
2473 //      switch (snapRes)
2474         switch (defaultSnapRes)
2475         {
2476         case RS2::RestrictOrthogonal:
2477 ////            snapCoord = restrictOrthogonal(snapSpot);
2478 //              rz = graphicView->getRelativeZero();
2479 //              retx = Vector(rz.x, snapSpot.y);
2480 //              rety = Vector(snapSpot.x, rz.y);
2481                 snapCoord = (restrictX.distanceTo(snapSpot) < restrictY.distanceTo(snapSpot) ?
2482                         restrictX : restrictY);
2483                 break;
2484         case RS2::RestrictHorizontal:
2485 ////            snapCoord = restrictHorizontal(snapSpot);
2486 //              rz = graphicView->getRelativeZero();
2487 //              snapCoord = Vector(snapSpot.x, rz.y);
2488                 snapCoord = restrictY;
2489                 break;
2490         case RS2::RestrictVertical:
2491 ////            snapCoord = restrictVertical(snapSpot);
2492 //              rz = graphicView->getRelativeZero();
2493 //              snapCoord = Vector(rz.x, snapSpot.y);
2494                 snapCoord = restrictX;
2495                 break;
2496         default:
2497         case RS2::RestrictNothing:
2498                 snapCoord = snapSpot;
2499                 break;
2500         }
2501
2502         if (DIALOGFACTORY)
2503                 DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - relZero);
2504
2505         DEBUG->print("GraphicView::SnapPoint: OK");
2506
2507         return snapCoord;
2508 }
2509
2510 /**
2511  * Snaps to a grid point.
2512  *
2513  * @param coord The mouse coordinate.
2514  * @return The coordinates of the point or an invalid vector.
2515  */
2516 Vector GraphicView::SnapGrid(Vector coord)
2517 {
2518         DEBUG->print("GraphicView::snapGrid begin");
2519
2520         Vector vec(false);
2521         double dist = 0.0;
2522
2523         DEBUG->print("GraphicView::snapGrid 001");
2524
2525         if (grid)
2526         {
2527                 DEBUG->print("GraphicView::snapGrid 002");
2528                 Vector * pts = grid->getPoints();
2529                 DEBUG->print("GraphicView::snapGrid 003");
2530                 int closest = -1;
2531                 dist = 32000.00;
2532                 DEBUG->print("GraphicView::snapGrid 004");
2533
2534                 for(int i=0; i<grid->count(); ++i)
2535                 {
2536                         double d = pts[i].distanceTo(coord);
2537
2538                         if (d < dist)
2539                         {
2540                                 closest = i;
2541                                 dist = d;
2542                         }
2543                 }
2544
2545                 DEBUG->print("GraphicView::snapGrid 005");
2546
2547                 if (closest >= 0)
2548                         vec = pts[closest];
2549
2550                 DEBUG->print("GraphicView::snapGrid 006");
2551         }
2552
2553         snapEntity = NULL;
2554
2555         DEBUG->print("GraphicView::snapGrid end");
2556
2557         return vec;
2558 }
2559
2560 void GraphicView::DrawSnapper(PaintInterface * painter)
2561 {
2562 //Is "finished" used at all? Seems it's used only in ActionInterface, and it's commented out
2563 //      if (finished || !snapSpot.valid || !snapCoord.valid)
2564         if (!snapSpot.valid || !snapCoord.valid)
2565 #if 1
2566 {
2567 printf("DrawSnapper: snapSpot=%s, snapCoord=%s...\n", (snapSpot.valid ? "valid" : "INVALID"), (snapCoord.valid ? "valid" : "INVALID"));
2568 #endif
2569                 return;
2570 #if 1
2571 }
2572 #endif
2573
2574         // Snap point (need to make sure the brush is NULL!)
2575 //      painter->setPen(Pen(Color(0, 127, 255), RS2::Width00, RS2::DashLine));
2576         painter->setPen(Pen(Color(255, 127, 0), RS2::Width00, RS2::DashLine));
2577         painter->drawCircle(toGui(snapCoord), 4);
2578
2579         // Crosshairs
2580         if (showCrosshairs)
2581         {
2582                 painter->setPen(Pen(Color(0, 255, 255), RS2::Width00, RS2::DashLine));
2583                 painter->drawLine(Vector(0, toGuiY(snapCoord.y)),
2584                         Vector(getWidth(), toGuiY(snapCoord.y)));
2585                 painter->drawLine(Vector(toGuiX(snapCoord.x), 0),
2586                         Vector(toGuiX(snapCoord.x), getHeight()));
2587         }
2588
2589         // Cursor
2590         if (snapCoord != snapSpot)
2591         {
2592                 painter->drawLine(toGui(snapSpot) + Vector(-5, 0), toGui(snapSpot) + Vector(-1, 4));
2593                 painter->drawLine(toGui(snapSpot) + Vector(0, 5), toGui(snapSpot) + Vector(4, 1));
2594                 painter->drawLine(toGui(snapSpot) + Vector(5, 0), toGui(snapSpot) + Vector(1, -4));
2595                 painter->drawLine(toGui(snapSpot) + Vector(0, -5), toGui(snapSpot) + Vector(-4, -1));
2596         }
2597 }
2598
2599 void GraphicView::SetSnapperVisible(bool visibility/*= true*/)
2600 {
2601         snapperVisible = visibility;
2602 }
2603
2604 bool GraphicView::SnapperVisible(void)
2605 {
2606         return snapperVisible;
2607 }
2608
2609 #if 0
2610 /*
2611 only place this is called is in ActionInterface. And its only function is to
2612 have it not drawn anymore. But, the GraphicView seems to draw it anyway... So
2613 some other approach is needed...
2614 */
2615 void Snapper::finish()
2616 {
2617         finished = true;
2618 }
2619
2620 /**
2621  * @return Pointer to the entity which was the key entity for the last
2622  * successful snapping action. If the snap mode is "end point" the key entity
2623  * is the entity whose end point was caught. If the snap mode didn't require an
2624  * entity (e.g. free, grid) this method will return NULL.
2625  */
2626 Entity * Snapper::getKeyEntity()
2627 {
2628         return keyEntity;
2629 }
2630
2631 /** Sets a new snap mode. */
2632 void Snapper::setSnapMode(RS2::SnapMode snapMode)
2633 {
2634         this->snapMode = snapMode;
2635 }
2636
2637 /** Sets a new snap restriction. */
2638 void Snapper::setSnapRestriction(RS2::SnapRestriction snapRes)
2639 {
2640         this->snapRes = snapRes;
2641 }
2642
2643 RS2::SnapMode Snapper::getSnapMode(void)
2644 {
2645         return snapMode;
2646 }
2647
2648 RS2::SnapRestriction Snapper::getSnapRestriction(void)
2649 {
2650         return snapRes;
2651 }
2652
2653 /**
2654  * Sets the snap range in pixels for catchEntity().
2655  *
2656  * @see catchEntity()
2657  */
2658 void Snapper::setSnapRange(int r)
2659 {
2660         snapRange = r;
2661 }
2662
2663 #if 0
2664 I think that these suspend() & resume() functions are not used anymore...
2665 #endif
2666 /**
2667  * Suspends this snapper while another action takes place.
2668  */
2669 /*virtual*/ void Snapper::suspend()
2670 {
2671 #warning "!!! This may need to have SetVisibility() called !!!"
2672 //      deleteSnapper();
2673         snapSpot = snapCoord = Vector(false);
2674 }
2675
2676 /**
2677  * Resumes this snapper after it has been suspended.
2678  */
2679 /*virtual*/ void Snapper::resume()
2680 {
2681 #warning "!!! This may need to have SetVisibility() called !!!"
2682 //      drawSnapper();
2683 }
2684
2685 /**
2686  * Hides the snapper options.
2687  */
2688 /*virtual*/ void Snapper::hideOptions()
2689 {
2690         if (snapMode == RS2::SnapDist && DIALOGFACTORY)
2691                 DIALOGFACTORY->requestSnapDistOptions(distance, false);
2692 }
2693
2694 /**
2695  * Shows the snapper options.
2696  */
2697 /*virtual*/ void Snapper::showOptions()
2698 {
2699         if (snapMode == RS2::SnapDist && DIALOGFACTORY)
2700                 DIALOGFACTORY->requestSnapDistOptions(distance, true);
2701 }
2702 #endif