File indexing completed on 2024-05-19 05:42:21
0001 // ct_lvtqtw_minimap.h -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 #include <ct_lvtqtc_minimap.h> 0021 0022 #include <QGraphicsScene> 0023 #include <QGuiApplication> 0024 #include <QMenu> 0025 #include <QMouseEvent> 0026 #include <QScreen> 0027 0028 #include <preferences.h> 0029 0030 namespace Codethink::lvtqtc { 0031 0032 struct Minimap::Private { 0033 bool isDraggingScene = false; 0034 bool isDraggingSelf = false; 0035 QPoint movementDelta; 0036 QRectF sceneRect; 0037 0038 int minimapSize = Minimap::MINIMAP_SMALL; 0039 }; 0040 0041 Minimap::Minimap(QGraphicsScene *mainScene, QWidget *parent): 0042 QGraphicsView(parent), d(std::make_unique<Minimap::Private>()) 0043 { 0044 setScene(mainScene); 0045 setBackgroundBrush(QBrush(Qt::white)); 0046 setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::TextAntialiasing 0047 | QPainter::RenderHint::SmoothPixmapTransform); 0048 0049 setCacheMode(QGraphicsView::CacheModeFlag::CacheNone); 0050 0051 setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); 0052 setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); 0053 0054 setViewportUpdateMode(QGraphicsView::FullViewportUpdate); 0055 0056 d->minimapSize = Preferences::minimapSize(); 0057 0058 setGeometry(QRect(0, 0, 100, 80)); 0059 0060 connect(scene(), &QGraphicsScene::sceneRectChanged, this, [this] { 0061 calculateGeometry(); 0062 }); 0063 } 0064 0065 Minimap::~Minimap() = default; 0066 0067 void Minimap::setSceneRect(const QRectF& rect) 0068 { 0069 if (d->sceneRect == rect) { 0070 return; 0071 } 0072 d->sceneRect = rect; 0073 scene()->update(); 0074 } 0075 0076 void Minimap::calculateGeometry() 0077 { 0078 QScreen *thisScreen = QGuiApplication::primaryScreen(); 0079 if (!thisScreen) { 0080 return; 0081 } 0082 0083 const qreal sceneWidth = scene()->sceneRect().width(); 0084 const qreal sceneHeight = scene()->sceneRect().height(); 0085 0086 if (sceneWidth == 0 || sceneHeight == 0) { 0087 setGeometry(QRect(0, 0, 100, 80)); 0088 return; 0089 } 0090 0091 int thisWidth = 0; 0092 int thisHeight = 0; 0093 0094 if (sceneWidth > sceneHeight) { 0095 thisWidth = thisScreen->geometry().width() / (int) d->minimapSize; 0096 assert(sceneHeight < INT_MAX && scene()->sceneRect().width() < INT_MAX); 0097 thisHeight = (thisWidth * (int) sceneHeight) / (int) sceneWidth; 0098 } else { 0099 thisHeight = thisScreen->geometry().height() / (int) d->minimapSize; 0100 assert(sceneHeight < INT_MAX && scene()->sceneRect().width() < INT_MAX); 0101 thisWidth = (thisHeight * (int) sceneWidth) / (int) sceneHeight; 0102 } 0103 0104 QRect geom = geometry(); 0105 geom.setWidth(thisWidth); 0106 geom.setHeight(thisHeight); 0107 if (geom.width() < 100 || geom.height() < 100) { 0108 geom.setWidth(geom.width() * 2); 0109 geom.setHeight(geom.height() * 2); 0110 } 0111 0112 setGeometry(geom); 0113 fitInView(scene()->sceneRect()); 0114 } 0115 0116 void Minimap::setMapSize(MinimapSize size) 0117 { 0118 if (d->minimapSize == size) { 0119 return; 0120 } 0121 0122 d->minimapSize = size; 0123 Preferences::setMinimapSize(size); 0124 0125 calculateGeometry(); 0126 } 0127 0128 void Minimap::contextMenuEvent(QContextMenuEvent *ev) 0129 { 0130 QMenu menu; 0131 menu.addAction(tr("Select Minimap Size")); 0132 menu.addSeparator(); 0133 QAction *ac = menu.addAction(tr("Small")); 0134 connect(ac, &QAction::triggered, this, [this] { 0135 setMapSize(MinimapSize::MINIMAP_SMALL); 0136 }); 0137 0138 ac = menu.addAction(tr("Medium")); 0139 connect(ac, &QAction::triggered, this, [this] { 0140 setMapSize(MinimapSize::MINIMAP_MEDIUM); 0141 }); 0142 0143 ac = menu.addAction(tr("Large")); 0144 connect(ac, &QAction::triggered, this, [this] { 0145 setMapSize(MinimapSize::MINIMAP_LARGE); 0146 }); 0147 0148 menu.exec(ev->globalPos()); 0149 } 0150 0151 void Minimap::drawForeground(QPainter *painter, const QRectF& rect) 0152 { 0153 if (d->sceneRect.width() > rect.width()) { 0154 return; 0155 } 0156 if (d->sceneRect.height() > rect.height()) { 0157 return; 0158 } 0159 0160 painter->save(); 0161 painter->setPen(QPen(Qt::NoPen)); 0162 painter->setBrush(QBrush(QColor(100, 100, 100, 100))); 0163 painter->drawRect(d->sceneRect); 0164 painter->restore(); 0165 } 0166 0167 void Minimap::mousePressEvent(QMouseEvent *ev) 0168 { 0169 if (ev->modifiers() & Preferences::dragModifier()) { 0170 d->isDraggingScene = false; 0171 d->isDraggingSelf = true; 0172 0173 QLine line(mapToParent(ev->pos()), pos()); 0174 d->movementDelta.setX(line.dx()); 0175 d->movementDelta.setY(line.dy()); 0176 } else { 0177 d->isDraggingScene = true; 0178 d->isDraggingSelf = false; 0179 Q_EMIT focusSceneAt(mapToScene(ev->localPos().toPoint())); 0180 } 0181 } 0182 0183 void Minimap::mouseMoveEvent(QMouseEvent *ev) 0184 { 0185 if (d->isDraggingScene) { 0186 Q_EMIT focusSceneAt(mapToScene(ev->localPos().toPoint())); 0187 } else if (d->isDraggingSelf) { 0188 QRect pos = geometry(); 0189 pos.moveTo(mapToParent(ev->pos()) + d->movementDelta); 0190 setGeometry(pos); 0191 } 0192 } 0193 0194 void Minimap::mouseReleaseEvent(QMouseEvent *ev) 0195 { 0196 Q_UNUSED(ev); 0197 d->isDraggingScene = false; 0198 d->isDraggingSelf = false; 0199 QGraphicsView::mouseReleaseEvent(ev); 0200 } 0201 0202 // TODO: Show a rect on the current visible part of the graph. 0203 } // namespace Codethink::lvtqtc