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