void RPolyline::appendShape(const RShape& shape, bool prepend) { // const RDirected* directed = dynamic_cast<const RDirected*>(&shape); // if (directed==NULL) { // qWarning() << "RPolyline::appendShape: shape is not a line, arc or polyline: " << shape; // return; // } const RPolyline* pl = dynamic_cast<const RPolyline*>(&shape); if (pl!=NULL) { if (prepend) { for (int i=pl->countSegments()-1; i>=0; --i) { QSharedPointer<RShape> s = pl->getSegmentAt(i); if (s.isNull()) { continue; } prependShape(*s); } } else { for (int i=0; i<pl->countSegments(); ++i) { QSharedPointer<RShape> s = pl->getSegmentAt(i); if (s.isNull()) { continue; } appendShape(*s); } } return; } const RDirected* directed = NULL; double bulge = 0.0; const RLine* line = dynamic_cast<const RLine*>(&shape); if (line!=NULL) { directed = line; } else { const RArc* arc = dynamic_cast<const RArc*>(&shape); if (arc!=NULL) { bulge = arc->getBulge(); directed = arc; } } if (directed==NULL) { qWarning() << "RPolyline::appendShape: shape is not a line, arc or polyline: " << shape; return; } RVector connectionPoint; RVector nextPoint; double gap; if (prepend) { connectionPoint = directed->getEndPoint(); nextPoint = directed->getStartPoint(); if (vertices.size()==0) { appendVertex(connectionPoint); } gap = vertices.first().getDistanceTo(connectionPoint); } else { connectionPoint = directed->getStartPoint(); nextPoint = directed->getEndPoint(); if (vertices.size()==0) { appendVertex(connectionPoint); } gap = vertices.last().getDistanceTo(connectionPoint); } if (!RMath::fuzzyCompare(gap, 0.0, 1.0e-4)) { qWarning() << "RPolyline::appendShape: arc or line not connected to polyline, gap: " << gap; } if (prepend) { prependVertex(nextPoint); setBulgeAt(0, bulge); } else { appendVertex(nextPoint); setBulgeAt(bulges.size()-2, bulge); } }
void CanvasController::setup() { // Padding is between each one of the two areas and the window double padding = 10; // Proportions for screen areas double canvasWidthRelative = 0.8; double toolsWidthRelative = 1 - canvasWidthRelative; double canvasWidth = window.getWidth()*canvasWidthRelative - 2*padding + padding/2; double canvasHeight = window.getHeight() - 2*padding; double toolsWidth = window.getWidth()*toolsWidthRelative - 2*padding + padding/2; double toolsHeight = window.getHeight() - 2*padding; // Create area objects backgroundArea = new Rectangle(Point(0, 0, 0), window.getWidth(), window.getHeight()); canvasArea = new Rectangle(Point(padding, padding, 0), canvasWidth, canvasHeight); toolsArea = new Rectangle(Point(canvasWidth + 2*padding, padding, 0), toolsWidth, toolsHeight); // Responders canvasArea->setRespondsToMouseButtonDown(false); // Color them backgroundArea->setColor(Color::grayColor().withHue(0.75)); canvasArea->setColor(Color::whiteColor()); toolsArea->setColor(Color::whiteColor().withAlpha(0.5)); // Add to hierarchy appendShape(backgroundArea); appendShape(canvasArea); appendShape(toolsArea); }
void CustomGraphicsScene::appendVerticalLine() { QPointF scenePosition = sceneRect().center(); // // Если выделена фигура, то новую добавляем чуть правее // Избегаем момента, когда выделена горизонтальная линия, чтобы не добавлять линию в самый конец // Shape* selectedShape = 0; const QList<QGraphicsItem*> selectedShapes = selectedItems(); if (!selectedShapes.isEmpty() && selectedShapes.size() == 1 && !dynamic_cast<HorizontalLineShape*>(selectedShapes.last()) && (selectedShape = dynamic_cast<Shape*>(selectedShapes.last()))) { scenePosition = selectedShape->scenePos(); scenePosition.setX(scenePosition.x() + selectedShape->boundingRect().width() + 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(); } } // // Добавляем линию // appendShape(new VerticalLineShape(scenePosition)); }
void CustomGraphicsScene::appendNote(const QString& _text) { QPointF scenePosition = sceneRect().center(); // // Если выделена карточка, то заметку добавляем справа-сверху на углу карточки // CardShape* selectedCard = 0; if (!selectedItems().isEmpty() && selectedItems().size() == 1 && (selectedCard = dynamic_cast<CardShape*>(selectedItems().last()))) { scenePosition = selectedCard->scenePos(); scenePosition.setX(scenePosition.x() + selectedCard->boundingRect().width() - SHAPE_MICROMOVE_DELTA); scenePosition.setY(scenePosition.y() - SHAPE_MICROMOVE_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(); } } // // Добавляем заметку // appendShape(new NoteShape(_text, scenePosition)); }
void RPolyline::appendShape(const RShape& shape) { const RDirected* directed = dynamic_cast<const RDirected*>(&shape); if (directed==NULL) { qWarning("RPolyline::appendShape: shape is not a line, arc or polyline"); return; } const RPolyline* pl = dynamic_cast<const RPolyline*>(&shape); if (pl!=NULL) { for (int i=0; i<pl->countSegments(); ++i) { QSharedPointer<RShape> s = pl->getSegmentAt(i); if (s.isNull()) { continue; } appendShape(*s.data()); } } double bulge = 0.0; const RArc* arc = dynamic_cast<const RArc*>(&shape); if (arc!=NULL) { bulge = arc->getBulge(); } if (vertices.size()==0) { appendVertex(directed->getStartPoint()); } appendVertex(directed->getEndPoint()); setBulgeAt(bulges.size()-2, bulge); }
void CustomGraphicsScene::removeShape(Shape* _shape) { if (m_shapes.contains(_shape)) { // // Удаляем детей // for (QGraphicsItem* childItem : _shape->childItems()) { if (Shape* childShape = dynamic_cast<Shape*>(childItem)) { removeShape(childShape); } } // // Определяем внешние элементы // Shape* previousCard = nullptr; Shape* nextCard = nullptr; if (CardShape* cardShape = dynamic_cast<CardShape*>(_shape)) { if (Flow* startFlow = cardFlow(cardShape, CARD_ON_FLOW_END)) { previousCard = startFlow->startShape(); } if (Flow* endFlow = cardFlow(cardShape, CARD_ON_FLOW_START)) { nextCard = endFlow->endShape(); } } // // Удаляем сам элемент // QList<Shape *> items; items.append(_shape); QList<Shape *> all = m_shapes; bool found; do { found = false; for (int i = 0; i < all.count(); ++i) { if (Flow* item=dynamic_cast<Flow *>(all[i])) { if ((items.contains(item->endShape()) || items.contains(item->startShape())) && !items.contains(item)) { items << item, found = true; } } } } while (found); for(int i = items.count()-1; i>=0; --i) { removeItem(items[i]); disconnect(_shape, SIGNAL(stateIsAboutToBeChangedByUser()), this, SIGNAL(stateChangedByUser())); m_shapes.removeAll(items[i]); delete items[i]; } // // Если надо добавляем связь между разорванными элементами // if (previousCard != nullptr && nextCard != nullptr) { appendShape(new ArrowFlow(previousCard, nextCard)); } } }
void RPolyline::prependShape(const RShape& shape) { appendShape(shape, true); // const RDirected* directed = dynamic_cast<const RDirected*>(&shape); // if (directed==NULL) { // qWarning() << "RPolyline::prependShape: shape is not a line, arc or polyline: " << shape; // return; // } // const RPolyline* pl = dynamic_cast<const RPolyline*>(&shape); // if (pl!=NULL) { // for (int i=pl->countSegments()-1; i>=0; --i) { // QSharedPointer<RShape> s = pl->getSegmentAt(i); // if (s.isNull()) { // continue; // } // prependShape(*s.data()); // } // } // double bulge = 0.0; // const RArc* arc = dynamic_cast<const RArc*>(&shape); // if (arc!=NULL) { // bulge = arc->getBulge(); // } // const RLine* line = dynamic_cast<const RLine*>(&shape); // if (line!=NULL) { // directed = line; // } // if (vertices.size()==0) { // prependVertex(directed->getEndPoint()); // } // if (!vertices.last().equalsFuzzy(directed->getEndPoint())) { // qWarning("RPolyline::prependShape: arc not connected to polyline"); // } // prependVertex(directed->getStartPoint()); // setBulgeAt(0, bulge); }
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; }
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)); } }