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