File indexing completed on 2024-10-13 05:05:19
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2006 David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "itemview.h" 0012 #include "canvasitemparts.h" 0013 #include "canvasmanipulator.h" 0014 #include "cnitem.h" 0015 #include "component.h" 0016 #include "connector.h" 0017 #include "docmanager.h" 0018 #include "drawpart.h" 0019 #include "ecnode.h" 0020 #include "itemdocument.h" 0021 #include "itemlibrary.h" 0022 #include "ktechlab.h" 0023 #include "utils.h" 0024 0025 //#include <kaccel.h> 0026 #include <KLocalizedString> 0027 #include <KStandardAction> 0028 // #include <k3popupmenu.h> 0029 #include <KActionCollection> 0030 #include <KToolBarPopupAction> 0031 0032 #include <QApplication> 0033 #include <QCursor> 0034 #include <QMenu> 0035 #include <QMimeData> 0036 #include <QMouseEvent> 0037 #include <QTimer> 0038 #include <QVBoxLayout> 0039 0040 #include <cmath> 0041 0042 #include <ktlconfig.h> 0043 #include <ktechlab_debug.h> 0044 0045 // BEGIN class ItemView 0046 ItemView::ItemView(ItemDocument *itemDocument, ViewContainer *viewContainer, uint viewAreaId) 0047 : View(itemDocument, viewContainer, viewAreaId) 0048 { 0049 KActionCollection *ac = actionCollection(); 0050 0051 KStandardAction::selectAll(itemDocument, SLOT(selectAll()), ac); 0052 KStandardAction::zoomIn(this, SLOT(zoomIn()), ac); 0053 KStandardAction::zoomOut(this, SLOT(zoomOut()), ac); 0054 KStandardAction::actualSize(this, SLOT(actualSize()), ac)->setEnabled(false); 0055 0056 // KAccel *pAccel = new KAccel(this); 0057 // pAccel->insert( "Cancel", i18n("Cancel"), i18n("Cancel the current operation"), Qt::Key_Escape, itemDocument, SLOT(cancelCurrentOperation()) ); 0058 // pAccel->readSettings(); // TODO what does this do? 0059 QAction *pAccel = new QAction(QIcon::fromTheme("process-stop"), i18n("Cancel"), ac); 0060 pAccel->setObjectName("cancelCurrentOperation"); 0061 pAccel->setShortcut(Qt::Key_Escape); 0062 connect(pAccel, &QAction::triggered, itemDocument, &ItemDocument::cancelCurrentOperation); 0063 ac->addAction("cancelCurrentOperation", pAccel); 0064 0065 { 0066 // new KAction( i18n("Delete"), "edit-delete", Qt::Key_Delete, itemDocument, SLOT(deleteSelection()), ac, "edit_delete" ); 0067 QAction *action = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete"), ac); 0068 action->setObjectName("edit_delete"); 0069 action->setShortcut(Qt::Key_Delete); 0070 connect(action, &QAction::triggered, itemDocument, &ItemDocument::deleteSelection); 0071 ac->addAction("edit_delete", action); 0072 } 0073 { 0074 // new KAction( i18n("Export as Image..."), 0, 0, itemDocument, SLOT(exportToImage()), ac, "file_export_image"); 0075 QAction *action = new QAction(QIcon::fromTheme("document-export"), i18n("Export as Image..."), ac); 0076 action->setObjectName("file_export_image"); 0077 connect(action, &QAction::triggered, itemDocument, &ItemDocument::exportToImage); 0078 ac->addAction("file_export_image", action); 0079 } 0080 0081 // BEGIN Item Alignment actions 0082 { 0083 // new KAction( i18n("Align Horizontally"), 0, 0, itemDocument, SLOT(alignHorizontally()), ac, "align_horizontally" ); 0084 QAction *action = new QAction(QIcon::fromTheme("align-horizontal-center"), i18n("Align Horizontally"), ac); 0085 action->setObjectName("align_horizontally"); 0086 connect(action, &QAction::triggered, itemDocument, &ItemDocument::alignHorizontally); 0087 ac->addAction("align_horizontally", action); 0088 } 0089 { 0090 // new KAction( i18n("Align Vertically"), 0, 0, itemDocument, SLOT(alignVertically()), ac, "align_vertically" ); 0091 QAction *action = new QAction(QIcon::fromTheme("align-vertical-center"), i18n("Align Vertically"), ac); 0092 action->setObjectName("align_vertically"); 0093 connect(action, &QAction::triggered, itemDocument, &ItemDocument::alignVertically); 0094 ac->addAction("align_vertically", action); 0095 } 0096 { 0097 // new KAction( i18n("Distribute Horizontally"), 0, 0, itemDocument, SLOT(distributeHorizontally()), ac, "distribute_horizontally" ); 0098 QAction *action = new QAction(QIcon::fromTheme("distribute-horizontal-x"), i18n("Distribute Horizontally"), ac); 0099 action->setObjectName("distribute_horizontally"); 0100 connect(action, &QAction::triggered, itemDocument, &ItemDocument::distributeHorizontally); 0101 ac->addAction("distribute_horizontally", action); 0102 } 0103 { 0104 // new KAction( i18n("Distribute Vertically"), 0, 0, itemDocument, SLOT(distributeVertically()), ac, "distribute_vertically" ); 0105 QAction *action = new QAction(QIcon::fromTheme("distribute-vertical-y"), i18n("Distribute Vertically"), ac); 0106 action->setObjectName("distribute_vertically"); 0107 connect(action, &QAction::triggered, itemDocument, &ItemDocument::distributeVertically); 0108 ac->addAction("distribute_vertically", action); 0109 } 0110 // END Item Alignment actions 0111 0112 // BEGIN Draw actions 0113 // KToolBarPopupAction * pa = new KToolBarPopupAction( i18n("Draw"), "paintbrush", 0, 0, 0, ac, "edit_draw" ); 0114 KToolBarPopupAction *pa = new KToolBarPopupAction(QIcon::fromTheme("draw-brush"), i18n("Draw"), ac); 0115 pa->setObjectName("edit_draw"); 0116 pa->setDelayed(false); 0117 ac->addAction("edit_draw", pa); 0118 0119 QMenu *m = pa->menu(); 0120 m->setTitle(i18n("Draw")); 0121 0122 m->addAction(QIcon::fromTheme("draw-text"), i18n("Text"))->setData(DrawPart::da_text); 0123 m->addAction(QIcon::fromTheme("draw-line"), i18n("Line"))->setData(DrawPart::da_line); 0124 m->addAction(QIcon::fromTheme("draw-arrow"), i18n("Arrow"))->setData(DrawPart::da_arrow); 0125 m->addAction(QIcon::fromTheme("draw-ellipse"), i18n("Ellipse"))->setData(DrawPart::da_ellipse); 0126 m->addAction(QIcon::fromTheme("draw-rectangle"), i18n("Rectangle"))->setData(DrawPart::da_rectangle); 0127 m->addAction(QIcon::fromTheme("insert-image"), i18n("Image"))->setData(DrawPart::da_image); 0128 connect(m, &QMenu::triggered, itemDocument, &ItemDocument::slotSetDrawAction); 0129 // END Draw actions 0130 0131 // BEGIN Item Control actions 0132 { 0133 // new KAction( i18n("Raise Selection"), "object-order-raise", Qt::Key_PageUp, itemDocument, SLOT(raiseZ()), ac, "edit_raise" ); 0134 QAction *action = new QAction(QIcon::fromTheme("object-order-raise"), i18n("Raise Selection"), ac); 0135 action->setObjectName("edit_raise"); 0136 action->setShortcut(Qt::Key_PageUp); 0137 connect(action, &QAction::triggered, itemDocument, qOverload<>(&ItemDocument::raiseZ)); 0138 ac->addAction("edit_raise", action); 0139 } 0140 { 0141 // new KAction( i18n("Lower Selection"), "object-order-lower", Qt::Key_PageDown, itemDocument, SLOT(lowerZ()), ac, "edit_lower" ); 0142 QAction *action = new QAction(QIcon::fromTheme("object-order-lower"), i18n("Lower Selection"), ac); 0143 action->setObjectName("edit_lower"); 0144 action->setShortcut(Qt::Key_PageDown); 0145 connect(action, &QAction::triggered, itemDocument, qOverload<>(&ItemDocument::lowerZ)); 0146 ac->addAction("edit_lower", action); 0147 } 0148 // END Item Control actions 0149 0150 { 0151 // KAction * na = new KAction( "", 0, 0, 0, 0, ac, "null_action" ); 0152 QAction *na = new QAction("", ac); 0153 na->setObjectName("null_action"); 0154 na->setEnabled(false); 0155 } 0156 0157 setXMLFile("ktechlabitemviewui.rc"); 0158 0159 m_pUpdateStatusTmr = new QTimer(this); 0160 connect(m_pUpdateStatusTmr, &QTimer::timeout, this, &ItemView::updateStatus); 0161 connect(this, &ItemView::unfocused, this, &ItemView::stopUpdatingStatus); 0162 0163 m_pDragItem = nullptr; 0164 p_itemDocument = itemDocument; 0165 m_zoomLevel = 1.; 0166 m_CVBEditor = new CVBEditor(p_itemDocument->canvas(), this); 0167 m_CVBEditor->setObjectName("cvbEditor"); 0168 m_CVBEditor->setLineWidth(1); 0169 0170 // connect(m_CVBEditor, SIGNAL(horizontalSliderReleased()), itemDocument, SLOT(requestCanvasResize())); 0171 connect(m_CVBEditor, &CVBEditor::horizontalSliderReleased, itemDocument, &ItemDocument::requestCanvasResize); 0172 connect(m_CVBEditor, &CVBEditor::verticalSliderReleased, itemDocument, &ItemDocument::requestCanvasResize); 0173 0174 m_layout->insertWidget(0, m_CVBEditor); 0175 0176 setAcceptDrops(true); 0177 0178 setFocusWidget(m_CVBEditor->viewport()); 0179 } 0180 0181 ItemView::~ItemView() 0182 { 0183 } 0184 0185 bool ItemView::canZoomIn() const 0186 { 0187 return true; 0188 } 0189 bool ItemView::canZoomOut() const 0190 { 0191 return int(std::floor((100 * m_zoomLevel) + 0.5)) > 25; 0192 } 0193 0194 QPoint ItemView::mousePosToCanvasPos(const QPoint &contentsClick) const 0195 { 0196 QPoint offsetPos = contentsClick + QPoint(cvbEditor()->contentsX(), cvbEditor()->contentsY()); 0197 return (offsetPos / zoomLevel()) + p_itemDocument->canvas()->rect().topLeft(); 0198 } 0199 0200 void ItemView::zoomIn(const QPoint ¢er) 0201 { 0202 // NOTE The code in this function is nearly the same as that in zoomOut. 0203 // Any updates to this code should also be done to zoomOut 0204 0205 // Previous position of center in widget coordinates 0206 QPoint previous = center * zoomLevel() - QPoint(cvbEditor()->contentsX(), cvbEditor()->contentsY()); 0207 0208 // Don't repaint the view until we've also shifted it 0209 cvbEditor()->viewport()->setUpdatesEnabled(false); 0210 0211 zoomIn(); 0212 0213 // Adjust the contents' position to ensure that "previous" remains fixed 0214 QPoint offset = center * zoomLevel() - previous; 0215 cvbEditor()->setContentsPos(offset.x(), offset.y()); 0216 0217 cvbEditor()->viewport()->setUpdatesEnabled(true); 0218 cvbEditor()->viewport()->update(); 0219 } 0220 0221 void ItemView::zoomOut(const QPoint ¢er) 0222 { 0223 // NOTE The code in this function is nearly the same as that in zoomIn. 0224 // Any updates to this code should also be done to zoomIn 0225 0226 // Previous position of center in widget coordinates 0227 QPoint previous = center * zoomLevel() - QPoint(cvbEditor()->contentsX(), cvbEditor()->contentsY()); 0228 0229 // Don't repaint the view until we've also shifted it 0230 cvbEditor()->viewport()->setUpdatesEnabled(false); 0231 0232 zoomOut(); 0233 0234 // Adjust the contents' position to ensure that "previous" remains fixed 0235 QPoint offset = center * zoomLevel() - previous; 0236 cvbEditor()->setContentsPos(offset.x(), offset.y()); 0237 0238 cvbEditor()->viewport()->setUpdatesEnabled(true); 0239 cvbEditor()->viewport()->update(); 0240 } 0241 0242 void ItemView::zoomIn() 0243 { 0244 int currentZoomPercent = int(std::floor((100 * m_zoomLevel) + 0.5)); 0245 int newZoom = currentZoomPercent; 0246 0247 if (currentZoomPercent < 100) 0248 newZoom += 25; 0249 else if (currentZoomPercent < 200) 0250 newZoom += 50; 0251 else 0252 newZoom += 100; 0253 0254 m_zoomLevel = newZoom / 100.0; 0255 m_CVBEditor->updateWorldMatrix(); 0256 0257 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 0258 updateZoomActions(); 0259 } 0260 0261 void ItemView::zoomOut() 0262 { 0263 int currentZoomPercent = int(std::floor((100 * m_zoomLevel) + 0.5)); 0264 int newZoom = currentZoomPercent; 0265 0266 if (currentZoomPercent <= 25) 0267 return; 0268 if (currentZoomPercent <= 100) 0269 newZoom -= 25; 0270 else if (currentZoomPercent <= 200) 0271 newZoom -= 50; 0272 else 0273 newZoom -= 100; 0274 0275 m_zoomLevel = newZoom / 100.0; 0276 m_CVBEditor->updateWorldMatrix(); 0277 0278 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 0279 updateZoomActions(); 0280 } 0281 0282 void ItemView::actualSize() 0283 { 0284 m_zoomLevel = 1.0; 0285 QTransform m(m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0); 0286 m_CVBEditor->setWorldTransform(m); 0287 0288 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 0289 updateZoomActions(); 0290 } 0291 0292 void ItemView::updateZoomActions() 0293 { 0294 actionByName("view_zoom_in")->setEnabled(canZoomIn()); 0295 actionByName("view_zoom_out")->setEnabled(canZoomOut()); 0296 actionByName("view_actual_size")->setEnabled(m_zoomLevel != 1.0); 0297 } 0298 0299 void ItemView::dropEvent(QDropEvent *event) 0300 { 0301 removeDragItem(); 0302 const QMimeData *mimeData = event->mimeData(); 0303 0304 if (mimeData->hasUrls()) { 0305 // Then it is URLs that we can decode :) 0306 const QList<QUrl> urls = mimeData->urls(); 0307 for (const QUrl &u : urls) { 0308 DocManager::self()->openURL(u); 0309 } 0310 return; 0311 } 0312 0313 QString matchingFormat; 0314 for (QString format : mimeData->formats()) { 0315 if (format.startsWith("ktechlab/")) { 0316 matchingFormat = format; 0317 break; 0318 } 0319 } 0320 if (matchingFormat.isEmpty()) { 0321 return; 0322 } 0323 event->acceptProposedAction(); 0324 0325 QString text; 0326 // QDataStream stream( event->encodedData(event->format()), QIODevice::ReadOnly ); 0327 QByteArray byteArray(mimeData->data(matchingFormat)); 0328 0329 QDataStream stream(&byteArray, QIODevice::ReadOnly); 0330 stream >> text; 0331 0332 // Get a new component item 0333 p_itemDocument->addItem(text, mousePosToCanvasPos(event->pos()), true); 0334 0335 setFocus(); 0336 } 0337 0338 void ItemView::scrollToMouse(const QPoint &pos) 0339 { 0340 QPoint viewPos = pos - p_itemDocument->canvas()->rect().topLeft(); 0341 viewPos *= m_zoomLevel; 0342 int x = viewPos.x(); 0343 int y = viewPos.y(); 0344 0345 int left = m_CVBEditor->contentsX(); 0346 int top = m_CVBEditor->contentsY(); 0347 int width = m_CVBEditor->contentsWidth(); 0348 int height = m_CVBEditor->contentsHeight(); 0349 int right = left + m_CVBEditor->visibleWidth(); 0350 int bottom = top + m_CVBEditor->visibleHeight(); 0351 0352 // A magic "snap" region whereby if the mouse is near the edge of the canvas, 0353 // then assume that we want to scroll right up to it 0354 int snapMargin = 32; 0355 0356 if (x < snapMargin) 0357 x = 0; 0358 else if (x > width - snapMargin) 0359 x = width; 0360 0361 if (y < snapMargin) 0362 y = 0; 0363 else if (y > height - snapMargin) 0364 y = height; 0365 0366 if (x < left) 0367 m_CVBEditor->scrollBy(x - left, 0); 0368 else if (x > right) 0369 m_CVBEditor->scrollBy(x - right, 0); 0370 0371 if (y < top) 0372 m_CVBEditor->scrollBy(0, y - top); 0373 else if (y > bottom) 0374 m_CVBEditor->scrollBy(0, y - bottom); 0375 } 0376 0377 void ItemView::contentsMousePressEvent(QMouseEvent *e) 0378 { 0379 if (!e) 0380 return; 0381 0382 e->accept(); 0383 0384 if (!p_itemDocument) 0385 return; 0386 0387 EventInfo eventInfo(this, e); 0388 0389 if (eventInfo.isRightClick && m_pDragItem) { 0390 // We are dragging an item, and the user has right clicked. 0391 // Therefore, we want to rotate the item. 0392 /// @todo we should implement a virtual method in item for "rotating the item by one" 0393 /// - whatever that one may be (e.g. by 90 degrees, or changing the pin layout for 0394 /// flowparts, or nothing if the item isn't rotatable). 0395 if (Component *c = dynamic_cast<Component *>(m_pDragItem)) 0396 c->setAngleDegrees(c->angleDegrees() + 90); 0397 0398 return; 0399 } 0400 0401 p_itemDocument->canvas()->setMessage(QString()); 0402 p_itemDocument->m_cmManager->mousePressEvent(eventInfo); 0403 } 0404 0405 void ItemView::contentsMouseDoubleClickEvent(QMouseEvent *e) 0406 { 0407 if (!e) 0408 return; 0409 0410 e->accept(); 0411 0412 // HACK: Pass this of as a single press event if widget underneath 0413 KtlQCanvasItem *atTop = p_itemDocument->itemAtTop(e->pos() / zoomLevel()); 0414 if (dynamic_cast<Widget *>(atTop)) 0415 contentsMousePressEvent(e); 0416 else 0417 p_itemDocument->m_cmManager->mouseDoubleClickEvent(EventInfo(this, e)); 0418 } 0419 0420 void ItemView::contentsMouseMoveEvent(QMouseEvent *e) 0421 { 0422 // qCDebug(KTL_LOG) << "state = " << e->state(); 0423 0424 if (!e || !p_itemDocument) 0425 return; 0426 0427 e->accept(); 0428 0429 EventInfo eventInfo(this, e); 0430 0431 p_itemDocument->m_cmManager->mouseMoveEvent(eventInfo); 0432 if (!m_pUpdateStatusTmr->isActive()) 0433 startUpdatingStatus(); 0434 } 0435 0436 void ItemView::contentsMouseReleaseEvent(QMouseEvent *e) 0437 { 0438 if (!e) 0439 return; 0440 0441 e->accept(); 0442 0443 p_itemDocument->m_cmManager->mouseReleaseEvent(EventInfo(this, e)); 0444 } 0445 0446 void ItemView::contentsWheelEvent(QWheelEvent *e) 0447 { 0448 if (!e) 0449 return; 0450 0451 e->accept(); 0452 EventInfo eventInfo(this, e); 0453 if (eventInfo.ctrlPressed) { 0454 // Zooming in or out 0455 0456 if (eventInfo.pixelDelta.y() > 0) 0457 zoomIn(eventInfo.pos); 0458 else 0459 zoomOut(eventInfo.pos); 0460 0461 return; 0462 } 0463 0464 p_itemDocument->m_cmManager->wheelEvent(eventInfo); 0465 } 0466 0467 void ItemView::dragEnterEvent(QDragEnterEvent *event) 0468 { 0469 startUpdatingStatus(); 0470 0471 if (event->mimeData()->hasUrls()) { 0472 event->setAccepted(true); 0473 // Then it is URLs that we can decode later :) 0474 return; 0475 } 0476 } 0477 0478 void ItemView::createDragItem(QDragEnterEvent *e) 0479 { 0480 removeDragItem(); 0481 0482 const QMimeData *mimeData = e->mimeData(); 0483 QString matchingFormat; 0484 for (QString format : mimeData->formats()) { 0485 if (format.startsWith("ktechlab/")) { 0486 matchingFormat = format; 0487 break; 0488 } 0489 } 0490 if (matchingFormat.isEmpty()) { 0491 qCWarning(KTL_LOG) << "Invalid mime data" << mimeData->formats(); 0492 return; 0493 } 0494 0495 e->accept(); 0496 0497 QString text; 0498 // QDataStream stream( e->encodedData(e->format()), QIODevice::ReadOnly ); 0499 // QByteArray byteArray( e->encodedData(e->format()) ); 0500 QByteArray byteArray(mimeData->data(matchingFormat)); 0501 QDataStream stream(&byteArray, QIODevice::ReadOnly); 0502 stream >> text; 0503 0504 QPoint p = mousePosToCanvasPos(e->pos()); 0505 0506 m_pDragItem = itemLibrary()->createItem(text, p_itemDocument, true); 0507 0508 if (CNItem *cnItem = dynamic_cast<CNItem *>(m_pDragItem)) { 0509 cnItem->move(snapToCanvas(p.x()), snapToCanvas(p.y())); 0510 } else { 0511 m_pDragItem->move(p.x(), p.y()); 0512 } 0513 0514 m_pDragItem->show(); 0515 } 0516 0517 void ItemView::removeDragItem() 0518 { 0519 if (!m_pDragItem) 0520 return; 0521 0522 m_pDragItem->removeItem(); 0523 p_itemDocument->flushDeleteList(); 0524 m_pDragItem = nullptr; 0525 } 0526 0527 void ItemView::dragMoveEvent(QDragMoveEvent *e) 0528 { 0529 if (!m_pDragItem) 0530 return; 0531 0532 QPoint p = mousePosToCanvasPos(e->pos()); 0533 0534 if (CNItem *cnItem = dynamic_cast<CNItem *>(m_pDragItem)) { 0535 cnItem->move(snapToCanvas(p.x()), snapToCanvas(p.y())); 0536 } else { 0537 m_pDragItem->move(p.x(), p.y()); 0538 } 0539 } 0540 0541 void ItemView::dragLeaveEvent(QDragLeaveEvent *) 0542 { 0543 removeDragItem(); 0544 } 0545 0546 void ItemView::enterEvent(QEvent *e) 0547 { 0548 Q_UNUSED(e); 0549 startUpdatingStatus(); 0550 } 0551 0552 void ItemView::leaveEvent(QEvent *e) 0553 { 0554 Q_UNUSED(e); 0555 stopUpdatingStatus(); 0556 0557 // Cleanup 0558 setCursor(Qt::ArrowCursor); 0559 0560 if (KTechlab::self()) 0561 KTechlab::self()->slotChangeStatusbar(QString()); 0562 0563 if (p_itemDocument) 0564 p_itemDocument->m_canvasTip->setVisible(false); 0565 } 0566 0567 void ItemView::requestDocumentResizeToCanvasItems() 0568 { 0569 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 0570 } 0571 0572 void ItemView::slotUpdateConfiguration() 0573 { 0574 // m_CVBEditor->setEraseColor( KTLConfig::bgColor() ); 0575 // m_CVBEditor->setEraseColor( Qt::white ); // 2018.12.02 0576 QPalette pe; 0577 pe.setColor(m_CVBEditor->backgroundRole(), Qt::white); 0578 m_CVBEditor->setPalette(pe); 0579 0580 if (m_pUpdateStatusTmr->isActive()) 0581 startUpdatingStatus(); 0582 } 0583 0584 void ItemView::startUpdatingStatus() 0585 { 0586 m_pUpdateStatusTmr->stop(); 0587 m_pUpdateStatusTmr->start(int(1000. / KTLConfig::refreshRate())); 0588 } 0589 0590 void ItemView::stopUpdatingStatus() 0591 { 0592 m_pUpdateStatusTmr->stop(); 0593 } 0594 0595 void ItemView::updateStatus() 0596 { 0597 QPoint pos = mousePosToCanvasPos(m_CVBEditor->mapFromGlobal(QCursor::pos())); 0598 0599 ItemDocument *itemDocument = static_cast<ItemDocument *>(document()); 0600 if (!itemDocument) 0601 return; 0602 0603 CMManager *cmManager = itemDocument->m_cmManager; 0604 CanvasTip *canvasTip = itemDocument->m_canvasTip; 0605 0606 bool displayTip = false; 0607 QCursor cursor = Qt::ArrowCursor; 0608 QString statusbar; 0609 0610 if (cmManager->cmState() & CMManager::cms_repeated_add) { 0611 cursor = Qt::CrossCursor; 0612 statusbar = i18n("Left click to add. Right click to resume normal editing"); 0613 } else if (cmManager->cmState() & CMManager::cms_draw) { 0614 cursor = Qt::CrossCursor; 0615 statusbar = i18n("Click and hold to start drawing."); 0616 } else if (cmManager->currentManipulator()) { 0617 switch (cmManager->currentManipulator()->type()) { 0618 case CanvasManipulator::RepeatedItemAdd: 0619 cursor = Qt::CrossCursor; 0620 statusbar = i18n("Left click to add. Right click to resume normal editing"); 0621 break; 0622 case CanvasManipulator::ManualConnector: 0623 statusbar = i18n("Right click to cancel the connector"); 0624 cursor = Qt::CrossCursor; 0625 break; 0626 case CanvasManipulator::AutoConnector: 0627 cursor = Qt::CrossCursor; 0628 break; 0629 case CanvasManipulator::ItemMove: 0630 case CanvasManipulator::MechItemMove: 0631 cursor = Qt::ClosedHandCursor; 0632 break; 0633 case CanvasManipulator::Draw: 0634 cursor = Qt::CrossCursor; 0635 break; 0636 default: 0637 break; 0638 } 0639 0640 } else if (KtlQCanvasItem *qcanvasItem = itemDocument->itemAtTop(pos)) { 0641 if (Connector *con = qobject_cast<Connector *>(qcanvasItem)) { 0642 cursor = Qt::CrossCursor; 0643 if (itemDocument->type() == Document::dt_circuit) { 0644 canvasTip->displayVI(con, pos); 0645 displayTip = true; 0646 } 0647 } else if (Node *node = qobject_cast<Node *>(qcanvasItem)) { 0648 cursor = Qt::CrossCursor; 0649 if (ECNode *ecnode = qobject_cast<ECNode *>(node)) { 0650 canvasTip->displayVI(ecnode, pos); 0651 displayTip = true; 0652 } 0653 } else if (CNItem *item = qobject_cast<CNItem *>(qcanvasItem)) { 0654 cursor = Qt::OpenHandCursor; 0655 statusbar = item->name(); 0656 } 0657 } 0658 setCursor(cursor); 0659 0660 if (KTechlab::self()) 0661 KTechlab::self()->slotChangeStatusbar(statusbar); 0662 0663 canvasTip->setVisible(displayTip); 0664 } 0665 0666 // END class ItemView 0667 0668 // BEGIN class CVBEditor 0669 CVBEditor::CVBEditor(Canvas *canvas, ItemView *itemView) 0670 : KtlQCanvasView(canvas, itemView /*,Qt::WNoAutoErase | Qt::WA_StaticContents */) 0671 { 0672 setAttribute(Qt::WA_StaticContents); 0673 m_pCanvas = canvas; 0674 b_ignoreEvents = false; 0675 b_passEventsToView = true; 0676 p_itemView = itemView; 0677 0678 setMouseTracking(true); 0679 viewport()->setMouseTracking(true); 0680 setAcceptDrops(true); 0681 setFrameShape(NoFrame); 0682 // setEraseColor( KTLConfig::bgColor() ); 0683 // setEraseColor( Qt::white ); 0684 // setPaletteBackgroundColor( Qt::white ); 0685 { 0686 QPalette p; 0687 p.setColor(backgroundRole(), Qt::white); 0688 setPalette(p); 0689 } 0690 // viewport()->setEraseColor( Qt::white ); 0691 // viewport()->setPaletteBackgroundColor( Qt::white ); // 2018.12.02 0692 { 0693 QPalette pv; 0694 pv.setColor(viewport()->backgroundRole(), Qt::white); 0695 viewport()->setPalette(pv); 0696 } 0697 0698 connect(canvas, &Canvas::resized, this, &CVBEditor::canvasResized); 0699 } 0700 0701 void CVBEditor::canvasResized(const QRect &oldSize, const QRect &newSize) 0702 { 0703 updateWorldMatrix(); 0704 0705 return; 0706 0707 qCDebug(KTL_LOG); 0708 0709 QPoint delta = oldSize.topLeft() - newSize.topLeft(); 0710 delta *= p_itemView->zoomLevel(); 0711 scrollBy(delta.x(), delta.y()); 0712 } 0713 0714 void CVBEditor::updateWorldMatrix() 0715 { 0716 double z = p_itemView->zoomLevel(); 0717 QRect r = m_pCanvas->rect(); 0718 // QTransform m( z, 0.0, 0.0, z, -r.left(), -r.top() ); 0719 // QTransform m( z, 0.0, 0.0, z, 0.0, 0.0 ); 0720 QTransform m; 0721 m.scale(z, z); 0722 m.translate(-r.left(), -r.top()); 0723 setWorldTransform(m); 0724 } 0725 0726 void CVBEditor::contentsWheelEvent(QWheelEvent *e) 0727 { 0728 QWheelEvent ce(viewport()->mapFromGlobal(e->globalPosition().toPoint()), 0729 e->globalPosition(), 0730 e->pixelDelta(), 0731 e->angleDelta(), 0732 e->buttons(), 0733 e->modifiers(), 0734 e->phase(), 0735 e->inverted()); 0736 0737 if ((e->angleDelta().x() != 0) && horizontalScrollBar()) 0738 QApplication::sendEvent(horizontalScrollBar(), e); 0739 else if ((e->angleDelta().y() != 0) && verticalScrollBar()) 0740 QApplication::sendEvent(verticalScrollBar(), e); 0741 0742 #if 0 0743 if ( b_ignoreEvents ) 0744 return; 0745 b_ignoreEvents = true; 0746 KtlQCanvasView::wheelEvent( e ); 0747 b_ignoreEvents = false; 0748 #endif 0749 } 0750 0751 bool CVBEditor::event(QEvent *e) 0752 { 0753 if (!b_passEventsToView) { 0754 bool isWheel = e->type() == QEvent::Wheel; 0755 if (isWheel && b_ignoreEvents) 0756 return false; 0757 0758 b_ignoreEvents = isWheel; 0759 bool accepted = KtlQCanvasView::event(e); 0760 b_ignoreEvents = false; 0761 return accepted; 0762 } 0763 0764 switch (e->type()) { 0765 case QEvent::MouseButtonPress: 0766 p_itemView->contentsMousePressEvent(static_cast<QMouseEvent *>(e)); 0767 return (static_cast<QMouseEvent *>(e))->isAccepted(); 0768 0769 case QEvent::MouseButtonRelease: 0770 p_itemView->contentsMouseReleaseEvent(static_cast<QMouseEvent *>(e)); 0771 return (static_cast<QMouseEvent *>(e))->isAccepted(); 0772 0773 case QEvent::MouseButtonDblClick: 0774 p_itemView->contentsMouseDoubleClickEvent(static_cast<QMouseEvent *>(e)); 0775 return (static_cast<QMouseEvent *>(e))->isAccepted(); 0776 0777 case QEvent::MouseMove: 0778 p_itemView->contentsMouseMoveEvent(static_cast<QMouseEvent *>(e)); 0779 return (static_cast<QMouseEvent *>(e))->isAccepted(); 0780 0781 case QEvent::DragEnter: 0782 p_itemView->dragEnterEvent(static_cast<QDragEnterEvent *>(e)); 0783 return true; 0784 0785 case QEvent::DragMove: 0786 p_itemView->dragMoveEvent(static_cast<QDragMoveEvent *>(e)); 0787 return true; 0788 0789 case QEvent::DragLeave: 0790 p_itemView->dragLeaveEvent(static_cast<QDragLeaveEvent *>(e)); 0791 return true; 0792 0793 case QEvent::Drop: 0794 p_itemView->dropEvent(static_cast<QDropEvent *>(e)); 0795 return true; 0796 0797 case QEvent::Enter: 0798 p_itemView->enterEvent(e); 0799 return true; 0800 0801 case QEvent::Leave: 0802 p_itemView->leaveEvent(e); 0803 return true; 0804 0805 case QEvent::Wheel: 0806 p_itemView->contentsWheelEvent(static_cast<QWheelEvent *>(e)); 0807 return (static_cast<QWheelEvent *>(e))->isAccepted(); 0808 0809 default: 0810 return KtlQCanvasView::event(e); 0811 } 0812 } 0813 0814 void CVBEditor::viewportResizeEvent(QResizeEvent *e) 0815 { 0816 KtlQCanvasView::viewportResizeEvent(e); 0817 // 2018.09.26 - move to explicit method 0818 // p_itemView->p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); 0819 p_itemView->requestDocumentResizeToCanvasItems(); 0820 } 0821 // END class CVBEditor 0822 0823 #include "moc_itemview.cpp"