diff --git a/GUI/View/Canvas/MaskEditorCanvas.cpp b/GUI/View/Canvas/MaskEditorCanvas.cpp index 040d801ae53343c23eed917de3534789b314db16..4350548774be6d113f3c8614e4ff295244305dbc 100644 --- a/GUI/View/Canvas/MaskEditorCanvas.cpp +++ b/GUI/View/Canvas/MaskEditorCanvas.cpp @@ -69,7 +69,7 @@ MaskEditorCanvas::MaskEditorCanvas() , m_status_label(new PlotStatusLabel({m_scene->colorMap()})) , m_data_item(nullptr) { - setCanvasMode(Canvas2DMode::PAN_ZOOM); + setCanvasMode(Canvas2DMode::SELECTION); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setMinimumSize(400, 400); diff --git a/GUI/View/Overlay/LineOverlays.cpp b/GUI/View/Overlay/LineOverlays.cpp index 37815b02a16d5d93af38d03aee688baee99840a7..675f4b4e2c023574de3b9dd26298380034262f19 100644 --- a/GUI/View/Overlay/LineOverlays.cpp +++ b/GUI/View/Overlay/LineOverlays.cpp @@ -67,7 +67,6 @@ OverlayItem* LineOverlay::parameterizedItem() const HorizontalLineOverlay::HorizontalLineOverlay(LineItem* item, ColorMap* plot) : LineOverlay(item, plot) { - setCursor(Qt::SizeVerCursor); } QRectF HorizontalLineOverlay::rectangle() const @@ -115,7 +114,6 @@ QVariant HorizontalLineOverlay::itemChange(QGraphicsItem::GraphicsItemChange cha VerticalLineOverlay::VerticalLineOverlay(LineItem* item, ColorMap* plot) : LineOverlay(item, plot) { - setCursor(Qt::SizeHorCursor); } QRectF VerticalLineOverlay::rectangle() const diff --git a/GUI/View/Overlay/PolygonOverlay.cpp b/GUI/View/Overlay/PolygonOverlay.cpp index 0e97afd01fd0f78eeb29d690b518655d4b171ab4..ad9c08ebee6e8b352e9a5ee78e6a614a6123190d 100644 --- a/GUI/View/Overlay/PolygonOverlay.cpp +++ b/GUI/View/Overlay/PolygonOverlay.cpp @@ -90,7 +90,6 @@ bool PolygonOverlay::closePolygonIfNecessary() childItem->setFlag(QGraphicsItem::ItemIsMovable); childItem->setFlag(QGraphicsItem::ItemSendsGeometryChanges); childItem->setAcceptHoverEvents(false); - childItem->setCursor(Qt::SizeAllCursor); } m_item->setIsClosed(true); update(); diff --git a/GUI/View/Scene/MaskGraphicsScene.cpp b/GUI/View/Scene/MaskGraphicsScene.cpp index c5af5ab8c0a433c5d267ab2a29c76bd61d3dad5b..cfec4a68504453df8fc7cf5d09c8014ca2512549 100644 --- a/GUI/View/Scene/MaskGraphicsScene.cpp +++ b/GUI/View/Scene/MaskGraphicsScene.cpp @@ -156,6 +156,7 @@ void MaskGraphicsScene::cancelCurrentDrawing() deleteCurrentItem(); setDrawingInProgress(false); + update(); // clears ghost lines from the unfinished polygon } // ************************************************************************************************ @@ -170,13 +171,8 @@ void MaskGraphicsScene::onActivityChanged(Canvas2DMode::Flag mode) cancelCurrentDrawing(); m_mode = mode; - const bool zooming = m_mode == Canvas2DMode::PAN_ZOOM; - m_proxy->setZooming(zooming); - for (auto const& [item, overlay] : m_mask2overlay) { - overlay->setAcceptedMouseButtons(zooming ? Qt::NoButton : Qt::LeftButton); - overlay->setCursor(zooming ? Qt::ArrowCursor : Qt::SizeAllCursor); - } - m_plot->setCursor(zooming ? Qt::PointingHandCursor : Qt::ArrowCursor); + m_proxy->setZooming(m_mode == Canvas2DMode::PAN_ZOOM); + updateCursors(); } // ************************************************************************************************ @@ -190,6 +186,9 @@ void MaskGraphicsScene::onActivityChanged(Canvas2DMode::Flag mode) void MaskGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { + // forbid multiple visual selection + event->setModifiers(Qt::NoModifier); + if (event->buttons() & Qt::LeftButton) m_mouse_is_pressed = true; @@ -197,7 +196,7 @@ void MaskGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent* event) if (m_drawing_in_progress) cancelCurrentDrawing(); else - makeViewAtMousePosSelected(event); + selectOnlyItemAtMousePos(event); return; } @@ -235,6 +234,8 @@ void MaskGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event) void MaskGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { + event->setModifiers(Qt::NoModifier); + m_mouse_is_pressed = false; if (!m_drawing_in_progress) @@ -242,12 +243,11 @@ void MaskGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) else if (Canvas2DMode::basedOnRectangle(m_mode)) { if (m_active_mask) { // drawing ended up with item drawn, let's make it selected - if (IOverlay* overlay = m_mask2overlay[m_active_mask]) - overlay->setSelected(true); + selectOnlyGivenItem(m_mask2overlay[m_active_mask]); } else { // drawing ended without item to be draw (too short mouse move) // making item beneath of mouse release position to be selected - makeViewAtMousePosSelected(event); + selectOnlyItemAtMousePos(event); } setDrawingInProgress(false); } @@ -298,6 +298,26 @@ void MaskGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) emit itemContextMenuRequest(event->screenPos()); } +void MaskGraphicsScene::updateCursors() +{ + const bool zooming = m_mode == Canvas2DMode::PAN_ZOOM; + const auto zoom_cursor = Qt::ClosedHandCursor; + for (auto const& [item, overlay] : m_mask2overlay) { + overlay->setAcceptedMouseButtons(zooming ? Qt::NoButton : Qt::LeftButton); + + if (dynamic_cast<HorizontalLineOverlay*>(overlay)) + overlay->setCursor(zooming ? zoom_cursor : Qt::SizeVerCursor); + else if (dynamic_cast<VerticalLineOverlay*>(overlay)) + overlay->setCursor(zooming ? zoom_cursor : Qt::SizeHorCursor); + else if (dynamic_cast<VertexOverlay*>(overlay)) + overlay->setCursor(zooming ? zoom_cursor : Qt::CrossCursor); + else + // rectangle, ellipse, polygon + overlay->setCursor(zooming ? zoom_cursor : Qt::PointingHandCursor); + } + m_viewport->setCursor(zooming ? zoom_cursor : Qt::ArrowCursor); +} + // ************************************************************************************************ // private modifying functions // ************************************************************************************************ @@ -317,7 +337,6 @@ void MaskGraphicsScene::updateOverlays() ASSERT(polygon_overlay); for (PointItem* point_item : polygon_item->points()) { IOverlay* point_overlay = registerOverlay(point_item); - point_overlay->show(); polygon_overlay->addOverlay(point_overlay); } } @@ -336,6 +355,8 @@ void MaskGraphicsScene::updateOverlays() IOverlay* overlay = registerOverlay(t); ASSERT(overlay); } + + updateCursors(); } //! Creates a view for given item. @@ -405,10 +426,27 @@ void MaskGraphicsScene::setDrawingInProgress(bool value) m_active_mask = nullptr; } -void MaskGraphicsScene::makeViewAtMousePosSelected(QGraphicsSceneMouseEvent* event) +void MaskGraphicsScene::selectOnlyItemAtMousePos(QGraphicsSceneMouseEvent* event) { - if (QGraphicsItem* graphicsItem = itemAt(event->scenePos(), QTransform())) - graphicsItem->setSelected(true); + selectOnlyGivenItem(itemAt(event->scenePos(), QTransform())); +} + +void MaskGraphicsScene::selectOnlyGivenItem(QGraphicsItem* givenItem) +{ + // prevent signaling with 'selectionChanged' during intermediate operations + blockSignals(true); + + auto old_selection = selectedItems(); + for (QGraphicsItem* otherItem : old_selection) + otherItem->setSelected(false); + + if (givenItem && givenItem != m_viewport) + givenItem->setSelected(true); + + blockSignals(false); + + if (old_selection != selectedItems()) + emit selectionChanged(); } //! Processes RectangleItem and EllipseItem drawing. @@ -484,21 +522,22 @@ void MaskGraphicsScene::processPolygonItem(QGraphicsSceneMouseEvent* event) m_masks->add_item(new_poly); new_poly->setMaskValue(m_mask_value); m_active_mask = new_poly; + registerOverlay(new_poly); } ASSERT(dynamic_cast<PolygonItem*>(m_active_mask)); + ASSERT(dynamic_cast<PolygonOverlay*>(currentPolygon())); - if (PolygonOverlay* polygon = currentPolygon()) { - if (polygon->closePolygonIfNecessary()) { - setDrawingInProgress(false); - m_mouse_position = {}; - return; - } - } + selectOnlyGivenItem(currentPolygon()); - const QPointF click_pos = event->buttonDownScenePos(Qt::LeftButton); - const double x = m_plot->xAxis->pixelToCoord(click_pos.x()); - const double y = m_plot->yAxis->pixelToCoord(click_pos.y()); - dynamic_cast<PolygonItem*>(m_active_mask)->addPoint(x, y); + if (currentPolygon()->closePolygonIfNecessary()) { + setDrawingInProgress(false); + m_mouse_position = {}; + } else { + const QPointF click_pos = event->buttonDownScenePos(Qt::LeftButton); + const double x = m_plot->xAxis->pixelToCoord(click_pos.x()); + const double y = m_plot->yAxis->pixelToCoord(click_pos.y()); + dynamic_cast<PolygonItem*>(m_active_mask)->addPoint(x, y); + } updateOverlays(); } diff --git a/GUI/View/Scene/MaskGraphicsScene.h b/GUI/View/Scene/MaskGraphicsScene.h index ccd03de8b5134c9757b255b0e40231df115b900a..52f740b3fdc0420024ecdb31e4a18df77f99d789 100644 --- a/GUI/View/Scene/MaskGraphicsScene.h +++ b/GUI/View/Scene/MaskGraphicsScene.h @@ -47,6 +47,7 @@ public: ColorMap* colorMap() { return m_plot.get(); } signals: + void mouseSelectionChanged(); void itemContextMenuRequest(const QPoint& point); void lineItemProcessed(); void lineItemMoved(LineItem* sender); @@ -62,6 +63,7 @@ private: void drawForeground(QPainter* painter, const QRectF& rect) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override; + void updateCursors(); void associateItems(Data2DItem* data_item); void clearOverlays(); void updateOverlays(); @@ -70,7 +72,8 @@ private: void setDrawingInProgress(bool value); - void makeViewAtMousePosSelected(QGraphicsSceneMouseEvent* event); + void selectOnlyItemAtMousePos(QGraphicsSceneMouseEvent* event); + void selectOnlyGivenItem(QGraphicsItem* givenItem); void processRectangleOrEllipseItem(QGraphicsSceneMouseEvent* event); void processPolygonItem(QGraphicsSceneMouseEvent* event); diff --git a/GUI/View/Setup/Data2DToolbar.cpp b/GUI/View/Setup/Data2DToolbar.cpp index 3ddbc53a42d664987b653c5b572db4a1095ad558..9bf18730a9abb1e9b2de6abb5d4161df652e2a98 100644 --- a/GUI/View/Setup/Data2DToolbar.cpp +++ b/GUI/View/Setup/Data2DToolbar.cpp @@ -35,6 +35,7 @@ Data2DToolbar::Data2DToolbar(bool mask_tools) selection_button->setIcon(QIcon(":/images/mask/arrow.svg")); selection_button->setToolTip("Select/modify mask"); selection_button->setCheckable(true); + selection_button->setChecked(true); addWidget(selection_button); m_activity_button_group->addButton(selection_button, Canvas2DMode::SELECTION); @@ -43,7 +44,6 @@ Data2DToolbar::Data2DToolbar(bool mask_tools) pan_button->setToolTip("Pan/zoom mode (space)\n" "Drag axes with the mouse, use mouse wheel to zoom in/out"); pan_button->setCheckable(true); - pan_button->setChecked(true); addWidget(pan_button); m_activity_button_group->addButton(pan_button, Canvas2DMode::PAN_ZOOM);