File indexing completed on 2025-02-02 09:10:23
0001 /*************************************************************************** 0002 * Copyright (C) 2004-2006 by 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 "canvasmanipulator.h" 0012 #include "canvasitemparts.h" 0013 #include "cnitemgroup.h" 0014 #include "connector.h" 0015 #include "dptext.h" 0016 #include "flowcontainer.h" 0017 #include "icndocument.h" 0018 #include "itemview.h" 0019 #include "mechanicsdocument.h" 0020 #include "mechanicsgroup.h" 0021 #include "mechanicsitem.h" 0022 #include "node.h" 0023 #include "nodegroup.h" 0024 #include "picitem.h" 0025 #include "resizeoverlay.h" 0026 0027 #include "utils.h" 0028 #include <cmath> 0029 #include <cstdlib> 0030 0031 #include <KConfigGroup> 0032 #include <KSharedConfig> 0033 0034 #include <QCursor> 0035 #include <QDebug> 0036 #include <QPainter> 0037 #include <QTimer> 0038 0039 // FIXME: This source file is HUUUGE!!!, contains numerous clases, should be broken down. 0040 0041 // BEGIN class CMManager 0042 CMManager::CMManager(ItemDocument *itemDocument) 0043 : QObject() 0044 { 0045 b_allowItemScroll = true; 0046 p_lastMouseOverResizeHandle = nullptr; 0047 m_canvasManipulator = nullptr; 0048 p_itemDocument = itemDocument; 0049 m_cmState = 0; 0050 p_lastMouseOverItem = nullptr; 0051 p_lastItemClicked = nullptr; 0052 m_drawAction = -1; 0053 m_allowItemScrollTmr = new QTimer(this); 0054 connect(m_allowItemScrollTmr, &QTimer::timeout, this, &CMManager::slotAllowItemScroll); 0055 0056 KConfigGroup grGen = KSharedConfig::openConfig()->group("General"); 0057 slotSetManualRoute(grGen.readEntry("ManualRouting", false)); 0058 } 0059 0060 CMManager::~CMManager() 0061 { 0062 delete m_allowItemScrollTmr; 0063 delete m_canvasManipulator; 0064 0065 qDeleteAll(m_manipulatorInfoList); 0066 m_manipulatorInfoList.clear(); 0067 } 0068 0069 void CMManager::addManipulatorInfo(ManipulatorInfo *eventInfo) 0070 { 0071 if (eventInfo && !m_manipulatorInfoList.contains(eventInfo)) { 0072 m_manipulatorInfoList.prepend(eventInfo); 0073 } 0074 } 0075 0076 void CMManager::cancelCurrentManipulation() 0077 { 0078 delete m_canvasManipulator; 0079 m_canvasManipulator = nullptr; 0080 setRepeatedAddId(); 0081 } 0082 0083 void CMManager::mousePressEvent(EventInfo eventInfo) 0084 { 0085 if (m_canvasManipulator) { 0086 if (m_canvasManipulator->mousePressedRepeat(eventInfo)) { 0087 delete m_canvasManipulator; 0088 m_canvasManipulator = nullptr; 0089 } 0090 return; 0091 } 0092 0093 uint eventState = 0; 0094 if (eventInfo.isRightClick) 0095 eventState |= CMManager::es_right_click; 0096 0097 if (eventInfo.ctrlPressed) 0098 eventState |= CMManager::es_ctrl_pressed; 0099 0100 uint itemType = 0; 0101 uint cnItemType = 0; 0102 0103 KtlQCanvasItem *qcanvasItem = eventInfo.qcanvasItemClickedOn; 0104 0105 if (!qcanvasItem) 0106 itemType = it_none; 0107 else if (dynamic_cast<Node *>(qcanvasItem)) 0108 itemType = it_node; 0109 else if (dynamic_cast<ConnectorLine *>(qcanvasItem) || dynamic_cast<Connector *>(qcanvasItem)) 0110 itemType = it_connector; 0111 else if (dynamic_cast<PinItem *>(qcanvasItem)) 0112 itemType = it_pin; 0113 else if (dynamic_cast<ResizeHandle *>(qcanvasItem)) 0114 itemType = it_resize_handle; 0115 else if (DrawPart *drawPartClickedOn = dynamic_cast<DrawPart *>(qcanvasItem)) { 0116 itemType = it_drawpart; 0117 0118 if (drawPartClickedOn->mousePressEvent(eventInfo)) { 0119 p_lastItemClicked = drawPartClickedOn; 0120 return; 0121 } 0122 0123 if (drawPartClickedOn->isMovable()) 0124 cnItemType |= CMManager::isi_isMovable; 0125 } else if (MechanicsItem *p_mechanicsItemClickedOn = dynamic_cast<MechanicsItem *>(qcanvasItem)) { 0126 itemType = it_mechanics_item; 0127 0128 if (p_mechanicsItemClickedOn->mousePressEvent(eventInfo)) { 0129 p_lastItemClicked = p_mechanicsItemClickedOn; 0130 return; 0131 } 0132 } else { 0133 if (Widget *widget = dynamic_cast<Widget *>(qcanvasItem)) 0134 qcanvasItem = widget->parent(); 0135 0136 if (CNItem *cnItemClickedOn = dynamic_cast<CNItem *>(qcanvasItem)) { 0137 itemType = it_canvas_item; 0138 0139 if (cnItemClickedOn->mousePressEvent(eventInfo)) { 0140 p_lastItemClicked = cnItemClickedOn; 0141 return; 0142 } 0143 0144 if (cnItemClickedOn->isMovable()) 0145 cnItemType |= CMManager::isi_isMovable; 0146 } 0147 } 0148 0149 // uint highestScore=0; 0150 // ManipulatorInfo *best = nullptr; 0151 const ManipulatorInfoList::iterator end = m_manipulatorInfoList.end(); 0152 for (ManipulatorInfoList::iterator it = m_manipulatorInfoList.begin(); it != end && !m_canvasManipulator; ++it) { 0153 if ((*it)->m_acceptManipulationPtr(eventState, m_cmState, itemType, cnItemType)) { 0154 m_canvasManipulator = (*it)->m_createManipulatorPtr(p_itemDocument, this); 0155 } 0156 } 0157 0158 if (m_canvasManipulator) { 0159 if (m_canvasManipulator->mousePressedInitial(eventInfo)) { 0160 delete m_canvasManipulator; 0161 m_canvasManipulator = nullptr; 0162 } 0163 } 0164 } 0165 0166 void CMManager::mouseDoubleClickEvent(const EventInfo &eventInfo) 0167 { 0168 if (m_canvasManipulator) { 0169 // Translate this into a repeat-click event 0170 if (m_canvasManipulator->mousePressedRepeat(eventInfo)) { 0171 delete m_canvasManipulator; 0172 m_canvasManipulator = nullptr; 0173 } 0174 return; 0175 } 0176 0177 Item *item = dynamic_cast<Item *>(eventInfo.qcanvasItemClickedOn); 0178 if (item) { 0179 item->mouseDoubleClickEvent(eventInfo); 0180 return; 0181 } 0182 0183 Widget *widget = dynamic_cast<Widget *>(eventInfo.qcanvasItemClickedOn); 0184 if (widget) { 0185 widget->parent()->mouseDoubleClickEvent(eventInfo); 0186 return; 0187 } 0188 } 0189 0190 void CMManager::mouseMoveEvent(const EventInfo &eventInfo) 0191 { 0192 if (m_canvasManipulator) { 0193 if (m_canvasManipulator->mouseMoved(eventInfo)) { 0194 delete m_canvasManipulator; 0195 m_canvasManipulator = nullptr; 0196 } 0197 ItemView *itemView = dynamic_cast<ItemView *>(p_itemDocument->activeView()); 0198 if (itemView) 0199 itemView->scrollToMouse(eventInfo.pos); 0200 return; 0201 } 0202 0203 // BEGIN 0204 KtlQCanvasItem *qcnItem = p_itemDocument->itemAtTop(eventInfo.pos); 0205 Item *item; 0206 Widget *widget = dynamic_cast<Widget *>(qcnItem); 0207 if (widget) 0208 item = widget->parent(); 0209 else 0210 item = dynamic_cast<Item *>(qcnItem); 0211 0212 if (p_lastMouseOverItem != static_cast<QPointer<Item> >(item)) { 0213 QEvent event(QEvent::Leave); 0214 0215 if (p_lastMouseOverItem) 0216 p_lastMouseOverItem->leaveEvent(nullptr); 0217 0218 if (item) 0219 item->enterEvent(nullptr); 0220 0221 p_lastMouseOverItem = item; 0222 } 0223 0224 // If we clicked on an item, then continue to pass mouse events to that item until we release the mouse... 0225 if (p_lastItemClicked) { 0226 p_lastItemClicked->mouseMoveEvent(eventInfo); 0227 } else if (item) { 0228 item->mouseMoveEvent(eventInfo); 0229 } 0230 // END 0231 0232 updateCurrentResizeHandle(dynamic_cast<ResizeHandle *>(qcnItem)); 0233 } 0234 0235 void CMManager::updateCurrentResizeHandle(ResizeHandle *resizeHandle) 0236 { 0237 if (p_lastMouseOverResizeHandle != static_cast<QPointer<ResizeHandle> >(resizeHandle)) { 0238 if (p_lastMouseOverResizeHandle) 0239 p_lastMouseOverResizeHandle->setHover(false); 0240 p_lastMouseOverResizeHandle = resizeHandle; 0241 if (resizeHandle) 0242 resizeHandle->setHover(true); 0243 } 0244 } 0245 0246 void CMManager::mouseReleaseEvent(const EventInfo &eventInfo) 0247 { 0248 // If it returns true, then it has finished its editing operation 0249 if (m_canvasManipulator && m_canvasManipulator->mouseReleased(eventInfo)) { 0250 delete m_canvasManipulator; 0251 m_canvasManipulator = nullptr; 0252 } 0253 0254 if (p_lastItemClicked) { 0255 p_lastItemClicked->mouseReleaseEvent(eventInfo); 0256 p_lastItemClicked = nullptr; 0257 } 0258 0259 updateCurrentResizeHandle(dynamic_cast<ResizeHandle *>(p_itemDocument->itemAtTop(eventInfo.pos))); 0260 } 0261 0262 void CMManager::wheelEvent(const EventInfo &eventInfo) 0263 { 0264 bool accepted = false; 0265 if (b_allowItemScroll) { 0266 KtlQCanvasItem *qcnItem = p_itemDocument->itemAtTop(eventInfo.pos); 0267 Item *item; 0268 Widget *widget = dynamic_cast<Widget *>(qcnItem); 0269 if (widget) 0270 item = widget->parent(); 0271 else 0272 item = dynamic_cast<Item *>(qcnItem); 0273 if (item) 0274 accepted = item->wheelEvent(eventInfo); 0275 } 0276 if (!accepted) { 0277 // Only allow scrolling of items if we have not just been scrolling the canvas 0278 b_allowItemScroll = false; 0279 m_allowItemScrollTmr->stop(); 0280 m_allowItemScrollTmr->setSingleShot(true); 0281 m_allowItemScrollTmr->start(500 /*,true */); 0282 0283 ItemView *itemView = dynamic_cast<ItemView *>(p_itemDocument->activeView()); 0284 if (itemView) { 0285 itemView->cvbEditor()->setPassEventsToView(false); 0286 itemView->cvbEditor()->contentsWheelEvent(eventInfo.wheelEvent(0, 0)); 0287 itemView->cvbEditor()->setPassEventsToView(true); 0288 } 0289 } 0290 } 0291 0292 void CMManager::setDrawAction(int drawAction) 0293 { 0294 if (m_drawAction == drawAction) 0295 return; 0296 0297 m_drawAction = drawAction; 0298 setCMState(cms_draw, (m_drawAction != -1)); 0299 } 0300 0301 void CMManager::slotSetManualRoute(bool manualRoute) 0302 { 0303 KConfigGroup grGen = KSharedConfig::openConfig()->group("General"); 0304 grGen.writeEntry("ManualRouting", manualRoute); 0305 0306 setCMState(cms_manual_route, manualRoute); 0307 } 0308 0309 void CMManager::setCMState(CMState type, bool state) 0310 { 0311 // Set or clear the correct bit 0312 state ? (m_cmState |= type) : (m_cmState &= (~type)); 0313 0314 if (type == CMManager::cms_manual_route) 0315 emit manualRoutingChanged(state); 0316 } 0317 0318 void CMManager::setRepeatedAddId(const QString &repeatedId) 0319 { 0320 m_repeatedItemId = repeatedId; 0321 } 0322 // END class CMManager 0323 0324 // BEGIN class CanvasManipulator 0325 CanvasManipulator::CanvasManipulator(ItemDocument *itemDocument, CMManager *cmManager) 0326 { 0327 p_itemDocument = itemDocument; 0328 p_icnDocument = dynamic_cast<ICNDocument *>(itemDocument); 0329 p_mechanicsDocument = dynamic_cast<MechanicsDocument *>(itemDocument); 0330 p_canvas = p_itemDocument->canvas(); 0331 // b_connectorsAllowedRouting = true; 0332 p_selectList = p_itemDocument->selectList(); 0333 p_cnItemSelectList = dynamic_cast<CNItemGroup *>(p_selectList); 0334 p_mechItemSelectList = dynamic_cast<MechanicsGroup *>(p_selectList); 0335 p_cnItemClickedOn = nullptr; 0336 p_cmManager = cmManager; 0337 0338 // connect(itemDocument->canvas(), SIGNAL(resized(const QRect &, const QRect &)), this, SLOT(canvasResized(const QRect &, const QRect &))); 0339 connect(itemDocument->canvas(), &Canvas::resized, this, &CanvasManipulator::canvasResized); 0340 } 0341 0342 CanvasManipulator::~CanvasManipulator() 0343 { 0344 } 0345 0346 QPoint CanvasManipulator::snapPoint(QPoint point) 0347 { 0348 point /= 8; 0349 point *= 8; 0350 point += QPoint(4, 4); 0351 return point; 0352 } 0353 // END class CanvasManipulator 0354 0355 CMRepeatedItemAdd::CMRepeatedItemAdd(ItemDocument *itemDocument, CMManager *cmManager) 0356 : CanvasManipulator(itemDocument, cmManager) 0357 { 0358 } 0359 0360 CMRepeatedItemAdd::~CMRepeatedItemAdd() 0361 { 0362 } 0363 0364 CanvasManipulator *CMRepeatedItemAdd::construct(ItemDocument *itemDocument, CMManager *cmManager) 0365 { 0366 return new CMRepeatedItemAdd(itemDocument, cmManager); 0367 } 0368 0369 ManipulatorInfo *CMRepeatedItemAdd::manipulatorInfo() 0370 { 0371 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 0372 eventInfo->m_acceptManipulationPtr = CMRepeatedItemAdd::acceptManipulation; 0373 eventInfo->m_createManipulatorPtr = CMRepeatedItemAdd::construct; 0374 return eventInfo; 0375 } 0376 0377 bool CMRepeatedItemAdd::acceptManipulation(uint /*eventState*/, uint cmState, uint /*itemType*/, uint /*cnItemType*/) 0378 { 0379 return (cmState & CMManager::cms_repeated_add); 0380 } 0381 0382 bool CMRepeatedItemAdd::mousePressedRepeat(const EventInfo &eventInfo) 0383 { 0384 return mousePressedInitial(eventInfo); 0385 } 0386 0387 bool CMRepeatedItemAdd::mousePressedInitial(const EventInfo &eventInfo) 0388 { 0389 m_eventInfo = eventInfo; 0390 if (eventInfo.isRightClick) { 0391 p_cmManager->setCMState(CMManager::cms_repeated_add, false); 0392 return true; 0393 } 0394 0395 p_icnDocument->addItem(p_cmManager->repeatedItemId(), eventInfo.pos, true); 0396 p_itemDocument->requestStateSave(); 0397 return false; 0398 } 0399 0400 bool CMRepeatedItemAdd::mouseMoved(const EventInfo & /*eventInfo*/) 0401 { 0402 return false; 0403 } 0404 0405 bool CMRepeatedItemAdd::mouseReleased(const EventInfo & /*eventInfo*/) 0406 { 0407 return false; 0408 } 0409 0410 CMRightClick::CMRightClick(ItemDocument *itemDocument, CMManager *cmManager) 0411 : CanvasManipulator(itemDocument, cmManager) 0412 { 0413 } 0414 0415 CMRightClick::~CMRightClick() 0416 { 0417 } 0418 0419 CanvasManipulator *CMRightClick::construct(ItemDocument *itemDocument, CMManager *cmManager) 0420 { 0421 return new CMRightClick(itemDocument, cmManager); 0422 } 0423 0424 ManipulatorInfo *CMRightClick::manipulatorInfo() 0425 { 0426 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 0427 // eventInfo->m_eventState.m_activate = CMManager::es_right_click; 0428 eventInfo->m_acceptManipulationPtr = CMRightClick::acceptManipulation; 0429 eventInfo->m_createManipulatorPtr = CMRightClick::construct; 0430 return eventInfo; 0431 } 0432 0433 bool CMRightClick::acceptManipulation(uint eventState, uint /*cmState*/, uint /*itemType*/, uint /*cnItemType*/) 0434 { 0435 return eventState & CMManager::es_right_click; 0436 } 0437 0438 bool CMRightClick::mousePressedInitial(const EventInfo &eventInfo) 0439 { 0440 m_eventInfo = eventInfo; 0441 p_itemDocument->canvasRightClick(eventInfo.globalPos, eventInfo.qcanvasItemClickedOn); 0442 return true; 0443 } 0444 0445 bool CMRightClick::mouseMoved(const EventInfo & /*eventInfo*/) 0446 { 0447 return true; 0448 } 0449 0450 bool CMRightClick::mouseReleased(const EventInfo & /*eventInfo*/) 0451 { 0452 return true; 0453 } 0454 0455 // BEGIN class ConnectorDraw 0456 ConnectorDraw::ConnectorDraw(ItemDocument *itemDocument, CMManager *cmManager) 0457 : CanvasManipulator(itemDocument, cmManager) 0458 { 0459 p_startNode = nullptr; 0460 p_startConnector = nullptr; 0461 p_endNode = nullptr; 0462 p_endConnector = nullptr; 0463 } 0464 0465 ConnectorDraw::~ConnectorDraw() 0466 { 0467 } 0468 0469 QColor ConnectorDraw::validConnectionColor() 0470 { 0471 return QColor(255, 166, 0); 0472 } 0473 0474 QPoint ConnectorDraw::toValidPos(const QPoint &clickPos, Connector *clickedConnector) const 0475 { 0476 if (!clickedConnector) 0477 return clickPos; 0478 0479 const QPointList pointList = clickedConnector->connectorPoints(); 0480 0481 QPointList::const_iterator end = pointList.end(); 0482 0483 double dl[] = {0.5, 8.5, 11.5, 18.0, 23.0}; // various distances rounded up of (0,0) cells, (0,1), etc 0484 for (unsigned i = 0; i < 5; ++i) { 0485 for (QPointList::const_iterator it = pointList.begin(); it != end; ++it) { 0486 if (qpoint_distance(*it, clickPos) <= dl[i]) 0487 return *it; 0488 } 0489 } 0490 0491 return clickPos; 0492 } 0493 0494 Connector *ConnectorDraw::toConnector(Node *node) 0495 { 0496 if (!node || node->numCon(true, false) < 3) 0497 return nullptr; 0498 0499 return node->getAConnector(); 0500 } 0501 0502 void ConnectorDraw::grabEndStuff(KtlQCanvasItem *endItem, const QPoint &pos, bool posIsExact) 0503 { 0504 if (!endItem) 0505 return; 0506 0507 CNItem *cnItem = dynamic_cast<CNItem *>(endItem); 0508 if (cnItem && !posIsExact) 0509 p_endNode = cnItem->getClosestNode(pos); 0510 else 0511 p_endNode = dynamic_cast<Node *>(endItem); 0512 0513 if (p_endNode && p_endNode->numCon(true, false) > 2) { 0514 p_endConnector = toConnector(p_endNode); 0515 p_endNode = nullptr; 0516 } 0517 0518 // If the endItem is a node, we have to finish exactly on the end when posIsExact is true 0519 if (posIsExact && p_endNode && (p_endNode->x() != pos.x() || p_endNode->y() != pos.y())) 0520 p_endNode = nullptr; 0521 0522 if (!p_endConnector) 0523 p_endConnector = dynamic_cast<Connector *>(endItem); 0524 } 0525 // END class ConnectorDraw 0526 0527 // BEGIN class CMAutoConnector 0528 CMAutoConnector::CMAutoConnector(ItemDocument *itemDocument, CMManager *cmManager) 0529 : ConnectorDraw(itemDocument, cmManager) 0530 { 0531 m_connectorLine = nullptr; 0532 p_startNode = nullptr; 0533 p_startConnector = nullptr; 0534 } 0535 0536 CMAutoConnector::~CMAutoConnector() 0537 { 0538 delete m_connectorLine; 0539 } 0540 0541 CanvasManipulator *CMAutoConnector::construct(ItemDocument *itemDocument, CMManager *cmManager) 0542 { 0543 return new CMAutoConnector(itemDocument, cmManager); 0544 } 0545 0546 ManipulatorInfo *CMAutoConnector::manipulatorInfo() 0547 { 0548 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 0549 eventInfo->m_acceptManipulationPtr = CMAutoConnector::acceptManipulation; 0550 eventInfo->m_createManipulatorPtr = CMAutoConnector::construct; 0551 return eventInfo; 0552 } 0553 0554 bool CMAutoConnector::acceptManipulation(uint /*eventState*/, uint cmState, uint itemType, uint /*cnItemType*/) 0555 { 0556 return (itemType & (CMManager::it_node | CMManager::it_connector)) && !(cmState & CMManager::cms_manual_route); 0557 } 0558 0559 bool CMAutoConnector::mousePressedInitial(const EventInfo &eventInfo) 0560 { 0561 m_eventInfo = eventInfo; 0562 0563 p_startNode = dynamic_cast<Node *>(eventInfo.qcanvasItemClickedOn); 0564 0565 if (p_startNode) { 0566 m_eventInfo.pos = m_prevPos = p_icnDocument->gridSnap(QPoint(int(p_startNode->x()), int(p_startNode->y()))); 0567 if (p_startNode->numCon(true, false) > 2) { 0568 p_startConnector = toConnector(p_startNode); 0569 p_startNode = nullptr; 0570 } 0571 } else if ((p_startConnector = dynamic_cast<Connector *>(eventInfo.qcanvasItemClickedOn))) { 0572 // startConnectorPoint = m_eventInfo.pos = m_prevPos = p_icnDocument->gridSnap(m_eventInfo.pos); 0573 startConnectorPoint = m_eventInfo.pos = m_prevPos = toValidPos(m_eventInfo.pos, p_startConnector); 0574 } else 0575 return true; 0576 0577 p_icnDocument->unselectAll(); 0578 0579 delete m_connectorLine; 0580 m_connectorLine = new KtlQCanvasLine(p_canvas); 0581 m_connectorLine->setPen(QColor(0, 0, 0)); 0582 m_connectorLine->setZ(ItemDocument::Z::ConnectorCreateLine); 0583 m_connectorLine->show(); 0584 return false; 0585 } 0586 0587 bool CMAutoConnector::mouseMoved(const EventInfo &eventInfo) 0588 { 0589 const QPoint pos = eventInfo.pos; 0590 0591 int newX = p_icnDocument->gridSnap(pos.x()); 0592 int newY = p_icnDocument->gridSnap(pos.y()); 0593 0594 bool movedFlag = false; 0595 0596 if (newX != m_prevPos.x()) { 0597 m_prevPos.setX(newX); 0598 movedFlag = true; 0599 } 0600 0601 if (newY != m_prevPos.y()) { 0602 m_prevPos.setY(newY); 0603 movedFlag = true; 0604 } 0605 0606 m_connectorLine->setPoints(m_eventInfo.pos.x(), m_eventInfo.pos.y(), newX, newY); 0607 0608 if (movedFlag) { 0609 KtlQCanvasItem *startItem = nullptr; 0610 if (p_startNode) 0611 startItem = p_startNode; 0612 else if (p_startConnector) 0613 startItem = p_startConnector; 0614 0615 KtlQCanvasItem *endItem = p_icnDocument->itemAtTop(QPoint(newX, newY)); 0616 if (CNItem *cni = dynamic_cast<CNItem *>(endItem)) 0617 endItem = cni->getClosestNode(QPoint(newX, newY)); 0618 0619 bool validLine = p_icnDocument->canConnect(startItem, endItem); 0620 m_connectorLine->setPen(validLine ? validConnectionColor() : Qt::black); 0621 } 0622 return false; 0623 } 0624 0625 bool CMAutoConnector::mouseReleased(const EventInfo &eventInfo) 0626 { 0627 const QPoint pos = eventInfo.pos; 0628 0629 QPoint end = m_connectorLine->endPoint(); 0630 delete m_connectorLine; 0631 m_connectorLine = nullptr; 0632 0633 KtlQCanvasItem *qcanvasItem = p_icnDocument->itemAtTop(end); 0634 if (!qcanvasItem) 0635 return true; 0636 0637 grabEndStuff(qcanvasItem, pos, false); 0638 0639 if (p_startConnector) { 0640 if (p_endConnector) { 0641 if (!p_icnDocument->createConnector(p_endConnector, p_startConnector, p_icnDocument->gridSnap(pos), startConnectorPoint)) 0642 return true; 0643 } else if (p_endNode) { 0644 if (!p_icnDocument->createConnector(p_endNode, p_startConnector, startConnectorPoint)) 0645 return true; 0646 } else 0647 return true; 0648 } else if (p_startNode) { 0649 if (p_endConnector) { 0650 if (!p_icnDocument->createConnector(p_startNode, p_endConnector, p_icnDocument->gridSnap(pos))) 0651 return true; 0652 } else if (p_endNode) { 0653 if (!p_icnDocument->createConnector(p_startNode, p_endNode)) 0654 return true; 0655 } else 0656 return true; 0657 } else 0658 return true; 0659 0660 p_itemDocument->requestStateSave(); 0661 return true; 0662 } 0663 // END class CMAutoConnector 0664 0665 // BEGIN class CMManualConnector 0666 CMManualConnector::CMManualConnector(ItemDocument *itemDocument, CMManager *cmManager) 0667 : ConnectorDraw(itemDocument, cmManager) 0668 { 0669 m_manualConnectorDraw = nullptr; 0670 } 0671 0672 CMManualConnector::~CMManualConnector() 0673 { 0674 delete m_manualConnectorDraw; 0675 } 0676 0677 CanvasManipulator *CMManualConnector::construct(ItemDocument *itemDocument, CMManager *cmManager) 0678 { 0679 return new CMManualConnector(itemDocument, cmManager); 0680 } 0681 0682 ManipulatorInfo *CMManualConnector::manipulatorInfo() 0683 { 0684 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 0685 eventInfo->m_acceptManipulationPtr = CMManualConnector::acceptManipulation; 0686 eventInfo->m_createManipulatorPtr = CMManualConnector::construct; 0687 return eventInfo; 0688 } 0689 0690 bool CMManualConnector::acceptManipulation(uint /*eventState*/, uint cmState, uint itemType, uint /*cnItemType*/) 0691 { 0692 return (itemType & (CMManager::it_node | CMManager::it_connector)) && (cmState & CMManager::cms_manual_route); 0693 } 0694 0695 bool CMManualConnector::mousePressedInitial(const EventInfo &eventInfo) 0696 { 0697 if (eventInfo.isRightClick) 0698 return true; 0699 0700 m_eventInfo = eventInfo; 0701 0702 p_icnDocument->unselectAll(); 0703 0704 QPoint sp; 0705 0706 if ((p_startNode = dynamic_cast<Node *>(eventInfo.qcanvasItemClickedOn))) { 0707 sp.setX(int(p_startNode->x())); 0708 sp.setY(int(p_startNode->y())); 0709 if (p_startNode->numCon(true, false) > 2) { 0710 p_startConnector = toConnector(p_startNode); 0711 p_startNode = nullptr; 0712 } 0713 } else { 0714 p_startConnector = dynamic_cast<Connector *>(eventInfo.qcanvasItemClickedOn); 0715 sp = toValidPos(eventInfo.pos, p_startConnector); 0716 } 0717 startConnectorPoint = sp; 0718 0719 if (m_manualConnectorDraw) 0720 delete m_manualConnectorDraw; 0721 m_manualConnectorDraw = new ManualConnectorDraw(p_icnDocument, sp); 0722 return false; 0723 } 0724 0725 bool CMManualConnector::mousePressedRepeat(const EventInfo &eventInfo) 0726 { 0727 m_eventInfo = eventInfo; 0728 if (eventInfo.isRightClick) { 0729 return true; 0730 } 0731 m_manualConnectorDraw->mouseClicked(p_icnDocument->gridSnap(m_eventInfo.pos)); 0732 return false; 0733 } 0734 0735 bool CMManualConnector::mouseMoved(const EventInfo &eventInfo) 0736 { 0737 if (!m_manualConnectorDraw) 0738 return true; 0739 0740 const QPoint pos = eventInfo.pos; 0741 0742 int newX = p_icnDocument->gridSnap(pos.x()); 0743 int newY = p_icnDocument->gridSnap(pos.y()); 0744 0745 bool movedFlag = false; 0746 0747 if (newX != m_prevPos.x()) { 0748 m_prevPos.setX(newX); 0749 movedFlag = true; 0750 } 0751 0752 if (newY != m_prevPos.y()) { 0753 m_prevPos.setY(newY); 0754 movedFlag = true; 0755 } 0756 0757 if (movedFlag) { 0758 KtlQCanvasItem *startItem = nullptr; 0759 if (p_startNode) 0760 startItem = p_startNode; 0761 else if (p_startConnector) 0762 startItem = p_startConnector; 0763 0764 KtlQCanvasItem *endItem = p_icnDocument->itemAtTop(QPoint(newX, newY)); 0765 0766 // If the endItem is a node, we have to finish exactly on the end. 0767 if (Node *node = dynamic_cast<Node *>(endItem)) { 0768 if (node->x() != newX || node->y() != newY) 0769 endItem = nullptr; 0770 } 0771 0772 bool validLine = p_icnDocument->canConnect(startItem, endItem); 0773 0774 m_manualConnectorDraw->setColor(validLine ? validConnectionColor() : Qt::black); 0775 m_manualConnectorDraw->mouseMoved(QPoint(newX, newY)); 0776 } 0777 0778 return false; 0779 } 0780 0781 bool CMManualConnector::mouseReleased(const EventInfo &eventInfo) 0782 { 0783 if (!m_manualConnectorDraw) 0784 return true; 0785 0786 QPoint pos = p_icnDocument->gridSnap(eventInfo.pos); 0787 0788 grabEndStuff(m_manualConnectorDraw->mouseClicked(pos), pos, true); 0789 0790 if (!p_endNode && !p_endConnector) 0791 return false; 0792 0793 // Create the points that define the manual route 0794 QPointList list = m_manualConnectorDraw->pointList(); 0795 delete m_manualConnectorDraw; 0796 m_manualConnectorDraw = nullptr; 0797 0798 if (p_startConnector) { 0799 if (p_endConnector) { 0800 if (!p_icnDocument->createConnector(p_endConnector, p_startConnector, p_icnDocument->gridSnap(pos), startConnectorPoint, &list)) 0801 return true; 0802 } else // if (p_endNode) 0803 { 0804 if (!p_icnDocument->createConnector(p_endNode, p_startConnector, startConnectorPoint, &list)) 0805 return true; 0806 } 0807 } else if (p_startNode) { 0808 if (p_endConnector) { 0809 if (!p_icnDocument->createConnector(p_startNode, p_endConnector, p_icnDocument->gridSnap(pos), &list)) 0810 return true; 0811 } else // if (p_endNode) 0812 { 0813 if (!p_icnDocument->createConnector(p_startNode, p_endNode, &list)) 0814 return true; 0815 } 0816 } else 0817 return true; 0818 0819 p_itemDocument->requestStateSave(); 0820 return true; 0821 } 0822 // END class CMManualConnector 0823 0824 // BEGIN class CMItemMove 0825 CMItemMove::CMItemMove(ItemDocument *itemDocument, CMManager *cmManager) 0826 : CanvasManipulator(itemDocument, cmManager) 0827 { 0828 p_flowContainerCandidate = nullptr; 0829 m_bItemsSnapToGrid = false; 0830 } 0831 0832 CMItemMove::~CMItemMove() 0833 { 0834 } 0835 0836 CanvasManipulator *CMItemMove::construct(ItemDocument *itemDocument, CMManager *cmManager) 0837 { 0838 return new CMItemMove(itemDocument, cmManager); 0839 } 0840 0841 ManipulatorInfo *CMItemMove::manipulatorInfo() 0842 { 0843 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 0844 eventInfo->m_acceptManipulationPtr = CMItemMove::acceptManipulation; 0845 eventInfo->m_createManipulatorPtr = CMItemMove::construct; 0846 return eventInfo; 0847 } 0848 0849 bool CMItemMove::acceptManipulation(uint eventState, uint /*cmState*/, uint itemType, uint cnItemType) 0850 { 0851 return ((itemType & CMManager::it_canvas_item) || (itemType & CMManager::it_drawpart)) && (cnItemType & CMManager::isi_isMovable) && !(eventState & CMManager::es_right_click); 0852 } 0853 0854 bool CMItemMove::mousePressedInitial(const EventInfo &eventInfo) 0855 { 0856 m_eventInfo = eventInfo; 0857 m_prevPos = eventInfo.pos; 0858 0859 Item *item = dynamic_cast<Item *>(eventInfo.qcanvasItemClickedOn); 0860 0861 if (!item) 0862 return true; 0863 0864 if (!p_selectList->contains(item)) { 0865 if (!eventInfo.ctrlPressed) 0866 p_itemDocument->unselectAll(); 0867 0868 p_itemDocument->select(item); 0869 } else if (m_eventInfo.ctrlPressed) 0870 p_itemDocument->unselect(item); 0871 0872 if (p_selectList->isEmpty()) 0873 return true; 0874 0875 // We want to allow dragging into FlowContainers if this is a FlowView 0876 p_flowContainerCandidate = nullptr; 0877 { 0878 const ItemList &itemList = p_icnDocument->itemList(); 0879 const ItemList::const_iterator ciEnd = itemList.end(); 0880 for (ItemList::const_iterator it = itemList.begin(); it != ciEnd; ++it) { 0881 if (FlowContainer *flowContainer = dynamic_cast<FlowContainer *>(static_cast<Item *>(*it))) 0882 flowContainer->setFullBounds(true); 0883 } 0884 } 0885 0886 ItemList itemList = p_cnItemSelectList->items(false); 0887 itemList.removeAll(static_cast<Item *>(nullptr)); 0888 0889 m_bItemsSnapToGrid = false; 0890 const ItemList::iterator itemListEnd = itemList.end(); 0891 for (ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it) { 0892 CNItem *cnItem = dynamic_cast<CNItem *>(static_cast<Item *>(*it)); 0893 if (!cnItem || !cnItem->canvas()) 0894 continue; 0895 0896 m_bItemsSnapToGrid = true; 0897 } 0898 0899 if (m_bItemsSnapToGrid) 0900 m_prevSnapPoint = this->snapPoint(m_prevPos); 0901 else 0902 m_prevSnapPoint = m_prevPos; 0903 0904 ConnectorList fixedConnectors; 0905 p_icnDocument->getTranslatable(itemList, &fixedConnectors, &m_translatableConnectors, &m_translatableNodeGroups); 0906 0907 const ConnectorList::iterator fixedConnectorsEnd = fixedConnectors.end(); 0908 for (ConnectorList::iterator it = fixedConnectors.begin(); it != fixedConnectorsEnd; ++it) 0909 (*it)->setSemiHidden(true); 0910 0911 p_flowContainerCandidate = p_icnDocument->flowContainer(eventInfo.pos); 0912 0913 return false; 0914 } 0915 0916 void CMItemMove::canvasResized(const QRect & /*oldSize*/, const QRect & /*newSize*/) 0917 { 0918 // QPoint delta = oldSize.topLeft() - newSize.topLeft(); // 2017.10.01 - comment out unused variable 0919 0920 // scrollCanvasToSelection(); 0921 0922 // QCursor::setPos( QCursor::pos() + delta ); 0923 // m_prevPos += delta; 0924 // m_prevSnapPoint += delta; 0925 } 0926 0927 void CMItemMove::scrollCanvasToSelection() 0928 { 0929 QRect bound; 0930 ItemList itemList = p_cnItemSelectList->items(false); 0931 itemList.removeAll(static_cast<Item *>(nullptr)); 0932 const ItemList::iterator itemListEnd = itemList.end(); 0933 for (ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it) 0934 bound |= (*it)->boundingRect(); 0935 0936 QPoint scrollToPos = m_prevPos; 0937 if (m_dx < 0) { 0938 // Scrolling left 0939 scrollToPos -= QPoint(bound.left(), 0); 0940 } else { 0941 // Scrolling right 0942 scrollToPos += QPoint(bound.right(), 0); 0943 } 0944 0945 if (m_dy < 0) { 0946 // Scrolling up 0947 scrollToPos -= QPoint(0, bound.top()); 0948 } else { 0949 // Scrolling right 0950 scrollToPos += QPoint(0, bound.bottom()); 0951 } 0952 0953 ItemView *itemView = dynamic_cast<ItemView *>(p_itemDocument->activeView()); 0954 if (itemView) 0955 itemView->scrollToMouse(scrollToPos); 0956 } 0957 0958 bool CMItemMove::mouseMoved(const EventInfo &eventInfo) 0959 { 0960 QPoint pos = eventInfo.pos; 0961 0962 QPoint snapPoint = pos; 0963 if (m_bItemsSnapToGrid) 0964 snapPoint = this->snapPoint(snapPoint); 0965 0966 int dx = snapPoint.x() - m_prevSnapPoint.x(); 0967 int dy = snapPoint.y() - m_prevSnapPoint.y(); 0968 0969 m_dx = dx; 0970 m_dy = dy; 0971 0972 const ItemList itemList = p_cnItemSelectList->items(); 0973 const ItemList::const_iterator end = itemList.end(); 0974 0975 for (ItemList::const_iterator it = itemList.begin(); it != end; ++it) { 0976 if (!*it || !(*it)->isMovable()) 0977 continue; 0978 0979 // QRect oldRect = (*it)->boundingRect(); // 2017.10.01 - comment out unused variable 0980 (*it)->moveBy(dx, dy); 0981 // QRect newRect = (*it)->boundingRect(); 0982 // QRect merged = oldRect | newRect; // 2017.10.01 - comment out unused variable 0983 } 0984 0985 if ((dx != 0) || (dy != 0)) { 0986 const ConnectorList::iterator frEnd = m_translatableConnectors.end(); 0987 for (ConnectorList::iterator it = m_translatableConnectors.begin(); it != frEnd; ++it) 0988 (*it)->translateRoute(dx, dy); 0989 0990 const NodeGroupList::iterator end = m_translatableNodeGroups.end(); 0991 for (NodeGroupList::iterator it = m_translatableNodeGroups.begin(); it != end; ++it) 0992 (*it)->translate(dx, dy); 0993 } 0994 0995 FlowContainer *fc = p_icnDocument->flowContainer(pos); 0996 if (fc != p_flowContainerCandidate) { 0997 if (p_flowContainerCandidate) { 0998 p_flowContainerCandidate->setSelected(false); 0999 p_flowContainerCandidate = nullptr; 1000 } 1001 } 1002 1003 if (fc) { 1004 p_flowContainerCandidate = fc; 1005 p_flowContainerCandidate->setSelected(true); 1006 } 1007 1008 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 1009 p_canvas->update(); 1010 m_prevPos = pos; 1011 m_prevSnapPoint = snapPoint; 1012 1013 // scrollCanvasToSelection(); 1014 1015 return false; 1016 } 1017 1018 bool CMItemMove::mouseReleased(const EventInfo &eventInfo) 1019 { 1020 // Is the release event from a right click (which rotates items)? 1021 if (eventInfo.isRightClick || eventInfo.isMiddleClick) 1022 return false; 1023 1024 QStringList itemIDs; 1025 1026 const ItemList itemList = p_cnItemSelectList->items(); 1027 const ItemList::const_iterator ilEnd = itemList.end(); 1028 for (ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it) { 1029 if (*it) 1030 itemIDs.append((*it)->id()); 1031 } 1032 1033 // const QPoint pos = eventInfo.pos; // 2017.10.10 - comment out unused variable 1034 1035 // And make sure all connectors are properly shown 1036 const ConnectorList &connectorList = p_icnDocument->connectorList(); 1037 const ConnectorList::const_iterator conEnd = connectorList.end(); 1038 for (ConnectorList::const_iterator it = connectorList.begin(); it != conEnd; ++it) { 1039 (*it)->setSemiHidden(false); 1040 } 1041 1042 if (p_flowContainerCandidate) { 1043 for (ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it) 1044 p_flowContainerCandidate->addChild(*it); 1045 1046 p_flowContainerCandidate->setSelected(false); 1047 p_flowContainerCandidate = nullptr; 1048 } else { 1049 for (ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it) 1050 (*it)->setParentItem(nullptr); 1051 } 1052 1053 // And disable the FlowContainers again... 1054 const ItemList &cnItemList = p_icnDocument->itemList(); 1055 const ItemList::const_iterator end = cnItemList.end(); 1056 for (ItemList::const_iterator it = cnItemList.begin(); it != end; ++it) { 1057 if (FlowContainer *flowContainer = dynamic_cast<FlowContainer *>(static_cast<Item *>(*it))) 1058 flowContainer->setFullBounds(false); 1059 } 1060 1061 if (p_icnDocument) 1062 p_icnDocument->requestRerouteInvalidatedConnectors(); 1063 1064 if (m_eventInfo.pos != eventInfo.pos) 1065 p_itemDocument->requestStateSave(); 1066 1067 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 1068 1069 return true; 1070 } 1071 1072 bool CMItemMove::mousePressedRepeat(const EventInfo &info) 1073 { 1074 if (info.isRightClick) 1075 p_cnItemSelectList->slotRotateCW(); 1076 else if (info.isMiddleClick) 1077 p_cnItemSelectList->flipHorizontally(); 1078 1079 return false; 1080 } 1081 // END class CMItemMove 1082 1083 CMItemResize::CMItemResize(ItemDocument *itemDocument, CMManager *cmManager) 1084 : CanvasManipulator(itemDocument, cmManager) 1085 { 1086 } 1087 1088 CMItemResize::~CMItemResize() 1089 { 1090 } 1091 1092 CanvasManipulator *CMItemResize::construct(ItemDocument *itemDocument, CMManager *cmManager) 1093 { 1094 return new CMItemResize(itemDocument, cmManager); 1095 } 1096 1097 ManipulatorInfo *CMItemResize::manipulatorInfo() 1098 { 1099 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 1100 // eventInfo->m_itemType.m_activate = CMManager::it_canvas_item; 1101 eventInfo->m_acceptManipulationPtr = CMItemResize::acceptManipulation; 1102 eventInfo->m_createManipulatorPtr = CMItemResize::construct; 1103 return eventInfo; 1104 } 1105 1106 bool CMItemResize::acceptManipulation(uint eventState, uint /*cmState*/, uint itemType, uint /*cnItemType*/) 1107 { 1108 return (itemType & CMManager::it_resize_handle) && !(eventState & CMManager::es_right_click); 1109 } 1110 1111 bool CMItemResize::mousePressedInitial(const EventInfo &eventInfo) 1112 { 1113 m_eventInfo = eventInfo; 1114 p_resizeHandle = dynamic_cast<ResizeHandle *>(eventInfo.qcanvasItemClickedOn); 1115 m_rh_dx = p_resizeHandle->x() - eventInfo.pos.x(); 1116 m_rh_dy = p_resizeHandle->y() - eventInfo.pos.y(); 1117 return false; 1118 } 1119 1120 bool CMItemResize::mouseMoved(const EventInfo &eventInfo) 1121 { 1122 int _x = int(m_rh_dx + eventInfo.pos.x()); 1123 int _y = int(m_rh_dy + eventInfo.pos.y()); 1124 1125 // Shift pressed == snap to grid 1126 if (eventInfo.shiftPressed) { 1127 _x = snapToCanvas(_x); 1128 _y = snapToCanvas(_y); 1129 } 1130 1131 p_resizeHandle->moveRH(_x, _y); 1132 return false; 1133 } 1134 1135 bool CMItemResize::mouseReleased(const EventInfo & /*eventInfo*/) 1136 { 1137 if (p_icnDocument) 1138 p_icnDocument->requestRerouteInvalidatedConnectors(); 1139 p_itemDocument->requestStateSave(); 1140 return true; 1141 } 1142 1143 CMMechItemMove::CMMechItemMove(ItemDocument *itemDocument, CMManager *cmManager) 1144 : CanvasManipulator(itemDocument, cmManager) 1145 { 1146 } 1147 1148 CMMechItemMove::~CMMechItemMove() 1149 { 1150 } 1151 1152 CanvasManipulator *CMMechItemMove::construct(ItemDocument *itemDocument, CMManager *cmManager) 1153 { 1154 return new CMMechItemMove(itemDocument, cmManager); 1155 } 1156 1157 ManipulatorInfo *CMMechItemMove::manipulatorInfo() 1158 { 1159 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 1160 // eventInfo->m_itemType.m_activate = CMManager::it_canvas_item; 1161 eventInfo->m_acceptManipulationPtr = CMMechItemMove::acceptManipulation; 1162 eventInfo->m_createManipulatorPtr = CMMechItemMove::construct; 1163 return eventInfo; 1164 } 1165 1166 bool CMMechItemMove::acceptManipulation(uint eventState, uint /*cmState*/, uint itemType, uint /*cnItemType*/) 1167 { 1168 return ((itemType & CMManager::it_mechanics_item) || (itemType & CMManager::it_drawpart)) && !(eventState & CMManager::es_right_click); 1169 } 1170 1171 bool CMMechItemMove::mousePressedInitial(const EventInfo &eventInfo) 1172 { 1173 m_eventInfo = eventInfo; 1174 m_prevPos = eventInfo.pos; 1175 1176 Item *item = dynamic_cast<Item *>(eventInfo.qcanvasItemClickedOn); 1177 if (!item) 1178 return true; 1179 1180 MechanicsItem *mechItem = dynamic_cast<MechanicsItem *>(eventInfo.qcanvasItemClickedOn); 1181 1182 if (mechItem) 1183 m_prevClickedOnSM = mechItem->selectionMode(); 1184 1185 if (eventInfo.shiftPressed) { 1186 p_mechanicsDocument->unselectAll(); 1187 p_mechanicsDocument->select(item); 1188 if (mechItem) { 1189 mechItem->setSelectionMode(MechanicsItem::sm_move); 1190 mechItem->setParentItem(nullptr); 1191 } 1192 } else if (!p_selectList->contains(mechItem)) { 1193 if (!eventInfo.ctrlPressed) 1194 p_mechanicsDocument->unselectAll(); 1195 1196 p_mechanicsDocument->select(item); 1197 1198 if (mechItem) 1199 mechItem->setSelectionMode(MechanicsItem::sm_move); 1200 } else { 1201 if (mechItem) 1202 mechItem->setSelectionMode(MechanicsItem::sm_move); 1203 1204 if (m_eventInfo.ctrlPressed) 1205 p_mechanicsDocument->unselect(item); 1206 } 1207 1208 if (p_selectList->isEmpty()) 1209 return true; 1210 1211 p_mechItemSelectList->setSelectionMode(MechanicsItem::sm_move); 1212 p_mechItemSelectList->setRaised(true); 1213 return false; 1214 } 1215 1216 bool CMMechItemMove::mouseMoved(const EventInfo &eventInfo) 1217 { 1218 const QPoint pos = eventInfo.pos; 1219 1220 int x = pos.x(); 1221 int y = pos.y(); 1222 1223 const MechItemList itemList = p_mechItemSelectList->toplevelMechItemList(); 1224 const MechItemList::const_iterator ilEnd = itemList.end(); 1225 for (MechItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it) { 1226 if (*it) 1227 (*it)->moveBy(x - m_prevPos.x(), y - m_prevPos.y()); 1228 } 1229 1230 m_prevPos = QPoint(x, y); 1231 1232 p_canvas->update(); 1233 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 1234 return false; 1235 } 1236 1237 bool CMMechItemMove::mouseReleased(const EventInfo &eventInfo) 1238 { 1239 const QPoint pos = eventInfo.pos; 1240 1241 int dx = pos.x() - m_eventInfo.pos.x(); 1242 int dy = pos.y() - m_eventInfo.pos.y(); 1243 1244 p_mechItemSelectList->setRaised(false); 1245 1246 MechanicsItem *mechItem = dynamic_cast<MechanicsItem *>(m_eventInfo.qcanvasItemClickedOn); 1247 if (dx == 0 && dy == 0) { 1248 if (mechItem && mechItem->isSelected()) { 1249 if (m_prevClickedOnSM == MechanicsItem::sm_resize) 1250 mechItem->setSelectionMode(MechanicsItem::sm_rotate); 1251 else 1252 mechItem->setSelectionMode(MechanicsItem::sm_resize); 1253 } 1254 p_itemDocument->requestStateSave(); 1255 return true; 1256 } 1257 1258 if (mechItem && mechItem->isSelected()) { 1259 if (m_prevClickedOnSM == MechanicsItem::sm_rotate) 1260 mechItem->setSelectionMode(MechanicsItem::sm_rotate); 1261 else 1262 mechItem->setSelectionMode(MechanicsItem::sm_resize); 1263 } 1264 1265 QStringList itemIDs; 1266 1267 ItemList itemList = p_mechItemSelectList->items(); 1268 const ItemList::iterator ilEnd = itemList.end(); 1269 for (ItemList::iterator it = itemList.begin(); it != ilEnd; ++it) { 1270 if (*it) { 1271 itemIDs.append((*it)->id()); 1272 } 1273 } 1274 1275 p_mechItemSelectList->setSelectionMode(MechanicsItem::sm_resize); 1276 p_itemDocument->requestStateSave(); 1277 p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::ResizeCanvasToItems); 1278 return true; 1279 } 1280 1281 // BEGIN class SelectRectangle 1282 SelectRectangle::SelectRectangle(int x, int y, int w, int h, KtlQCanvas *qcanvas) 1283 : m_x(x) 1284 , m_y(y) 1285 { 1286 m_topLine = new KtlQCanvasLine(qcanvas); 1287 m_rightLine = new KtlQCanvasLine(qcanvas); 1288 m_bottomLine = new KtlQCanvasLine(qcanvas); 1289 m_leftLine = new KtlQCanvasLine(qcanvas); 1290 setSize(w, h); 1291 1292 KtlQCanvasLine *lines[] = {m_topLine, m_rightLine, m_bottomLine, m_leftLine}; 1293 for (int i = 0; i < 4; ++i) { 1294 lines[i]->setPen(QPen(QColor(190, 190, 190), 1, Qt::DotLine)); 1295 lines[i]->setZ(ICNDocument::Z::Select); 1296 lines[i]->show(); 1297 } 1298 } 1299 1300 SelectRectangle::~SelectRectangle() 1301 { 1302 delete m_topLine; 1303 delete m_rightLine; 1304 delete m_bottomLine; 1305 delete m_leftLine; 1306 } 1307 1308 void SelectRectangle::setSize(int w, int h) 1309 { 1310 m_topLine->setPoints(m_x, m_y, m_x + w, m_y); 1311 m_rightLine->setPoints(m_x + w, m_y, m_x + w, m_y + h); 1312 m_bottomLine->setPoints(m_x + w, m_y + h, m_x, m_y + h); 1313 m_leftLine->setPoints(m_x, m_y + h, m_x, m_y); 1314 m_w = w; 1315 m_h = h; 1316 } 1317 1318 KtlQCanvasItemList SelectRectangle::collisions() 1319 { 1320 KtlQCanvas *canvas = m_topLine->canvas(); 1321 1322 return canvas->collisions(QRect(m_x, m_y, m_w, m_h)); 1323 } 1324 // END class SelectRectangle 1325 1326 // BEGIN class CMSelect 1327 CMSelect::CMSelect(ItemDocument *itemDocument, CMManager *cmManager) 1328 : CanvasManipulator(itemDocument, cmManager) 1329 { 1330 m_selectRectangle = nullptr; 1331 } 1332 1333 CMSelect::~CMSelect() 1334 { 1335 delete m_selectRectangle; 1336 } 1337 1338 CanvasManipulator *CMSelect::construct(ItemDocument *itemDocument, CMManager *cmManager) 1339 { 1340 return new CMSelect(itemDocument, cmManager); 1341 } 1342 1343 ManipulatorInfo *CMSelect::manipulatorInfo() 1344 { 1345 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 1346 // eventInfo->m_itemType.m_activate = CMManager::it_none; 1347 eventInfo->m_acceptManipulationPtr = CMSelect::acceptManipulation; 1348 eventInfo->m_createManipulatorPtr = CMSelect::construct; 1349 return eventInfo; 1350 } 1351 1352 bool CMSelect::acceptManipulation(uint /*eventState*/, uint /*cmState*/, uint itemType, uint /*cnItemType*/) 1353 { 1354 return (itemType & CMManager::it_none); 1355 } 1356 1357 bool CMSelect::mousePressedInitial(const EventInfo &eventInfo) 1358 { 1359 m_eventInfo = eventInfo; 1360 1361 if (!eventInfo.ctrlPressed) { 1362 p_itemDocument->unselectAll(); 1363 } 1364 1365 m_selectRectangle = new SelectRectangle(eventInfo.pos.x(), eventInfo.pos.y(), 0, 0, p_canvas); 1366 return false; 1367 } 1368 1369 bool CMSelect::mouseMoved(const EventInfo &eventInfo) 1370 { 1371 QPoint pos = eventInfo.pos; 1372 1373 m_selectRectangle->setSize(pos.x() - m_eventInfo.pos.x(), pos.y() - m_eventInfo.pos.y()); 1374 1375 if (m_eventInfo.ctrlPressed) { 1376 p_itemDocument->select(m_selectRectangle->collisions()); 1377 } else if (p_selectList) { 1378 p_selectList->setItems(m_selectRectangle->collisions()); 1379 } 1380 1381 if (p_selectList && !p_mechanicsDocument) { 1382 p_selectList->setSelected(true); 1383 } 1384 return false; 1385 } 1386 1387 bool CMSelect::mouseReleased(const EventInfo & /*eventInfo*/) 1388 { 1389 delete m_selectRectangle; 1390 m_selectRectangle = nullptr; 1391 1392 return true; 1393 } 1394 // END class CMSelect 1395 1396 CMItemDrag::CMItemDrag(ItemDocument *itemDocument, CMManager *cmManager) 1397 : CanvasManipulator(itemDocument, cmManager) 1398 { 1399 b_dragged = false; 1400 } 1401 1402 CMItemDrag::~CMItemDrag() 1403 { 1404 } 1405 1406 CanvasManipulator *CMItemDrag::construct(ItemDocument *itemDocument, CMManager *cmManager) 1407 { 1408 return new CMItemDrag(itemDocument, cmManager); 1409 } 1410 1411 ManipulatorInfo *CMItemDrag::manipulatorInfo() 1412 { 1413 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 1414 // eventInfo->m_itemType.m_activate = CMManager::it_canvas_item; 1415 eventInfo->m_acceptManipulationPtr = CMItemDrag::acceptManipulation; 1416 eventInfo->m_createManipulatorPtr = CMItemDrag::construct; 1417 return eventInfo; 1418 } 1419 1420 bool CMItemDrag::acceptManipulation(uint /*eventState*/, uint /*cmState*/, uint itemType, uint cnItemType) 1421 { 1422 return (itemType & (CMManager::it_canvas_item | CMManager::it_pin)) && !(cnItemType & CMManager::isi_isMovable); 1423 } 1424 1425 bool CMItemDrag::mousePressedInitial(const EventInfo &eventInfo) 1426 { 1427 m_eventInfo = eventInfo; 1428 b_dragged = false; 1429 return false; 1430 } 1431 1432 bool CMItemDrag::mouseMoved(const EventInfo &eventInfo) 1433 { 1434 const QPoint pos = eventInfo.pos; 1435 1436 if (b_dragged || pos.x() > (m_eventInfo.pos.x() + 4) || pos.x() < (m_eventInfo.pos.x() - 4) || pos.y() > (m_eventInfo.pos.y() + 4) || pos.y() < (m_eventInfo.pos.y() - 4)) { 1437 b_dragged = true; 1438 1439 if (PinItem *pi = dynamic_cast<PinItem *>(m_eventInfo.qcanvasItemClickedOn)) 1440 pi->dragged(pos.x() - m_eventInfo.pos.x()); 1441 } 1442 return false; 1443 } 1444 1445 bool CMItemDrag::mouseReleased(const EventInfo & /*eventInfo*/) 1446 { 1447 if (!b_dragged) { 1448 if (PinItem *pi = dynamic_cast<PinItem *>(m_eventInfo.qcanvasItemClickedOn)) 1449 pi->switchState(); 1450 } 1451 1452 p_itemDocument->requestStateSave(); 1453 return true; 1454 } 1455 1456 // BEGIN class CanvasEllipseDraw 1457 CanvasEllipseDraw::CanvasEllipseDraw(int x, int y, KtlQCanvas *canvas) 1458 : KtlQCanvasEllipse(0, 0, canvas) 1459 { 1460 move(x, y); 1461 } 1462 1463 void CanvasEllipseDraw::drawShape(QPainter &p) 1464 { 1465 p.drawEllipse(int(x() - width() / 2), int(y() - height() / 2), width(), height()); 1466 } 1467 // END class CanvasEllipseDraw 1468 1469 // BEGIN class CMDraw 1470 CMDraw::CMDraw(ItemDocument *itemDocument, CMManager *cmManager) 1471 : CanvasManipulator(itemDocument, cmManager) 1472 { 1473 m_pDrawLine = nullptr; 1474 m_pDrawRectangle = nullptr; 1475 m_pDrawEllipse = nullptr; 1476 } 1477 1478 CMDraw::~CMDraw() 1479 { 1480 p_cmManager->setDrawAction(-1); 1481 } 1482 1483 CanvasManipulator *CMDraw::construct(ItemDocument *itemDocument, CMManager *cmManager) 1484 { 1485 return new CMDraw(itemDocument, cmManager); 1486 } 1487 1488 ManipulatorInfo *CMDraw::manipulatorInfo() 1489 { 1490 ManipulatorInfo *eventInfo = new ManipulatorInfo(); 1491 eventInfo->m_acceptManipulationPtr = CMDraw::acceptManipulation; 1492 eventInfo->m_createManipulatorPtr = CMDraw::construct; 1493 return eventInfo; 1494 } 1495 1496 bool CMDraw::acceptManipulation(uint /*eventState*/, uint cmState, uint /*itemType*/, uint /*cnItemType*/) 1497 { 1498 return (cmState & CMManager::cms_draw); 1499 } 1500 1501 bool CMDraw::mousePressedInitial(const EventInfo &eventInfo) 1502 { 1503 m_eventInfo = eventInfo; 1504 1505 switch (static_cast<DrawPart::DrawAction>(p_cmManager->drawAction())) { 1506 case DrawPart::da_text: 1507 case DrawPart::da_rectangle: 1508 case DrawPart::da_image: { 1509 m_pDrawRectangle = new KtlQCanvasRectangle(eventInfo.pos.x(), eventInfo.pos.y(), 0, 0, p_canvas); 1510 m_pDrawRectangle->setPen(QPen(QColor(0, 0, 0), 1)); 1511 m_pDrawRectangle->setZ(ICNDocument::Z::ConnectorCreateLine); 1512 m_pDrawRectangle->show(); 1513 break; 1514 } 1515 case DrawPart::da_ellipse: { 1516 m_pDrawEllipse = new CanvasEllipseDraw(eventInfo.pos.x(), eventInfo.pos.y(), p_canvas); 1517 m_pDrawEllipse->setPen(QPen(QColor(0, 0, 0), 1)); 1518 m_pDrawEllipse->setZ(ICNDocument::Z::ConnectorCreateLine); 1519 m_pDrawEllipse->show(); 1520 break; 1521 } 1522 case DrawPart::da_line: 1523 case DrawPart::da_arrow: { 1524 m_pDrawLine = new KtlQCanvasLine(p_canvas); 1525 m_pDrawLine->setPoints(eventInfo.pos.x(), eventInfo.pos.y(), eventInfo.pos.x(), eventInfo.pos.y()); 1526 m_pDrawLine->setPen(QPen(QColor(0, 0, 0), 1)); 1527 m_pDrawLine->setZ(ICNDocument::Z::ConnectorCreateLine); 1528 m_pDrawLine->show(); 1529 break; 1530 } 1531 default: 1532 return true; 1533 } 1534 1535 return false; 1536 } 1537 1538 bool CMDraw::mouseMoved(const EventInfo &eventInfo) 1539 { 1540 const QPoint pos = eventInfo.pos; 1541 1542 if (m_pDrawRectangle) 1543 m_pDrawRectangle->setSize(pos.x() - m_eventInfo.pos.x(), pos.y() - m_eventInfo.pos.y()); 1544 1545 else if (m_pDrawEllipse) { 1546 // QRect r( m_eventInfo.pos.x(), m_eventInfo.pos.y(), pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() ); 1547 // r = r.normalized(); 1548 // 1549 // m_pDrawEllipse->setSize( r.width(), r.height() ); 1550 // m_pDrawEllipse->move( r.left()+(r.width()/2), r.top()+(r.height()/2) ); 1551 1552 m_pDrawEllipse->setSize(2 * abs(pos.x() - m_eventInfo.pos.x()), 2 * abs(pos.y() - m_eventInfo.pos.y())); 1553 } 1554 1555 else if (m_pDrawLine) 1556 m_pDrawLine->setPoints(eventInfo.pos.x(), eventInfo.pos.y(), m_pDrawLine->endPoint().x(), m_pDrawLine->endPoint().y()); 1557 else 1558 return true; 1559 1560 return false; 1561 } 1562 1563 bool CMDraw::mouseReleased(const EventInfo & /*eventInfo*/) 1564 { 1565 // const QPoint pos = eventInfo.pos; // 2017.10.01 - comment out unused variable 1566 1567 QRect sizeRect; 1568 1569 if (m_pDrawRectangle || m_pDrawEllipse) { 1570 if (m_pDrawRectangle) { 1571 sizeRect = m_pDrawRectangle->rect(); 1572 1573 // We have to manually adjust the size rect so that it matches up with what the user has drawn 1574 1575 sizeRect.setWidth(sizeRect.width() + 1); 1576 sizeRect.setHeight(sizeRect.height() + 1); 1577 1578 sizeRect = sizeRect.normalized(); 1579 1580 if (m_pDrawRectangle->rect().width() < 0) 1581 sizeRect.moveLeft(sizeRect.left() + 1); 1582 1583 if (m_pDrawRectangle->rect().height() < 0) 1584 sizeRect.moveTop(sizeRect.top() + 1); 1585 } else { 1586 int w = m_pDrawEllipse->width() + 1; 1587 int h = m_pDrawEllipse->height() + 1; 1588 int x = int(m_pDrawEllipse->x() - w / 2); 1589 int y = int(m_pDrawEllipse->y() - h / 2); 1590 sizeRect = QRect(x, y, w, h).normalized(); 1591 } 1592 1593 delete m_pDrawRectangle; 1594 delete m_pDrawEllipse; 1595 m_pDrawRectangle = nullptr; 1596 m_pDrawEllipse = nullptr; 1597 } else if (m_pDrawLine) { 1598 int sx = m_pDrawLine->startPoint().x(); 1599 int sy = m_pDrawLine->startPoint().y(); 1600 int ex = m_pDrawLine->endPoint().x(); 1601 int ey = m_pDrawLine->endPoint().y(); 1602 1603 sizeRect = QRect(ex, ey, sx - ex, sy - ey); 1604 1605 delete m_pDrawLine; 1606 m_pDrawLine = nullptr; 1607 } else 1608 return true; 1609 1610 QString id; 1611 switch (static_cast<DrawPart::DrawAction>(p_cmManager->drawAction())) { 1612 case DrawPart::da_rectangle: 1613 id = "dp/rectangle"; 1614 break; 1615 1616 case DrawPart::da_image: 1617 id = "dp/image"; 1618 break; 1619 1620 case DrawPart::da_ellipse: 1621 id = "dp/ellipse"; 1622 break; 1623 1624 case DrawPart::da_text: 1625 id = "dp/canvas_text"; 1626 1627 if (sizeRect.width() < 56) 1628 sizeRect.setWidth(56); 1629 1630 if (sizeRect.height() < 24) 1631 sizeRect.setHeight(24); 1632 1633 break; 1634 1635 case DrawPart::da_line: 1636 id = "dp/line"; 1637 break; 1638 1639 case DrawPart::da_arrow: 1640 id = "dp/arrow"; 1641 break; 1642 } 1643 1644 if (id.isEmpty()) 1645 return true; 1646 1647 Item *item = p_itemDocument->addItem(id, sizeRect.topLeft(), true); 1648 1649 if (!item) 1650 return true; 1651 1652 item->move(sizeRect.x(), sizeRect.y()); // We call this again as p_itemDocument->addItem will move the item if it is slightly off the canvas. 1653 1654 item->setSize(0, 0, sizeRect.width(), sizeRect.height()); 1655 1656 p_itemDocument->requestStateSave(); 1657 return true; 1658 } 1659 // END class CMDraw 1660 1661 // BEGIN class ManualConnectorDraw 1662 ManualConnectorDraw::ManualConnectorDraw(ICNDocument *_icnDocument, const QPoint &initialPos) 1663 { 1664 m_color = Qt::black; 1665 1666 icnDocument = _icnDocument; 1667 m_currentPos = m_previousPos = m_initialPos = initialPos; 1668 p_initialItem = icnDocument->itemAtTop(initialPos); 1669 1670 b_currentVertical = false; 1671 b_orientationDefined = false; 1672 1673 m_connectorLines.append(m_previousCon = new KtlQCanvasLine(icnDocument->canvas())); 1674 m_connectorLines.append(m_currentCon = new KtlQCanvasLine(icnDocument->canvas())); 1675 1676 m_currentCon->setPoints(initialPos.x(), initialPos.y(), initialPos.x(), initialPos.y()); 1677 m_previousCon->setPoints(initialPos.x(), initialPos.y(), initialPos.x(), initialPos.y()); 1678 1679 m_currentCon->setPen(m_color); 1680 m_previousCon->setPen(m_color); 1681 1682 updateConnectorEnds(); 1683 1684 m_currentCon->show(); 1685 m_previousCon->show(); 1686 } 1687 1688 ManualConnectorDraw::~ManualConnectorDraw() 1689 { 1690 qDeleteAll(m_connectorLines); 1691 m_connectorLines.clear(); 1692 } 1693 1694 void ManualConnectorDraw::setColor(const QColor &color) 1695 { 1696 m_color = color; 1697 1698 const QList<KtlQCanvasLine *>::iterator end = m_connectorLines.end(); 1699 for (QList<KtlQCanvasLine *>::iterator it = m_connectorLines.begin(); it != end; ++it) 1700 (*it)->setPen(m_color); 1701 } 1702 1703 void ManualConnectorDraw::mouseMoved(const QPoint &pos) 1704 { 1705 if (m_currentPos == pos) 1706 return; 1707 1708 if (!b_orientationDefined) { 1709 QPoint previousStart = m_previousCon->startPoint(); 1710 1711 double distance = std::sqrt(std::pow(double(m_currentPos.x() - previousStart.x()), 2.) + std::pow(double(m_currentPos.y() - previousStart.y()), 2.)); 1712 1713 if (distance < 24) { 1714 b_currentVertical = (std::abs(double(m_currentPos.x() - previousStart.x())) >= std::abs(double(m_currentPos.y() - previousStart.y()))); 1715 } 1716 } 1717 1718 m_previousPos = m_currentPos; 1719 m_currentPos = pos; 1720 updateConnectorEnds(); 1721 } 1722 1723 KtlQCanvasItem *ManualConnectorDraw::mouseClicked(const QPoint &pos) 1724 { 1725 if (b_orientationDefined) 1726 b_currentVertical = !b_currentVertical; 1727 else 1728 mouseMoved(pos); 1729 1730 b_orientationDefined = true; 1731 1732 m_currentPos = pos; 1733 1734 KtlQCanvasItem *qcanvasItem = icnDocument->itemAtTop(pos); 1735 1736 if (qcanvasItem && pos != m_initialPos && qcanvasItem != p_initialItem) 1737 return qcanvasItem; 1738 1739 m_previousCon = m_currentCon; 1740 1741 m_connectorLines.append(m_currentCon = new KtlQCanvasLine(icnDocument->canvas())); 1742 m_currentCon->setPoints(pos.x(), pos.y(), pos.x(), pos.y()); 1743 m_currentCon->setPen(m_color); 1744 updateConnectorEnds(); 1745 m_currentCon->show(); 1746 1747 return nullptr; 1748 } 1749 1750 void ManualConnectorDraw::updateConnectorEnds() 1751 { 1752 QPoint pivot = m_currentPos; 1753 QPoint previousStart = m_previousCon->startPoint(); 1754 1755 if (b_currentVertical) { 1756 pivot.setY(previousStart.y()); 1757 m_currentCon->setPoints(pivot.x(), pivot.y(), pivot.x(), m_currentPos.y()); 1758 } else { 1759 pivot.setX(previousStart.x()); 1760 m_currentCon->setPoints(pivot.x(), pivot.y(), m_currentPos.x(), pivot.y()); 1761 } 1762 1763 m_previousCon->setPoints(previousStart.x(), previousStart.y(), pivot.x(), pivot.y()); 1764 } 1765 1766 QPointList ManualConnectorDraw::pointList() 1767 { 1768 QPointList list; 1769 list.append(m_initialPos); 1770 1771 const QList<KtlQCanvasLine *>::iterator end = m_connectorLines.end(); 1772 for (QList<KtlQCanvasLine *>::iterator it = m_connectorLines.begin(); it != end; ++it) { 1773 list.append((*it)->endPoint()); 1774 } 1775 1776 return list; 1777 } 1778 // END class ManualConnectorDraw 1779 1780 // BEGIN class ManipulatorInfo 1781 ManipulatorInfo::ManipulatorInfo() 1782 { 1783 } 1784 // END class ManipulatorInfo 1785 1786 #include "moc_canvasmanipulator.cpp"