From 7b3540f0c1c8aeab8e07529c6aa500f50e5de2fa Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Sun, 8 Apr 2018 23:08:23 +0800 Subject: [PATCH] Add multiple selection --- src/meshgenerator.cpp | 2 +- src/skeletondocument.h | 2 + src/skeletondocumentwindow.cpp | 16 +- src/skeletongraphicswidget.cpp | 366 +++++++++++++++++++++++---------- src/skeletongraphicswidget.h | 85 +++++--- 5 files changed, 333 insertions(+), 138 deletions(-) diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index 4628c72a..e495d34c 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -206,7 +206,7 @@ void MeshGenerator::process() int mergedMeshId = 0; if (meshIds.size() > 1) { mergedMeshId = unionMeshs(meshliteContext, meshIds); - } else { + } else if (meshIds.size() > 0) { mergedMeshId = meshIds[0]; } if (mergedMeshId > 0) { diff --git a/src/skeletondocument.h b/src/skeletondocument.h index ea417ac9..75e0209b 100644 --- a/src/skeletondocument.h +++ b/src/skeletondocument.h @@ -39,6 +39,8 @@ public: float y; float z; float radius; + bool xMirrored; + bool zMirrored; SkeletonNodeRootMarkMode rootMarkMode; std::vector edgeIds; }; diff --git a/src/skeletondocumentwindow.cpp b/src/skeletondocumentwindow.cpp index 89ad98d6..6210acfa 100644 --- a/src/skeletondocumentwindow.cpp +++ b/src/skeletondocumentwindow.cpp @@ -44,13 +44,13 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : QPushButton *changeTurnaroundButton = new QPushButton(QChar(fa::image)); initButton(changeTurnaroundButton); - QPushButton *markTrivialBranchButton = new QPushButton(QChar(fa::leaf)); - initButton(markTrivialBranchButton); - QPushButton *markCenterButton = new QPushButton(QChar(fa::bullseye)); initButton(markCenterButton); - QPushButton *markMirrorButton = new QPushButton(QChar(fa::adjust)); + QPushButton *markTrivialBranchButton = new QPushButton(QChar(fa::link)); + initButton(markTrivialBranchButton); + + QPushButton *markMirrorButton = new QPushButton(QChar(fa::clone)); initButton(markMirrorButton); toolButtonLayout->addWidget(undoButton); @@ -62,10 +62,10 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : toolButtonLayout->addWidget(zoomOutButton); //toolButtonLayout->addSpacing(10); //toolButtonLayout->addWidget(changeTurnaroundButton); - toolButtonLayout->addSpacing(30); - toolButtonLayout->addWidget(markCenterButton); - toolButtonLayout->addWidget(markTrivialBranchButton); - toolButtonLayout->addWidget(markMirrorButton); + //toolButtonLayout->addSpacing(30); + //toolButtonLayout->addWidget(markCenterButton); + //toolButtonLayout->addWidget(markTrivialBranchButton); + //toolButtonLayout->addWidget(markMirrorButton); QLabel *dust3dJezzasoftLabel = new QLabel; QImage dust3dJezzasoftImage; diff --git a/src/skeletongraphicswidget.cpp b/src/skeletongraphicswidget.cpp index c50964c5..d7f4024c 100644 --- a/src/skeletongraphicswidget.cpp +++ b/src/skeletongraphicswidget.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "skeletongraphicswidget.h" #include "theme.h" #include "util.h" @@ -15,14 +16,16 @@ SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document) m_dragStarted(false), m_cursorNodeItem(nullptr), m_cursorEdgeItem(nullptr), - m_checkedNodeItem(nullptr), + m_addFromNodeItem(nullptr), m_moveStarted(false), m_hoveredNodeItem(nullptr), m_hoveredEdgeItem(nullptr), - m_checkedEdgeItem(nullptr), m_lastAddedX(0), m_lastAddedY(0), - m_lastAddedZ(0) + m_lastAddedZ(0), + m_selectionItem(nullptr), + m_rangeSelectionStarted(false), + m_mouseEventFromSelf(false) { setRenderHint(QPainter::Antialiasing, false); setBackgroundBrush(QBrush(QWidget::palette().color(QWidget::backgroundRole()), Qt::SolidPattern)); @@ -45,6 +48,10 @@ SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document) m_cursorEdgeItem->hide(); scene()->addItem(m_cursorEdgeItem); + m_selectionItem = new SkeletonGraphicsSelectionItem(); + m_selectionItem->hide(); + scene()->addItem(m_selectionItem); + scene()->setSceneRect(rect()); setMouseTracking(true); @@ -126,7 +133,7 @@ void SkeletonGraphicsWidget::updateCursor() setCursor(QCursor(Theme::awesome()->icon(fa::plus).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize))); break; case SkeletonDocumentEditMode::Select: - setCursor(QCursor(Theme::awesome()->icon(fa::mousepointer).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize))); + setCursor(QCursor(Theme::awesome()->icon(fa::mousepointer).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize), Theme::toolIconFontSize / 5, 0)); break; case SkeletonDocumentEditMode::Drag: setCursor(QCursor(Theme::awesome()->icon(m_dragStarted ? fa::handrocko : fa::handpapero).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize))); @@ -144,16 +151,17 @@ void SkeletonGraphicsWidget::updateCursor() void SkeletonGraphicsWidget::editModeChanged() { - if (m_checkedNodeItem) { - if (!m_checkedNodeItem->checked()) { - if (m_hoveredNodeItem == m_checkedNodeItem) { - m_checkedNodeItem->setHovered(false); - m_hoveredNodeItem = nullptr; - } - m_checkedNodeItem = nullptr; - } - } updateCursor(); + if (SkeletonDocumentEditMode::Add == m_document->editMode) { + SkeletonGraphicsNodeItem *choosenNodeItem = nullptr; + if (!m_rangeSelectionSet.empty()) { + std::set nodeItems; + readMergedSkeletonNodeSetFromRangeSelection(&nodeItems); + if (nodeItems.size() == 1) + choosenNodeItem = *nodeItems.begin(); + } + m_addFromNodeItem = choosenNodeItem; + } } void SkeletonGraphicsWidget::mouseMoveEvent(QMouseEvent *event) @@ -180,7 +188,20 @@ void SkeletonGraphicsWidget::mouseReleaseEvent(QMouseEvent *event) void SkeletonGraphicsWidget::mousePressEvent(QMouseEvent *event) { QGraphicsView::mousePressEvent(event); - mousePress(event); + m_mouseEventFromSelf = true; + if (mousePress(event)) { + m_mouseEventFromSelf = false; + return; + } + m_mouseEventFromSelf = false; + if (event->button() == Qt::LeftButton) { + if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (!m_rangeSelectionStarted) { + m_rangeSelectionStartPos = mouseEventScenePos(event); + m_rangeSelectionStarted = true; + } + } + } } void SkeletonGraphicsWidget::mouseDoubleClickEvent(QMouseEvent *event) @@ -207,6 +228,17 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event) return true; } + if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (m_rangeSelectionStarted) { + QPointF mouseScenePos = mouseEventScenePos(event); + m_selectionItem->updateRange(m_rangeSelectionStartPos, mouseScenePos); + if (!m_selectionItem->isVisible()) + m_selectionItem->setVisible(true); + checkRangeSelection(); + return true; + } + } + if (SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Add == m_document->editMode) { SkeletonGraphicsNodeItem *newHoverNodeItem = nullptr; @@ -250,8 +282,8 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event) if (!m_cursorNodeItem->isVisible()) { m_cursorNodeItem->show(); } - if (m_checkedNodeItem) { - m_cursorEdgeItem->setEndpoints(m_checkedNodeItem, m_cursorNodeItem); + if (m_addFromNodeItem) { + m_cursorEdgeItem->setEndpoints(m_addFromNodeItem, m_cursorNodeItem); if (!m_cursorEdgeItem->isVisible()) { m_cursorEdgeItem->show(); } @@ -260,14 +292,19 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event) } if (SkeletonDocumentEditMode::Select == m_document->editMode) { - if (m_moveStarted && m_checkedNodeItem) { + if (m_moveStarted && !m_rangeSelectionSet.empty()) { QPointF mouseScenePos = mouseEventScenePos(event); float byX = sceneRadiusToUnified(mouseScenePos.x() - m_lastScenePos.x()); float byY = sceneRadiusToUnified(mouseScenePos.y() - m_lastScenePos.y()); - if (SkeletonProfile::Main == m_checkedNodeItem->profile()) { - emit moveNodeBy(m_checkedNodeItem->id(), byX, byY, 0); - } else { - emit moveNodeBy(m_checkedNodeItem->id(), 0, byY, byX); + std::set nodeItems; + readMergedSkeletonNodeSetFromRangeSelection(&nodeItems); + for (const auto &it: nodeItems) { + SkeletonGraphicsNodeItem *nodeItem = it; + if (SkeletonProfile::Main == nodeItem->profile()) { + emit moveNodeBy(nodeItem->id(), byX, byY, 0); + } else { + emit moveNodeBy(nodeItem->id(), 0, byY, byX); + } } m_lastScenePos = mouseScenePos; return true; @@ -295,11 +332,37 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent *event) return true; } } else if (SkeletonDocumentEditMode::Select == m_document->editMode) { - if (m_hoveredNodeItem) { - emit scaleNodeByAddRadius(m_hoveredNodeItem->id(), sceneRadiusToUnified(delta)); + if (!m_rangeSelectionSet.empty()) { + std::set nodeItems; + readMergedSkeletonNodeSetFromRangeSelection(&nodeItems); + float unifiedDelta = sceneRadiusToUnified(delta); + if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) { + QVector2D center; + for (const auto &nodeItem: nodeItems) { + center += QVector2D(nodeItem->origin()); + } + center /= nodeItems.size(); + for (const auto &nodeItem: nodeItems) { + QVector2D origin = QVector2D(nodeItem->origin()); + QVector2D ray = (center - origin) * 0.01 * delta; + float byX = -sceneRadiusToUnified(ray.x()); + float byY = -sceneRadiusToUnified(ray.y()); + if (SkeletonProfile::Main == nodeItem->profile()) { + emit moveNodeBy(nodeItem->id(), byX, byY, 0); + } else { + emit moveNodeBy(nodeItem->id(), 0, byY, byX); + } + } + } else { + for (const auto &it: nodeItems) { + SkeletonGraphicsNodeItem *nodeItem = it; + emit scaleNodeByAddRadius(nodeItem->id(), unifiedDelta); + } + } return true; - } else if (m_checkedNodeItem) { - emit scaleNodeByAddRadius(m_checkedNodeItem->id(), sceneRadiusToUnified(delta)); + } else if (m_hoveredNodeItem) { + float unifiedDelta = sceneRadiusToUnified(delta); + emit scaleNodeByAddRadius(m_hoveredNodeItem->id(), unifiedDelta); return true; } } @@ -309,7 +372,7 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent *event) bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { - bool processed = m_dragStarted || m_moveStarted; + bool processed = m_dragStarted || m_moveStarted || m_rangeSelectionStarted; if (m_dragStarted) { m_dragStarted = false; updateCursor(); @@ -317,6 +380,10 @@ bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event) if (m_moveStarted) { m_moveStarted = false; } + if (m_rangeSelectionStarted) { + m_selectionItem->hide(); + m_rangeSelectionStarted = false; + } return processed; } return false; @@ -332,13 +399,13 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent *event) if (event->button() == Qt::LeftButton) { if (SkeletonDocumentEditMode::ZoomIn == m_document->editMode) { ViewportAnchor lastAnchor = transformationAnchor(); - setTransformationAnchor(QGraphicsView::AnchorUnderMouse) ; + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); scale(1.5, 1.5); setTransformationAnchor(lastAnchor); return true; } else if (SkeletonDocumentEditMode::ZoomOut == m_document->editMode) { ViewportAnchor lastAnchor = transformationAnchor(); - setTransformationAnchor(QGraphicsView::AnchorUnderMouse) ; + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); scale(0.5, 0.5); setTransformationAnchor(lastAnchor); if ((!verticalScrollBar() || !verticalScrollBar()->isVisible()) && @@ -354,20 +421,20 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent *event) } } else if (SkeletonDocumentEditMode::Add == m_document->editMode) { if (m_cursorNodeItem->isVisible()) { - if (m_checkedNodeItem) { - if (m_hoveredNodeItem && m_checkedNodeItem && - m_hoveredNodeItem != m_checkedNodeItem && - m_hoveredNodeItem->profile() == m_checkedNodeItem->profile()) { - if (m_document->findEdgeByNodes(m_checkedNodeItem->id(), m_hoveredNodeItem->id())) + if (m_addFromNodeItem) { + if (m_hoveredNodeItem && m_addFromNodeItem && + m_hoveredNodeItem != m_addFromNodeItem && + m_hoveredNodeItem->profile() == m_addFromNodeItem->profile()) { + if (m_document->findEdgeByNodes(m_addFromNodeItem->id(), m_hoveredNodeItem->id())) return true; - emit addEdge(m_checkedNodeItem->id(), m_hoveredNodeItem->id()); + emit addEdge(m_addFromNodeItem->id(), m_hoveredNodeItem->id()); return true; } } QPointF mainProfile = m_cursorNodeItem->origin(); QPointF sideProfile = mainProfile; - if (m_checkedNodeItem) { - auto itemIt = nodeItemMap.find(m_checkedNodeItem->id()); + if (m_addFromNodeItem) { + auto itemIt = nodeItemMap.find(m_addFromNodeItem->id()); sideProfile.setX(itemIt->second.second->origin().x()); } else { if (mainProfile.x() >= scene()->width() / 2) { @@ -384,52 +451,35 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent *event) m_lastAddedY = unifiedMainPos.y(); m_lastAddedZ = unifiedSidePos.x(); qDebug() << "Emit add node " << m_lastAddedX << m_lastAddedY << m_lastAddedZ; - emit addNode(unifiedMainPos.x(), unifiedMainPos.y(), unifiedSidePos.x(), sceneRadiusToUnified(m_cursorNodeItem->radius()), nullptr == m_checkedNodeItem ? QUuid() : m_checkedNodeItem->id()); + emit addNode(unifiedMainPos.x(), unifiedMainPos.y(), unifiedSidePos.x(), sceneRadiusToUnified(m_cursorNodeItem->radius()), nullptr == m_addFromNodeItem ? QUuid() : m_addFromNodeItem->id()); return true; } } else if (SkeletonDocumentEditMode::Select == m_document->editMode) { - bool processed = false; - if (m_hoveredNodeItem) { - if (m_checkedNodeItem != m_hoveredNodeItem) { - if (m_checkedNodeItem) { - emit uncheckNode(m_checkedNodeItem->id()); - m_checkedNodeItem->setChecked(false); + if (m_mouseEventFromSelf) { + bool processed = false; + if ((nullptr == m_hoveredNodeItem || m_rangeSelectionSet.find(m_hoveredNodeItem) == m_rangeSelectionSet.end()) && + (nullptr == m_hoveredEdgeItem || m_rangeSelectionSet.find(m_hoveredEdgeItem) == m_rangeSelectionSet.end())) { + if (!QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) { + clearRangeSelection(); } - m_checkedNodeItem = m_hoveredNodeItem; - m_checkedNodeItem->setChecked(true); - emit checkNode(m_checkedNodeItem->id()); - } - m_moveStarted = true; - m_lastScenePos = mouseEventScenePos(event); - processed = true; - } else { - if (m_checkedNodeItem) { - m_checkedNodeItem->setChecked(false); - emit uncheckNode(m_checkedNodeItem->id()); - m_checkedNodeItem = nullptr; - processed = true; - } - } - if (m_hoveredEdgeItem) { - if (m_checkedEdgeItem != m_hoveredEdgeItem) { - if (m_checkedEdgeItem) { - emit uncheckEdge(m_checkedEdgeItem->id()); - m_checkedEdgeItem->setChecked(false); + if (m_hoveredNodeItem) { + m_hoveredNodeItem->setChecked(true); + m_rangeSelectionSet.insert(m_hoveredNodeItem); + } else if (m_hoveredEdgeItem) { + m_hoveredEdgeItem->setChecked(true); + m_rangeSelectionSet.insert(m_hoveredEdgeItem); } - m_checkedEdgeItem = m_hoveredEdgeItem; - m_checkedEdgeItem->setChecked(true); - emit checkEdge(m_checkedEdgeItem->id()); } - } else { - if (m_checkedEdgeItem) { - m_checkedEdgeItem->setChecked(false); - emit uncheckEdge(m_checkedEdgeItem->id()); - m_checkedEdgeItem = nullptr; - processed = true; + if (!m_rangeSelectionSet.empty()) { + if (!QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) { + m_moveStarted = true; + m_lastScenePos = mouseEventScenePos(event); + processed = true; + } + } + if (processed) { + return true; } - } - if (processed) { - return true; } } } @@ -469,13 +519,18 @@ bool SkeletonGraphicsWidget::keyPress(QKeyEvent *event) { if (event->key() == Qt::Key_Delete || event->key() ==Qt::Key_Backspace) { bool processed = false; - if (m_checkedNodeItem) { - emit removeNode(m_checkedNodeItem->id()); - processed = true; - } - if (m_checkedEdgeItem) { - emit removeEdge(m_checkedEdgeItem->id()); - processed = true; + if (!m_rangeSelectionSet.empty()) { + std::set nodeIdSet; + std::set edgeIdSet; + readSkeletonNodeAndEdgeIdSetFromRangeSelection(&nodeIdSet, &edgeIdSet); + for (const auto &id: edgeIdSet) { + emit removeEdge(id); + processed = true; + } + for (const auto &id: nodeIdSet) { + emit removeNode(id); + processed = true; + } } if (processed) { return true; @@ -510,15 +565,15 @@ void SkeletonGraphicsWidget::nodeAdded(QUuid nodeId) scene()->addItem(sideProfileItem); nodeItemMap[nodeId] = std::make_pair(mainProfileItem, sideProfileItem); - if (nullptr == m_checkedNodeItem) { - m_checkedNodeItem = mainProfileItem; + if (nullptr == m_addFromNodeItem) { + m_addFromNodeItem = mainProfileItem; } else { - if (SkeletonProfile::Main == m_checkedNodeItem->profile()) { - m_checkedNodeItem = mainProfileItem; + if (SkeletonProfile::Main == m_addFromNodeItem->profile()) { + m_addFromNodeItem = mainProfileItem; } else { - m_checkedNodeItem = sideProfileItem; + m_addFromNodeItem = sideProfileItem; } - m_cursorEdgeItem->setEndpoints(m_checkedNodeItem, m_cursorNodeItem); + m_cursorEdgeItem->setEndpoints(m_addFromNodeItem, m_cursorNodeItem); } } @@ -556,6 +611,17 @@ void SkeletonGraphicsWidget::edgeAdded(QUuid edgeId) edgeItemMap[edgeId] = std::make_pair(mainProfileEdgeItem, sideProfileEdgeItem); } +void SkeletonGraphicsWidget::removeItem(QGraphicsItem *item) +{ + if (m_hoveredNodeItem == item) + m_hoveredNodeItem = nullptr; + if (m_addFromNodeItem == item) + m_addFromNodeItem = nullptr; + if (m_hoveredEdgeItem == item) + m_hoveredEdgeItem = nullptr; + m_rangeSelectionSet.erase(item); +} + void SkeletonGraphicsWidget::nodeRemoved(QUuid nodeId) { m_lastAddedX = 0; @@ -566,14 +632,8 @@ void SkeletonGraphicsWidget::nodeRemoved(QUuid nodeId) qDebug() << "Node removed but node id not exist:" << nodeId; return; } - if (m_hoveredNodeItem == nodeItemIt->second.first) - m_hoveredNodeItem = nullptr; - if (m_hoveredNodeItem == nodeItemIt->second.second) - m_hoveredNodeItem = nullptr; - if (m_checkedNodeItem == nodeItemIt->second.first) - m_checkedNodeItem = nullptr; - if (m_checkedNodeItem == nodeItemIt->second.second) - m_checkedNodeItem = nullptr; + removeItem(nodeItemIt->second.first); + removeItem(nodeItemIt->second.second); delete nodeItemIt->second.first; delete nodeItemIt->second.second; nodeItemMap.erase(nodeItemIt); @@ -586,14 +646,8 @@ void SkeletonGraphicsWidget::edgeRemoved(QUuid edgeId) qDebug() << "Edge removed but edge id not exist:" << edgeId; return; } - if (m_hoveredEdgeItem == edgeItemIt->second.first) - m_hoveredEdgeItem = nullptr; - if (m_hoveredEdgeItem == edgeItemIt->second.second) - m_hoveredEdgeItem = nullptr; - if (m_checkedEdgeItem == edgeItemIt->second.first) - m_checkedEdgeItem = nullptr; - if (m_checkedEdgeItem == edgeItemIt->second.second) - m_checkedEdgeItem = nullptr; + removeItem(edgeItemIt->second.first); + removeItem(edgeItemIt->second.second); delete edgeItemIt->second.first; delete edgeItemIt->second.second; edgeItemMap.erase(edgeItemIt); @@ -671,3 +725,107 @@ void SkeletonGraphicsWidget::partVisibleStateChanged(QUuid partId) } } +bool SkeletonGraphicsWidget::checkSkeletonItem(QGraphicsItem *item, bool checked) +{ + if (item->data(0) == "node") { + SkeletonGraphicsNodeItem *nodeItem = (SkeletonGraphicsNodeItem *)item; + if (checked != nodeItem->checked()) + nodeItem->setChecked(checked); + return true; + } else if (item->data(0) == "edge") { + SkeletonGraphicsEdgeItem *edgeItem = (SkeletonGraphicsEdgeItem *)item; + if (checked != edgeItem->checked()) + edgeItem->setChecked(checked); + return true; + } + return false; +} + +SkeletonProfile SkeletonGraphicsWidget::readSkeletonItemProfile(QGraphicsItem *item) +{ + if (item->data(0) == "node") { + SkeletonGraphicsNodeItem *nodeItem = (SkeletonGraphicsNodeItem *)item; + return nodeItem->profile(); + } else if (item->data(0) == "edge") { + SkeletonGraphicsEdgeItem *edgeItem = (SkeletonGraphicsEdgeItem *)item; + return edgeItem->profile(); + } + return SkeletonProfile::Unknown; +} + +void SkeletonGraphicsWidget::checkRangeSelection() +{ + std::set newSet; + std::set deleteSet; + SkeletonProfile choosenProfile = SkeletonProfile::Unknown; + if (!m_rangeSelectionSet.empty()) { + auto it = m_rangeSelectionSet.begin(); + choosenProfile = readSkeletonItemProfile(*it); + } + if (m_selectionItem->isVisible()) { + QList items = scene()->items(m_selectionItem->sceneBoundingRect()); + for (auto it = items.begin(); it != items.end(); it++) { + QGraphicsItem *item = *it; + if (SkeletonProfile::Unknown == choosenProfile) { + if (checkSkeletonItem(item, true)) { + choosenProfile = readSkeletonItemProfile(item); + newSet.insert(item); + } + } else if (choosenProfile == readSkeletonItemProfile(item)) { + if (checkSkeletonItem(item, true)) + newSet.insert(item); + } + } + } + if (!QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) { + for (const auto &item: m_rangeSelectionSet) { + if (newSet.find(item) == newSet.end()) { + checkSkeletonItem(item, false); + deleteSet.insert(item); + } + } + } + for (const auto &item: newSet) { + m_rangeSelectionSet.insert(item); + } + for (const auto &item: deleteSet) { + m_rangeSelectionSet.erase(item); + } +} + +void SkeletonGraphicsWidget::clearRangeSelection() +{ + for (const auto &item: m_rangeSelectionSet) { + checkSkeletonItem(item, false); + } + m_rangeSelectionSet.clear(); +} + +void SkeletonGraphicsWidget::readMergedSkeletonNodeSetFromRangeSelection(std::set *nodeItemSet) +{ + for (const auto &it: m_rangeSelectionSet) { + QGraphicsItem *item = it; + if (item->data(0) == "node") { + nodeItemSet->insert((SkeletonGraphicsNodeItem *)item); + } else if (item->data(0) == "edge") { + SkeletonGraphicsEdgeItem *edgeItem = (SkeletonGraphicsEdgeItem *)item; + if (edgeItem->firstItem() && edgeItem->secondItem()) { + nodeItemSet->insert(edgeItem->firstItem()); + nodeItemSet->insert(edgeItem->secondItem()); + } + } + } +} + +void SkeletonGraphicsWidget::readSkeletonNodeAndEdgeIdSetFromRangeSelection(std::set *nodeIdSet, std::set *edgeIdSet) +{ + for (const auto &it: m_rangeSelectionSet) { + QGraphicsItem *item = it; + if (item->data(0) == "node") { + nodeIdSet->insert(((SkeletonGraphicsNodeItem *)item)->id()); + } else if (item->data(0) == "edge") { + edgeIdSet->insert(((SkeletonGraphicsEdgeItem *)item)->id()); + } + } +} + diff --git a/src/skeletongraphicswidget.h b/src/skeletongraphicswidget.h index e99501ec..1d02c5c9 100644 --- a/src/skeletongraphicswidget.h +++ b/src/skeletongraphicswidget.h @@ -9,10 +9,28 @@ #include #include #include +#include #include "skeletondocument.h" #include "turnaroundloader.h" #include "theme.h" +class SkeletonGraphicsSelectionItem : public QGraphicsRectItem +{ +public: + SkeletonGraphicsSelectionItem() + { + QColor penColor = Theme::white; + QPen pen(penColor); + pen.setWidth(0); + pen.setStyle(Qt::DashLine); + setPen(pen); + } + void updateRange(QPointF beginPos, QPointF endPos) + { + setRect(QRectF(beginPos, endPos).normalized()); + } +}; + class SkeletonGraphicsNodeItem : public QGraphicsEllipseItem { public: @@ -24,7 +42,6 @@ public: setData(0, "node"); setRadius(32); } - void updateAppearance() { QColor color = Theme::white; @@ -52,7 +69,6 @@ public: QBrush brush(brushColor); setBrush(brush); } - void setOrigin(QPointF point) { QPointF moveBy = point - origin(); @@ -61,18 +77,15 @@ public: setRect(newRect); updateAppearance(); } - QPointF origin() { return QPointF(rect().x() + rect().width() / 2, rect().y() + rect().height() / 2); } - float radius() { return rect().width() / 2; } - void setRadius(float radius) { if (radius < 4) @@ -82,38 +95,36 @@ public: radius * 2, radius * 2); updateAppearance(); } - SkeletonProfile profile() { return m_profile; } - QUuid id() { return m_uuid; } - void setId(QUuid id) { m_uuid = id; } - void setHovered(bool hovered) { m_hovered = hovered; updateAppearance(); } - void setChecked(bool checked) { m_checked = checked; updateAppearance(); } - bool checked() { return m_checked; } + bool hovered() + { + return m_hovered; + } private: QUuid m_uuid; SkeletonProfile m_profile; @@ -128,23 +139,32 @@ public: m_firstItem(nullptr), m_secondItem(nullptr), m_hovered(false), - m_checked(false) + m_checked(false), + m_profile(SkeletonProfile::Unknown) { setData(0, "edge"); } - void setEndpoints(SkeletonGraphicsNodeItem *first, SkeletonGraphicsNodeItem *second) { m_firstItem = first; m_secondItem = second; updateAppearance(); } - + SkeletonGraphicsNodeItem *firstItem() + { + return m_firstItem; + } + SkeletonGraphicsNodeItem *secondItem() + { + return m_secondItem; + } void updateAppearance() { if (nullptr == m_firstItem || nullptr == m_secondItem) return; + m_profile = m_firstItem->profile(); + QLineF line(m_firstItem->origin(), m_secondItem->origin()); QPolygonF polygon; @@ -176,29 +196,36 @@ public: pen.setWidth(0); setPen(pen); } - QUuid id() { return m_uuid; } - void setId(QUuid id) { m_uuid = id; } - + SkeletonProfile profile() + { + return m_profile; + } void setHovered(bool hovered) { m_hovered = hovered; updateAppearance(); } - void setChecked(bool checked) { m_checked = checked; updateAppearance(); } - + bool checked() + { + return m_checked; + } + bool hovered() + { + return m_hovered; + } private: QUuid m_uuid; SkeletonGraphicsNodeItem *m_firstItem; @@ -206,6 +233,7 @@ private: QPolygonF m_selectionPolygon; bool m_hovered; bool m_checked; + SkeletonProfile m_profile; }; class SkeletonGraphicsFunctions @@ -224,10 +252,6 @@ class SkeletonGraphicsWidget : public QGraphicsView, public SkeletonGraphicsFunc Q_OBJECT signals: void addNode(float x, float y, float z, float radius, QUuid fromNodeId); - void uncheckNode(QUuid nodeId); - void checkNode(QUuid nodeId); - void uncheckEdge(QUuid edgeId); - void checkEdge(QUuid edgeId); void scaleNodeByAddRadius(QUuid nodeId, float amount); void moveNodeBy(QUuid nodeId, float x, float y, float z); void removeNode(QUuid nodeId); @@ -245,6 +269,10 @@ public: bool mousePress(QMouseEvent *event); bool mouseDoubleClick(QMouseEvent *event); bool keyPress(QKeyEvent *event); + static bool checkSkeletonItem(QGraphicsItem *item, bool checked); + static SkeletonProfile readSkeletonItemProfile(QGraphicsItem *item); + void readMergedSkeletonNodeSetFromRangeSelection(std::set *nodeItemSet); + void readSkeletonNodeAndEdgeIdSetFromRangeSelection(std::set *nodeIdSet, std::set *edgeIdSet); protected: void mouseMoveEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); @@ -275,6 +303,9 @@ private: float sceneRadiusFromUnified(float radius); void updateTurnaround(); void updateItems(); + void checkRangeSelection(); + void clearRangeSelection(); + void removeItem(QGraphicsItem *item); private: QGraphicsPixmapItem *m_backgroundItem; const SkeletonDocument *m_document; @@ -286,13 +317,17 @@ private: QPointF m_lastScenePos; SkeletonGraphicsNodeItem *m_cursorNodeItem; SkeletonGraphicsEdgeItem *m_cursorEdgeItem; - SkeletonGraphicsNodeItem *m_checkedNodeItem; + SkeletonGraphicsNodeItem *m_addFromNodeItem; SkeletonGraphicsNodeItem *m_hoveredNodeItem; SkeletonGraphicsEdgeItem *m_hoveredEdgeItem; - SkeletonGraphicsEdgeItem *m_checkedEdgeItem; float m_lastAddedX; float m_lastAddedY; float m_lastAddedZ; + SkeletonGraphicsSelectionItem *m_selectionItem; + QPointF m_rangeSelectionStartPos; + bool m_rangeSelectionStarted; + std::set m_rangeSelectionSet; + bool m_mouseEventFromSelf; }; class SkeletonGraphicsContainerWidget : public QWidget