void CustomGraphicsScene::appendCard(int _cardType, const QString& _title, const QString& _description) { QPointF scenePosition = sceneRect().center(); // // Если выделена карточка // CardShape* selectedCard = nullptr; CardShape* previousCard = nullptr; CardShape* nextCard = nullptr; CardShape* parentCard = nullptr; if (!selectedItems().isEmpty() && selectedItems().size() == 1 && (selectedCard = dynamic_cast<CardShape*>(selectedItems().last()))) { // // Если карточка вложена в группирующую, то расширяем родителя и вкладываем карту в него // if (selectedCard->parentItem() != nullptr) { // // Запомним родителя // parentCard = dynamic_cast<CardShape*>(selectedCard->parentItem()); } // // Если выделен группирующий элемент, то соединять будем с последним из его детей // if (hasCards(selectedCard)) { selectedCard = dynamic_cast<CardShape*>(lastCard(selectedCard)); } // // Предыдущей будет выделенная // previousCard = selectedCard; // // Настроим позицию для добавления новой карточки // scenePosition = previousCard->scenePos(); scenePosition.setX(scenePosition.x() + previousCard->boundingRect().width() + SHAPE_MOVE_DELTA); scenePosition.setY(scenePosition.y() + previousCard->boundingRect().height() + SHAPE_MOVE_DELTA); // // Определим карточку, которая будет следовать за новой // Flow* flow = cardFlow(previousCard, CARD_ON_FLOW_START); if (flow != nullptr) { nextCard = dynamic_cast<CardShape*>(flow->endShape()); removeShape(flow); } } // // В противном случае добавляем карточку после самой последней карточки, если карточки уже есть // else if (hasCards()) { // // Определим последнюю карточку // Shape* lastCardShape = lastCard(); previousCard = dynamic_cast<CardShape*>(lastCardShape); // // Настроим позицию для добавления новой карточки // scenePosition = previousCard->scenePos(); scenePosition.setX(scenePosition.x() + previousCard->boundingRect().width() + SHAPE_MOVE_DELTA); scenePosition.setY(scenePosition.y() + previousCard->boundingRect().height() + SHAPE_MOVE_DELTA); } // // В противном случае добавляем карточку по середине видимой части сцены, если подключены представления // else if (!views().isEmpty()) { if (QGraphicsView* view = views().last()) { const QRect viewportRect(0, 0, view->viewport()->width(), view->viewport()->height()); const QRectF visibleSceneRect = view->mapToScene(viewportRect).boundingRect(); scenePosition = visibleSceneRect.center(); } } // // Добавляем карточку // CardShape* newCard = new CardShape((CardShape::CardType)_cardType, _title, _description, scenePosition, parentCard); insertShape(newCard, previousCard); // // ... корректируем позицию вкладываемой карточки // if (parentCard != nullptr) { const QPointF newPos = parentCard->mapFromScene(newCard->scenePos()); const QPointF newBottomRightPos = newPos + QPointF(newCard->boundingRect().width(), newCard->boundingRect().height()); // newCard->setParentItem(parentCard); newCard->setPos(newPos); // // ... и масштабируем родителя, если нужно // if (!parentCard->contains(newBottomRightPos)) { QSizeF newSize = parentCard->size(); if (newSize.width() <= newBottomRightPos.x()) { newSize.setWidth(newBottomRightPos.x() + SHAPE_MICROMOVE_DELTA); } if (newSize.height() <= newBottomRightPos.y()) { newSize.setHeight(newBottomRightPos.y() + SHAPE_MICROMOVE_DELTA); } parentCard->setSize(newSize); } } // // Соединяем с предыдущей // if (previousCard != nullptr) { appendShape(new ArrowFlow(previousCard, newCard, parentCard)); } // // Соединяем со следующей // if (nextCard != nullptr) { appendShape(new ArrowFlow(newCard, nextCard, parentCard)); } }
void CustomGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* _event) { // // Обработку производим только после перемещения мыши // if (m_afterMoving) { // // 1. Перемещение карточки на связь // QList<Shape*> selected = selectedShapes(); CardShape* selectedCard = nullptr; ArrowFlow* selectedFlow = nullptr; if (selected.size() == 2) { if (dynamic_cast<CardShape*>(selected.first())) { selectedCard = dynamic_cast<CardShape*>(selected.first()); selectedFlow = dynamic_cast<ArrowFlow*>(selected.last()); } else { selectedCard = dynamic_cast<CardShape*>(selected.last()); selectedFlow = dynamic_cast<ArrowFlow*>(selected.first()); } // // Если это действительно перемещение карточки на связь // if (selectedCard != nullptr && selectedFlow != nullptr && selectedFlow->startShape() != selectedCard && selectedFlow->endShape() != selectedCard) { // // Изымаем карточку из сцены // takeShape(selectedCard); // // Определяем элементы к которым теперь будет присоединена карточка // CardShape* previousCard = dynamic_cast<CardShape*>(selectedFlow->startShape()); CardShape* nextCard = dynamic_cast<CardShape*>(selectedFlow->endShape()); // // Заменяем старую связь на новые // removeShape(selectedFlow); appendShape(new ArrowFlow(previousCard, selectedCard)); if (hasCards(selectedCard)) { appendShape(new ArrowFlow(lastCard(selectedCard), nextCard)); } else { appendShape(new ArrowFlow(selectedCard, nextCard)); } // // Меняем порядок следования фигур // insertShape(selectedCard, previousCard); // // Если предыдущая карточка вложена в группирующий элемент // QGraphicsItem* previousParentItem = previousCard->parentItem(); QGraphicsItem* nextParentItem = nextCard->parentItem(); bool handled = false; if (previousParentItem != nullptr) { const QRectF selectedCardRect = selectedCard->mapToScene(selectedCard->boundingRect()).boundingRect(); const QRectF parentCardRect = previousParentItem->mapToScene(previousParentItem->boundingRect()).boundingRect(); // // ... и если текущая карточка тоже помещена внутрь группирующего элемента // if (parentCardRect.contains(selectedCardRect)) { // // ... поместим её внутрь // const QPointF lastPos = selectedCard->scenePos(); selectedCard->setParentItem(previousParentItem); selectedCard->setPos(previousParentItem->mapFromScene(lastPos)); handled = true; } } // // Если следующая карточка вложена в группирующий элемент // if (!handled && nextParentItem != nullptr) { const QRectF selectedCardRect = selectedCard->mapToScene(selectedCard->boundingRect()).boundingRect(); const QRectF parentCardRect = nextParentItem->mapToScene(nextParentItem->boundingRect()).boundingRect(); // // ... и если текущая карточка тоже помещена внутрь группирующего элемента // if (parentCardRect.contains(selectedCardRect)) { // // ... поместим её внутрь // const QPointF lastPos = selectedCard->scenePos(); selectedCard->setParentItem(nextParentItem); selectedCard->setPos(nextParentItem->mapFromScene(lastPos)); handled = true; } } // // Если не удалось вложить, то убираем родителя у элемента // if (!handled && selectedCard->parentItem() != nullptr) { const QPointF lastPos = selectedCard->scenePos(); selectedCard->setParentItem(nullptr); selectedCard->setPos(lastPos); } } } // // 2. Обработка вложения и вытаскивания элементов из групп сцен и папок // selected = selectedShapes(); if (selected.size() == 1) { selectedCard = dynamic_cast<CardShape*>(selected.first()); if (selectedCard != nullptr) { // // Определим, есть ли группирующий элемент, помеченный на вложение // CardShape* parentCard = nullptr; for (Shape* shape : shapes()) { if (CardShape* card = dynamic_cast<CardShape*>(shape)) { if (card->isOnInstertionState()) { parentCard = card; break; } } } // // Если это перемещение карточки внутри своего родителя, просто снимем режим выделения // if (parentCard != nullptr && selectedCard->parentItem() == parentCard) { parentCard->setOnInstertionState(false); } // // В противном случае // else { // // Вложение // if (parentCard != nullptr) { // // Изымаем карточку из сцены // takeShape(selectedCard); // // Если у группирующего элемента есть дети, то связываем с последней карточкой // if (hasCards(parentCard)) { // // Определяем элементы к которым теперь будет присоединена карточка // CardShape* previousCard = dynamic_cast<CardShape*>(lastCard(parentCard)); Flow* previousCardFlow = cardFlow(previousCard, CARD_ON_FLOW_START); if (previousCardFlow != nullptr) { CardShape* nextCard = dynamic_cast<CardShape*>(previousCardFlow->endShape()); // // Заменяем старую связь на новые // removeShape(previousCardFlow); if (hasCards(selectedCard)) { appendShape(new ArrowFlow(lastCard(selectedCard), nextCard)); } else { appendShape(new ArrowFlow(selectedCard, nextCard)); } } appendShape(new ArrowFlow(previousCard, selectedCard)); // // Меняем порядок следования фигур // insertShape(selectedCard, previousCard); } // // Если детей нет, то связываем непосредственно с группирующим элементом // else { // // Определяем элементы к которым теперь будет присоединена карточка // CardShape* previousCard = parentCard; Flow* previousCardFlow = cardFlow(previousCard, CARD_ON_FLOW_START); if (previousCardFlow != nullptr) { CardShape* nextCard = dynamic_cast<CardShape*>(previousCardFlow->endShape()); // // Заменяем старую связь на новые // removeShape(previousCardFlow); if (hasCards(selectedCard)) { appendShape(new ArrowFlow(lastCard(selectedCard), nextCard)); } else { appendShape(new ArrowFlow(selectedCard, nextCard)); } } appendShape(new ArrowFlow(previousCard, selectedCard)); // // Меняем порядок следования фигур // insertShape(selectedCard, previousCard); } // // Назначаем нового родителя // const QPointF lastPos = selectedCard->scenePos(); selectedCard->setParentItem(parentCard); selectedCard->setPos(parentCard->mapFromScene(lastPos)); parentCard->setOnInstertionState(false); } // // Вытаскивание - соединяем с последней карточкой в сценарии // else if (selectedCard->parentItem() != nullptr) { // // Изымаем карточку из сцены // takeShape(selectedCard); // // Определяем элемент к которому теперь будет присоединена карточка // CardShape* previousCard = dynamic_cast<CardShape*>(lastCard()); // // Добавляем связь // appendShape(new ArrowFlow(previousCard, selectedCard)); // // Меняем порядок следования фигур // insertShape(selectedCard, previousCard); // // Убираем родителя // const QPointF lastPos = selectedCard->scenePos(); selectedCard->setParentItem(nullptr); selectedCard->setPos(lastPos); } } } } } update(); QGraphicsScene::mouseReleaseEvent(_event); m_afterMoving = false; }
Shape* CustomGraphicsScene::takeShape(Shape* _shape, bool _removeCardFlows) { if (m_shapes.contains(_shape)) { // // При необходимости соединяем между собой окружающие карточку элементы // if (_removeCardFlows) { // // ... если это карточка, конечно // if (CardShape* cardShape = dynamic_cast<CardShape*>(_shape)) { // // Определяем элементы, с которыми соединена карточка, чтобы соеденить их между собой // Flow* startFlow = cardFlow(cardShape, CARD_ON_FLOW_END); Flow* endFlow = nullptr; if (hasCards(cardShape)) { endFlow = cardFlow(lastCard(cardShape), CARD_ON_FLOW_START); } else { endFlow = cardFlow(cardShape, CARD_ON_FLOW_START); } // // ... если есть связь в оба конца, соединяем карточки на концах этих связей // if (startFlow != nullptr && endFlow != nullptr) { startFlow->setEndShape(endFlow->endShape()); removeShape(endFlow); } // // ... если есть связь только в начале, просто уберём эту связь // else if (startFlow != nullptr) { removeShape(startFlow); } // // ... если есть связь только в конце, просто уберём эту связь // else { removeShape(endFlow); } } } // // Извлекаем фигуру // disconnect(_shape, SIGNAL(stateIsAboutToBeChangedByUser()), this, SIGNAL(stateChangedByUser())); m_shapes.removeAll(_shape); // // ... извлекаем все вложенные карточки // for (QGraphicsItem* childItem : _shape->childItems()) { if (CardShape* childCard = dynamic_cast<CardShape*>(childItem)) { const bool DONT_REMOVE_FLOWS = false; takeShape(childCard, DONT_REMOVE_FLOWS); } } return _shape; } return NULL; }