$search
00001 #include "arenaview.h" 00002 #include "arenascene.h" 00003 #include "arenasceneelement.h" 00004 #include "../model/arena.h" 00005 #include "../model/arenaelement.h" 00006 #include "../model/arenaelementtype.h" 00007 00008 #include <QDebug> 00009 #include <QScrollBar> 00010 #include <QMouseEvent> 00011 #include <QMessageBox> 00012 #include <QTimer> 00013 00014 ArenaView::ArenaView(ArenaController *controller, QWidget *parent) 00015 : QGraphicsView(parent) 00016 , m_controller(controller) 00017 { 00018 setDragMode(QGraphicsView::RubberBandDrag); 00019 setViewportUpdateMode(QGraphicsView::FullViewportUpdate); 00020 00021 m_rubberBandActive = false; 00022 } 00023 00024 void drawCross(QPainter *painter, QPoint p, int lineLength) 00025 { 00026 painter->drawLine(p.x() - lineLength, p.y(), p.x() + lineLength, p.y()); 00027 painter->drawLine(p.x(), p.y() - lineLength, p.x(), p.y() + lineLength); 00028 } 00029 00030 void ArenaView::slotGridPaintingDisabled() 00031 { 00032 QMessageBox::warning(parentWidget(), "Grid Painting Monkey", 00033 "Aaargh. This is just too many grid points. Sorry. Falling back to white background."); 00034 } 00035 00036 void ArenaView::drawBackground(QPainter *painter, const QRectF& rect) 00037 { 00038 // When the grid becomes too small, don't draw anything because it won't 00039 // help and only consume (a lot of) CPU cycles 00040 qreal scale = qMin(transform().m11(), transform().m22()); 00041 if (scale < 0.2001) 00042 return; 00043 00044 // It is important to know that we effectively draw in *scene* coordinates, 00045 // not view coordinates! Before drawBackground() is called, the painter is 00046 // transformed accordingly by Qt. 00047 00048 painter->setPen(0xE0E0E0); 00049 00050 QPointF p0 = ArenaScene::nearestGridPoint(rect.topLeft()); 00051 QRectF scRect = scene()->sceneRect(); 00052 p0.rx() = qMax(p0.x(), scRect.left()); 00053 p0.ry() = qMax(p0.y(), scRect.top()); 00054 int visibleSceneWidth = qMin(rect.width(), scRect.width()) + CELL_SIZE; 00055 int visibleSceneHeight = qMin(rect.height(), scRect.height()) + CELL_SIZE; 00056 00057 00058 /*int numCells = (visibleSceneWidth / CELL_SIZE) * (visibleSceneHeight / CELL_SIZE); 00059 // Paintint a grid for > 1000 cells is just too much for the average CPU 00060 if (numCells > 1000) 00061 { 00062 static bool warned = false; 00063 if (!warned) 00064 { 00065 QTimer::singleShot(0, this, SLOT(slotGridPaintingDisabled())); 00066 warned = true; 00067 } 00068 return; 00069 }*/ 00070 00071 // One cell has a grid line to its left *and* to its right, therefore 00072 // we always have (number of cells + 1) grid lines 00073 for (int x = 0; x <= visibleSceneWidth; x += CELL_SIZE) 00074 { 00075 for (int y = 0; y <= visibleSceneHeight; y += CELL_SIZE) 00076 { 00077 int lineLength = 2; 00078 QPoint p = p0.toPoint() + QPoint(x, y) 00079 - QPoint(ITEM_SIZE, ITEM_SIZE) / 2 - QPoint(SPACING, SPACING); 00080 00081 p.rx() -= 1; 00082 p.ry() -= 1; 00083 drawCross(painter, p, lineLength); 00084 p.rx() += SPACING + 1; 00085 drawCross(painter, p, lineLength); 00086 p.rx() -= SPACING + 1; 00087 p.ry() += SPACING + 1; 00088 drawCross(painter, p, lineLength); 00089 p.rx() += SPACING + 1; 00090 drawCross(painter, p, lineLength); 00091 00092 } 00093 } 00094 } 00095 00096 void ArenaView::drawForeground(QPainter *painter, const QRectF &rect) 00097 { 00098 m_controller->draw(painter, rect); 00099 } 00100 00101 void ArenaView::mousePressEvent(QMouseEvent *event) 00102 { 00103 bool forwardEvent = true; 00104 00105 // Shortcut to inserting elements 00106 if (event->modifiers() & Qt::ShiftModifier && arenaScene()->selectedElements().count() == 1) 00107 { 00108 dragStarted(); 00109 ArenaSceneElement *selection = arenaScene()->selectedElements().first(); 00110 QString elementType = selection->element()->type()->name(); 00111 m_controller->startInsertion(elementType, mapToScene(event->pos())); 00112 m_rubberBandActive = false; 00113 // Do not mess with item selection (set by ArenaController) 00114 forwardEvent = false; 00115 } 00116 else 00117 { 00118 m_rubberBandActive = itemAt(event->pos()) == 0; 00119 } 00120 00121 if (m_rubberBandActive) 00122 setDragMode(QGraphicsView::RubberBandDrag); 00123 else 00124 setDragMode(QGraphicsView::NoDrag); 00125 00126 m_lastMousePos = event->pos(); 00127 m_lastMousePosScene = mapToScene(event->pos()); 00128 00129 if (forwardEvent) 00130 QGraphicsView::mousePressEvent(event); 00131 } 00132 00133 void ArenaView::mouseMoveEvent(QMouseEvent *event) 00134 { 00135 if (!arenaScene()) 00136 return; 00137 00138 bool forwardEvent = true; 00139 00140 if (event->buttons() & Qt::LeftButton && !m_rubberBandActive) 00141 { 00142 QPointF mousePos = mapToScene(event->pos()); 00143 QList<ArenaSceneElement*> selectedElements = arenaScene()->selectedElements(); 00144 00145 if (!m_controller->operationInProgress()) 00146 { 00147 dragStarted(); 00148 m_controller->startDrag(selectedElements); 00149 } 00150 00151 // In this case, we will move the selected element directly to the 00152 // position of the mouse cursor 00153 if (selectedElements.count() == 1 && 00154 !selectedElements.first()->element()->isItem()) 00155 { 00156 m_controller->dragTo(mousePos); 00157 } 00158 else 00159 { 00160 // Offset the mouse has been moved by 00161 QPointF offset = mousePos - m_lastMousePosScene; 00162 m_controller->dragBy(offset); 00163 } 00164 00165 forwardEvent = false; 00166 } 00167 else if (event->buttons() & Qt::RightButton) 00168 { 00169 QPoint diff = event->pos() - m_lastMousePos; 00170 00171 int oldX = horizontalScrollBar()->value(); 00172 int oldY = verticalScrollBar()->value(); 00173 horizontalScrollBar()->setValue(oldX - diff.x()); 00174 verticalScrollBar()->setValue(oldY - diff.y()); 00175 } 00176 00177 m_lastMousePos = event->pos(); 00178 m_lastMousePosScene = mapToScene(event->pos()); 00179 00180 if (forwardEvent) 00181 QGraphicsView::mouseMoveEvent(event); 00182 } 00183 00184 void ArenaView::mouseReleaseEvent(QMouseEvent *event) 00185 { 00186 QGraphicsView::mouseReleaseEvent(event); 00187 m_rubberBandActive = false; 00188 if (m_controller->operationInProgress()) 00189 { 00190 m_controller->endOperation(); 00191 // Update to make controller handles disappear 00192 update(); 00193 } 00194 00195 dragEnded(); 00196 } 00197 00198 ArenaScene *ArenaView::arenaScene() 00199 { 00200 return dynamic_cast<ArenaScene*>(scene()); 00201 } 00202 00203 void ArenaView::wheelEvent(QWheelEvent *event) 00204 { 00205 if (event->delta() > 0) 00206 slotZoomIn(); 00207 else 00208 slotZoomOut(); 00209 } 00210 00211 #define MIN_SCALE 0.1 00212 #define MAX_SCALE 5.0 00213 00214 void ArenaView::slotZoomIn() 00215 { 00216 QTransform trans = transform().scale(2.0, 2.0); 00217 if (trans.m11() <= MAX_SCALE || trans.m22() <= MAX_SCALE) 00218 setTransform(trans); 00219 } 00220 00221 void ArenaView::slotZoomOut() 00222 { 00223 QTransform trans = transform().scale(0.5, 0.5); 00224 if (trans.m11() >= MIN_SCALE || trans.m22() >= MIN_SCALE) 00225 setTransform(trans); 00226 } 00227 00228 void ArenaView::dragStarted() 00229 { 00230 // Do not change visible scene rect while an element is being inserted 00231 if (scene()) 00232 setSceneRect(scene()->sceneRect()); 00233 } 00234 00235 void ArenaView::dragEnded() 00236 { 00237 // Change scene rect with scene again 00238 setSceneRect(QRectF()); 00239 } 00240 00241 00242 void ArenaView::dragEnterEvent(QDragEnterEvent *event) 00243 { 00244 dragStarted(); 00245 00246 QString elementTypeName = event->mimeData()->data("type"); 00247 m_controller->startInsertion(elementTypeName, mapToScene(event->pos())); 00248 00249 event->accept(); 00250 } 00251 00252 void ArenaView::dragLeaveEvent(QDragLeaveEvent *event) 00253 { 00254 m_controller->cancelInsertion(); 00255 event->accept(); 00256 00257 dragEnded(); 00258 } 00259 00260 void ArenaView::dragMoveEvent(QDragMoveEvent *event) 00261 { 00262 m_controller->dragTo(mapToScene(event->pos())); 00263 event->accept(); 00264 } 00265 00266 void ArenaView::dropEvent(QDropEvent *event) 00267 { 00268 event->accept(); 00269 m_controller->endOperation(); 00270 // Make controller handles disappear 00271 update(); 00272 dragEnded(); 00273 //QGraphicsScene::dropEvent(event); 00274 }