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