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