File indexing completed on 2024-05-19 05:42:19
0001 // ct_lvtqtw_itool.cpp -*-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_itool.h> 0021 0022 #include <ct_lvtqtc_graphicsscene.h> 0023 #include <ct_lvtqtc_graphicsview.h> 0024 0025 #include <QAction> 0026 #include <QDebug> 0027 #include <QEvent> 0028 #include <QGraphicsSceneMouseEvent> 0029 #include <QKeyEvent> 0030 #include <QToolButton> 0031 0032 // in one source file 0033 Q_LOGGING_CATEGORY(LogTool, "log.itool") 0034 0035 namespace Codethink::lvtqtc { 0036 struct ITool::Private { 0037 QString name; 0038 QString tooltip; 0039 QIcon icon; 0040 GraphicsView *graphicsView = nullptr; 0041 QAction *action = nullptr; 0042 lvtldr::NodeStorage *nodeStorage = nullptr; 0043 }; 0044 0045 ITool::ITool(const QString& name, const QString& tooltip, const QIcon& icon, GraphicsView *gv): 0046 d(std::make_unique<ITool::Private>()) 0047 { 0048 d->name = name; 0049 d->tooltip = tooltip; 0050 d->icon = icon; 0051 d->graphicsView = gv; 0052 0053 d->action = new QAction(); 0054 d->action->setIcon(d->icon); 0055 d->action->setText(d->name); 0056 d->action->setToolTip(d->tooltip); 0057 d->action->setCheckable(true); 0058 0059 connect(d->action, &QAction::toggled, this, [this](bool value) { 0060 value ? activate() : deactivate(); 0061 0062 // this won't re-trigger the toggled signal, and it's needed 0063 // to actually select the button on click, because of the 0064 // invisible button on the button group being selected after 0065 // one is deactivated. see this example: 0066 // btn1 is active, we click in btn2. 0067 // btn2 get's active, this disables btn1 0068 // because btn1 got deactivated, invisibleButton will get active, deactivating btn2 0069 // so we need to check the 2nd button twice. 0070 d->action->setChecked(value); 0071 }); 0072 0073 connect(this, &lvtqtc::ITool::undoCommandCreated, d->graphicsView, &lvtqtc::GraphicsView::undoCommandReceived); 0074 } 0075 0076 ITool::~ITool() noexcept 0077 { 0078 d->action->deleteLater(); 0079 } 0080 0081 QAction *ITool::action() const 0082 { 0083 return d->action; 0084 } 0085 0086 QString ITool::name() const 0087 { 0088 return d->name; 0089 } 0090 0091 QString ITool::toolTip() const 0092 { 0093 return d->tooltip; 0094 } 0095 0096 QIcon ITool::icon() const 0097 { 0098 return d->icon; 0099 } 0100 0101 void ITool::setEnabled(bool enabled) 0102 { 0103 d->action->setEnabled(enabled); 0104 } 0105 0106 bool ITool::eventFilter(QObject *obj, QEvent *ev) 0107 { 0108 if (ev->type() == QEvent::KeyPress) { 0109 auto *keyEv = static_cast<QKeyEvent *>(ev); // NOLINT 0110 0111 // If the user manually cancels the action by pressing esc, also clean the message message. 0112 if (keyEv->key() == Qt::Key_Escape) { 0113 d->action->setChecked(false); 0114 Q_EMIT sendMessage(QString(), KMessageWidget::Information); 0115 } 0116 } 0117 0118 if (obj == d->graphicsView) { 0119 switch (ev->type()) { 0120 case QEvent::KeyRelease: 0121 keyReleaseEvent(static_cast<QKeyEvent *>(ev)); // NOLINT 0122 return ev->isAccepted(); 0123 case QEvent::KeyPress: 0124 keyPressEvent(static_cast<QKeyEvent *>(ev)); // NOLINT 0125 return ev->isAccepted(); 0126 default: 0127 return false; 0128 } 0129 return false; 0130 } 0131 0132 if (obj == d->graphicsView->viewport()) { 0133 switch (ev->type()) { 0134 case QEvent::MouseMove: 0135 mouseMoveEvent(static_cast<QMouseEvent *>(ev)); // NOLINT 0136 return ev->isAccepted(); 0137 case QEvent::MouseButtonPress: 0138 mousePressEvent(static_cast<QMouseEvent *>(ev)); // NOLINT 0139 return ev->isAccepted(); 0140 case QEvent::MouseButtonRelease: 0141 mouseReleaseEvent(static_cast<QMouseEvent *>(ev)); // NOLINT 0142 return ev->isAccepted(); 0143 default: 0144 return false; 0145 } 0146 return true; 0147 } 0148 0149 if (obj == d->graphicsView->scene()) { 0150 switch (ev->type()) { 0151 case QEvent::GraphicsSceneMouseMove: 0152 sceneMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(ev)); // NOLINT 0153 return ev->isAccepted(); 0154 case QEvent::GraphicsSceneMousePress: 0155 sceneMousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(ev)); // NOLINT 0156 return ev->isAccepted(); 0157 case QEvent::GraphicsSceneMouseRelease: 0158 sceneMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(ev)); // NOLINT 0159 return ev->isAccepted(); 0160 default: 0161 return false; 0162 } 0163 return true; 0164 } 0165 return false; 0166 } 0167 0168 GraphicsView *ITool::graphicsView() const 0169 { 0170 return d->graphicsView; 0171 } 0172 0173 GraphicsScene *ITool::graphicsScene() const 0174 { 0175 return qobject_cast<GraphicsScene *>(d->graphicsView->scene()); 0176 } 0177 0178 void ITool::setupInfra(bool install) 0179 { 0180 if (install) { 0181 d->graphicsView->installEventFilter(this); 0182 d->graphicsView->viewport()->installEventFilter(this); 0183 d->graphicsView->scene()->installEventFilter(this); 0184 d->graphicsView->setCurrentTool(this); 0185 d->graphicsView->setFocus(Qt::OtherFocusReason); 0186 } else { 0187 d->graphicsView->removeEventFilter(this); 0188 d->graphicsView->viewport()->removeEventFilter(this); 0189 d->graphicsView->scene()->removeEventFilter(this); 0190 d->graphicsView->setCurrentTool(nullptr); 0191 } 0192 } 0193 0194 void ITool::activate() 0195 { 0196 qCDebug(LogTool) << name() << "Activated"; 0197 // because of the double selection needed - for the invisibleButton 0198 // we need to, before activating anything, making sure this anything 0199 // is not already connected to the view. 0200 setupInfra(false); 0201 setupInfra(true); 0202 Q_EMIT activated(); 0203 } 0204 0205 void ITool::deactivate() 0206 { 0207 qCDebug(LogTool) << name() << "Deactivate"; 0208 setupInfra(false); 0209 Q_EMIT deactivated(); 0210 } 0211 0212 void ITool::mousePressEvent(QMouseEvent *event) 0213 { 0214 qCDebug(LogTool) << name() << "Mouse Press Event ignored"; 0215 event->setAccepted(false); 0216 Q_UNUSED(event); 0217 } 0218 0219 void ITool::mouseMoveEvent(QMouseEvent *event) 0220 { 0221 event->setAccepted(false); 0222 Q_UNUSED(event); 0223 } 0224 0225 void ITool::mouseReleaseEvent(QMouseEvent *event) 0226 { 0227 qCDebug(LogTool) << name() << "Mouse Press Release ignored"; 0228 event->setAccepted(false); 0229 Q_UNUSED(event); 0230 } 0231 0232 void ITool::keyPressEvent(QKeyEvent *event) 0233 { 0234 qCDebug(LogTool) << name() << "Key Press Event ignored"; 0235 event->setAccepted(false); 0236 Q_UNUSED(event); 0237 } 0238 0239 void ITool::keyReleaseEvent(QKeyEvent *event) 0240 { 0241 qCDebug(LogTool) << name() << "Key Release ignored"; 0242 event->setAccepted(false); 0243 Q_UNUSED(event); 0244 } 0245 0246 void ITool::drawForeground(QPainter *painter, const QRectF& rect) 0247 { 0248 Q_UNUSED(painter); 0249 Q_UNUSED(rect); 0250 } 0251 0252 // those acts on the scene 0253 void ITool::sceneMousePressEvent(QGraphicsSceneMouseEvent *event) 0254 { 0255 qCDebug(LogTool) << name() << "Scene Mouse Press Event Ignored"; 0256 event->setAccepted(false); 0257 Q_UNUSED(event); 0258 } 0259 0260 void ITool::sceneMouseMoveEvent(QGraphicsSceneMouseEvent *event) 0261 { 0262 event->setAccepted(false); 0263 Q_UNUSED(event); 0264 } 0265 0266 void ITool::sceneMouseReleaseEvent(QGraphicsSceneMouseEvent *event) 0267 { 0268 qCDebug(LogTool) << name() << "Scene Mouse Release Event Ignored"; 0269 event->setAccepted(false); 0270 Q_UNUSED(event); 0271 } 0272 0273 } // namespace Codethink::lvtqtc