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