3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 06/16/2010 Created this file. :-)
17 #include "graphicview.h"
19 #include "rs_dialogfactory.h"
21 #include "rs_eventhandler.h"
23 #include "rs_linetypepattern.h"
24 #include "paintinterface.h"
32 GraphicView::GraphicView(): background(), foreground()
34 drawingMode = RS2::ModeFull;
37 factor = Vector(1.0, 1.0);
40 previousFactor = Vector(1.0, 1.0);
44 eventHandler = new RS_EventHandler(this);
46 metaGridColor = RS_Color(64, 64, 64);
47 grid = new RS_Grid(this);
58 relativeZero = Vector(false);
59 relativeZeroLocked = false;
63 defaultSnapMode = RS2::SnapFree;
64 defaultSnapRes = RS2::RestrictNothing;
66 settings.beginGroup("Appearance");
67 setBackground(QColor(settings.value("BackgroundColor", "#000000").toString()));
68 setGridColor(QColor(settings.value("GridColor", "#7F7F7F").toString()));
69 setMetaGridColor(QColor(settings.value("MetaGridColor", "#3F3F3F").toString()));
70 setSelectedColor(QColor(settings.value("SelectedColor", "#A54747").toString()));
71 setHighlightedColor(QColor(settings.value("HighlightedColor", "#739373").toString()));
76 simulationSpeed = 100;
77 simulationSmooth = false;
78 simulationRapid = false;
79 simulationRunning = false;
85 GraphicView::~GraphicView()
91 * Must be called by any derrived class in the destructor.
93 void GraphicView::cleanUp()
99 * @return Pointer to the graphic entity if the entity container
100 * connected to this view is a graphic and valid.
103 Drawing * GraphicView::getGraphic()
105 if (container && container->rtti() == RS2::EntityGraphic)
106 return (Drawing *)container;
112 * Sets the drawing mode.
114 void GraphicView::setDrawingMode(RS2::DrawingMode m)
120 * @return Current drawing mode.
122 RS2::DrawingMode GraphicView::getDrawingMode()
128 * Activates or deactivates the delete mode.
130 void GraphicView::setDeleteMode(bool m)
136 * @reval true Deleting instead of drawing.
137 * false Normal drawing mode.
139 bool GraphicView::getDeleteMode()
144 /** This virtual method must be overwritten and is then
145 called whenever the view changed */
146 void GraphicView::adjustOffsetControls()
150 /** This virtual method must be overwritten and is then
151 called whenever the view changed */
152 void GraphicView::adjustZoomControls()
157 * Sets the background color. Note that applying the background
158 * color for the widget is up to the implementing class.
160 void GraphicView::setBackground(const RS_Color & bg)
164 // bright background:
165 if (bg.red() + bg.green() + bg.blue() > 380)
166 // foreground = Qt::black;
167 foreground = RS_Color(0, 0, 0);
169 // foreground = Qt::white;
170 foreground = RS_Color(255, 255, 255);
174 * @return Current background color.
176 RS_Color GraphicView::getBackground()
182 * @return Current foreground color.
184 RS_Color GraphicView::getForeground()
190 * Sets the grid color.
192 void GraphicView::setGridColor(const RS_Color & c)
198 * Sets the meta grid color.
200 void GraphicView::setMetaGridColor(const RS_Color & c)
206 * Sets the selection color.
208 void GraphicView::setSelectedColor(const RS_Color & c)
214 * Sets the highlight color.
216 void GraphicView::setHighlightedColor(const RS_Color & c)
218 highlightedColor = c;
222 * This virtual method can be overwritten to set the mouse
223 * cursor to the given type.
225 void GraphicView::setMouseCursor(RS2::CursorType /*c*/)
229 RS_EntityContainer * GraphicView::getContainer()
234 void GraphicView::setFactor(double f)
240 Vector GraphicView::getFactor()
246 * Sets the offset of the graphic.
248 void GraphicView::setOffset(int ox, int oy)
254 void GraphicView::setOffsetX(int ox)
259 void GraphicView::setOffsetY(int oy)
264 int GraphicView::getOffsetX()
269 int GraphicView::getOffsetY()
275 * Sets a fixed border in pixel around the graphic. This border
276 * specifies how far the user can scroll outside the graphic
279 void GraphicView::setBorders(int left, int top, int right, int bottom)
284 borderBottom = bottom;
287 int GraphicView::getBorderLeft()
292 int GraphicView::getBorderTop()
297 int GraphicView::getBorderRight()
302 int GraphicView::getBorderBottom()
307 void GraphicView::disableUpdate()
312 void GraphicView::enableUpdate()
317 bool GraphicView::isUpdateEnabled()
319 return (updateEnabled == 0);
322 void GraphicView::freezeZoom(bool freeze)
327 bool GraphicView::isZoomFrozen()
333 * Sets the pointer to the graphic which contains the entities
334 * which are visualized by this widget.
336 void GraphicView::setContainer(RS_EntityContainer * container)
338 this->container = container;
342 * Sets the zoom factor in X for this visualization of the graphic.
344 void GraphicView::setFactorX(double f)
351 * Sets the zoom factor in Y for this visualization of the graphic.
353 void GraphicView::setFactorY(double f)
360 * @return true if the grid is switched on.
362 bool GraphicView::isGridOn()
366 Drawing * g = container->getGraphic();
369 return g->isGridOn();
376 * Centers the drawing in x-direction.
378 void GraphicView::centerOffsetX()
380 if (container != NULL && !zoomFrozen)
381 offsetX = (int)(((getWidth() - borderLeft - borderRight)
382 - (container->getSize().x * factor.x)) / 2.0
383 - (container->getMin().x * factor.x)) + borderLeft;
387 * Centers the drawing in y-direction.
389 void GraphicView::centerOffsetY()
391 if (container != NULL && !zoomFrozen)
392 offsetY = (int)((getHeight() - borderTop - borderBottom
393 - (container->getSize().y * factor.y)) / 2.0
394 - (container->getMin().y * factor.y)) + borderBottom;
398 * Centers the given coordinate in the view in x-direction.
400 void GraphicView::centerX(double v)
403 offsetX = (int)((v * factor.x) - (double)(getWidth() - borderLeft - borderRight) / 2.0);
407 * Centers the given coordinate in the view in y-direction.
409 void GraphicView::centerY(double v)
412 offsetY = (int)((v * factor.y) - (double)(getHeight() - borderTop - borderBottom) / 2.0);
415 void GraphicView::updateView()
417 static int running = 0;
422 adjustZoomControls();
423 adjustOffsetControls();
433 * @return Current action or NULL.
435 ActionInterface * GraphicView::getDefaultAction()
437 if (eventHandler != NULL)
438 return eventHandler->getDefaultAction();
444 * Sets the default action of the event handler.
446 void GraphicView::setDefaultAction(ActionInterface * action)
449 eventHandler->setDefaultAction(action);
453 * @return Current action or NULL.
455 ActionInterface * GraphicView::getCurrentAction()
458 return eventHandler->getCurrentAction();
464 * Sets the current action of the event handler.
466 void GraphicView::setCurrentAction(ActionInterface * action)
468 RS_DEBUG->print("GraphicView::setCurrentAction");
471 eventHandler->setCurrentAction(action);
473 RS_DEBUG->print("GraphicView::setCurrentAction: OK");
477 * Kills all running selection actions. Called when a selection action
478 * is launched to reduce confusion.
480 void GraphicView::killSelectActions()
483 eventHandler->killSelectActions();
487 * Kills all running actions.
489 void GraphicView::killAllActions()
492 eventHandler->killAllActions();
496 * Go back in menu or current action.
498 void GraphicView::back()
500 if (eventHandler && eventHandler->hasAction())
501 eventHandler->back();
502 else if (RS_DIALOGFACTORY)
503 RS_DIALOGFACTORY->requestPreviousMenu();
507 * Go forward with the current action.
509 void GraphicView::enter()
511 if (eventHandler && eventHandler->hasAction())
512 eventHandler->enter();
516 * Called by the actual GUI class which implements the GraphicView
517 * interface to notify qcadlib about mouse events.
519 void GraphicView::mousePressEvent(QMouseEvent * e)
522 eventHandler->mousePressEvent(e);
526 * Called by the actual GUI class which implements the GraphicView
527 * interface to notify qcadlib about mouse events.
529 void GraphicView::mouseReleaseEvent(QMouseEvent * e)
531 RS_DEBUG->print("GraphicView::mouseReleaseEvent");
536 if (e->button() != Qt::RightButton || eventHandler->hasAction())
538 eventHandler->mouseReleaseEvent(e);
546 RS_DEBUG->print("GraphicView::mouseReleaseEvent: OK");
550 * Called by the actual GUI class which implements the GraphicView
551 * interface to notify qcadlib about mouse events.
553 void GraphicView::mouseMoveEvent(QMouseEvent * e)
555 RS_DEBUG->print("GraphicView::mouseMoveEvent begin");
557 Drawing * graphic = NULL;
559 if (container->rtti() == RS2::EntityGraphic)
560 graphic = (Drawing *)container;
562 RS_DEBUG->print("GraphicView::mouseMoveEvent 001");
570 RS_DEBUG->print("GraphicView::mouseMoveEvent 002");
573 eventHandler->mouseMoveEvent(e);
575 RS_DEBUG->print("GraphicView::mouseMoveEvent 003");
577 if (!eventHandler || !eventHandler->hasAction() && graphic)
579 Vector mouse = toGraph(Vector(mx, my));
580 Vector relMouse = mouse - getRelativeZero();
582 if (RS_DIALOGFACTORY)
583 RS_DIALOGFACTORY->updateCoordinateWidget(mouse, relMouse);
586 RS_DEBUG->print("GraphicView::mouseMoveEvent end");
590 * Called by the actual GUI class which implements the GraphicView
591 * interface to notify qcadlib about mouse events.
593 void GraphicView::mouseLeaveEvent()
596 eventHandler->mouseLeaveEvent();
600 * Called by the actual GUI class which implements the GraphicView
601 * interface to notify qcadlib about mouse events.
603 void GraphicView::mouseEnterEvent()
606 eventHandler->mouseEnterEvent();
610 * Called by the actual GUI class which implements the GraphicView
611 * interface to notify qcadlib about key events.
613 void GraphicView::keyPressEvent(QKeyEvent * e)
616 eventHandler->keyPressEvent(e);
620 * Called by the actual GUI class which implements the GraphicView
621 * interface to notify qcadlib about key events.
623 void GraphicView::keyReleaseEvent(QKeyEvent * e)
626 eventHandler->keyReleaseEvent(e);
630 * Called by the actual GUI class which implements a command line.
632 void GraphicView::commandEvent(RS_CommandEvent * e)
635 eventHandler->commandEvent(e);
639 * Enables coordinate input in the command line.
641 void GraphicView::enableCoordinateInput()
644 eventHandler->enableCoordinateInput();
648 * Disables coordinate input in the command line.
650 void GraphicView::disableCoordinateInput()
653 eventHandler->disableCoordinateInput();
657 * zooms in by factor f
659 void GraphicView::zoomIn(double f, const Vector & center)
663 RS_DEBUG->print(RS_Debug::D_WARNING, "GraphicView::zoomIn: invalid factor");
667 if (simulationRunning)
671 if (c.valid == false)
672 c = toGraph(Vector(getWidth() / 2, getHeight() / 2));
674 zoomWindow(toGraph(Vector(0, 0)).scale(c, Vector(1.0 / f, 1.0 / f)),
675 toGraph(Vector(getWidth(), getHeight())).scale(c, Vector(1.0 / f, 1.0 / f)));
679 * zooms in by factor f in x
681 void GraphicView::zoomInX(double f)
683 if (simulationRunning)
687 offsetX = (int)((offsetX - getWidth() / 2) * f) + getWidth() / 2;
688 adjustOffsetControls();
689 adjustZoomControls();
695 * zooms in by factor f in y
697 void GraphicView::zoomInY(double f)
699 if (simulationRunning)
703 offsetY = (int)((offsetY - getHeight() / 2) * f)+getHeight() / 2;
704 adjustOffsetControls();
705 adjustZoomControls();
711 * zooms out by factor f
713 void GraphicView::zoomOut(double f, const Vector & center)
717 RS_DEBUG->print(RS_Debug::D_WARNING,
718 "GraphicView::zoomOut: invalid factor");
722 if (simulationRunning)
729 * zooms out by factor f in x
731 void GraphicView::zoomOutX(double f)
735 RS_DEBUG->print(RS_Debug::D_WARNING,
736 "GraphicView::zoomOutX: invalid factor");
740 if (simulationRunning)
744 offsetX = (int)(offsetX / f);
745 adjustOffsetControls();
746 adjustZoomControls();
752 * zooms out by factor of y
754 void GraphicView::zoomOutY(double f)
758 RS_DEBUG->print(RS_Debug::D_WARNING, "GraphicView::zoomOutY: invalid factor");
762 if (simulationRunning)
766 offsetY = (int)(offsetY / f);
767 adjustOffsetControls();
768 adjustZoomControls();
776 * @param axis include axis in zoom
777 * @param keepAspectRatio true: keep aspect ratio 1:1
778 * false: factors in x and y are stretched to the max
780 void GraphicView::zoomAuto(bool axis, bool keepAspectRatio)
782 RS_DEBUG->print("GraphicView::zoomAuto");
784 if (simulationRunning)
789 if (container != NULL)
791 container->calculateBorders();
796 sx = std::max(container->getMax().x, 0.0) - std::min(container->getMin().x, 0.0);
797 sy = std::max(container->getMax().y, 0.0) - std::min(container->getMin().y, 0.0);
801 sx = container->getSize().x;
802 sy = container->getSize().y;
807 if (sx > RS_TOLERANCE)
808 fx = (getWidth() - borderLeft - borderRight) / sx;
812 if (sy > RS_TOLERANCE)
813 fy = (getHeight() - borderTop - borderBottom) / sy;
817 RS_DEBUG->print("f: %f/%f", fx, fy);
820 fx = fy = std::min(fx, fy);
822 RS_DEBUG->print("f: %f/%f", fx, fy);
824 if (fx < RS_TOLERANCE)
830 RS_DEBUG->print("f: %f/%f", fx, fy);
832 RS_DEBUG->print("adjustOffsetControls");
833 adjustOffsetControls();
834 RS_DEBUG->print("adjustZoomControls");
835 adjustZoomControls();
836 RS_DEBUG->print("centerOffsetX");
838 RS_DEBUG->print("centerOffsetY");
840 RS_DEBUG->print("updateGrid");
845 RS_DEBUG->print("GraphicView::zoomAuto OK");
849 * Shows previous view.
851 void GraphicView::zoomPrevious()
853 RS_DEBUG->print("GraphicView::zoomPrevious");
855 if (simulationRunning)
863 * Saves the current view as previous view to which we can
864 * switch back later with @see restoreView().
866 void GraphicView::saveView()
868 previousOffsetX = offsetX;
869 previousOffsetY = offsetY;
870 previousFactor = factor;
874 * Restores the view previously saved with
877 void GraphicView::restoreView()
879 int pox = previousOffsetX;
880 int poy = previousOffsetY;
881 Vector pf = previousFactor;
889 adjustOffsetControls();
890 adjustZoomControls();
896 * performs autozoom in y only
898 * @param axis include axis in zoom
900 void GraphicView::zoomAutoY(bool axis)
902 if (simulationRunning)
905 if (container != NULL)
907 double visibleHeight = 0.0;
908 double minY = RS_MAXDOUBLE;
909 double maxY = RS_MINDOUBLE;
910 bool noChange = false;
912 for(RS_Entity * e=container->firstEntity(RS2::ResolveNone);
913 e!=NULL; e = container->nextEntity(RS2::ResolveNone))
915 if (e->rtti() == RS2::EntityLine)
917 RS_Line * l = (RS_Line *)e;
919 x1 = toGuiX(l->getStartpoint().x);
920 x2 = toGuiX(l->getEndpoint().x);
922 if (x1 > 0.0 && x1 < (double)getWidth() || x2 > 0.0 && x2 < (double)getWidth())
924 minY = std::min(minY, l->getStartpoint().y);
925 minY = std::min(minY, l->getEndpoint().y);
926 maxY = std::max(maxY, l->getStartpoint().y);
927 maxY = std::max(maxY, l->getEndpoint().y);
933 visibleHeight = std::max(maxY, 0.0) - std::min(minY, 0.0);
935 visibleHeight = maxY - minY;
937 if (visibleHeight < 1.0)
942 if (visibleHeight > 1.0e-6)
944 fy = (getHeight() - borderTop - borderBottom) / visibleHeight;
946 if (factor.y < 0.000001)
950 if (noChange == false)
954 offsetY = (int)((getHeight() - borderTop - borderBottom - (visibleHeight * factor.y)) / 2.0
955 - (minY * factor.y)) + borderBottom;
956 adjustOffsetControls();
957 adjustZoomControls();
961 RS_DEBUG->print("Auto zoom y ok");
966 * Zooms the area given by v1 and v2.
968 * @param keepAspectRatio true: keeps the aspect ratio 1:1
969 * false: zooms exactly the selected range to the
970 * current graphic view
972 void GraphicView::zoomWindow(Vector v1, Vector v2, bool keepAspectRatio)
974 if (simulationRunning)
979 double zoomX = 480.0; // Zoom for X-Axis
980 double zoomY = 640.0; // Zoom for Y-Axis (Set smaller one)
981 double dum; // Dummy for switching values
984 // Switch left/right and top/bottom is necessary:
999 // Get zoom in X and zoom in Y:
1000 if (v2.x - v1.x > 1.0e-6)
1001 zoomX = getWidth() / (v2.x - v1.x);
1003 if (v2.y - v1.y > 1.0e-6)
1004 zoomY = getHeight() / (v2.y - v1.y);
1006 // Take smaller zoom:
1007 if (keepAspectRatio)
1011 if (getWidth() != 0)
1013 zoomX = zoomY = ((double)(getWidth() - 2 * zoomBorder)) /
1014 (double)getWidth() * zoomX;
1019 if (getHeight() != 0)
1021 zoomX = zoomY = ((double)(getHeight() - 2 * zoomBorder)) /
1022 (double)getHeight() * zoomY;
1033 // Borders in pixel after zoom
1034 int pixLeft = (int)(v1.x * zoomX);
1035 int pixTop = (int)(v2.y * zoomY);
1036 int pixRight = (int)(v2.x * zoomX);
1037 int pixBottom = (int)(v1.y * zoomY);
1039 // Set new offset for zero point:
1040 offsetX = - pixLeft + (getWidth() - pixRight + pixLeft) / 2;
1041 offsetY = - pixTop + (getHeight() - pixBottom + pixTop) / 2;
1045 adjustOffsetControls();
1046 adjustZoomControls();
1052 * Centers the point v1.
1054 void GraphicView::zoomPan(int dx, int dy)
1056 if (simulationRunning)
1063 adjustOffsetControls();
1070 * Scrolls in the given direction.
1072 void GraphicView::zoomScroll(RS2::Direction direction)
1074 if (simulationRunning)
1093 adjustOffsetControls();
1094 adjustZoomControls();
1100 * Zooms to page extends.
1102 void GraphicView::zoomPage()
1104 RS_DEBUG->print("GraphicView::zoomPage");
1106 if (container == NULL)
1109 if (simulationRunning)
1112 Drawing * graphic = container->getGraphic();
1114 if (graphic == NULL)
1117 Vector s = graphic->getPaperSize();
1118 Vector pinsbase = graphic->getPaperInsertionBase();
1122 if (s.x > RS_TOLERANCE)
1123 fx = (getWidth() - borderLeft - borderRight) / s.x;
1127 if (s.y > RS_TOLERANCE)
1128 fy = (getHeight() - borderTop - borderBottom) / s.y;
1132 RS_DEBUG->print("f: %f/%f", fx, fy);
1134 fx = fy = std::min(fx, fy);
1136 RS_DEBUG->print("f: %f/%f", fx, fy);
1138 if (fx < RS_TOLERANCE)
1144 RS_DEBUG->print("f: %f/%f", fx, fy);
1148 adjustOffsetControls();
1149 adjustZoomControls();
1155 * Draws the entities within the given range.
1157 void GraphicView::drawWindow(Vector v1, Vector v2)
1159 RS_DEBUG->print("GraphicView::drawWindow() begin");
1161 if (simulationRunning)
1166 for(RS_Entity * se=container->firstEntity(RS2::ResolveNone); se!=NULL;
1167 se=container->nextEntity(RS2::ResolveNone))
1169 if (se->isInWindow(v1, v2))
1174 RS_DEBUG->print("GraphicView::drawWindow() end");
1178 * Draws the entities. If painter is NULL a new painter will
1179 * be created and destroyed.
1181 void GraphicView::drawIt()
1183 if (!isUpdateEnabled())
1185 //printf("GraphicView::drawIt(): isUpdateEnabled() == false!\n");
1189 if (simulationRunning)
1191 //printf("GraphicView::drawIt(): simulationRunning == true!\n");
1195 settings.beginGroup("Appearance");
1196 draftMode = settings.value("DraftMode", false).toBool();
1197 settings.endGroup();
1201 //printf("GraphicView::drawIt(): painter == NULL!\n");
1207 // drawing paper border:
1208 if (isPrintPreview())
1210 // drawing meta grid:
1214 // drawing entities:
1215 //#warning "!!! This looks like a bug, no match for 'drawEntity(RS_Entity *, bool) !!!"
1216 // and indeed it *is* a bug... true is converted to 1.0 here. Dumb, dumb, dumb.
1217 drawEntity(container);//, true);
1219 // drawing zero points:
1220 if (!isPrintPreview())
1227 if (!isPrintPreview())
1232 * Sets the pen of the painter object to the suitable pen for the given
1235 void GraphicView::setPenForEntity(RS_Entity * e)
1237 if (drawingMode == RS2::ModePreview /*|| draftMode==true*/)
1240 if (!painter || painter->isPreviewMode())
1243 // set color of entity
1244 // Getting pen from entity (or layer)
1245 RS_Pen pen = e->getPen(true);
1247 int w = pen.getWidth();
1255 double uf = 1.0; // unit factor
1256 double wf = 1.0; // width factor
1257 Drawing * graphic = container->getGraphic();
1261 uf = RS_Units::convert(1.0, RS2::Millimeter, graphic->getUnit());
1263 if ((isPrinting() || isPrintPreview()) && graphic->getPaperScale() > 1.0e-6)
1264 wf = 1.0 / graphic->getPaperScale();
1267 pen.setScreenWidth(toGuiDX(w / 100.0 * uf * wf));
1271 //pen.setWidth(RS2::Width00);
1272 pen.setScreenWidth(0);
1275 // prevent drawing with 1-width which is slow:
1276 if (RS_Math::round(pen.getScreenWidth()) == 1)
1277 pen.setScreenWidth(0.0);
1279 // prevent background color on background drawing:
1280 if (pen.getColor().stripFlags() == background.stripFlags())
1281 pen.setColor(foreground);
1283 // this entity is selected:
1284 if (e->isSelected())
1286 pen.setLineType(RS2::DotLine);
1287 //pen.setColor(RS_Color(0xa5,0x47,0x47));
1288 pen.setColor(selectedColor);
1291 // this entity is highlighted:
1292 if (e->isHighlighted())
1294 //pen.setColor(RS_Color(0x73, 0x93, 0x73));
1295 pen.setColor(highlightedColor);
1298 // deleting not drawing:
1299 if (getDeleteMode())
1300 pen.setColor(background);
1302 painter->setPen(pen);
1306 * Draws an entity. Might be recusively called e.g. for polylines.
1307 * If the class wide painter is NULL a new painter will be created
1308 * and destroyed afterwards.
1310 * @param patternOffset Offset of line pattern (used for connected
1311 * lines e.g. in splines).
1312 * @param db Double buffering on (recommended) / off
1314 void GraphicView::drawEntity(RS_Entity * e, double patternOffset, bool db)
1316 //RS_DEBUG->print("GraphicView::drawEntity() begin");
1318 // update is diabled:
1319 if (!isUpdateEnabled())
1322 // given entity is NULL:
1326 // entity is not visible:
1327 if (!e->isVisible())
1330 // test if the entity is in the viewport
1331 if (!e->isContainer() && !isPrinting()
1332 && (!painter || !painter->isPreviewMode())
1333 && (toGuiX(e->getMax().x) < 0 || toGuiX(e->getMin().x) > getWidth()
1334 || toGuiY(e->getMin().y) < 0 || toGuiY(e->getMax().y) > getHeight()))
1336 //printf("GraphicView::drawEntity(): Bailing out of big test!!!\n");
1341 //RS_DEBUG->print("recursion 1: %d", drawRecursion);
1346 //RS_DEBUG->print("draw plain");
1349 // large texts as rectangles:
1350 if (e->rtti() == RS2::EntityText)
1352 if (toGuiDX(((RS_Text *)e)->getHeight()) < 4 || e->countDeep() > 100)
1353 painter->drawRect(toGui(e->getMin()), toGui(e->getMax()));
1355 drawEntityPlain(e, patternOffset);
1357 // all images as rectangles:
1358 else if (e->rtti() == RS2::EntityImage)
1359 painter->drawRect(toGui(e->getMin()), toGui(e->getMax()));
1361 else if (e->rtti() == RS2::EntityHatch)
1366 drawEntityPlain(e, patternOffset);
1369 drawEntityPlain(e, patternOffset);
1371 // draw reference points:
1372 if (e->isSelected())
1374 if (!e->isParentSelected())
1376 VectorSolutions s = e->getRefPoints();
1378 for(int i=0; i<s.getNumber(); ++i)
1381 RS_Color col = RS_Color(0, 0, 255);
1383 if (e->rtti() == RS2::EntityPolyline)
1385 if (i == 0 || i == s.getNumber() - 1)
1390 // col = QColor(0, 64, 255);
1391 col = RS_Color(0, 64, 255);
1396 // col = QColor(0, 0, 128);
1397 col = RS_Color(0, 0, 128);
1402 if (getDeleteMode())
1403 painter->drawHandle(toGui(s.get(i)), background, sz);
1405 painter->drawHandle(toGui(s.get(i)), col, sz);
1410 //RS_DEBUG->print("draw plain OK");
1411 //RS_DEBUG->print("GraphicView::drawEntity() end");
1415 * Deletes an entity with the background color.
1416 * Might be recusively called e.g. for polylines.
1418 void GraphicView::deleteEntity(RS_Entity * e)
1420 #warning "!!! This is part of obsolete rendering !!!"
1421 setDeleteMode(true);
1423 setDeleteMode(false);
1428 * The painter must be initialized and all the attributes (pen) must be set.
1430 void GraphicView::drawEntityPlain(RS_Entity * e, double patternOffset/*= 0.0*/)
1432 //Problems can still occur here when passing in a deleted object... It won't be
1433 //NULL, but it will cause a segfault here...
1436 //printf("GraphicView::drawEntityPlain(): Entity passed in is NULL!\n");
1440 //printf("GraphicView::drawEntityPlain(): Passing in painter=%08X, view=%08X\n", painter, this);
1441 e->draw(painter, this, patternOffset);
1445 * Simulates this drawing in slow motion.
1447 void GraphicView::simulateIt()
1449 if (simulationRunning)
1452 simulationRunning = true;
1453 simulationLast = Vector(0.0, 0.0);
1457 // drawing paper border:
1458 if (isPrintPreview())
1461 // drawing meta grid:
1462 if (!isPrintPreview())
1466 if (!isPrintPreview())
1469 // drawing entities:
1470 RS_Pen pen(foreground, RS2::Width00, RS2::SolidLine);
1471 simulateEntity(container, pen);
1473 // drawing zero points:
1474 if (!isPrintPreview())
1480 simulationRunning = false;
1484 * Simulates the given entity.
1486 * @param smooth If true, the entity will be drawn slowly (pixel by pixel).
1488 void GraphicView::simulateEntity(RS_Entity * e, const RS_Pen & pen)
1490 if (painter == NULL || e == NULL)
1493 if (e->isContainer())
1495 RS_EntityContainer * ec = (RS_EntityContainer *)e;
1497 for(RS_Entity* en=ec->firstEntity(RS2::ResolveNone);
1498 en!=NULL; en = ec->nextEntity(RS2::ResolveNone))
1500 if (en->isVisible() && en->isUndone() == false)
1503 if (en->isAtomic() && simulationRapid)
1505 Vector sp = ((RS_AtomicEntity *)en)->getStartpoint();
1507 if (sp.distanceTo(simulationLast) > 1.0e-4)
1509 RS_Pen rpen(RS_Color(0, 0, 255), RS2::Width00, RS2::SolidLine);
1510 RS_Line rapidLine(NULL, RS_LineData(simulationLast, sp));
1511 simulateEntity(&rapidLine, rpen);
1515 if (en->isHighlighted())
1517 RS_Pen hpen(highlightedColor, RS2::Width00, RS2::SolidLine);
1518 simulateEntity(en, hpen);
1521 simulateEntity(en, pen);
1524 simulationLast = ((RS_AtomicEntity *)en)->getEndpoint();
1526 if (!simulationSmooth)
1527 simulationDelay(true);
1533 if (simulationSmooth)
1537 case RS2::EntityLine:
1539 RS_Line * line = (RS_Line *)e;
1540 drawLineSmooth(toGui(line->getStartpoint()), toGui(line->getEndpoint()), pen);
1545 case RS2::EntityArc:
1547 RS_Arc * arc = (RS_Arc *)e;
1548 drawArcSmooth(toGui(arc->getCenter()), toGuiDX(arc->getRadius()),
1549 arc->getAngle1(), arc->getAngle2(), arc->isReversed(), pen);
1553 case RS2::EntityCircle:
1555 RS_Circle * circle = (RS_Circle *)e;
1556 drawArcSmooth(toGui(circle->getCenter()), toGuiDX(circle->getRadius()),
1557 0.0, 2.0 * M_PI, false, pen);
1567 painter->setPen(pen);
1574 * Delay for slow motion simulation.
1576 * @param step true: stepping mode (entity by entity simulation). adds a delay.
1578 void GraphicView::simulationDelay(bool step)
1581 settings.beginGroup("CAM");
1582 double fact = settings.value("SimulationFactor", 12000.0).toDouble();
1583 settings.endGroup();
1585 // simulationSpeed: 0..100
1588 delay = (int)(((1.0 / (simulationSpeed + 1.0)) * fact) - (fact / 100.0));
1593 static int call = 0;
1595 if (call >= (fact - delay) / 1000)
1598 for(int i=0; i<delay; ++i)
1599 RS_APP->processEvents(10);
1604 delay = (int)(((1.0 / (simulationSpeed + 1.0)) * fact) - (fact / 100.0));
1611 for(int i=0; i<delay; ++i)
1613 #warning "Qt3->4 conversion: commented out problem line... !!! FIX !!!"
1614 // RS_APP->processEvents(10);
1620 * Draws a line slowly from (x1, y1) to (x2, y2). This is used for simulation only.
1622 void GraphicView::drawLineSmooth(const Vector & p1, const Vector & p2, const RS_Pen & pen)
1624 double alpha = p1.angleTo(p2);
1625 double xStep, yStep;
1628 if (RS_Math::cmpDouble(alpha, 0.0) || RS_Math::cmpDouble(alpha, 2 * M_PI))
1634 else if (RS_Math::cmpDouble(alpha, M_PI / 2.0))
1640 else if (RS_Math::cmpDouble(alpha, M_PI))
1646 else if (RS_Math::cmpDouble(alpha, M_PI / 2.0 * 3.0))
1652 else if (fabs(p2.x - p1.x) > fabs(p2.y - p1.y))
1659 yStep = tan(alpha) * xStep;
1669 xStep = yStep / tan(alpha);
1678 if (lx >= 0.0 && lx <= (double)getWidth() && ly >= 0.0 && ly <= (double)getHeight())
1680 painter->setPen(pen);
1681 painter->drawGridPoint(Vector(lx, ly));
1690 while ((xIsOne && ((lx >= p1.x && lx <= p2.x) || (lx >= p2.x && lx <= p1.x)))
1691 || (!xIsOne && ((ly >= p1.y && ly <= p2.y) || (ly >= p2.y && ly <= p1.y))));
1694 void GraphicView::drawArcSmooth(const Vector & center, double radius, double a1, double a2, bool rev,
1699 painter->setPen(pen);
1700 painter->drawGridPoint(center);
1704 int ix1 = RS_Math::round(center.x + cos(a1) * radius);
1705 int iy1 = RS_Math::round(center.y - sin(a1) * radius);
1706 int ix2 = RS_Math::round(center.x + cos(a2) * radius);
1707 int iy2 = RS_Math::round(center.y - sin(a2) * radius);
1708 int k2x = 0; // Next point on circle
1710 int k1x = ix1; // Prev point on circle
1712 double aStep; // Angle Step (rad)
1713 double a; // Actual Angle (rad)
1714 double a2cp = a2; // Copy of a2
1716 if (1.0 / (radius * factor.x) <= 1.0)
1717 aStep = asin(1.0 / (radius * factor.x));
1726 // Arc Counterclockwise:
1728 if (a1 > a2cp - 0.01)
1731 for(a=a1+aStep; a<=a2cp; a+=aStep)
1733 k2x = RS_Math::round(center.x+cos(a)*radius);
1734 k2y = RS_Math::round(center.y-sin(a)*radius);
1735 painter->setPen(pen);
1737 if ((k2x >= 0 && k2x <= painter->getWidth()
1738 && k2y >= 0 && k2y <= painter->getHeight())
1739 || (k1x >= 0 && k1x <= painter->getWidth()
1740 && k1y >= 0 && k1y <= painter->getHeight()))
1742 painter->drawLine(Vector(k1x, k1y), Vector(k2x, k2y));
1750 painter->setPen(pen);
1751 painter->drawLine(Vector(k2x, k2y), Vector(ix2, iy2));
1757 if (a1 < a2cp + 0.01)
1760 for(a=a1-aStep; a>=a2cp; a-=aStep)
1762 k2x = RS_Math::round(center.x + cos(a) * radius);
1763 k2y = RS_Math::round(center.y - sin(a) * radius);
1764 painter->setPen(pen);
1766 if ((k2x >=0 && k2x <= painter->getWidth()
1767 && k2y >= 0 && k2y <= painter->getHeight())
1768 || (k1x >= 0 && k1x <= painter->getWidth()
1769 && k1y >= 0 && k1y <= painter->getHeight()))
1771 painter->drawLine(Vector(k1x, k1y), Vector(k2x, k2y));
1779 painter->setPen(pen);
1780 painter->drawLine(Vector(k2x, k2y), Vector(ix2, iy2));
1786 * @return Pointer to the static pattern struct that belongs to the
1787 * given pattern type or NULL.
1789 RS_LineTypePattern * GraphicView::getPattern(RS2::LineType t)
1793 case RS2::SolidLine:
1794 return &patternSolidLine;
1798 return &patternDotLine;
1801 return &patternDotLine2;
1803 case RS2::DotLineX2:
1804 return &patternDotLineX2;
1808 return &patternDashLine;
1810 case RS2::DashLine2:
1811 return &patternDashLine2;
1813 case RS2::DashLineX2:
1814 return &patternDashLineX2;
1817 case RS2::DashDotLine:
1818 return &patternDashDotLine;
1820 case RS2::DashDotLine2:
1821 return &patternDashDotLine2;
1823 case RS2::DashDotLineX2:
1824 return &patternDashDotLineX2;
1827 case RS2::DivideLine:
1828 return &patternDivideLine;
1830 case RS2::DivideLine2:
1831 return &patternDivideLine2;
1833 case RS2::DivideLineX2:
1834 return &patternDivideLineX2;
1837 case RS2::CenterLine:
1838 return &patternCenterLine;
1840 case RS2::CenterLine2:
1841 return &patternCenterLine2;
1843 case RS2::CenterLineX2:
1844 return &patternCenterLineX2;
1847 case RS2::BorderLine:
1848 return &patternBorderLine;
1850 case RS2::BorderLine2:
1851 return &patternBorderLine2;
1853 case RS2::BorderLineX2:
1854 return &patternBorderLineX2;
1857 case RS2::LineByLayer:
1858 return &patternBlockLine;
1860 case RS2::LineByBlock:
1861 return &patternBlockLine;
1871 * This virtual method can be overwritten to draw the absolute
1872 * zero. It's called from within drawIt(). The default implemetation
1873 * draws a simple red round zero point.
1875 * Actually, we have to rework the rendering code because the way that QCad did
1876 * it was wrong on so many levels... Part of that is making sure the rendering
1877 * path is 100% clear!
1881 void GraphicView::drawAbsoluteZero()
1888 // RS_Pen p(Qt::red, RS2::Width00, RS2::SolidLine);
1889 //Using Qt::red doesn't seem to work here...
1890 //It's because Qt colors and RS_Color are not 100% compatible...
1891 RS_Pen p(RS_Color(255, 0, 0), RS2::Width00, RS2::SolidLine);
1894 painter->drawLine(Vector(toGuiX(0.0) - zr, toGuiY(0.0)),
1895 Vector(toGuiX(0.0) + zr, toGuiY(0.0)));
1897 painter->drawLine(Vector(toGuiX(0.0), toGuiY(0.0) - zr),
1898 Vector(toGuiX(0.0), toGuiY(0.0) + zr));
1902 * This virtual method can be overwritten to draw the relative
1903 * zero point. It's called from within drawIt(). The default implemetation
1904 * draws a simple red round zero point.
1908 void GraphicView::drawRelativeZero()
1910 if (!relativeZero.valid || !painter)
1915 if (!relativeZero.valid)
1916 printf("GraphicView::drawRelativeZero(): relativeZero is NOT valid!!!\n");
1919 printf("GraphicView::drawRelativeZero(): painter is NOT valid!!!\n");
1925 //Using Qt::red doesn't seem to work here...
1926 RS_Pen p(RS_Color(255, 0, 0), RS2::Width00, RS2::SolidLine);
1928 painter->setXORMode();
1932 painter->drawLine(Vector(toGuiX(relativeZero.x) - zr, toGuiY(relativeZero.y)),
1933 Vector(toGuiX(relativeZero.x) + zr, toGuiY(relativeZero.y)));
1935 painter->drawLine(Vector(toGuiX(relativeZero.x), toGuiY(relativeZero.y) - zr),
1936 Vector(toGuiX(relativeZero.x), toGuiY(relativeZero.y) + zr));
1938 painter->drawCircle(toGui(relativeZero), zr);
1939 painter->setNormalMode();
1943 * Draws the paper border (for print previews).
1947 void GraphicView::drawPaper()
1952 Drawing * graphic = container->getGraphic();
1957 if (graphic->getPaperScale() < 1.0e-6)
1964 painter->setPen(RS_Pen(Qt::gray));
1966 Vector pinsbase = graphic->getPaperInsertionBase();
1967 Vector size = graphic->getPaperSize();
1968 double scale = graphic->getPaperScale();
1970 Vector v1 = toGui((Vector(0, 0) - pinsbase) / scale);
1971 Vector v2 = toGui((size - pinsbase) / scale);
1974 painter->fillRect(0,0, getWidth(), getHeight(), RS_Color(200, 200, 200));
1977 painter->fillRect((int)(v1.x) + 6, (int)(v1.y) + 6,
1978 (int)((v2.x - v1.x)), (int)((v2.y - v1.y)), RS_Color(64, 64, 64));
1981 painter->fillRect((int)(v1.x), (int)(v1.y),
1982 (int)((v2.x - v1.x)), (int)((v2.y - v1.y)), RS_Color(64, 64, 64));
1985 painter->fillRect((int)(v1.x) + 1, (int)(v1.y) - 1,
1986 (int)((v2.x - v1.x)) - 2, (int)((v2.y - v1.y)) + 2, RS_Color(255, 255, 255));
1994 void GraphicView::drawGrid()
1996 if (!grid || isGridOn() == false)
1998 // printf("GraphicView::drawGrid(): Aborting: grid=%08X, isGridOn=%s\n", grid, (isGridOn() ? "true" : "false"));
2003 painter->setPen(gridColor);
2005 //Problem here: pts is NULL!
2006 Vector * pts = grid->getPoints();
2010 for(int i=0; i<grid->count(); ++i)
2011 painter->drawGridPoint(toGui(pts[i]));
2014 // printf("GraphicView::drawGrid(): pts == NULL!\n");
2017 QString info = grid->getInfo();
2018 updateGridStatusWidget(info);
2022 * Draws the meta grid.
2026 void GraphicView::drawMetaGrid()
2028 if (!grid || isGridOn() == false)
2034 RS_Pen pen(metaGridColor, RS2::Width00, RS2::DotLine);
2035 painter->setPen(pen);
2038 double * mx = grid->getMetaX();
2039 double * my = grid->getMetaY();
2043 for(int i=0; i<grid->countMetaX(); ++i)
2044 painter->drawLine(Vector(toGuiX(mx[i]), 0), Vector(toGuiX(mx[i]), getHeight()));
2049 for(int i=0; i<grid->countMetaY(); ++i)
2050 painter->drawLine(Vector(0, toGuiY(my[i])), Vector(getWidth(), toGuiY(my[i])));
2055 * Updates the grid if there is one.
2057 void GraphicView::updateGrid()
2063 RS_Grid * GraphicView::getGrid()
2068 void GraphicView::updateGridStatusWidget(const QString & /*text*/)
2072 RS2::SnapMode GraphicView::getDefaultSnapMode()
2074 return defaultSnapMode;
2077 RS2::SnapRestriction GraphicView::getSnapRestriction()
2079 return defaultSnapRes;
2083 * Sets the default snap mode used by newly created actions.
2085 void GraphicView::setDefaultSnapMode(RS2::SnapMode sm)
2087 defaultSnapMode = sm;
2090 eventHandler->setSnapMode(sm);
2092 //OK, the above sets the snap mode in the snapper that's derived from
2093 //the RS_ActionInterface and RS_Snapper. So the following should fix
2094 //us up, hm notwithstanding. [and it does. :-)]
2096 snapper.setSnapMode(sm);
2100 * Sets a snap restriction (e.g. orthogonal).
2102 void GraphicView::setSnapRestriction(RS2::SnapRestriction sr)
2104 defaultSnapRes = sr;
2106 if (eventHandler != NULL)
2107 eventHandler->setSnapRestriction(sr);
2111 * Translates a vector in real coordinates to a vector in screen coordinates.
2113 Vector GraphicView::toGui(Vector v)
2115 return Vector(toGuiX(v.x), toGuiY(v.y), 0.0);
2119 * Translates a real coordinate in X to a screen coordinate X.
2120 * @param visible Pointer to a boolean which will contain true
2121 * after the call if the coordinate is within the visible range.
2123 double GraphicView::toGuiX(double x, bool * visible)
2125 if (visible != NULL)
2127 double res = x * factor.x + offsetX;
2129 if (res > 0.0 && res < getWidth())
2135 return x * factor.x + offsetX;
2139 * Translates a real coordinate in Y to a screen coordinate Y.
2141 double GraphicView::toGuiY(double y)
2143 return -y * factor.y + getHeight() - offsetY;
2147 * Translates a real coordinate distance to a screen coordinate distance.
2149 double GraphicView::toGuiDX(double d)
2151 return d * factor.x;
2155 * Translates a real coordinate distance to a screen coordinate distance.
2157 double GraphicView::toGuiDY(double d)
2159 return d * factor.y;
2163 * Translates a vector in screen coordinates to a vector in real coordinates.
2165 Vector GraphicView::toGraph(Vector v)
2167 return Vector(toGraphX(RS_Math::round(v.x)), toGraphY(RS_Math::round(v.y)), 0.0);
2171 * Translates two screen coordinates to a vector in real coordinates.
2173 Vector GraphicView::toGraph(int x, int y)
2175 return Vector(toGraphX(x), toGraphY(y), 0.0);
2179 * Translates a screen coordinate in X to a real coordinate X.
2181 double GraphicView::toGraphX(int x)
2183 return (x - offsetX) / factor.x;
2187 * Translates a screen coordinate in Y to a real coordinate Y.
2189 double GraphicView::toGraphY(int y)
2191 return -(y - getHeight() + offsetY) / factor.y;
2195 * Translates a screen coordinate distance to a real coordinate distance.
2197 double GraphicView::toGraphDX(int d)
2199 return d / factor.x;
2203 * Translates a screen coordinate distance to a real coordinate distance.
2205 double GraphicView::toGraphDY(int d)
2207 return d / factor.y;
2211 * (Un-)Locks the position of the relative zero.
2213 * @param lock true: lock, false: unlock
2215 void GraphicView::lockRelativeZero(bool lock)
2217 relativeZeroLocked = lock;
2221 * @return true if the position of the realtive zero point is
2224 bool GraphicView::isRelativeZeroLocked()
2226 return relativeZeroLocked;
2230 * @return Relative zero coordinate.
2232 Vector GraphicView::getRelativeZero()
2234 return relativeZero;
2238 * Sets the relative zero coordinate (if not locked)
2239 * without deleting / drawing the point.
2241 void GraphicView::setRelativeZero(const Vector & pos)
2243 if (!relativeZeroLocked)
2248 * Sets the relative zero coordinate, deletes the old position
2249 * on the screen and draws the new one.
2251 void GraphicView::moveRelativeZero(const Vector & pos)
2253 setRelativeZero(pos);
2256 RS_EventHandler * GraphicView::getEventHandler()
2258 return eventHandler;
2262 * Enables or disables print preview.
2264 void GraphicView::setPrintPreview(bool pv)
2270 * @retval true This is a print preview graphic view.
2271 * @retval false Otherwise.
2273 bool GraphicView::isPrintPreview()
2275 return printPreview;
2279 * Enables or disables printing.
2281 void GraphicView::setPrinting(bool p)
2287 * @retval true This is a a graphic view for printing.
2288 * @retval false Otherwise.
2290 bool GraphicView::isPrinting()
2296 * @retval true Draft mode is on for this view (all lines with 1 pixel / no style scaling).
2297 * @retval false Otherwise.
2299 bool GraphicView::isDraftMode()
2305 * Sets the simulation speed in percentage.
2307 void GraphicView::setSimulationSpeed(int s)
2309 simulationSpeed = s;
2313 * @return the simulation speed in percentage.
2315 int GraphicView::getSimulationSpeed()
2317 return simulationSpeed;
2321 * Sets the simulation smooth mode.
2323 void GraphicView::setSimulationSmooth(bool s)
2325 simulationSmooth = s;
2328 * Sets the simulation rapid mode.
2330 void GraphicView::setSimulationRapid(bool r)
2332 simulationRapid = r;
2336 * @return the simulation rapid mode.
2338 bool GraphicView::getSimulationRapid()
2340 return simulationRapid;