]> Shamusworld >> Repos - architektonas/blob - src/widgets/qg_graphicview.cpp
d885f8a0a820a59c2f24def12d029d3d97cf9f61
[architektonas] / src / widgets / qg_graphicview.cpp
1 // qg_graphicview.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/10/2010  Added this text. :-)
13 //
14
15 #include "qg_graphicview.h"
16
17 #include "rs_actiondefault.h"
18 #include "rs_actionzoomin.h"
19 #include "rs_actionzoompan.h"
20 #include "rs_actionzoomscroll.h"
21 #include "rs_actionmodifydelete.h"
22 #include "rs_actionselectsingle.h"
23 #include "rs_dialogfactory.h"
24 #include "graphicview.h"
25 #include "rs_preview.h"
26 #include "drawing.h"
27 #include "settings.h"
28 #include "rs_system.h"
29 #include "rs_patternlist.h"
30 #include "cadtoolbar.h"
31 #include "paintintf.h"
32 #include "qg_dialogfactory.h"
33
34 #define QG_SCROLLMARGIN 400
35
36 /**
37  * Constructor.
38  */
39 QG_GraphicView::QG_GraphicView(QWidget * parent, const char */*name*/, Qt::WindowFlags f):
40         QWidget(parent, f), GraphicView()//, refCount(0)
41 {
42         RS_DEBUG->print("QG_GraphicView::QG_GraphicView(parent, name, flags)...");
43         CommonInitialization();
44 }
45
46 /**
47  * Constructor II.
48  */
49 QG_GraphicView::QG_GraphicView(RS_Document * doc, QWidget * parent)
50 {
51 //      QG_GraphicView(parent, "graphicview");
52         CommonInitialization();
53
54         RS_DEBUG->print("QG_GraphicView::QG_GraphicView(doc, parent)...");
55         //document = doc;
56         RS_DEBUG->print("  Setting Container...");
57
58         if (doc)
59                 setContainer(doc);
60
61         RS_DEBUG->print("  container set.");
62         setFactorX(4.0);
63         setFactorY(4.0);
64         setOffset(50, 50);
65         setBorders(10, 10, 10, 10);
66
67         if (doc)
68                 setDefaultAction(new RS_ActionDefault(*doc, *this));
69 }
70
71 void QG_GraphicView::CommonInitialization(void)
72 {
73         setBackground(background);
74         buffer = NULL;
75         lastWidth = 0;
76         lastHeight = 0;
77 //hrm.
78 painter = NULL;
79
80         RS_DEBUG->print("--> Setting up layout...");
81         layout = new QGridLayout(this);
82         layout->setColumnStretch(0, 1);
83         layout->setColumnStretch(1, 0);
84         layout->setColumnStretch(2, 0);
85         layout->setRowStretch(0, 1);
86         layout->setRowStretch(1, 0);
87
88 /*
89 void QGridLayout::addMultiCellWidget ( QWidget * w, int fromRow, int toRow, int fromCol, int toCol, int alignment = 0 )
90 Adds the widget w to the cell grid, spanning multiple rows/columns. The cell will span from fromRow, fromCol to toRow, toCol.
91
92 Alignment is specified by alignment, which is a bitwise OR of Qt::AlignmentFlags values. The default alignment is 0, which means that the widget fills the entire cell.
93
94 A non-zero alignment indicates that the widget should not grow to fill the available space but should be sized according to sizeHint().
95 */
96         RS_DEBUG->print("--> Creating hScrollBar...");
97         hScrollBar = new QG_ScrollBar(Qt::Horizontal, this);
98 //    hScrollBar->setLineStep(50);
99         hScrollBar->setSingleStep(50);
100 //    layout->addMultiCellWidget(hScrollBar, 1, 1, 0, 0);
101         layout->addWidget(hScrollBar, 1, 0);
102 //    layout->addRowSpacing(1, hScrollBar->sizeHint().height());
103         layout->addItem(new QSpacerItem(0, hScrollBar->sizeHint().height()), 1, 0);
104
105         RS_DEBUG->print("--> Creating vScrollBar...");
106         vScrollBar = new QG_ScrollBar(Qt::Vertical, this);
107 //    vScrollBar->setLineStep(50);
108         vScrollBar->setSingleStep(50);
109 //    layout->addMultiCellWidget(vScrollBar, 0, 0, 2, 2);
110         layout->addWidget(vScrollBar, 0, 2);
111 //    layout->addColSpacing(2, vScrollBar->sizeHint().width());
112         layout->addItem(new QSpacerItem(vScrollBar->sizeHint().width(), 0), 0, 2);
113
114         connect(hScrollBar, SIGNAL(valueChanged(int)), this, SLOT(slotHScrolled(int)));
115         connect(vScrollBar, SIGNAL(valueChanged(int)), this, SLOT(slotVScrolled(int)));
116
117 #ifndef __APPLE__
118         // Mouse Cursors:
119         QBitmap bmp;
120         QPixmap cur1(":/res/cur_cad_bmp.xpm");
121         bmp = QPixmap(":/res/cur_cad_mask.xpm");
122         cur1.setMask(bmp);
123         curCad = new QCursor(cur1, 15, 15);
124
125         QPixmap cur2(":/res/cur_glass_bmp.xpm");
126         bmp = QPixmap(":/res/cur_glass_mask.xpm");
127         cur2.setMask(bmp);
128         curMagnifier = new QCursor(cur2, 12, 12);
129
130         QPixmap cur3(":/res/cur_del_bmp.xpm");
131         bmp = QPixmap(":/res/cur_del_mask.xpm");
132         cur3.setMask(bmp);
133         curDel = new QCursor(cur3, 15, 15);
134
135         QPixmap cur4(":/res/cur_select_bmp.xpm");
136         bmp = QPixmap(":/res/cur_select_mask.xpm");
137         cur4.setMask(bmp);
138         curSelect = new QCursor(cur4, 15, 15);
139
140         QPixmap cur5(":/res/cur_hand_bmp.xpm");
141         bmp = QPixmap(":/res/cur_hand_mask.xpm");
142         cur5.setMask(bmp);
143         curHand = new QCursor(cur5, 15, 15);
144 #else
145         // No individual cursors for the Mac
146         curCad = NULL;
147         curMagnifier = NULL;
148         curDel = NULL;
149         curSelect = NULL;
150         curHand = NULL;
151 #endif
152
153         // Dummy widgets for scrollbar corners:
154         //layout->addWidget(new QWidget(this), 1, 1);
155         //QWidget* w = new QWidget(this);
156         //w->setEraseColor(QColor(255,0,0));
157         gridStatus = new QLabel("-", this);
158         gridStatus->setAlignment(Qt::AlignRight);
159 //    layout->addMultiCellWidget(gridStatus, 1, 1, 1, 2);
160         layout->addWidget(gridStatus, 1, 1, 1, 2);
161 //    layout->addColSpacing(1, 50);
162         layout->addItem(new QSpacerItem(50, 0), 0, 1);
163
164         setMouseTracking(true);
165         // flickering under win:
166         //setFocusPolicy(WheelFocus);
167
168 #warning "QG_GraphicView constructor is setting Qt::NoFocus!!!"
169 // A-HAH! THIS IS THE PROBLEM!!!
170 //    setFocusPolicy(Qt::NoFocus);
171 //hm.
172 //      setFocusPolicy(Qt::StrongFocus);
173 }
174
175 /**
176  * Destructor
177  */
178 QG_GraphicView::~QG_GraphicView()
179 {
180         if (painter)
181                 delete painter;
182
183         if (buffer)
184         {
185                 delete buffer;
186                 buffer = NULL;
187         }
188
189         cleanUp();
190 }
191
192 /**
193  * @return width of widget.
194  */
195 int QG_GraphicView::getWidth()
196 {
197         return width() - vScrollBar->sizeHint().width();
198 }
199
200 /**
201  * @return height of widget.
202  */
203 int QG_GraphicView::getHeight()
204 {
205         return height() - hScrollBar->sizeHint().height();
206 }
207
208 /**
209  * Changes the current background color of this view.
210  */
211 void QG_GraphicView::setBackground(const RS_Color & bg)
212 {
213         GraphicView::setBackground(bg);
214
215 //      setBackgroundColor(bg);
216         QPalette palette;
217         palette.setColor(backgroundRole(), bg);
218         setPalette(palette);
219 }
220
221 /**
222  * Sets the mouse cursor to the given type.
223  */
224 void QG_GraphicView::setMouseCursor(RS2::CursorType c)
225 {
226         switch (c)
227         {
228         default:
229         case RS2::ArrowCursor:
230                 setCursor(Qt::ArrowCursor);
231                 break;
232         case RS2::UpArrowCursor:
233                 setCursor(Qt::UpArrowCursor);
234                 break;
235         case RS2::CrossCursor:
236                 setCursor(Qt::CrossCursor);
237                 break;
238         case RS2::WaitCursor:
239                 setCursor(Qt::WaitCursor);
240                 break;
241         case RS2::IbeamCursor:
242                 setCursor(Qt::IBeamCursor);
243                 break;
244         case RS2::SizeVerCursor:
245                 setCursor(Qt::SizeVerCursor);
246                 break;
247         case RS2::SizeHorCursor:
248                 setCursor(Qt::SizeHorCursor);
249                 break;
250         case RS2::SizeBDiagCursor:
251                 setCursor(Qt::SizeBDiagCursor);
252                 break;
253         case RS2::SizeFDiagCursor:
254                 setCursor(Qt::SizeFDiagCursor);
255                 break;
256         case RS2::SizeAllCursor:
257                 setCursor(Qt::SizeAllCursor);
258                 break;
259         case RS2::BlankCursor:
260                 setCursor(Qt::BlankCursor);
261                 break;
262         case RS2::SplitVCursor:
263                 setCursor(Qt::SplitVCursor);
264                 break;
265         case RS2::SplitHCursor:
266                 setCursor(Qt::SplitHCursor);
267                 break;
268         case RS2::PointingHandCursor:
269                 setCursor(Qt::PointingHandCursor);
270                 break;
271         case RS2::ForbiddenCursor:
272                 setCursor(Qt::ForbiddenCursor);
273                 break;
274         case RS2::WhatsThisCursor:
275                 setCursor(Qt::WhatsThisCursor);
276                 break;
277
278 #ifndef __APPLE__
279         case RS2::CadCursor:
280                 setCursor(*curCad);
281                 break;
282         case RS2::DelCursor:
283                 setCursor(*curDel);
284                 break;
285         case RS2::SelectCursor:
286                 setCursor(*curSelect);
287                 break;
288         case RS2::MagnifierCursor:
289                 setCursor(*curMagnifier);
290                 break;
291         case RS2::MovingHandCursor:
292                 setCursor(*curHand);
293                 break;
294 #else
295                 // Reduced cursor selection for the Mac:
296         case RS2::CadCursor:
297                 setCursor(Qt::CrossCursor);
298                 break;
299         case RS2::DelCursor:
300                 setCursor(Qt::CrossCursor);
301                 break;
302         case RS2::SelectCursor:
303                 setCursor(Qt::CrossCursor);
304                 break;
305         case RS2::MagnifierCursor:
306                 setCursor(Qt::CrossCursor);
307                 break;
308         case RS2::MovingHandCursor:
309                 setCursor(Qt::PointingHandCursor);
310                 break;
311 #endif
312         }
313 }
314
315 /**
316  * Sets the text for the grid status widget in the left bottom corner.
317  */
318 void QG_GraphicView::updateGridStatusWidget(const QString & text)
319 {
320         gridStatus->setText(text);
321 }
322
323 /**
324  * Redraws the widget.
325  */
326 void QG_GraphicView::redraw()
327 {
328         RS_DEBUG->print("QG_GraphicView::redraw begin 1");
329
330         if (simulationRunning)
331                 return;
332
333 //Also, this stuff is properly taken care of by the Qt toolkit--
334 //so we don't have to be concerned with shit like this as long
335 //as we use update() instead of repaint()
336         // never run twice
337         static bool running = false;
338
339         if (!running)
340         {
341                 running = true;
342                 RS_DEBUG->print("QG_GraphicView::redraw begin 2");
343
344 /*
345 This is the only place in the entire codebase that a proper update is
346 triggered.
347 */
348                 if (isUpdateEnabled())
349 //                      repaint(false);
350                         update();
351
352                 RS_DEBUG->print("QG_GraphicView::redraw end 2");
353                 running = false;
354         }
355
356         RS_DEBUG->print("QG_GraphicView::redraw end 1");
357 }
358
359 void QG_GraphicView::resizeEvent(QResizeEvent * /*e*/)
360 {
361         RS_DEBUG->print("QG_GraphicView::resizeEvent begin");
362         adjustOffsetControls();
363         adjustZoomControls();
364         updateGrid();
365         RS_DEBUG->print("QG_GraphicView::resizeEvent end");
366 }
367
368 // Next three methods from RS_LayerListListener Interface:
369 void QG_GraphicView::layerEdited(RS_Layer *)
370 {
371         redraw();
372 }
373
374 void QG_GraphicView::layerRemoved(RS_Layer *)
375 {
376         redraw();
377 }
378
379 void QG_GraphicView::layerToggled(RS_Layer *)
380 {
381         redraw();
382 }
383
384 void QG_GraphicView::emulateMouseMoveEvent()
385 {
386 //      QMouseEvent e(QEvent::MouseMove, QPoint(mx, my), Qt::NoButton, Qt::NoButton);
387         //mouseMoveEvent(&e);
388 }
389
390 void QG_GraphicView::mousePressEvent(QMouseEvent * e)
391 {
392         // pan zoom with middle mouse button
393         if (e->button() == Qt::MidButton /*|| (e->state()==Qt::LeftButton|Qt::AltButton)*/)
394                 setCurrentAction(new RS_ActionZoomPan(*container, *this));
395
396         GraphicView::mousePressEvent(e);
397         QWidget::mousePressEvent(e);
398 }
399
400 void QG_GraphicView::mouseReleaseEvent(QMouseEvent * e)
401 {
402         RS_DEBUG->print("QG_GraphicView::mouseReleaseEvent");
403         GraphicView::mouseReleaseEvent(e);
404         //QWidget::mouseReleaseEvent(e);
405
406         if (!e->isAccepted())
407         {
408                 if (QG_DIALOGFACTORY && QG_DIALOGFACTORY->getCadToolBar())
409                 {
410                         RS_DEBUG->print("QG_GraphicView::mouseReleaseEvent: fwd to cadtoolbar");
411                         QG_DIALOGFACTORY->getCadToolBar()->mouseReleaseEvent(e);
412                 }
413         }
414
415         RS_DEBUG->print("QG_GraphicView::mouseReleaseEvent: OK");
416 }
417
418 void QG_GraphicView::mouseMoveEvent(QMouseEvent * e)
419 {
420         //RS_DEBUG->print("QG_GraphicView::mouseMoveEvent begin");
421         //QMouseEvent rsm = QG_Qt2Rs::mouseEvent(e);
422
423         GraphicView::mouseMoveEvent(e);
424         QWidget::mouseMoveEvent(e);
425
426 //What kind of cacamamie crap is this???
427 //#ifdef Q_OS_WIN32
428 //      // make sure that we can still use hotkeys and the mouse wheel
429 //      if (parent() != NULL)
430 //              ((QWidget *)parent())->setFocus();
431 //#endif
432
433         //RS_DEBUG->print("QG_GraphicView::mouseMoveEvent end");
434 }
435
436 /**
437  * support for the wacom graphic tablet.
438  */
439 void QG_GraphicView::tabletEvent(QTabletEvent * e)
440 {
441 //      if (hasMouse())
442         if (testAttribute(Qt::WA_UnderMouse))
443         {
444                 switch (e->device())
445                 {
446                 case QTabletEvent::Eraser:
447                         if (e->type() == QEvent::TabletRelease)
448                         {
449                                 if (container != NULL)
450                                 {
451                                         RS_ActionSelectSingle * a = new RS_ActionSelectSingle(*container, *this);
452                                         setCurrentAction(a);
453 #warning "!!! !!!"
454 //                                      QMouseEvent ev(QEvent::MouseButtonRelease, e->pos(), Qt::LeftButton, Qt::LeftButton);
455 //                                      mouseReleaseEvent(&ev);
456                                         a->finish();
457
458                                         if (container->countSelected() > 0)
459                                                 setCurrentAction(new RS_ActionModifyDelete(*container, *this));
460                                 }
461                         }
462                         break;
463
464                 case QTabletEvent::Stylus:
465                 case QTabletEvent::Puck:
466                         if (e->type() == QEvent::TabletPress)
467                         {
468 #warning "!!! !!!"
469 //                              QMouseEvent ev(QEvent::MouseButtonPress, e->pos(), Qt::LeftButton, Qt::LeftButton);
470 //                              mousePressEvent(&ev);
471                         }
472                         else if (e->type() == QEvent::TabletRelease)
473                         {
474 #warning "!!! !!!"
475 //                              QMouseEvent ev(QEvent::MouseButtonRelease, e->pos(), Qt::LeftButton, Qt::LeftButton);
476 //                              mouseReleaseEvent(&ev);
477                         }
478                         else if (e->type() == QEvent::TabletMove)
479                         {
480 #warning "!!! !!!"
481 //                              QMouseEvent ev(QEvent::MouseMove, e->pos(), Qt::NoButton, 0);
482 //                              mouseMoveEvent(&ev);
483                         }
484                         break;
485
486                 default:
487                         break;
488                 }
489         }
490
491         // a 'mouse' click:
492         /*if (e->pressure()>10 && lastPressure<10) {
493                 QMouseEvent e(QEvent::MouseButtonPress, e->pos(),
494                 Qt::LeftButton, Qt::LeftButton);
495                 mousePressEvent(&e);
496 }
497         else if (e->pressure()<10 && lastPressure>10) {
498                 QMouseEvent e(QEvent::MouseButtonRelease, e->pos(),
499                 Qt::LeftButton, Qt::LeftButton);
500                 mouseReleaseEvent(&e);
501 }       else if (lastPos!=e->pos()) {
502                 QMouseEvent e(QEvent::MouseMove, e->pos(),
503                 Qt::NoButton, 0);
504                 mouseMoveEvent(&e);
505 }
506
507         lastPressure = e->pressure();
508         lastPos = e->pos();
509         */
510 }
511
512 void QG_GraphicView::leaveEvent(QEvent * e)
513 {
514         GraphicView::mouseLeaveEvent();
515         QWidget::leaveEvent(e);
516 }
517
518 void QG_GraphicView::enterEvent(QEvent * e)
519 {
520         GraphicView::mouseEnterEvent();
521         QWidget::enterEvent(e);
522 }
523
524 void QG_GraphicView::focusOutEvent(QFocusEvent * e)
525 {
526         QWidget::focusOutEvent(e);
527 }
528
529 void QG_GraphicView::focusInEvent(QFocusEvent * e)
530 {
531 //printf("-->QG_GraphicView::focusInEvent(): Start. this %s focus...\n", (hasFocus() ? "has" : "DOES NOT HAVE"));
532         GraphicView::mouseEnterEvent();
533         QWidget::focusInEvent(e);
534 //printf("-->QG_GraphicView::focusInEvent(): End.   this %s focus...\n", (hasFocus() ? "has" : "DOES NOT HAVE"));
535 }
536
537 /**
538  * mouse wheel event. zooms in/out or scrolls when
539  * shift or ctrl is pressed.
540  */
541 void QG_GraphicView::wheelEvent(QWheelEvent * e)
542 {
543         //RS_DEBUG->print("wheel: %d", e->delta());
544
545         //printf("state: %d\n", e->state());
546         //printf("ctrl: %d\n", Qt::ControlButton);
547         if (!container)
548                 return;
549
550         Qt::KeyboardModifiers keyState = QApplication::keyboardModifiers();
551         Vector mouse = toGraph(Vector(e->x(), e->y()));
552
553         bool scroll = false;
554         RS2::Direction direction = RS2::Up;
555
556         // scroll up / down:
557 //      if (e->state() == Qt::ControlModifier)
558         if (keyState == Qt::ControlModifier)
559         {
560                 scroll = true;
561
562                 if (e->delta() > 0)
563                         direction = RS2::Up;
564                 else
565                         direction = RS2::Down;
566         }
567         // scroll left / right:
568 //      else if (e->state() == Qt::ShiftModifier)
569         else if (keyState == Qt::ShiftModifier)
570         {
571                 scroll = true;
572
573                 if (e->delta() > 0)
574                         direction = RS2::Right;
575                 else
576                         direction = RS2::Left;
577         }
578
579         if (scroll)
580                 setCurrentAction(new RS_ActionZoomScroll(direction, *container, *this));
581         // zoom in / out:
582 //      else if (e->state() == 0)
583         else if (keyState == 0)
584         {
585                 if (e->delta() > 0)
586                         setCurrentAction(new RS_ActionZoomIn(*container, *this, RS2::In, RS2::Both, mouse));
587                 else
588                         setCurrentAction(new RS_ActionZoomIn(*container, *this, RS2::Out, RS2::Both, mouse));
589         }
590
591         e->accept();
592 }
593
594 void QG_GraphicView::keyPressEvent(QKeyEvent * e)
595 {
596         if (!container)
597                 return;
598
599         bool scroll = false;
600         RS2::Direction direction = RS2::Up;
601
602         switch (e->key())
603         {
604         case Qt::Key_Left:
605                 scroll = true;
606                 direction = RS2::Right;
607                 break;
608         case Qt::Key_Right:
609                 scroll = true;
610                 direction = RS2::Left;
611                 break;
612         case Qt::Key_Up:
613                 scroll = true;
614                 direction = RS2::Up;
615                 break;
616         case Qt::Key_Down:
617                 scroll = true;
618                 direction = RS2::Down;
619                 break;
620         default:
621                 scroll = false;
622                 break;
623         }
624
625         if (scroll)
626                 setCurrentAction(new RS_ActionZoomScroll(direction, *container, *this));
627
628         GraphicView::keyPressEvent(e);
629 }
630
631 void QG_GraphicView::keyReleaseEvent(QKeyEvent * e)
632 {
633         GraphicView::keyReleaseEvent(e);
634 }
635
636 /**
637  * Called whenever the graphic view has changed.
638  * Adjusts the scrollbar ranges / steps.
639  */
640 void QG_GraphicView::adjustOffsetControls()
641 {
642         static bool running = false;
643
644         if (running)
645                 return;
646
647         running = true;
648
649         RS_DEBUG->print("QG_GraphicView::adjustOffsetControls() begin");
650
651         if (container == NULL || hScrollBar == NULL || vScrollBar == NULL)
652                 return;
653
654         disableUpdate();
655         int ox = getOffsetX();
656         int oy = getOffsetY();
657
658         Vector min = container->getMin();
659         Vector max = container->getMax();
660
661         // no drawing yet - still allow to scroll
662         if (max.x < min.x + 1.0e-6 || max.y < min.y + 1.0e-6
663                 || max.x > RS_MAXDOUBLE || max.x < RS_MINDOUBLE
664                 || min.x > RS_MAXDOUBLE || min.x < RS_MINDOUBLE
665                 || max.y > RS_MAXDOUBLE || max.y < RS_MINDOUBLE
666                 || min.y > RS_MAXDOUBLE || min.y < RS_MINDOUBLE)
667         {
668                 min = Vector(-10, -10);
669                 max = Vector(100, 100);
670         }
671
672         int minVal = (int)(min.x * getFactor().x - QG_SCROLLMARGIN - getBorderLeft());
673         int maxVal = (int)(max.x * getFactor().x - getWidth() + QG_SCROLLMARGIN + getBorderRight());
674
675         hScrollBar->setValue(0);
676
677         if (minVal <= maxVal)
678                 hScrollBar->setRange(minVal, maxVal);
679
680         minVal = (int)(getHeight() - max.y * getFactor().y
681                 - QG_SCROLLMARGIN - getBorderTop());
682         maxVal = (int)(QG_SCROLLMARGIN + getBorderBottom()
683                 - (min.y * getFactor().y));
684
685         if (minVal <= maxVal)
686                 vScrollBar->setRange(minVal, maxVal);
687
688         hScrollBar->setPageStep((int)(getWidth()));
689         vScrollBar->setPageStep((int)(getHeight()));
690
691         hScrollBar->setValue(-ox);
692         vScrollBar->setValue(oy);
693
694         slotHScrolled(-ox);
695         slotVScrolled(oy);
696
697         RS_DEBUG->print("H min: %d / max: %d / step: %d / value: %d\n",
698                 hScrollBar->minimum(), hScrollBar->maximum(), hScrollBar->pageStep(), ox);
699         RS_DEBUG->print("V min: %d / max: %d / step: %d / value: %d\n",
700                 vScrollBar->minimum(), vScrollBar->maximum(), vScrollBar->pageStep(), oy);
701
702         enableUpdate();
703
704         RS_DEBUG->print("QG_GraphicView::adjustOffsetControls() end");
705
706         running = false;
707 }
708
709 /**
710  * override this to adjust controls and widgets that
711  * control the zoom factor of the graphic.
712  */
713 void QG_GraphicView::adjustZoomControls()
714 {
715 }
716
717 /**
718  * Slot for horizontal scroll events.
719  */
720 void QG_GraphicView::slotHScrolled(int value)
721 {
722         // Scrollbar behaviour tends to change with every Qt version..
723         // so let's keep old code in here for now
724
725         //static int running = false;
726         //if (!running) {
727         //running = true;
728         ////RS_DEBUG->print("value x: %d\n", value);
729         if (hScrollBar->maximum() == hScrollBar->minimum())
730                 centerOffsetX();
731         else
732                 setOffsetX(-value);
733
734         //if (isUpdateEnabled()) {
735         updateGrid();
736         redraw();
737         //}
738         ////updateView();
739         //running = false;
740         //}
741 }
742
743 /**
744  * Slot for vertical scroll events.
745  */
746 void QG_GraphicView::slotVScrolled(int value)
747 {
748         // Scrollbar behaviour tends to change with every Qt version..
749         // so let's keep old code in here for now
750
751         //static int running = false;
752         //if (!running) {
753         //running = true;
754         ////RS_DEBUG->print("value y: %d\n", value);
755         if (vScrollBar->maximum() == vScrollBar->minimum())
756                 centerOffsetY();
757         else
758                 setOffsetY(value);
759
760         //if (isUpdateEnabled()) {
761         updateGrid();
762         redraw();
763         //}
764         ////updateView();
765         //running = false;
766         //}
767 }
768
769 /**
770  * Handles paint events by redrawing the graphic in this view.
771  * usually that's very fast since we only paint the buffer we
772  * have from the last call..
773  *
774  * This is not true anymore--even if it was true in the first place, which
775  * seems doubtful to me. Everything is redrawn every time; we need to see if
776  * relying on Qt do to the clipping is wise or not... Also, we need to clarify
777  * all rendering paths since they are not all logical or consistent.
778  */
779 void QG_GraphicView::paintEvent(QPaintEvent *)
780 {
781         RS_DEBUG->print("QG_GraphicView::paintEvent begin");
782
783         if (simulationRunning)
784                 return;
785
786 /*
787 To fix the broken rendering here, we need to do one of the following:
788
789 1) Put preview object here and fix draw code to do an update() instead
790    of trying to draw directly to a widget context
791 2) Use a QPixmap as a randomly drawable surface and fix createDirectPainter()
792    to do an update() after drawing to the pixmap which will eventually end
793    up here.
794
795 I think 1) is cleaner in the long run, and will make the codebase much more
796 maintainable. However, 2) would make it possible to fix things fairly easily
797 without having to rearrange classes too much.
798
799 The way the UI is written is crap. It tries to be clever by doing direct
800 painting, bypassing the toolkit's built in rendering pipeline. Also, there
801 are tons of references to Qt stuff in what is supposed to be a toolkit
802 independent manner, resulting in unnecessary divisions of code and rendundant
803 class definitions. Still, the core is still useful and worth fixing just to
804 have something back in portage. We can make it better, faster, stronger. ;-)
805
806 If we can make the UI more like Inkscape we'll be in good shape. Plus elements
807 of VectorWorks & etc. as well...
808
809 -------------------------------------------------------------------------------
810
811 What's needed:
812
813 - Draw the entities
814 - Draw the preview (if any)
815 - Draw the snapper (if any)
816
817 */
818
819 // Qt4 handles double buffering of screen writes now, so this needs
820 // a rewrite.
821 #warning "!!! Need to pass a valid QPainter to drawIt() !!!"
822 #if 0
823         drawIt();
824
825 //#warning "!!! Double buffering is out... !!!"
826 // Seems most rendering is going through this path... Hrm.
827         if (buffer != NULL)
828         {
829                 QPainter wPainter;
830                 wPainter.begin(this);
831                 wPainter.drawPixmap(0, 0, *buffer);
832                 wPainter.end();
833         }
834 #else
835 //      refCount++;
836 //if (refCount > 1)
837 //{
838 ////    RS_DEBUG->print(RS_Debug::D_CRITICAL, "paintEvent seems to be called recursively: refCount=%u", refCount);
839 //      printf("paintEvent seems to be called recursively: refCount=%u\n", refCount);
840 //}
841
842         QPainter pntr(this);
843         pntr.setBackgroundMode(Qt::OpaqueMode);
844 //      pntr.setBackgroundColor(background);
845         pntr.setBackground(QBrush(background));
846
847         painter = new PaintInterface(&pntr);
848
849 #if 0
850         if (!painter)
851         {
852                 painter = new RS_PainterQt(this);
853
854                 //Nope, this didn't fix the problem...
855                 //The problem is, unless we specifically tell Qt NOT to
856                 //clear the window every time, it will...
857                 //So...
858 //              if (!previewMode)
859                 {
860                         painter->setDrawingMode(drawingMode);
861                         ((RS_PainterQt *)painter)->setBackgroundMode(Qt::OpaqueMode);
862                         ((RS_PainterQt *)painter)->setBackgroundColor(background);
863 //                      ((RS_PainterQt *)painter)->eraseRect(0, 0, getWidth(), getHeight());
864                 }
865         }
866         else
867         {
868                 printf("QG_GraphicView::paintEvent: painter is NOT NULL!\n");
869         }
870 #endif
871
872 #if 1
873 //Note that we do drawIt() regardless here because paintEvent() clears the background
874 //*unless* we create the window with a specific style. Depending on our draw code, we
875 //just may go that way...
876         drawIt();
877 //Need some logic here to do drawing in preview mode, since it'll be calling
878 //update now instead of trying to do a direct draw...
879         if (previewMode)
880         {
881 //hrm.          painter->setCompositionMode(QPainter::CompositionMode_Xor);
882 //needed anymore?               painter->setXORMode();
883                 painter->setOffset(previewOffset);
884                 drawEntity(previewEntity);//meh -> , 1.0, false);
885                 painter->setOffset(Vector(0, 0));
886                 // We'll set previewMode to false here, just because we can
887                 previewMode = false;
888         }
889 #endif
890
891         if (snapperDraw)
892 //      if (false)
893         {
894                 snapperDraw = false;
895
896                 if (snapCoord1.valid)
897                 {
898                         // snap point
899 //This is causing segfaults in the Qt::Painter code...
900 //*This* is causing the segfault!
901 //Actually, it looks like buggy painting code in PaintInterface()...
902                         painter->drawCircle(toGui(snapCoord1), 4);
903
904 #if 1
905                         // crosshairs:
906                         if (showCrosshairs1 == true)
907                         {
908                                 painter->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width00, RS2::DashLine));
909                                 painter->drawLine(Vector(0, toGuiY(snapCoord1.y)),
910                                         Vector(getWidth(), toGuiY(snapCoord1.y)));
911                                 painter->drawLine(Vector(toGuiX(snapCoord1.x), 0),
912                                         Vector(toGuiX(snapCoord1.x), getHeight()));
913                         }
914 #endif
915                 }
916 #if 1
917                 if (snapCoord1.valid && snapCoord1 != snapSpot1)
918                 {
919                         painter->drawLine(toGui(snapSpot1) + Vector(-5, 0), toGui(snapSpot1) + Vector(-1, 4));
920                         painter->drawLine(toGui(snapSpot1) + Vector(0, 5), toGui(snapSpot1) + Vector(4, 1));
921                         painter->drawLine(toGui(snapSpot1) + Vector(5, 0), toGui(snapSpot1) + Vector(1, -4));
922                         painter->drawLine(toGui(snapSpot1) + Vector(0, -5), toGui(snapSpot1) + Vector(-4, -1));
923                 }
924 #endif
925         }
926
927         delete painter;
928         painter = NULL;
929
930 //      refCount--;
931 #endif
932
933         RS_DEBUG->print("QG_GraphicView::paintEvent end");
934 }
935
936 #if 0 //JLH
937 /**
938  * Previews the given url for the file open dialog.
939  */
940 void QG_GraphicView::previewUrl(const Q3Url & u)
941 {
942         //static Drawing* gr = new Drawing();
943
944         RS_DEBUG->print("QG_GraphicView::previewUrl");
945
946         if (container != NULL && container->rtti() == RS2::EntityGraphic)
947         {
948                 ((Drawing *)container)->open(u.path(), RS2::FormatUnknown);
949                 zoomAuto();
950         }
951         //setContainer(gr);
952
953         RS_DEBUG->print("QG_GraphicView::previewUrl: OK");
954 }
955 #endif