Warning, file /education/step/step/worldscene.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*. 0002 SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "worldscene.h" 0008 0009 #ifdef _WIN32 0010 #include <windows.h> 0011 #endif 0012 0013 #include "settings.h" 0014 0015 #include "arrow.h" 0016 #include "worldmodel.h" 0017 #include "worldfactory.h" 0018 #include "stepgraphicsitem.h" 0019 #include "worldgraphics.h" 0020 0021 #include <stepcore/world.h> 0022 #include <stepcore/particle.h> 0023 #include <stepcore/rigidbody.h> 0024 0025 #include <QCoreApplication> 0026 #include <QOpenGLWidget> 0027 #include <QGraphicsItem> 0028 #include <QGraphicsSceneMouseEvent> 0029 #include <QItemSelectionModel> 0030 #include <QPainter> 0031 #include <QScrollBar> 0032 #include <QTimer> 0033 #include <QToolTip> 0034 #include <QUrl> 0035 #include <QWheelEvent> 0036 0037 #include <KLocalizedString> 0038 0039 class WorldSceneAxes: public QGraphicsItem 0040 { 0041 public: 0042 WorldSceneAxes(QGraphicsItem* parent = nullptr, QGraphicsScene* scene = nullptr); 0043 QRectF boundingRect() const override; 0044 QPainterPath shape() const override; 0045 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; 0046 void viewScaleChanged(); 0047 0048 protected: 0049 QRectF _boundingRect; 0050 double _viewScale; 0051 static const int LENGTH = 100; 0052 static const int LENGTHT = 100; 0053 static const int LENGTH1 = 10; 0054 static const int ARROW_STROKE = 6; 0055 }; 0056 0057 WorldSceneAxes::WorldSceneAxes(QGraphicsItem* parent, QGraphicsScene* scene) 0058 : QGraphicsItem(parent), 0059 _boundingRect(-LENGTH, -LENGTH, LENGTH+LENGTH, LENGTH+LENGTH) 0060 { 0061 _viewScale = 1; 0062 setZValue(-100); 0063 if (scene) 0064 scene->addItem(this); 0065 } 0066 0067 QRectF WorldSceneAxes::boundingRect() const 0068 { 0069 return _boundingRect; 0070 } 0071 0072 QPainterPath WorldSceneAxes::shape() const 0073 { 0074 return QPainterPath(); 0075 } 0076 0077 void WorldSceneAxes::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) 0078 { 0079 QPen pen(Qt::gray, 2); 0080 pen.setCosmetic(true); 0081 painter->setPen(pen);//, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin)); 0082 //painter->drawLine(QLineF(0, -LENGTH, 0, LENGTH)); 0083 //painter->drawLine(QLineF(-LENGTH, 0, LENGTH, 0)); 0084 Arrow arrow(0, LENGTH, 0, -LENGTH, 8); 0085 arrow.draw(painter); 0086 Arrow arrow2(-LENGTH, 0, LENGTH, 0, 8); 0087 arrow2.draw(painter); 0088 //painter->drawLine(QLineF(0, -LENGTH, 0, LENGTH)); 0089 //painter->drawLine(QLineF(-LENGTH, 0, LENGTH, 0)); 0090 //painter->drawLine(QLineF(-2, -LENGTHT, 2, -LENGTHT)); 0091 //painter->drawLine(QLineF(LENGTHT, -2, LENGTHT, 2)); 0092 0093 //painter->drawLine(QLineF(0, -LENGTH, -0.5*ARROW_STROKE, -LENGTH+0.866*ARROW_STROKE )); 0094 //painter->drawLine(QLineF(0, -LENGTH, +0.5*ARROW_STROKE, -LENGTH+0.866*ARROW_STROKE )); 0095 //painter->drawLine(QLineF(LENGTH, 0, LENGTH-0.866*ARROW_STROKE, -0.5*ARROW_STROKE )); 0096 //painter->drawLine(QLineF(LENGTH, 0, LENGTH-0.866*ARROW_STROKE, +0.5*ARROW_STROKE )); 0097 0098 painter->drawText(QRectF(-LENGTH - 6, 6, LENGTH, LENGTH), 0099 Qt::AlignRight | Qt::AlignTop, 0100 QStringLiteral("%1,%2").arg( pos().x(), 0, 'g', 3 ).arg( pos().y(), 0, 'g', 3 )); 0101 painter->drawText(QRectF(6, -LENGTH, LENGTH - 6, LENGTH - 6), 0102 Qt::AlignLeft | Qt::AlignTop, QString::number( pos().y() + LENGTH/_viewScale, 'g', 3 )); 0103 painter->drawText(QRectF(6, -LENGTH, LENGTH - 6, LENGTH - 6), 0104 Qt::AlignRight | Qt::AlignBottom, QString::number( pos().x() + LENGTH/_viewScale, 'g', 3 )); 0105 0106 //painter->drawText(QRectF(ARROW_STROKE, -LENGTHT-50, LENGTHT, 100), Qt::AlignLeft | Qt::AlignVCenter, 0107 // QString::number( pos().y() + LENGTHT/_viewScale, 'g', 3 )); 0108 //painter->drawText(QRectF(LENGTHT-50, -LENGTHT, 100, LENGTHT), Qt::AlignHCenter | Qt::AlignBottom, 0109 // QString::number( pos().x() + LENGTHT/_viewScale, 'g', 3 )); 0110 } 0111 0112 void WorldSceneAxes::viewScaleChanged() 0113 { 0114 prepareGeometryChange(); 0115 _viewScale = static_cast<WorldScene*>(scene())->currentViewScale(); 0116 setTransform(QTransform::fromScale(1/_viewScale, -1/_viewScale), false); 0117 } 0118 0119 WorldScene::WorldScene(WorldModel* worldModel, QObject* parent) 0120 : QGraphicsScene(parent), _worldModel(worldModel), _worldView(nullptr), 0121 _currentViewScale(1), _itemCreator(nullptr), _bgColor(0), 0122 _sceneAxes(nullptr), _snapItem(nullptr) 0123 { 0124 #ifdef __GNUC__ 0125 #warning TODO: measure what index method is faster 0126 #endif 0127 0128 // Alternative index method is BspTreeIndex 0129 setItemIndexMethod(NoIndex); 0130 //XXX 0131 //setct(-200,-200,400,400); 0132 setSceneRect(-20, -20, 40, 40); 0133 0134 _messageFrame = new MessageFrame(); 0135 _snapTimer = new QTimer(this); 0136 _snapTimer->setInterval(0); 0137 _snapTimer->setSingleShot(true); 0138 0139 worldModelReset(); 0140 0141 connect(_worldModel, &QAbstractItemModel::modelReset, this, &WorldScene::worldModelReset); 0142 connect(_worldModel, &WorldModel::worldDataChanged, this, &WorldScene::worldDataChanged); 0143 connect(_worldModel->selectionModel(), &QItemSelectionModel::currentChanged, 0144 this, &WorldScene::worldCurrentChanged); 0145 connect(_worldModel->selectionModel(), &QItemSelectionModel::selectionChanged, 0146 this, &WorldScene::worldSelectionChanged); 0147 connect(_worldModel, &QAbstractItemModel::rowsInserted, 0148 this, &WorldScene::worldRowsInserted); 0149 connect(_worldModel, &QAbstractItemModel::rowsAboutToBeRemoved, 0150 this, &WorldScene::worldRowsAboutToBeRemoved); 0151 0152 connect(_messageFrame, &MessageFrame::linkActivated, 0153 this, &WorldScene::messageLinkActivated); 0154 connect(_snapTimer, &QTimer::timeout, this, &WorldScene::snapUpdateToolTip); 0155 } 0156 0157 WorldScene::~WorldScene() 0158 { 0159 } 0160 0161 StepCore::Item* WorldScene::itemFromGraphics(const QGraphicsItem* graphicsItem) const 0162 { 0163 const StepGraphicsItem* worldGraphicsItem = 0164 dynamic_cast<const StepGraphicsItem*>(graphicsItem); 0165 if(worldGraphicsItem != nullptr) return worldGraphicsItem->item(); 0166 else return nullptr; 0167 } 0168 0169 StepGraphicsItem* WorldScene::graphicsFromItem(const StepCore::Item* item) const 0170 { 0171 return _itemsHash.value(item, NULL); 0172 } 0173 0174 void WorldScene::beginAddItem(const QString& name) 0175 { 0176 //_currentCreator = name; 0177 if(_itemCreator) { 0178 _itemCreator->abort(); 0179 emit endAddItem(_itemCreator->className(), _itemCreator->item() != nullptr); 0180 delete _itemCreator; 0181 } 0182 if(name == QLatin1String("Pointer")) { 0183 _itemCreator = nullptr; 0184 } else { 0185 _itemCreator = _worldModel->worldFactory()->newItemCreator(name, _worldModel, this); 0186 Q_ASSERT(_itemCreator != nullptr); 0187 _itemCreator->start(); 0188 } 0189 } 0190 0191 bool WorldScene::event(QEvent* event) 0192 { 0193 //qDebug("event, _currentCreator = %s", _currentCreator.toAscii().constData()); 0194 /*if(!_currentCreator.isEmpty()) { 0195 if(_worldModel->worldFactory()->graphicsCreateItem(_currentCreator, _worldModel, 0196 this, event)) { 0197 emit endAddItem(_currentCreator, true); 0198 _currentCreator.clear(); 0199 } 0200 if(event->isAccepted()) return true; 0201 }*/ 0202 if(_itemCreator) { 0203 bool handled = _itemCreator->sceneEvent(event); 0204 if(_itemCreator->finished()) { 0205 emit endAddItem(_itemCreator->className(), _itemCreator->item() != nullptr); 0206 // ~ItemCreator() will indirectly call this method, thus we must set 0207 // the pointer to NULL before deleting the ItemCreator. 0208 ItemCreator* itemCreator = _itemCreator; 0209 _itemCreator = nullptr; 0210 delete itemCreator; 0211 } 0212 if(handled) { 0213 event->accept(); 0214 return true; 0215 } 0216 } 0217 return QGraphicsScene::event(event); 0218 } 0219 0220 void WorldScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) 0221 { 0222 if(itemAt(mouseEvent->scenePos(), QTransform()) == nullptr) { 0223 // XXX: how to easily select World ? 0224 //_worldModel->selectionModel()->clearSelection(); 0225 _worldModel->selectionModel()->setCurrentIndex(_worldModel->worldIndex(), QItemSelectionModel::Clear); 0226 } 0227 0228 QGraphicsScene::mousePressEvent(mouseEvent); 0229 } 0230 0231 void WorldScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent) 0232 { 0233 helpEvent->accept(); 0234 0235 if(_snapItem || _snapTimer->isActive()) return; 0236 0237 QString text; 0238 0239 QList<StepCore::Item*> activeItems; 0240 foreach(QGraphicsItem* it, items(helpEvent->scenePos())) { 0241 if(it->parentItem()) continue; 0242 StepCore::Item* item = itemFromGraphics(it); 0243 if(item) activeItems << item; 0244 } 0245 0246 int count = activeItems.count(); 0247 if(count > 1) { //XXX 0248 text = QStringLiteral("<nobr><h4><u>%1</u></h4></nobr>").arg(i18n("Objects under mouse:")); 0249 for(int i=0; i<qMin<int>(count,10); ++i) 0250 text += QStringLiteral("<br /><nobr>%1</nobr>") 0251 .arg(_worldModel->objectIndex(activeItems[i]).data(Qt::DisplayRole).toString()); 0252 if(count > 10) 0253 text += QStringLiteral("<br /><nobr>%1</nobr>").arg(i18np("... (1 more item)", "... (%1 more items)", count - 10)); 0254 } else { 0255 for(int i=0; i<count; ++i) 0256 text += _worldModel->objectIndex(activeItems[i]).data(Qt::ToolTipRole).toString(); 0257 } 0258 0259 Q_ASSERT(helpEvent->widget()); 0260 QToolTip::showText(helpEvent->screenPos(), text, helpEvent->widget(), QRect()); 0261 } 0262 0263 void WorldScene::worldModelReset() 0264 { 0265 /* Clear */ 0266 while(!items().isEmpty()) { 0267 QGraphicsItem* item = items()[0]; 0268 removeItem(item); 0269 delete item; 0270 } 0271 _itemsHash.clear(); 0272 _sceneAxes = nullptr; 0273 0274 /* Background */ 0275 if(_bgColor != _worldModel->world()->color()) { 0276 _bgColor = _worldModel->world()->color(); 0277 if(_bgColor == 0) setBackgroundBrush(Qt::NoBrush); 0278 else setBackgroundBrush(QBrush(QColor::fromRgba(_bgColor))); 0279 } 0280 0281 /* Axes */ 0282 if(Settings::showAxes()) { 0283 _sceneAxes = new WorldSceneAxes(); 0284 addItem(_sceneAxes); 0285 _sceneAxes->viewScaleChanged(); 0286 } 0287 0288 /* Check for new items */ 0289 worldGetItemsRecursive(_worldModel->worldIndex()); 0290 0291 update(); 0292 } 0293 0294 void WorldScene::worldGetItemsRecursive(const QModelIndex& parent) 0295 { 0296 for(int i=0; i<_worldModel->rowCount(parent); ++i) { 0297 worldRowsInserted(parent, i, i); 0298 worldGetItemsRecursive(_worldModel->index(i, 0, parent)); 0299 } 0300 } 0301 0302 void WorldScene::worldRowsInserted(const QModelIndex& parent, int start, int end) 0303 { 0304 for(int i=start; i<=end; ++i) { 0305 QModelIndex index = _worldModel->index(i, 0, parent); 0306 0307 StepCore::Item* item = _worldModel->item(index); 0308 if(!item) continue; 0309 StepGraphicsItem* graphicsItem = 0310 _worldModel->worldFactory()->newGraphicsItem(item, _worldModel); 0311 if(!graphicsItem) continue; 0312 0313 _itemsHash.insert(item, graphicsItem); 0314 addItem(graphicsItem); 0315 graphicsItem->viewScaleChanged(); 0316 graphicsItem->worldDataChanged(false); 0317 foreach(QGraphicsItem *item, items()) { 0318 if(graphicsItem->isAncestorOf(item)) { 0319 StepGraphicsItem* gItem = dynamic_cast<StepGraphicsItem*>(item); 0320 if(gItem) gItem->viewScaleChanged(); 0321 } 0322 } 0323 0324 worldGetItemsRecursive(index); 0325 } 0326 } 0327 0328 void WorldScene::worldRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) 0329 { 0330 for(int i=start; i<=end; ++i) { 0331 QModelIndex index = _worldModel->index(i, 0, parent); 0332 0333 int childCount = _worldModel->rowCount(index); 0334 if(childCount > 0) worldRowsAboutToBeRemoved(index, 0, childCount-1); 0335 0336 QGraphicsItem* graphicsItem = graphicsFromItem(_worldModel->item(index)); 0337 if(graphicsItem) { 0338 removeItem(graphicsItem); 0339 delete graphicsItem; 0340 } 0341 } 0342 } 0343 0344 void WorldScene::worldCurrentChanged(const QModelIndex& current, const QModelIndex& /*previous*/) 0345 { 0346 if(!_worldView || _worldView->viewport()->hasFocus()) return; 0347 QGraphicsItem* graphicsItem = graphicsFromItem(_worldModel->item(current)); 0348 if(graphicsItem) graphicsItem->ensureVisible(QRectF(), 5, 5); 0349 } 0350 0351 void WorldScene::worldSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) 0352 { 0353 foreach(const QModelIndex &index, selected.indexes()) { 0354 QGraphicsItem* item = _itemsHash.value(_worldModel->item(index)); 0355 if(item) item->setSelected(true); 0356 } 0357 foreach(const QModelIndex &index, deselected.indexes()) { 0358 QGraphicsItem* item = _itemsHash.value(_worldModel->item(index)); 0359 if(item) item->setSelected(false); 0360 } 0361 } 0362 0363 void WorldScene::worldDataChanged(bool dynamicOnly) 0364 { 0365 //if(dynamicOnly) return; 0366 _worldModel->simulationPause(); 0367 0368 if(!dynamicOnly) { 0369 /* Background */ 0370 if(_bgColor != _worldModel->world()->color()) { 0371 _bgColor = _worldModel->world()->color(); 0372 if(_bgColor == 0) setBackgroundBrush(Qt::NoBrush); 0373 else setBackgroundBrush(QBrush(QColor::fromRgba(_bgColor))); 0374 } 0375 } 0376 0377 foreach (QGraphicsItem *item, items()) { 0378 StepGraphicsItem* gItem = dynamic_cast<StepGraphicsItem*>(item); 0379 if(gItem) { 0380 gItem->worldDataChanged(dynamicOnly); 0381 } 0382 } 0383 0384 QRectF boundingRect = itemsBoundingRect(); 0385 setSceneRect(boundingRect.united(QRectF(-20, -20, 40, 40))); 0386 } 0387 0388 void WorldScene::updateViewScale() 0389 { 0390 if(_worldView) { 0391 _currentViewScale = _worldView->transform().m11(); 0392 _worldModel->simulationPause(); 0393 foreach (QGraphicsItem *item, items()) { 0394 StepGraphicsItem* gItem = dynamic_cast<StepGraphicsItem*>(item); 0395 if(gItem) gItem->viewScaleChanged(); 0396 } 0397 if(_sceneAxes) _sceneAxes->viewScaleChanged(); 0398 } 0399 } 0400 0401 QRectF WorldScene::calcItemsBoundingRect() 0402 { 0403 QRectF boundingRect; 0404 foreach(QGraphicsItem* item, items()) { 0405 StepGraphicsItem* wItem = dynamic_cast<StepGraphicsItem*>(item); 0406 if(wItem) { 0407 boundingRect |= wItem->sceneBoundingRect(); 0408 //qDebug() << itemFromGraphics(wItem)->name() << ": " << wItem->sceneBoundingRect() << endl; 0409 } 0410 } 0411 return boundingRect; 0412 } 0413 0414 void WorldScene::messageLinkActivated(const QString& link) 0415 { 0416 emit linkActivated(QUrl::fromUserInput(link)); 0417 } 0418 0419 void WorldScene::settingsChanged() 0420 { 0421 worldModelReset(); 0422 _messageFrame->raise(); 0423 } 0424 0425 void WorldScene::snapClear() 0426 { 0427 if(_snapItem) { 0428 _snapItem->setItemHighlighted(false); 0429 _snapItem = nullptr; 0430 _snapToolTip.clear(); 0431 _snapTimer->start(); 0432 } 0433 } 0434 0435 StepCore::Item* WorldScene::snapHighlight(QPointF pos, SnapFlags flags, const SnapList* moreTypes) 0436 { 0437 SnapList types; 0438 if(flags.testFlag(SnapParticle)) types << StepCore::Particle::staticMetaObject(); 0439 if(flags.testFlag(SnapRigidBody)) types << StepCore::RigidBody::staticMetaObject(); 0440 if(moreTypes) types << *moreTypes; 0441 0442 StepCore::Item* item = nullptr; 0443 QGraphicsItem* gItem = nullptr; 0444 foreach(gItem, items(pos)) { 0445 item = itemFromGraphics(gItem); if(!item) continue; 0446 if(flags.testFlag(SnapParticle) && item->metaObject()->inherits<StepCore::Particle>()) break; 0447 if(flags.testFlag(SnapRigidBody) && item->metaObject()->inherits<StepCore::RigidBody>()) break; 0448 0449 if(moreTypes) { 0450 bool found = false; 0451 foreach(const StepCore::MetaObject* type, *moreTypes) 0452 if(item->metaObject()->inherits(type)) { found = true; break; } 0453 if(found) break; 0454 } 0455 item = nullptr; 0456 } 0457 0458 if(item) { 0459 if(_snapItem != gItem) { 0460 snapClear(); 0461 _snapItem = static_cast<StepGraphicsItem*>(gItem); 0462 _snapItem->setItemHighlighted(true); 0463 } 0464 _snapPos = pos; 0465 _snapToolTip = _worldModel->formatNameFull(item); 0466 _snapTimer->start(); 0467 return item; 0468 0469 } else { 0470 snapClear(); 0471 return nullptr; 0472 } 0473 } 0474 0475 StepCore::Item* WorldScene::snapItem(QPointF pos, SnapFlags flags, const SnapList* moreTypes, 0476 int movingState, StepCore::Item* item, int num) 0477 { 0478 QString n; 0479 if(num >= 0) n = QString::number(num); 0480 0481 _worldModel->simulationPause(); 0482 StepCore::Item* sItem = snapHighlight(pos, flags, moreTypes); 0483 0484 if(movingState == StepGraphicsItem::Started || movingState == StepGraphicsItem::Moving) { 0485 if(movingState == StepGraphicsItem::Started) 0486 _worldModel->setProperty(item, "body"+n, 0487 QVariant::fromValue<StepCore::Object*>(NULL), WorldModel::UndoNoMerge); 0488 0489 if(flags.testFlag(SnapSetPosition)) 0490 _worldModel->setProperty(item, "position"+n, 0491 QVariant::fromValue(StepGraphicsItem::pointToVector(pos))); 0492 0493 if(flags.testFlag(SnapSetLocalPosition)) 0494 _worldModel->setProperty(item, "localPosition"+n, 0495 QVariant::fromValue(StepGraphicsItem::pointToVector(pos))); 0496 0497 if(flags.testFlag(SnapSetAngle) && movingState == StepGraphicsItem::Started) 0498 _worldModel->setProperty(item, "angle"+n, QVariant::fromValue(0.0)); 0499 0500 } else if(movingState == StepGraphicsItem::Finished) { 0501 StepCore::Vector2d wPos(StepGraphicsItem::pointToVector(pos)); 0502 StepCore::Vector2d lPos(0,0); 0503 double angle = 0.0; 0504 0505 if(sItem) { 0506 if(sItem->metaObject()->inherits<StepCore::Particle>()) { 0507 wPos = static_cast<StepCore::Particle*>(sItem)->position(); 0508 } else if(sItem->metaObject()->inherits<StepCore::RigidBody>()) { 0509 if(flags.testFlag(SnapOnCenter)) 0510 wPos = static_cast<StepCore::RigidBody*>(sItem)->position(); 0511 else 0512 lPos = static_cast<StepCore::RigidBody*>(sItem)->pointWorldToLocal(wPos); 0513 angle = static_cast<StepCore::RigidBody*>(sItem)->angle(); 0514 } 0515 0516 } else { 0517 lPos = wPos; 0518 } 0519 0520 _worldModel->setProperty(item, "body"+n, 0521 QVariant::fromValue<StepCore::Object*>(sItem), WorldModel::UndoNoMerge); 0522 0523 if(flags.testFlag(SnapSetPosition)) 0524 _worldModel->setProperty(item, "position"+n, QVariant::fromValue(wPos)); 0525 if(flags.testFlag(SnapSetLocalPosition)) 0526 _worldModel->setProperty(item, "localPosition"+n, QVariant::fromValue(lPos)); 0527 if(flags.testFlag(SnapSetAngle)) 0528 _worldModel->setProperty(item, "angle"+n, angle); 0529 0530 snapClear(); 0531 } 0532 0533 return sItem; 0534 } 0535 0536 void WorldScene::snapUpdateToolTip() 0537 { 0538 if(!_snapToolTip.isEmpty()) { 0539 QGraphicsView* view = views()[0]; 0540 QPoint pos = view->viewport()->mapToGlobal(view->mapFromScene(_snapPos)); 0541 QPoint size(1,1); 0542 QToolTip::showText(pos, _snapToolTip, view->viewport(), QRect(pos-size,pos+size)); 0543 } else { 0544 QToolTip::hideText(); 0545 // Hack to hide tooltip immediately 0546 QWheelEvent fakeEvent(QPointF(0,0), QPointF(0,0), QPoint(0, 0), QPoint(0, 0), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); 0547 QCoreApplication::sendEvent(_messageFrame, &fakeEvent); 0548 } 0549 } 0550 0551 bool WorldScene::hasItemCreator() const 0552 { 0553 return _itemCreator && !_itemCreator->finished(); 0554 } 0555 0556 WorldGraphicsView::WorldGraphicsView(WorldScene* worldScene, QWidget* parent) 0557 : QGraphicsView(worldScene, parent) 0558 { 0559 worldScene->_worldView = this; 0560 worldScene->_messageFrame->setParent(this); 0561 worldScene->_messageFrame->move(15,15); 0562 0563 _sceneRect = worldScene->sceneRect(); 0564 updateSceneRect(); 0565 connect(worldScene, &QGraphicsScene::sceneRectChanged, 0566 this, &WorldGraphicsView::sceneRectChanged); 0567 0568 //worldGraphicsView->setRenderHints(QPainter::Antialiasing); 0569 setDragMode(QGraphicsView::RubberBandDrag); 0570 //setDragMode(QGraphicsView::ScrollHandDrag); 0571 setResizeAnchor(QGraphicsView::AnchorViewCenter); 0572 #ifdef __GNUC__ 0573 #warning Check paint() for all items to preserve painter state 0574 #warning Use NoViewportUpdate and manual updating here ! 0575 #endif 0576 setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); 0577 actualSize(); 0578 settingsChanged(); 0579 } 0580 0581 void WorldGraphicsView::zoomIn() 0582 { 0583 scale(1.25, 1.25); 0584 updateSceneRect(); 0585 0586 static_cast<WorldScene*>(scene())->updateViewScale(); 0587 } 0588 0589 void WorldGraphicsView::zoomOut() 0590 { 0591 scale(1 / 1.25, 1 / 1.25); 0592 updateSceneRect(); 0593 0594 static_cast<WorldScene*>(scene())->updateViewScale(); 0595 } 0596 0597 void WorldGraphicsView::fitToPage() 0598 { 0599 QRectF br = static_cast<WorldScene*>(scene())->calcItemsBoundingRect(); 0600 if(br.isNull()) 0601 return; 0602 //qDebug() << br << " " << (br | QRectF(0,0,0,0)) << endl; 0603 QRect ws = viewport()->rect(); 0604 0605 double currentViewScale = transform().m11(); 0606 double s = qMin( ws.width()/br.width(), ws.height()/br.height() ); 0607 0608 // XXX: use QSize::scale ! 0609 0610 if(s < currentViewScale || s*0.8 > currentViewScale) { 0611 s *= 0.9; 0612 resetTransform(); 0613 scale(s, -s); 0614 updateSceneRect(); 0615 } else { 0616 s = currentViewScale; 0617 } 0618 0619 centerOn(br.center()); 0620 0621 if(s != currentViewScale) 0622 static_cast<WorldScene*>(scene())->updateViewScale(); 0623 } 0624 0625 void WorldGraphicsView::actualSize() 0626 { 0627 resetTransform(); 0628 scale(100, -100); 0629 updateSceneRect(); 0630 0631 centerOn(0, 0); 0632 0633 static_cast<WorldScene*>(scene())->updateViewScale(); 0634 } 0635 0636 void WorldGraphicsView::settingsChanged() 0637 { 0638 if(qobject_cast<QOpenGLWidget*>(viewport())) { 0639 if(!Settings::enableOpenGL()) setViewport(new QWidget(this)); 0640 } else { 0641 if(Settings::enableOpenGL()) { 0642 //qDebug() << "enable OpenGL" << endl; 0643 setViewport(new QOpenGLWidget(this)); 0644 if(!qobject_cast<QOpenGLWidget*>(viewport())) { 0645 qDebug() << "can't create QOpenGLWidget!" << Qt::endl; 0646 } 0647 } 0648 } 0649 if(scene()) static_cast<WorldScene*>(scene())->settingsChanged(); 0650 } 0651 0652 void WorldGraphicsView::mousePressEvent(QMouseEvent* e) 0653 { 0654 if(e->button() == Qt::MiddleButton) { 0655 setDragMode(QGraphicsView::ScrollHandDrag); 0656 QMouseEvent e1(e->type(), e->pos(), e->globalPos(), Qt::LeftButton, 0657 e->buttons(), e->modifiers()); 0658 QGraphicsView::mousePressEvent(&e1); 0659 } else { 0660 QGraphicsView::mousePressEvent(e); 0661 } 0662 } 0663 0664 void WorldGraphicsView::mouseReleaseEvent(QMouseEvent* e) 0665 { 0666 QGraphicsView::mouseReleaseEvent(e); 0667 if(e->button() == Qt::MiddleButton) { 0668 setDragMode(QGraphicsView::RubberBandDrag); 0669 } 0670 } 0671 0672 void WorldGraphicsView::wheelEvent(QWheelEvent* e) 0673 { 0674 if (e->modifiers() == Qt::ControlModifier) { 0675 if (e->angleDelta().y() == 0) { 0676 e->ignore(); 0677 return; 0678 } 0679 0680 QGraphicsView::ViewportAnchor anchor = transformationAnchor(); 0681 setTransformationAnchor(QGraphicsView::AnchorUnderMouse); 0682 if (e->angleDelta().y() > 0) { 0683 zoomIn(); 0684 } 0685 else { 0686 zoomOut(); 0687 } 0688 setTransformationAnchor(anchor); 0689 0690 e->accept(); 0691 return; 0692 } 0693 0694 QGraphicsView::wheelEvent(e); 0695 } 0696 0697 void WorldGraphicsView::scrollContentsBy(int dx, int dy) 0698 { 0699 QGraphicsView::scrollContentsBy(dx, dy); 0700 WorldSceneAxes* axes = static_cast<WorldScene*>(scene())->_sceneAxes; 0701 if(axes) 0702 axes->setPos(mapToScene(viewport()->width()/2, viewport()->height()/2)); 0703 //axes->setPos(mapToScene(20, maximumViewportSize().height()-horizontalScrollBar()->height()-23)); 0704 } 0705 0706 void WorldGraphicsView::sceneRectChanged(const QRectF& rect) 0707 { 0708 _sceneRect = rect; 0709 updateSceneRect(); 0710 } 0711 0712 void WorldGraphicsView::updateSceneRect() 0713 { 0714 QPointF topleft = mapToScene(0, 0); 0715 QPointF bottomright = mapToScene(viewport()->width(), viewport()->height()); 0716 0717 QRectF viewportRect(topleft, bottomright); 0718 QRectF sceneRect = _sceneRect.adjusted(-viewportRect.width() / 4, 0719 viewportRect.height() / 4, 0720 viewportRect.width() / 4, 0721 -viewportRect.height() / 4); 0722 setSceneRect(sceneRect.united(viewportRect)); 0723 } 0724 0725 #include "moc_worldscene.cpp"