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