1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
6 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
7 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
8 **
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License version 2 as published by the Free Software
12 ** Foundation and appearing in the file gpl-2.0.txt included in the
13 ** packaging of this file.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 **
24 ** This copyright notice MUST APPEAR in all copies of the script!
25 **
26 **********************************************************************/
27 
28 #include<climits>
29 #include<cmath>
30 
31 #include <QApplication>
32 #include <QDesktopWidget>
33 #include <QAction>
34 #include <QMouseEvent>
35 #include <QtAlgorithms>
36 
37 #include "rs_graphicview.h"
38 
39 #include "rs_line.h"
40 #include "rs_linetypepattern.h"
41 #include "rs_eventhandler.h"
42 #include "rs_graphic.h"
43 #include "rs_grid.h"
44 #include "rs_painter.h"
45 #include "rs_mtext.h"
46 #include "rs_text.h"
47 #include "rs_settings.h"
48 #include "rs_dialogfactory.h"
49 #include "rs_layer.h"
50 #include "rs_math.h"
51 #include "rs_debug.h"
52 #include "rs_color.h"
53 
54 #ifdef EMU_C99
55 #include "emu_c99.h"
56 #endif
57 
58 /**
59  * Constructor.
60  */
RS_GraphicView(QWidget * parent,Qt::WindowFlags f)61 RS_GraphicView::RS_GraphicView(QWidget* parent, Qt::WindowFlags f)
62     :QWidget(parent, f)
63 	,eventHandler{new RS_EventHandler{this}}
64 	,gridColor(Qt::gray)
65 	,metaGridColor{64, 64, 64}
66 	,grid{new RS_Grid{this}}
67 	,drawingMode(RS2::ModeFull)
68 	,savedViews(16)
69     ,previousViewTime(QDateTime::currentDateTime())
70     ,panning(false)
71 {
72     RS_SETTINGS->beginGroup("Colors");
73     setBackground(QColor(RS_SETTINGS->readEntry("/background", Colors::background)));
74     setGridColor(QColor(RS_SETTINGS->readEntry("/grid", Colors::grid)));
75     setMetaGridColor(QColor(RS_SETTINGS->readEntry("/meta_grid", Colors::meta_grid)));
76     setSelectedColor(QColor(RS_SETTINGS->readEntry("/select", Colors::select)));
77     setHighlightedColor(QColor(RS_SETTINGS->readEntry("/highlight", Colors::highlight)));
78     setStartHandleColor(QColor(RS_SETTINGS->readEntry("/start_handle", Colors::start_handle)));
79     setHandleColor(QColor(RS_SETTINGS->readEntry("/handle", Colors::handle)));
80     setEndHandleColor(QColor(RS_SETTINGS->readEntry("/end_handle", Colors::end_handle)));
81     RS_SETTINGS->endGroup();
82 }
83 
~RS_GraphicView()84 RS_GraphicView::~RS_GraphicView()
85 {
86     qDeleteAll(overlayEntities);
87 }
88 
89 /**
90  * Must be called by any derived class in the destructor.
91  */
cleanUp()92 void RS_GraphicView::cleanUp() {
93 	m_bIsCleanUp=true;
94 }
95 
96 /**
97  * Sets the pointer to the graphic which contains the entities
98  * which are visualized by this widget.
99  */
setContainer(RS_EntityContainer * container)100 void RS_GraphicView::setContainer(RS_EntityContainer* container) {
101 	this->container = container;
102 	//adjustOffsetControls();
103 }
104 
105 
106 
107 /**
108  * Sets the zoom factor in X for this visualization of the graphic.
109  */
setFactorX(double f)110 void RS_GraphicView::setFactorX(double f) {
111 	if (!zoomFrozen) {
112 		factor.x = fabs(f);
113 	}
114 }
115 
116 
117 
118 /**
119  * Sets the zoom factor in Y for this visualization of the graphic.
120  */
setFactorY(double f)121 void RS_GraphicView::setFactorY(double f) {
122 	if (!zoomFrozen) {
123 		factor.y = fabs(f);
124 	}
125 }
126 
setOffset(int ox,int oy)127 void RS_GraphicView::setOffset(int ox, int oy) {
128 	//    DEBUG_HEADER
129 	//    RS_DEBUG->print(/*RS_Debug::D_WARNING, */"set offset from (%d, %d) to (%d, %d)", getOffsetX(), getOffsetY(), ox, oy);
130 	setOffsetX(ox);
131 	setOffsetY(oy);
132 }
133 
134 /**
135  * @return true if the grid is switched on.
136  */
isGridOn() const137 bool RS_GraphicView::isGridOn() const{
138 	if (container) {
139 		RS_Graphic* g = container->getGraphic();
140 		if (g) {
141 			return g->isGridOn();
142 		}
143 	}
144 	return true;
145 }
146 
147 /**
148  * @return true if the grid is isometric
149  *
150  *@Author: Dongxu Li
151  */
isGridIsometric() const152 bool RS_GraphicView::isGridIsometric() const{
153 	return grid->isIsometric();
154 }
155 
156 
setCrosshairType(RS2::CrosshairType chType)157 void RS_GraphicView::setCrosshairType(RS2::CrosshairType chType){
158 	grid->setCrosshairType(chType);
159 }
160 
getCrosshairType() const161 RS2::CrosshairType RS_GraphicView::getCrosshairType() const{
162 	return grid->getCrosshairType();
163 }
164 
165 /**
166  * Centers the drawing in x-direction.
167  */
centerOffsetX()168 void RS_GraphicView::centerOffsetX() {
169 	if (container && !zoomFrozen) {
170 		offsetX = (int)(((getWidth()-borderLeft-borderRight)
171 						 - (container->getSize().x*factor.x))/2.0
172 						- (container->getMin().x*factor.x)) + borderLeft;
173 	}
174 }
175 
176 
177 
178 /**
179  * Centers the drawing in y-direction.
180  */
centerOffsetY()181 void RS_GraphicView::centerOffsetY() {
182 	if (container && !zoomFrozen) {
183 		offsetY = (int)((getHeight()-borderTop-borderBottom
184 						 - (container->getSize().y*factor.y))/2.0
185 						- (container->getMin().y*factor.y)) + borderBottom;
186 	}
187 }
188 
189 
190 
191 /**
192  * Centers the given coordinate in the view in x-direction.
193  */
centerX(double v)194 void RS_GraphicView::centerX(double v) {
195 	if (!zoomFrozen) {
196 		offsetX = (int)((v*factor.x)
197 						- (double)(getWidth()-borderLeft-borderRight)/2.0);
198 	}
199 }
200 
201 
202 
203 /**
204  * Centers the given coordinate in the view in y-direction.
205  */
centerY(double v)206 void RS_GraphicView::centerY(double v) {
207 	if (!zoomFrozen) {
208 		offsetY = (int)((v*factor.y)
209 						- (double)(getHeight()-borderTop-borderBottom)/2.0);
210 	}
211 }
212 
213 /**
214  * @return Current action or nullptr.
215  */
getDefaultAction()216 RS_ActionInterface* RS_GraphicView::getDefaultAction() {
217 	if (eventHandler) {
218 		return eventHandler->getDefaultAction();
219 	} else {
220         return nullptr;
221 	}
222 }
223 
224 
225 
226 /**
227  * Sets the default action of the event handler.
228  */
setDefaultAction(RS_ActionInterface * action)229 void RS_GraphicView::setDefaultAction(RS_ActionInterface* action) {
230 	if (eventHandler) {
231 		eventHandler->setDefaultAction(action);
232 	}
233 }
234 
235 
236 
237 /**
238  * @return Current action or nullptr.
239  */
getCurrentAction()240 RS_ActionInterface* RS_GraphicView::getCurrentAction() {
241 	if (eventHandler) {
242 		return eventHandler->getCurrentAction();
243 	} else {
244         return nullptr;
245 	}
246 }
247 
248 
249 
250 /**
251  * Sets the current action of the event handler.
252  */
setCurrentAction(RS_ActionInterface * action)253 void RS_GraphicView::setCurrentAction(RS_ActionInterface* action) {
254     RS_DEBUG->print("RS_GraphicView::setCurrentAction");
255 	if (eventHandler) {
256 		eventHandler->setCurrentAction(action);
257 	}
258 	RS_DEBUG->print("RS_GraphicView::setCurrentAction: OK");
259 }
260 
261 
262 /**
263  * Kills all running selection actions. Called when a selection action
264  * is launched to reduce confusion.
265  */
killSelectActions()266 void RS_GraphicView::killSelectActions() {
267 	if (eventHandler) {
268 		eventHandler->killSelectActions();
269 	}
270 }
271 
272 
273 
274 /**
275  * Kills all running actions.
276  */
killAllActions()277 void RS_GraphicView::killAllActions() {
278 	if (eventHandler) {
279 		eventHandler->killAllActions();
280 	}
281 }
282 
283 
284 
285 /**
286  * Go back in menu or current action.
287  */
back()288 void RS_GraphicView::back()
289 {
290 	if (eventHandler && eventHandler->hasAction())
291     {
292 		eventHandler->back();
293     }
294 }
295 
296 /**
297  * Go forward with the current action.
298  */
enter()299 void RS_GraphicView::enter() {
300 	if (eventHandler && eventHandler->hasAction()) {
301 		eventHandler->enter();
302 	}
303 }
304 
305 /**
306  * Called by the actual GUI class which implements a command line.
307  */
commandEvent(RS_CommandEvent * e)308 void RS_GraphicView::commandEvent(RS_CommandEvent* e) {
309 	if (eventHandler) {
310 		eventHandler->commandEvent(e);
311 	}
312 }
313 
314 /**
315  * Enables coordinate input in the command line.
316  */
enableCoordinateInput()317 void RS_GraphicView::enableCoordinateInput() {
318 	if (eventHandler) {
319 		eventHandler->enableCoordinateInput();
320 	}
321 }
322 
323 
324 
325 /**
326  * Disables coordinate input in the command line.
327  */
disableCoordinateInput()328 void RS_GraphicView::disableCoordinateInput() {
329 	if (eventHandler) {
330 		eventHandler->disableCoordinateInput();
331 	}
332 }
333 
334 
335 
336 /**
337  * zooms in by factor f
338  */
zoomIn(double f,const RS_Vector & center)339 void RS_GraphicView::zoomIn(double f, const RS_Vector& center) {
340 
341 	if (f<1.0e-6) {
342 		RS_DEBUG->print(RS_Debug::D_WARNING,
343 						"RS_GraphicView::zoomIn: invalid factor");
344 		return;
345 	}
346 
347     RS_Vector c = center;
348     if (!c.valid) {
349         //find mouse position
350         c= getMousePosition();
351     }
352 
353 	zoomWindow(
354 				toGraph(0, 0)
355 				.scale(c, RS_Vector(1.0/f,1.0/f)),
356 				toGraph(getWidth(), getHeight())
357 				.scale(c, RS_Vector(1.0/f,1.0/f)));
358 
359 	//adjustOffsetControls();
360 	//adjustZoomControls();
361 	// updateGrid();
362 	redraw();
363 }
364 
365 
366 
367 /**
368  * zooms in by factor f in x
369  */
zoomInX(double f)370 void RS_GraphicView::zoomInX(double f) {
371 	factor.x*=f;
372 	offsetX=(int)((offsetX-getWidth()/2)*f)+getWidth()/2;
373 	adjustOffsetControls();
374 	adjustZoomControls();
375 	// updateGrid();
376 	redraw();
377 }
378 
379 
380 
381 /**
382  * zooms in by factor f in y
383  */
zoomInY(double f)384 void RS_GraphicView::zoomInY(double f) {
385 	factor.y*=f;
386 	offsetY=(int)((offsetY-getHeight()/2)*f)+getHeight()/2;
387 	adjustOffsetControls();
388 	adjustZoomControls();
389 	//    updateGrid();
390 	redraw();
391 }
392 
393 
394 
395 /**
396  * zooms out by factor f
397  */
zoomOut(double f,const RS_Vector & center)398 void RS_GraphicView::zoomOut(double f, const RS_Vector& center) {
399 	if (f<1.0e-6) {
400 		RS_DEBUG->print(RS_Debug::D_WARNING,
401 						"RS_GraphicView::zoomOut: invalid factor");
402 		return;
403 	}
404 	zoomIn(1/f, center);
405 }
406 
407 
408 
409 /**
410  * zooms out by factor f in x
411  */
zoomOutX(double f)412 void RS_GraphicView::zoomOutX(double f) {
413 	if (f<1.0e-6) {
414 		RS_DEBUG->print(RS_Debug::D_WARNING,
415 						"RS_GraphicView::zoomOutX: invalid factor");
416 		return;
417 	}
418 	factor.x/=f;
419 	offsetX=(int)(offsetX/f);
420 	adjustOffsetControls();
421 	adjustZoomControls();
422 	//    updateGrid();
423 	redraw();
424 }
425 
426 
427 
428 /**
429  * zooms out by factor f y
430  */
zoomOutY(double f)431 void RS_GraphicView::zoomOutY(double f) {
432 	if (f<1.0e-6) {
433 		RS_DEBUG->print(RS_Debug::D_WARNING,
434 						"RS_GraphicView::zoomOutY: invalid factor");
435 		return;
436 	}
437 	factor.y/=f;
438 	offsetY=(int)(offsetY/f);
439 	adjustOffsetControls();
440 	adjustZoomControls();
441 	//    updateGrid();
442 	redraw();
443 }
444 
445 /**
446  * performs autozoom
447  *
448  * @param axis include axis in zoom
449  * @param keepAspectRatio true: keep aspect ratio 1:1
450  *                        false: factors in x and y are stretched to the max
451  */
452 #include <iostream>
zoomAuto(bool axis,bool keepAspectRatio)453 void RS_GraphicView::zoomAuto(bool axis, bool keepAspectRatio) {
454 
455 	RS_DEBUG->print("RS_GraphicView::zoomAuto");
456 
457 
458 	if (container) {
459         container->calculateBorders();
460 
461 		double sx, sy;
462 		if (axis) {
463 			auto const dV = container->getMax() - container->getMin();
464 			sx = std::max(dV.x, 0.);
465 			sy = std::max(dV.y, 0.);
466 		} else {
467 			sx = container->getSize().x;
468 			sy = container->getSize().y;
469 		}
470 //		    std::cout<<" RS_GraphicView::zoomAuto("<<sx<<","<<sy<<")"<<std::endl;
471 //			std::cout<<" RS_GraphicView::zoomAuto("<<axis<<","<<keepAspectRatio<<")"<<std::endl;
472 
473 		double fx=1., fy=1.;
474 		unsigned short fFlags=0;
475 
476 		if (sx>RS_TOLERANCE) {
477 			fx = (getWidth()-borderLeft-borderRight) / sx;
478 		} else {
479 			fFlags += 1; //invalid x factor
480 		}
481 
482 		if (sy>RS_TOLERANCE) {
483 			fy = (getHeight()-borderTop-borderBottom) / sy;
484 		} else {
485 			fFlags += 2; //invalid y factor
486 		}
487 		//    std::cout<<"0: fx= "<<fx<<"\tfy="<<fy<<std::endl;
488 
489 		RS_DEBUG->print("f: %f/%f", fx, fy);
490 
491 		switch(fFlags){
492 		case 1:
493 			fx=fy;
494 			break;
495 		case 2:
496 			fy=fx;
497 			break;
498 		case 3:
499 			return; //do not do anything, invalid factors
500 		default:
501 			if (keepAspectRatio) {
502 				fx = fy = std::min(fx, fy);
503 			}
504 			//                break;
505 		}
506 		//    std::cout<<"1: fx= "<<fx<<"\tfy="<<fy<<std::endl;
507 
508 		RS_DEBUG->print("f: %f/%f", fx, fy);
509 		//exclude invalid factors
510 		fFlags=0;
511 		if (fx<RS_TOLERANCE||fx>RS_MAXDOUBLE) {
512 			fx=1.0;
513 			fFlags += 1;
514 		}
515 		if (fy<RS_TOLERANCE||fy>RS_MAXDOUBLE) {
516 			fy=1.0;
517 			fFlags += 2;
518 		}
519 		if(fFlags == 3 ) return;
520 		saveView();
521 		//        std::cout<<"2: fx= "<<fx<<"\tfy="<<fy<<std::endl;
522 		setFactorX(fx);
523 		setFactorY(fy);
524 
525 		RS_DEBUG->print("f: %f/%f", fx, fy);
526 
527 
528 		//        RS_DEBUG->print("adjustZoomControls");
529 		adjustZoomControls();
530 		//        RS_DEBUG->print("centerOffsetX");
531 		centerOffsetX();
532 		//        RS_DEBUG->print("centerOffsetY");
533 		centerOffsetY();
534 		//        RS_DEBUG->print("adjustOffsetControls");
535 		adjustOffsetControls();
536 		//        RS_DEBUG->print("updateGrid");
537 		//    updateGrid();
538 
539 		redraw();
540 	}
541 	RS_DEBUG->print("RS_GraphicView::zoomAuto OK");
542 }
543 
544 
545 
546 /**
547  * Shows previous view.
548  */
zoomPrevious()549 void RS_GraphicView::zoomPrevious() {
550 
551 	RS_DEBUG->print("RS_GraphicView::zoomPrevious");
552 
553 	if (container) {
554 		restoreView();
555 	}
556 }
557 
558 
559 
560 /**
561  * Saves the current view as previous view to which we can
562  * switch back later with @see restoreView().
563  */
saveView()564 void RS_GraphicView::saveView() {
565 	if(getGraphic()) getGraphic()->setModified(true);
566 	QDateTime noUpdateWindow=QDateTime::currentDateTime().addMSecs(-500);
567 	//do not update view within 500 milliseconds
568 	if(previousViewTime > noUpdateWindow) return;
569 	previousViewTime = QDateTime::currentDateTime();
570 	savedViews[savedViewIndex]=std::make_tuple(offsetX,offsetY,factor);
571 	savedViewIndex = (savedViewIndex+1)%savedViews.size();
572 	if(savedViewCount<savedViews.size()) savedViewCount++;
573 
574 	if(savedViewCount==1){
575 		emit previous_zoom_state(true);
576 	}
577 }
578 
579 
580 
581 /**
582  * Restores the view previously saved with
583  * @see saveView().
584  */
restoreView()585 void RS_GraphicView::restoreView() {
586 	if(savedViewCount == 0) return;
587 	savedViewCount --;
588 	if(savedViewCount==0){
589 		emit previous_zoom_state(false);
590 	}
591 	savedViewIndex = (savedViewIndex + savedViews.size() - 1)%savedViews.size();
592 
593 	offsetX = std::get<0>(savedViews[savedViewIndex]);
594 	offsetY = std::get<1>(savedViews[savedViewIndex]);
595 	factor = std::get<2>(savedViews[savedViewIndex]);
596 
597 	adjustOffsetControls();
598 	adjustZoomControls();
599 	//    updateGrid();
600 
601 	redraw();
602 }
603 
604 
605 /*	*
606  *	Function name:
607  *	Description:		Performs autozoom in Y axis only.
608  *	Author(s):			..., Claude Sylvain
609  *	Created:				?
610  *	Last modified:		23 July 2011
611  *
612  *	Parameters:			bool axis:
613  *								Axis in zoom.
614  *
615  *	Returns:				void
616  *	*/
617 
zoomAutoY(bool axis)618 void RS_GraphicView::zoomAutoY(bool axis) {
619 	if (container) {
620 		double visibleHeight = 0.0;
621 		double minY = RS_MAXDOUBLE;
622 		double maxY = RS_MINDOUBLE;
623 		bool noChange = false;
624 
625 		for(auto e: *container){
626 
627 			if (e->rtti()==RS2::EntityLine) {
628 				RS_Line* l = (RS_Line*)e;
629 				double x1, x2;
630 				x1 = toGuiX(l->getStartpoint().x);
631 				x2 = toGuiX(l->getEndpoint().x);
632 
633 				if (	((x1 > 0.0) && (x1 < (double) getWidth())) ||
634 						((x2 > 0.0) && (x2 < (double) getWidth())))
635 				{
636 					minY = std::min(minY, l->getStartpoint().y);
637 					minY = std::min(minY, l->getEndpoint().y);
638 					maxY = std::max(maxY, l->getStartpoint().y);
639 					maxY = std::max(maxY, l->getEndpoint().y);
640 				}
641 			}
642 		}
643 
644 		if (axis) {
645 			visibleHeight = std::max(maxY, 0.0) - std::min(minY, 0.0);
646 		} else {
647 			visibleHeight = maxY-minY;
648 		}
649 
650 		if (visibleHeight<1.0) {
651 			noChange = true;
652 		}
653 
654 		double fy = 1.0;
655 		if (visibleHeight>1.0e-6) {
656 			fy = (getHeight()-borderTop-borderBottom)
657 					/ visibleHeight;
658 			if (factor.y<0.000001) {
659 				noChange = true;
660 			}
661 		}
662 
663 		if (noChange==false) {
664 			setFactorY(fy);
665 			//centerOffsetY();
666 			offsetY = (int)((getHeight()-borderTop-borderBottom
667 							 - (visibleHeight*factor.y))/2.0
668 							- (minY*factor.y)) + borderBottom;
669 			adjustOffsetControls();
670 			adjustZoomControls();
671 			//    updateGrid();
672 
673 		}
674 		RS_DEBUG->print("Auto zoom y ok");
675 	}
676 }
677 
678 
679 
680 /**
681  * Zooms the area given by v1 and v2.
682  *
683  * @param keepAspectRatio true: keeps the aspect ratio 1:1
684  *                        false: zooms exactly the selected range to the
685  *                               current graphic view
686  */
zoomWindow(RS_Vector v1,RS_Vector v2,bool keepAspectRatio)687 void RS_GraphicView::zoomWindow(RS_Vector v1, RS_Vector v2,
688 								bool keepAspectRatio) {
689 
690 
691 
692 	double zoomX=480.0;    // Zoom for X-Axis
693 	double zoomY=640.0;    // Zoom for Y-Axis   (Set smaller one)
694 	int zoomBorder = 0;
695 
696 	// Switch left/right and top/bottom is necessary:
697 	if(v1.x>v2.x) {
698 		std::swap(v1.x,v2.x);
699 	}
700 	if(v1.y>v2.y) {
701 		std::swap(v1.y,v2.y);
702 	}
703 
704 	// Get zoom in X and zoom in Y:
705 	if(v2.x-v1.x>1.0e-6) {
706 		zoomX = getWidth() / (v2.x-v1.x);
707 	}
708 	if(v2.y-v1.y>1.0e-6) {
709 		zoomY = getHeight() / (v2.y-v1.y);
710 	}
711 
712 	// Take smaller zoom:
713 	if (keepAspectRatio) {
714 		if(zoomX<zoomY) {
715 			if(getWidth()!=0) {
716 				zoomX = zoomY = ((double)(getWidth()-2*zoomBorder)) /
717 						(double)getWidth()*zoomX;
718 			}
719 		} else {
720 			if(getHeight()!=0) {
721 				zoomX = zoomY = ((double)(getHeight()-2*zoomBorder)) /
722 						(double)getHeight()*zoomY;
723 			}
724 		}
725 	}
726 
727 	zoomX=fabs(zoomX);
728 	zoomY=fabs(zoomY);
729 
730 	// Borders in pixel after zoom
731 	int pixLeft  =(int)(v1.x*zoomX);
732 	int pixTop   =(int)(v2.y*zoomY);
733 	int pixRight =(int)(v2.x*zoomX);
734 	int pixBottom=(int)(v1.y*zoomY);
735 	if(  pixLeft == INT_MIN || pixLeft== INT_MAX ||
736 		 pixRight == INT_MIN || pixRight== INT_MAX ||
737 		 pixTop == INT_MIN || pixTop== INT_MAX ||
738 		 pixBottom == INT_MIN || pixBottom== INT_MAX ) {
739 		RS_DIALOGFACTORY->commandMessage("Requested zooming factor out of range. Zooming not changed");
740 		return;
741 	}
742 	saveView();
743 
744 	// Set new offset for zero point:
745 	offsetX = - pixLeft + (getWidth() -pixRight +pixLeft)/2;
746 	offsetY = - pixTop + (getHeight() -pixBottom +pixTop)/2;
747 	factor.x = zoomX;
748 	factor.y = zoomY;
749 
750 	adjustOffsetControls();
751 	adjustZoomControls();
752 	//    updateGrid();
753 
754 	redraw();
755 }
756 
757 
758 
759 /**
760  * Centers the point v1.
761  */
zoomPan(int dx,int dy)762 void RS_GraphicView::zoomPan(int dx, int dy) {
763 	//offsetX+=(int)toGuiDX(v1.x);
764 	//offsetY+=(int)toGuiDY(v1.y);
765 
766 	offsetX += dx;
767 	offsetY -= dy;
768 
769 	adjustOffsetControls();
770 	//adjustZoomControls();
771 	//    updateGrid();
772 
773 	redraw();
774 }
775 
776 
777 
778 /**
779  * Scrolls in the given direction.
780  */
zoomScroll(RS2::Direction direction)781 void RS_GraphicView::zoomScroll(RS2::Direction direction) {
782 	switch (direction) {
783 	case RS2::Up:
784 		offsetY-=50;
785 		break;
786 	case RS2::Down:
787 		offsetY+=50;
788 		break;
789 	case RS2::Right:
790 		offsetX+=50;
791 		break;
792 	case RS2::Left:
793 		offsetX-=50;
794 		break;
795 	}
796 	adjustOffsetControls();
797 	adjustZoomControls();
798 	//    updateGrid();
799 
800 	redraw();
801 }
802 
803 
804 
805 /**
806  * Zooms to page extends.
807  */
zoomPage()808 void RS_GraphicView::zoomPage() {
809 
810 	RS_DEBUG->print("RS_GraphicView::zoomPage");
811 	if (!container) {
812 		return;
813 	}
814 
815 	RS_Graphic* graphic = container->getGraphic();
816 	if (!graphic) {
817 		return;
818 	}
819 
820 	RS_Vector s = graphic->getPrintAreaSize()/graphic->getPaperScale();
821 
822 	double fx, fy;
823 
824 	if (s.x>RS_TOLERANCE) {
825 		fx = (getWidth()-borderLeft-borderRight) / s.x;
826 	} else {
827 		fx = 1.0;
828 	}
829 
830 	if (s.y>RS_TOLERANCE) {
831 		fy = (getHeight()-borderTop-borderBottom) / s.y;
832 	} else {
833 		fy = 1.0;
834 	}
835 
836 	RS_DEBUG->print("f: %f/%f", fx, fy);
837 
838 	fx = fy = std::min(fx, fy);
839 
840 	RS_DEBUG->print("f: %f/%f", fx, fy);
841 
842 	if (fx<RS_TOLERANCE) {
843 		fx=fy=1.0;
844 	}
845 
846 	setFactorX(fx);
847 	setFactorY(fy);
848 
849 	RS_DEBUG->print("f: %f/%f", fx, fy);
850 
851 	centerOffsetX();
852 	centerOffsetY();
853 	adjustOffsetControls();
854 	adjustZoomControls();
855 	//    updateGrid();
856 
857 	redraw();
858 }
859 
860 
861 
862 /**
863  * Draws the entities within the given range.
864  */
drawWindow_DEPRECATED(RS_Vector v1,RS_Vector v2)865 void RS_GraphicView::drawWindow_DEPRECATED(RS_Vector v1, RS_Vector v2) {
866 	RS_DEBUG->print("RS_GraphicView::drawWindow() begin");
867 	if (container) {
868 		for(auto se: *container){
869 			if (se->isInWindow(v1, v2)) {
870                 drawEntity(nullptr, se);
871 			}
872 		}
873 	}
874 	RS_DEBUG->print("RS_GraphicView::drawWindow() end");
875 }
876 
877 /**
878  * Draws the entities.
879  * This function can only be called from within the paint event
880  *
881  */
drawLayer1(RS_Painter * painter)882 void RS_GraphicView::drawLayer1(RS_Painter *painter) {
883 
884 	// drawing paper border:
885 	if (isPrintPreview()) {
886 		drawPaper(painter);
887 	}
888 
889 	// drawing meta grid:
890 	if (!isPrintPreview()) {
891 
892 		//increase grid point size on for DPI>96
893 		int dpiX = qApp->desktop()->logicalDpiX();
894 		//        DEBUG_HEADER
895 		//        RS_DEBUG->print(RS_Debug::D_ERROR, "dpiX=%d\n",dpiX);
896 		const RS_Pen penSaved=painter->getPen();
897 		if(dpiX>96) {
898 			RS_Pen pen=penSaved;
899 			pen.setWidth(RS2::Width01);
900 			painter->setPen(pen);
901 		}
902 
903 		//only drawGrid updates the grid layout (updatePointArray())
904 		drawMetaGrid(painter);
905 		//draw grid after metaGrid to avoid overwriting grid points by metaGrid lines
906 		//bug# 3430258
907 		drawGrid(painter);
908 
909 		if(dpiX>96) painter->setPen(penSaved);
910 
911 	}
912 
913 }
914 
915 
916 /*	*
917  *	Function name:
918  *	Description: 		Do the drawing, step 2/3.
919  *	Author(s):			..., Claude Sylvain
920  *	Created:				?
921  *	Last modified:		23 July 2011
922  *
923  *	Parameters:			RS_Painter *painter:
924  *								...
925  *
926  *	Returns:				void
927  *	*/
928 
drawLayer2(RS_Painter * painter)929 void RS_GraphicView::drawLayer2(RS_Painter *painter)
930 {
931 	drawEntity(painter, container);	//	Draw all entities.
932 
933 	//	If not in print preview, draw the absolute zero reference.
934 	//	----------------------------------------------------------
935 	if (!isPrintPreview())
936 		drawAbsoluteZero(painter);
937 }
938 
939 
drawLayer3(RS_Painter * painter)940 void RS_GraphicView::drawLayer3(RS_Painter *painter) {
941 	// drawing zero points:
942 	if (!isPrintPreview()) {
943 		drawRelativeZero(painter);
944 		drawOverlay(painter);
945 	}
946 }
947 
948 
949 /*	*
950  *	Function name:
951  *
952  *	Description:	- Sets the pen of the painter object to the suitable pen
953  *						  for the given entity.
954  *
955  *	Author(s):		..., Claude Sylvain
956  *	Created:			?
957  *	Last modified:	17 November 2011
958  *
959  *	Parameters:		RS_Painter *painter:
960  *							...
961  *
962  *						RS_Entity *e:
963  *							...
964  *
965  *	Returns:			void
966  */
967 
setPenForEntity(RS_Painter * painter,RS_Entity * e)968 void RS_GraphicView::setPenForEntity(RS_Painter *painter,RS_Entity *e)
969 {
970 	if (draftMode) {
971 		painter->setPen(RS_Pen(foreground,
972 							   RS2::Width00, RS2::SolidLine));
973 	}
974 
975 	// Getting pen from entity (or layer)
976 	RS_Pen pen = e->getPen(true);
977 
978 	int w = pen.getWidth();
979 	if (w<0) {
980 		w = 0;
981 	}
982 
983 	// - Scale pen width.
984 	// - By default pen width is not scaled on print and print preview.
985 	//   This is the standard (AutoCAD like) behaviour.
986 	// bug# 3437941
987 	// ------------------------------------------------------------
988 	if (!draftMode)
989 	{
990 		double	uf = 1.0;	// Unit factor.
991 		double	wf = 1.0;	// Width factor.
992 
993 		RS_Graphic* graphic = container->getGraphic();
994 
995         if (graphic)
996 		{
997 			uf = RS_Units::convert(1.0, RS2::Millimeter, graphic->getUnit());
998 
999 			if ((isPrinting() || isPrintPreview()) &&
1000 					graphic->getPaperScale() > RS_TOLERANCE )
1001 			{
1002 				if (scaleLineWidth)
1003 				{
1004 					wf = graphic->getVariableDouble("$DIMSCALE", 1.0);
1005 				}
1006 				else
1007 				{
1008 					wf = 1.0 / graphic->getPaperScale();
1009 				}
1010 
1011 			}
1012 		}
1013 
1014 		pen.setScreenWidth(toGuiDX(w / 100.0 * uf * wf));
1015 	}
1016 	else
1017 	{
1018 		//		pen.setWidth(RS2::Width00);
1019 		pen.setScreenWidth(0);
1020 	}
1021 
1022 	// prevent drawing with 1-width which is slow:
1023 	if (RS_Math::round(pen.getScreenWidth())==1) {
1024 		pen.setScreenWidth(0.0);
1025 	}
1026 
1027     // prevent background color on background drawing
1028     // and enhance visibility of black lines on dark backgrounds
1029     RS_Color    penColor {pen.getColor().stripFlags()};
1030     if ( penColor == background.stripFlags()
1031          || (penColor.toIntColor() == RS_Color::Black
1032              && penColor.colorDistance( background) < RS_Color::MinColorDistance)) {
1033         pen.setColor( foreground);
1034     }
1035 
1036 	if (!isPrinting() && !isPrintPreview())
1037 	{
1038 		// this entity is selected:
1039 		if (e->isSelected()) {
1040 			pen.setLineType(RS2::DotLine);
1041 			pen.setColor(selectedColor);
1042 		}
1043 
1044 		// this entity is highlighted:
1045 		if (e->isHighlighted()) {
1046 			pen.setColor(highlightedColor);
1047 		}
1048 	}
1049 
1050 	// deleting not drawing:
1051 	if (getDeleteMode()) {
1052 		pen.setColor(background);
1053 	}
1054 
1055 	painter->setPen(pen);
1056 }
1057 
1058 
1059 /**
1060  * Draws an entity. Might be recursively called e.g. for polylines.
1061  * If the class wide painter is nullptr a new painter will be created
1062  * and destroyed afterwards.
1063  *
1064  * @param patternOffset Offset of line pattern (used for connected
1065  *        lines e.g. in splines).
1066  * @param db Double buffering on (recommended) / off
1067  */
drawEntity(RS_Entity *,double &)1068 void RS_GraphicView::drawEntity(RS_Entity* /*e*/, double& /*patternOffset*/) {
1069 	RS_DEBUG->print("RS_GraphicView::drawEntity(RS_Entity*,patternOffset) not supported anymore");
1070 	// RVT_PORT this needs to be optimized
1071 	// One way to do is to send a RS2::RedrawSelected, then the draw routine will only draw all selected entities
1072 	// Dis-advantage is that we still need to iterate over all entities, but
1073 	// this might be very fast
1074 	// For now we just redraw the drawing until we are going to optimize drawing
1075 	redraw(RS2::RedrawDrawing);
1076 }
drawEntity(RS_Entity *)1077 void RS_GraphicView::drawEntity(RS_Entity* /*e*/ /*patternOffset*/) {
1078 	RS_DEBUG->print("RS_GraphicView::drawEntity(RS_Entity*,patternOffset) not supported anymore");
1079 	// RVT_PORT this needs to be optimized
1080 	// One way to do is to send a RS2::RedrawSelected, then the draw routine will only draw all selected entities
1081 	// Dis-advantage is that we still need to iterate over all entities, but
1082 	// this might be very fast
1083 	// For now we just redraw the drawing until we are going to optimize drawing
1084 	redraw(RS2::RedrawDrawing);
1085 }
drawEntity(RS_Painter * painter,RS_Entity * e)1086 void RS_GraphicView::drawEntity(RS_Painter *painter, RS_Entity* e) {
1087 	double offset(0.);
1088 	drawEntity(painter,e,offset);
1089 }
drawEntity(RS_Painter * painter,RS_Entity * e,double & patternOffset)1090 void RS_GraphicView::drawEntity(RS_Painter *painter, RS_Entity* e, double& patternOffset) {
1091 
1092 	// update is disabled:
1093     // given entity is nullptr:
1094 	if (!e) {
1095 		return;
1096 	}
1097 
1098 	// entity is not visible:
1099 	if (!e->isVisible()) {
1100 		return;
1101 	}
1102 	if( isPrintPreview() || isPrinting() ) {
1103 		// do not draw construction layer on print preview or print
1104 		if( ! e->isPrint()
1105 				||  e->isConstruction())
1106         return;
1107 	}
1108 
1109     // test if the entity is in the viewport
1110     if (!isPrinting() &&
1111         e->rtti() != RS2::EntityGraphic &&
1112         e->rtti() != RS2::EntityLine &&
1113        (toGuiX(e->getMax().x)<0 || toGuiX(e->getMin().x)>getWidth() ||
1114         toGuiY(e->getMin().y)<0 || toGuiY(e->getMax().y)>getHeight())) {
1115         return;
1116     }
1117 
1118 	// set pen (color):
1119 	setPenForEntity(painter, e );
1120 
1121 	//RS_DEBUG->print("draw plain");
1122 	if (isDraftMode()) {
1123         switch(e->rtti()){
1124         case RS2::EntityMText:
1125         case RS2::EntityText:
1126             painter->drawRect(toGui(e->getMin()), toGui(e->getMax()));
1127             break;
1128         case RS2::EntityImage:
1129             // all images as rectangles:
1130             painter->drawRect(toGui(e->getMin()), toGui(e->getMax()));
1131             break;
1132         case RS2::EntityHatch:
1133             //skip hatches
1134             break;
1135         default:
1136             drawEntityPlain(painter, e, patternOffset);
1137         }
1138 	} else {
1139 		drawEntityPlain(painter, e, patternOffset);
1140 	}
1141 
1142 	// draw reference points:
1143 	if (e->isSelected() && !(isPrinting() || isPrintPreview())) {
1144 		if (!e->isParentSelected()) {
1145 			RS_VectorSolutions const& s = e->getRefPoints();
1146 
1147 			for (size_t i=0; i<s.getNumber(); ++i) {
1148 				int sz = -1;
1149 				RS_Color col = handleColor;
1150 				if (i == 0) {
1151 					col = startHandleColor;
1152 				}
1153 				else if (i == s.getNumber() - 1) {
1154 					col = endHandleColor;
1155 				}
1156 				if (getDeleteMode()) {
1157 					painter->drawHandle(toGui(s.get(i)), background, sz);
1158 				} else {
1159 					painter->drawHandle(toGui(s.get(i)), col, sz);
1160 				}
1161 			}
1162 		}
1163 	}
1164 
1165 	//RS_DEBUG->print("draw plain OK");
1166 
1167 
1168 	//RS_DEBUG->print("RS_GraphicView::drawEntity() end");
1169 }
1170 
1171 
1172 /**
1173  * Draws an entity.
1174  * The painter must be initialized and all the attributes (pen) must be set.
1175  */
drawEntityPlain(RS_Painter * painter,RS_Entity * e,double & patternOffset)1176 void RS_GraphicView::drawEntityPlain(RS_Painter *painter, RS_Entity* e, double& patternOffset) {
1177 	if (!e) {
1178 		return;
1179 	}
1180 
1181 	if (!e->isContainer() && (e->isSelected()!=painter->shouldDrawSelected())) {
1182 		return;
1183 	}
1184 
1185 	e->draw(painter, this, patternOffset);
1186 
1187 }
drawEntityPlain(RS_Painter * painter,RS_Entity * e)1188 void RS_GraphicView::drawEntityPlain(RS_Painter *painter, RS_Entity* e) {
1189 	if (!e) {
1190 		return;
1191 	}
1192 
1193 	if (!e->isContainer() && (e->isSelected()!=painter->shouldDrawSelected())) {
1194 		return;
1195 	}
1196 	double patternOffset(0.);
1197 	e->draw(painter, this, patternOffset);
1198 }
1199 /**
1200  * Deletes an entity with the background color.
1201  * Might be recursively called e.g. for polylines.
1202  */
deleteEntity(RS_Entity * e)1203 void RS_GraphicView::deleteEntity(RS_Entity* e) {
1204 
1205 	// RVT_PORT When we delete a single entity, we can do this but we need to remove this then also from containerEntities
1206 	RS_DEBUG->print("RS_GraphicView::deleteEntity will for now redraw the whole screen instead of just deleting the entity");
1207 	setDeleteMode(true);
1208 	drawEntity(e);
1209 	setDeleteMode(false);
1210 	redraw(RS2::RedrawDrawing);
1211 }
1212 
1213 
1214 
1215 
1216 /**
1217  * @return Pointer to the static pattern struct that belongs to the
1218  * given pattern type or nullptr.
1219  */
getPattern(RS2::LineType t)1220 const RS_LineTypePattern* RS_GraphicView::getPattern(RS2::LineType t) {
1221 	switch (t) {
1222 	case RS2::SolidLine:
1223 		return &RS_LineTypePattern::patternSolidLine;
1224 		break;
1225 
1226 	case RS2::DotLine:
1227 		return &RS_LineTypePattern::patternDotLine;
1228 		break;
1229 	case RS2::DotLineTiny:
1230 		return &RS_LineTypePattern::patternDotLineTiny;
1231 		break;
1232 	case RS2::DotLine2:
1233 		return &RS_LineTypePattern::patternDotLine2;
1234 		break;
1235 	case RS2::DotLineX2:
1236 		return &RS_LineTypePattern::patternDotLineX2;
1237 		break;
1238 
1239 	case RS2::DashLine:
1240 		return &RS_LineTypePattern::patternDashLine;
1241 		break;
1242 	case RS2::DashLineTiny:
1243 		return &RS_LineTypePattern::patternDashLineTiny;
1244 		break;
1245 	case RS2::DashLine2:
1246 		return &RS_LineTypePattern::patternDashLine2;
1247 		break;
1248 	case RS2::DashLineX2:
1249 		return &RS_LineTypePattern::patternDashLineX2;
1250 		break;
1251 
1252 	case RS2::DashDotLine:
1253 		return &RS_LineTypePattern::patternDashDotLine;
1254 		break;
1255 	case RS2::DashDotLineTiny:
1256 		return &RS_LineTypePattern::patternDashDotLineTiny;
1257 		break;
1258 	case RS2::DashDotLine2:
1259 		return &RS_LineTypePattern::patternDashDotLine2;
1260 		break;
1261 	case RS2::DashDotLineX2:
1262 		return &RS_LineTypePattern::patternDashDotLineX2;
1263 		break;
1264 
1265 	case RS2::DivideLine:
1266 		return &RS_LineTypePattern::patternDivideLine;
1267 		break;
1268 	case RS2::DivideLineTiny:
1269 		return &RS_LineTypePattern::patternDivideLineTiny;
1270 		break;
1271 	case RS2::DivideLine2:
1272 		return &RS_LineTypePattern::patternDivideLine2;
1273 		break;
1274 	case RS2::DivideLineX2:
1275 		return &RS_LineTypePattern::patternDivideLineX2;
1276 		break;
1277 
1278 	case RS2::CenterLine:
1279 		return &RS_LineTypePattern::patternCenterLine;
1280 		break;
1281 	case RS2::CenterLineTiny:
1282 		return &RS_LineTypePattern::patternCenterLineTiny;
1283 		break;
1284 	case RS2::CenterLine2:
1285 		return &RS_LineTypePattern::patternCenterLine2;
1286 		break;
1287 	case RS2::CenterLineX2:
1288 		return &RS_LineTypePattern::patternCenterLineX2;
1289 		break;
1290 
1291 	case RS2::BorderLine:
1292 		return &RS_LineTypePattern::patternBorderLine;
1293 		break;
1294 	case RS2::BorderLineTiny:
1295 		return &RS_LineTypePattern::patternBorderLineTiny;
1296 		break;
1297 	case RS2::BorderLine2:
1298 		return &RS_LineTypePattern::patternBorderLine2;
1299 		break;
1300 	case RS2::BorderLineX2:
1301 		return &RS_LineTypePattern::patternBorderLineX2;
1302 		break;
1303 
1304 	case RS2::LineByLayer:
1305 		return &RS_LineTypePattern::patternBlockLine;
1306 		break;
1307 	case RS2::LineByBlock:
1308 		return &RS_LineTypePattern::patternBlockLine;
1309 		break;
1310 	default:
1311 		break;
1312 	}
1313     return nullptr;
1314 }
1315 
1316 
1317 
1318 /**
1319  * This virtual method can be overwritten to draw the absolute
1320  * zero. It's called from within drawIt(). The default implementation
1321  * draws a simple red cross on the zero of the sheet
1322  * This function can ONLY be called from within a paintEvent because it will
1323  * use the painter
1324  *
1325  * @see drawIt()
1326  */
drawAbsoluteZero(RS_Painter * painter)1327 void RS_GraphicView::drawAbsoluteZero(RS_Painter *painter) {
1328 
1329     int const zr = 20;
1330 
1331     RS_Pen p(RS_Color(255,0,0), RS2::Width00, RS2::SolidLine);
1332 	p.setScreenWidth(0);
1333 	painter->setPen(p);
1334 	//painter->setBrush(Qt::NoBrush);
1335     auto vp=toGui(RS_Vector(0,0));
1336     if( vp.x +zr<0 || vp.x-zr>getWidth()) return;
1337     if( vp.y +zr<0 || vp.y-zr>getHeight()) return;
1338 
1339     painter->drawLine(RS_Vector(vp.x-zr, vp.y),
1340                       RS_Vector(vp.x+zr, vp.y)
1341                       );
1342     painter->drawLine(RS_Vector(vp.x, vp.y-zr),
1343                       RS_Vector(vp.x, vp.y+zr)
1344                       );
1345 }
1346 
1347 /**
1348  * This virtual method can be overwritten to draw the relative
1349  * zero point. It's called from within drawIt(). The default implementation
1350  * draws a simple red round zero point. This is the point that was last created by the user, end of a line for example
1351  * This function can ONLY be called from within a paintEvent because it will
1352  * use the painter
1353  *
1354  * @see drawIt()
1355  */
drawRelativeZero(RS_Painter * painter)1356 void RS_GraphicView::drawRelativeZero(RS_Painter *painter) {
1357 
1358     if (!relativeZero.valid) {
1359 		return;
1360 	}
1361 
1362     RS_Pen p(RS_Color(255,0,0), RS2::Width00, RS2::SolidLine);
1363 	p.setScreenWidth(0);
1364 	painter->setPen(p);
1365 
1366     int const zr=5;
1367     auto vp=toGui(relativeZero);
1368     if( vp.x +zr<0 || vp.x-zr>getWidth()) return;
1369     if( vp.y +zr<0 || vp.y-zr>getHeight()) return;
1370 
1371     painter->drawLine(RS_Vector(vp.x-zr, vp.y),
1372                       RS_Vector(vp.x+zr, vp.y)
1373                       );
1374     painter->drawLine(RS_Vector(vp.x, vp.y-zr),
1375                       RS_Vector(vp.x, vp.y+zr)
1376                       );
1377 
1378     painter->drawCircle(vp, 5);
1379 }
1380 
1381 
1382 
1383 /**
1384  * Draws the paper border (for print previews).
1385  * This function can ONLY be called from within a paintEvent because it will
1386  * use the painter
1387  *
1388  * @see drawIt()
1389  */
drawPaper(RS_Painter * painter)1390 void RS_GraphicView::drawPaper(RS_Painter *painter) {
1391 
1392 	if (!container) {
1393 		return;
1394 	}
1395 
1396 	RS_Graphic* graphic = container->getGraphic();
1397 	if (graphic->getPaperScale()<1.0e-6) {
1398 		return;
1399 	}
1400 
1401 	// draw paper:
1402 	// RVT_PORT rewritten from     painter->setPen(Qt::gray);
1403 	painter->setPen(QColor(Qt::gray));
1404 
1405 	RS_Vector pinsbase = graphic->getPaperInsertionBase();
1406 	RS_Vector printAreaSize = graphic->getPrintAreaSize();
1407 	double scale = graphic->getPaperScale();
1408 
1409 	RS_Vector v1 = toGui((RS_Vector(0,0)-pinsbase)/scale);
1410 	RS_Vector v2 = toGui((printAreaSize-pinsbase)/scale);
1411 
1412 	int marginLeft = (int)(graphic->getMarginLeftInUnits() * factor.x / scale);
1413 	int marginTop = (int)(graphic->getMarginTopInUnits() * factor.y / scale);
1414 	int marginRight = (int)(graphic->getMarginRightInUnits() * factor.x / scale);
1415 	int marginBottom = (int)(graphic->getMarginBottomInUnits() * factor.y / scale);
1416 
1417 	int printAreaW = (int)(v2.x-v1.x);
1418 	int printAreaH = (int)(v2.y-v1.y);
1419 
1420 	int paperX1 = (int)v1.x;
1421 	int paperY1 = (int)v1.y;
1422 	// Don't show margins between neighbor pages.
1423 	int paperW = printAreaW + marginLeft + marginRight;
1424 	int paperH = printAreaH - marginTop - marginBottom;
1425 
1426 	int numX = graphic->getPagesNumHoriz();
1427 	int numY = graphic->getPagesNumVert();
1428 
1429 	// gray background:
1430 	painter->fillRect(0,0, getWidth(), getHeight(),
1431 					  RS_Color(200,200,200));
1432 
1433 	// shadow:
1434 	painter->fillRect(paperX1+6, paperY1+6, paperW, paperH,
1435 					  RS_Color(64,64,64));
1436 
1437 	// border:
1438 	painter->fillRect(paperX1, paperY1, paperW, paperH,
1439 					  RS_Color(64,64,64));
1440 
1441 	// paper:
1442 	painter->fillRect(paperX1+1, paperY1-1, paperW-2, paperH+2,
1443 					  RS_Color(180,180,180));
1444 
1445 	// print area:
1446 	painter->fillRect(paperX1+1+marginLeft, paperY1-1-marginBottom,
1447 					  printAreaW-2, printAreaH+2,
1448 					  RS_Color(255,255,255));
1449 
1450 	// don't paint boundaries if zoom is to small
1451 	if (qMin(fabs(printAreaW/numX), fabs(printAreaH/numY)) > 2) {
1452 		// boundaries between pages:
1453 		for (int pX = 1; pX < numX; pX++) {
1454 			double offset = ((double)printAreaW*pX)/numX;
1455 			painter->fillRect(paperX1+marginLeft+offset, paperY1,
1456 							  1, paperH,
1457 							  RS_Color(64,64,64));
1458 		}
1459 		for (int pY = 1; pY < numY; pY++) {
1460 			double offset = ((double)printAreaH*pY)/numY;
1461 			painter->fillRect(paperX1, paperY1-marginBottom+offset,
1462 							  paperW, 1,
1463 							  RS_Color(64,64,64));
1464 		}
1465 	}
1466 }
1467 
1468 
1469 /**
1470  * Draws the grid.
1471  *
1472  * @see drawIt()
1473  */
drawGrid(RS_Painter * painter)1474 void RS_GraphicView::drawGrid(RS_Painter *painter) {
1475 
1476 	if (!(grid && isGridOn())) return;
1477 
1478 
1479 	// draw grid:
1480 	//painter->setPen(Qt::gray);
1481 	painter->setPen(gridColor);
1482 
1483 	//grid->updatePointArray();
1484 	auto const& pts = grid->getPoints();
1485 	for(auto const& v: pts){
1486 		painter->drawGridPoint(toGui(v));
1487 	}
1488 
1489 	// draw grid info:
1490 	//painter->setPen(Qt::white);
1491 	QString info = grid->getInfo();
1492 	//info = QString("%1 / %2")
1493 	//       .arg(grid->getSpacing())
1494 	//       .arg(grid->getMetaSpacing());
1495 
1496 	updateGridStatusWidget(info);
1497 
1498 
1499 }
1500 
1501 
1502 
1503 /**
1504  * Draws the meta grid.
1505  *
1506  * @see drawIt()
1507  */
drawMetaGrid(RS_Painter * painter)1508 void RS_GraphicView::drawMetaGrid(RS_Painter *painter) {
1509 
1510 	if (!(grid && isGridOn()) /*|| grid->getMetaSpacing()<0.0*/) {
1511 		return;
1512 	}
1513 
1514 	//draw grid after metaGrid to avoid overwriting grid points by metaGrid lines
1515 	//bug# 3430258
1516 	grid->updatePointArray();
1517 	RS_Pen pen(metaGridColor,
1518 			   RS2::Width00,
1519 			   RS2::DotLine);
1520 	painter->setPen(pen);
1521 
1522 	RS_Vector dv=grid->getMetaGridWidth().scale(factor);
1523 	double dx=fabs(dv.x);
1524 	double dy=fabs(dv.y); //potential bug, need to recover metaGrid.width
1525 	// draw meta grid:
1526 	auto mx = grid->getMetaX();
1527 	for(auto const& x: mx){
1528 		painter->drawLine(RS_Vector(toGuiX(x), 0),
1529 						  RS_Vector(toGuiX(x), getHeight()));
1530 		if(grid->isIsometric()){
1531 			painter->drawLine(RS_Vector(toGuiX(x)+0.5*dx, 0),
1532 							  RS_Vector(toGuiX(x)+0.5*dx, getHeight()));
1533 		}
1534 	}
1535 	auto my = grid->getMetaY();
1536 	if(grid->isIsometric()){//isometric metaGrid
1537 		dx=fabs(dx);
1538 		dy=fabs(dy);
1539 		if(!my.size()|| dx<1||dy<1) return;
1540 		RS_Vector baseMeta(toGui(RS_Vector(mx[0],my[0])));
1541 		// x-x0=k*dx, x-remainder(x-x0,dx)
1542 		RS_Vector vp0(-remainder(-baseMeta.x,dx)-dx,getHeight()-remainder(getHeight()-baseMeta.y,dy)+dy);
1543 		RS_Vector vp1(vp0);
1544 		RS_Vector vp2(getWidth()-remainder(getWidth()-baseMeta.x,dx)+dx,vp0.y);
1545 		RS_Vector vp3(vp2);
1546 		int cmx = round((vp2.x - vp0.x)/dx);
1547 		int cmy = round((vp0.y +remainder(-baseMeta.y,dy)+dy)/dy);
1548 		for(int i=cmx+cmy+2;i>=0;i--){
1549 			if ( i <= cmx ) {
1550 				vp0.x += dx;
1551 				vp2.y -= dy;
1552 			}else{
1553 				vp0.y -= dy;
1554 				vp2.x -= dx;
1555 			}
1556 			if ( i <= cmy ) {
1557 				vp1.y -= dy;
1558 				vp3.x -= dx;
1559 			}else{
1560 				vp1.x += dx;
1561 				vp3.y -= dy;
1562 			}
1563 			painter->drawLine(vp0,vp1);
1564 			painter->drawLine(vp2,vp3);
1565 		}
1566 
1567 	}else{//orthogonal
1568 
1569 		for(auto const& y: my){
1570 			painter->drawLine(RS_Vector(0, toGuiY(y)),
1571 							  RS_Vector(getWidth(), toGuiY(y)));
1572 		}
1573 	}
1574 
1575 
1576 }
1577 
drawOverlay(RS_Painter * painter)1578 void RS_GraphicView::drawOverlay(RS_Painter *painter)
1579 {
1580     double patternOffset(0.);
1581 
1582     foreach (auto ec, overlayEntities)
1583     {
1584         foreach (auto e, ec->getEntityList())
1585         {
1586             setPenForEntity(painter, e);
1587             e->draw(painter, this, patternOffset);
1588         }
1589     }
1590 }
1591 
getSnapRestriction() const1592 RS2::SnapRestriction RS_GraphicView::getSnapRestriction() const
1593 {
1594 	return defaultSnapRes;
1595 }
1596 
getDefaultSnapMode() const1597 RS_SnapMode RS_GraphicView::getDefaultSnapMode() const
1598 {
1599 	return defaultSnapMode;
1600 }
1601 
1602 /**
1603  * Sets the default snap mode used by newly created actions.
1604  */
setDefaultSnapMode(RS_SnapMode sm)1605 void RS_GraphicView::setDefaultSnapMode(RS_SnapMode sm) {
1606 	defaultSnapMode = sm;
1607 	if (eventHandler) {
1608 		eventHandler->setSnapMode(sm);
1609 	}
1610 }
1611 
1612 /**
1613  * Sets a snap restriction (e.g. orthogonal).
1614  */
setSnapRestriction(RS2::SnapRestriction sr)1615 void RS_GraphicView::setSnapRestriction(RS2::SnapRestriction sr) {
1616 	defaultSnapRes = sr;
1617 
1618 	if (eventHandler) {
1619 		eventHandler->setSnapRestriction(sr);
1620 	}
1621 }
1622 
1623 /**
1624  * Translates a vector in real coordinates to a vector in screen coordinates.
1625  */
toGui(RS_Vector v) const1626 RS_Vector RS_GraphicView::toGui(RS_Vector v) const{
1627 	return RS_Vector(toGuiX(v.x), toGuiY(v.y));
1628 }
1629 
1630 /**
1631  * Translates a real coordinate in X to a screen coordinate X.
1632  * @param visible Pointer to a boolean which will contain true
1633  * after the call if the coordinate is within the visible range.
1634  */
toGuiX(double x) const1635 double RS_GraphicView::toGuiX(double x) const{
1636 	return x*factor.x + offsetX;
1637 }
1638 
1639 
1640 
1641 /**
1642  * Translates a real coordinate in Y to a screen coordinate Y.
1643  */
toGuiY(double y) const1644 double RS_GraphicView::toGuiY(double y) const{
1645 	return -y*factor.y + getHeight() - offsetY;
1646 }
1647 
1648 
1649 
1650 /**
1651  * Translates a real coordinate distance to a screen coordinate distance.
1652  */
toGuiDX(double d) const1653 double RS_GraphicView::toGuiDX(double d) const{
1654 	return d*factor.x;
1655 }
1656 
1657 
1658 
1659 /**
1660  * Translates a real coordinate distance to a screen coordinate distance.
1661  */
toGuiDY(double d) const1662 double RS_GraphicView::toGuiDY(double d) const{
1663 	return d*factor.y;
1664 }
1665 
1666 
1667 
1668 /**
1669  * Translates a vector in screen coordinates to a vector in real coordinates.
1670  */
toGraph(RS_Vector v) const1671 RS_Vector RS_GraphicView::toGraph(RS_Vector v) const{
1672 	return RS_Vector(toGraphX(RS_Math::round(v.x)),
1673 					 toGraphY(RS_Math::round(v.y)));
1674 }
1675 
1676 
1677 
1678 /**
1679  * Translates two screen coordinates to a vector in real coordinates.
1680  */
toGraph(int x,int y) const1681 RS_Vector RS_GraphicView::toGraph(int x, int y) const{
1682 	return RS_Vector(toGraphX(x), toGraphY(y));
1683 }
1684 
1685 
1686 /**
1687  * Translates a screen coordinate in X to a real coordinate X.
1688  */
toGraphX(int x) const1689 double RS_GraphicView::toGraphX(int x) const{
1690 	return (x - offsetX)/factor.x;
1691 }
1692 
1693 
1694 
1695 /**
1696  * Translates a screen coordinate in Y to a real coordinate Y.
1697  */
toGraphY(int y) const1698 double RS_GraphicView::toGraphY(int y) const{
1699 	return -(y - getHeight() + offsetY)/factor.y;
1700 }
1701 
1702 
1703 
1704 /**
1705  * Translates a screen coordinate distance to a real coordinate distance.
1706  */
toGraphDX(int d) const1707 double RS_GraphicView::toGraphDX(int d) const{
1708 	return d/factor.x;
1709 }
1710 
1711 
1712 
1713 /**
1714  * Translates a screen coordinate distance to a real coordinate distance.
1715  */
toGraphDY(int d) const1716 double RS_GraphicView::toGraphDY(int d) const{
1717 	return d/factor.y;
1718 }
1719 
1720 
1721 /**
1722  * Sets the relative zero coordinate (if not locked)
1723  * without deleting / drawing the point.
1724  */
setRelativeZero(const RS_Vector & pos)1725 void RS_GraphicView::setRelativeZero(const RS_Vector& pos) {
1726 	if (relativeZeroLocked==false) {
1727 		relativeZero = pos;
1728         emit relative_zero_changed(pos);
1729 	}
1730 }
1731 
1732 
1733 
1734 /**
1735  * Sets the relative zero coordinate, deletes the old position
1736  * on the screen and draws the new one.
1737  */
moveRelativeZero(const RS_Vector & pos)1738 void RS_GraphicView::moveRelativeZero(const RS_Vector& pos) {
1739 	setRelativeZero(pos);
1740 	redraw(RS2::RedrawGrid);
1741 }
1742 
1743 
1744 /**
1745  * Gets the specified overlay container.
1746  */
getOverlayContainer(RS2::OverlayGraphics position)1747 RS_EntityContainer* RS_GraphicView::getOverlayContainer(RS2::OverlayGraphics position)
1748 {
1749 	if (overlayEntities[position]) {
1750 		return overlayEntities[position];
1751 	}
1752     overlayEntities[position]=new RS_EntityContainer(nullptr);
1753 
1754 	return overlayEntities[position];
1755 
1756 }
1757 
getGrid() const1758 RS_Grid* RS_GraphicView::getGrid() const{
1759 	return grid.get();
1760 }
1761 
getEventHandler() const1762 RS_EventHandler* RS_GraphicView::getEventHandler() const{
1763     return eventHandler;
1764 }
1765 
setBackground(const RS_Color & bg)1766 void RS_GraphicView::setBackground(const RS_Color& bg) {
1767 	background = bg;
1768 
1769     RS_Color black(0,0,0);
1770     if (black.colorDistance( bg) >= RS_Color::MinColorDistance) {
1771         foreground = black;
1772     }
1773     else {
1774         foreground = RS_Color(255,255,255);
1775     }
1776 }
1777 
setBorders(int left,int top,int right,int bottom)1778 void RS_GraphicView::setBorders(int left, int top, int right, int bottom) {
1779 	borderLeft = left;
1780 	borderTop = top;
1781 	borderRight = right;
1782 	borderBottom = bottom;
1783 }
1784 
getGraphic() const1785 RS_Graphic* RS_GraphicView::getGraphic() const{
1786 	if (container && container->rtti()==RS2::EntityGraphic) {
1787 		return static_cast<RS_Graphic *>(container);
1788 	} else {
1789 		return nullptr;
1790 	}
1791 }
1792 
getContainer() const1793 RS_EntityContainer* RS_GraphicView::getContainer() const{
1794 	return container;
1795 }
1796 
setFactor(double f)1797 void RS_GraphicView::setFactor(double f) {
1798 	setFactorX(f);
1799 	setFactorY(f);
1800 }
1801 
getFactor() const1802 RS_Vector RS_GraphicView::getFactor() const{
1803 	return factor;
1804 }
getBorderLeft() const1805 int RS_GraphicView::getBorderLeft() const{
1806 	return borderLeft;
1807 }
getBorderTop() const1808 int RS_GraphicView::getBorderTop() const{
1809 	return borderTop;
1810 }
getBorderRight() const1811 int RS_GraphicView::getBorderRight() const{
1812 	return borderRight;
1813 }
getBorderBottom() const1814 int RS_GraphicView::getBorderBottom() const{
1815 	return borderBottom;
1816 }
1817 
freezeZoom(bool freeze)1818 void RS_GraphicView::freezeZoom(bool freeze) {
1819 	zoomFrozen=freeze;
1820 }
isZoomFrozen() const1821 bool RS_GraphicView::isZoomFrozen() const{
1822 	return zoomFrozen;
1823 }
setOffsetX(int ox)1824 void RS_GraphicView::setOffsetX(int ox) {
1825 	offsetX = ox;
1826 }
setOffsetY(int oy)1827 void RS_GraphicView::setOffsetY(int oy) {
1828 	offsetY = oy;
1829 }
getOffsetX() const1830 int RS_GraphicView::getOffsetX() const{
1831 	return offsetX;
1832 }
getOffsetY() const1833 int RS_GraphicView::getOffsetY() const{
1834 	return offsetY;
1835 }
lockRelativeZero(bool lock)1836 void RS_GraphicView::lockRelativeZero(bool lock) {
1837 	relativeZeroLocked=lock;
1838 }
1839 
isRelativeZeroLocked() const1840 bool RS_GraphicView::isRelativeZeroLocked() const{
1841 	return relativeZeroLocked;
1842 }
1843 
getRelativeZero() const1844 RS_Vector const& RS_GraphicView::getRelativeZero() const{
1845 	return relativeZero;
1846 }
1847 
setPrintPreview(bool pv)1848 void RS_GraphicView::setPrintPreview(bool pv) {
1849 	printPreview = pv;
1850 }
1851 
isPrintPreview() const1852 bool RS_GraphicView::isPrintPreview() const{
1853 	return printPreview;
1854 }
1855 
setPrinting(bool p)1856 void RS_GraphicView::setPrinting(bool p) {
1857 	printing = p;
1858 }
1859 
isPrinting() const1860 bool RS_GraphicView::isPrinting() const{
1861 	return printing;
1862 }
1863 
isDraftMode() const1864 bool RS_GraphicView::isDraftMode() const{
1865 	return draftMode;
1866 }
1867 
setDraftMode(bool dm)1868 void RS_GraphicView::setDraftMode(bool dm) {
1869 	draftMode=dm;
1870 }
1871 
isCleanUp(void) const1872 bool RS_GraphicView::isCleanUp(void) const
1873 {
1874 	return m_bIsCleanUp;
1875 }
1876 
isPanning() const1877 bool RS_GraphicView::isPanning() const {
1878     return panning;
1879 }
1880 
setPanning(bool state)1881 void RS_GraphicView::setPanning(bool state) {
1882     panning = state;
1883 }
1884