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