//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Mask/MaskGraphicsScene.cpp
//! @brief     Implements class MaskGraphicsScene
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/View/Mask/MaskGraphicsScene.h"
#include "GUI/Model/Data/IntensityDataItem.h"
#include "GUI/Model/Data/MaskItems.h"
#include "GUI/Model/Data/ProjectionItems.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Mask/ColorMapSceneAdaptor.h"
#include "GUI/View/Mask/MaskGraphicsProxy.h"
#include "GUI/View/Mask/MaskViewFactory.h"
#include "GUI/View/Mask/PolygonView.h"
#include <QGraphicsSceneContextMenuEvent>
#include <boost/polymorphic_cast.hpp>

using boost::polymorphic_downcast;

namespace {

const QRectF default_scene_rect(0, 0, 800, 600);
const qreal min_distance_to_create_rect = 10;

} // namespace

MaskGraphicsScene::MaskGraphicsScene(QObject* parent)
    : QGraphicsScene(parent)
{
    setSceneRect(default_scene_rect);
    connect(this, &MaskGraphicsScene::selectionChanged, this,
            &MaskGraphicsScene::onSceneSelectionChanged, Qt::UniqueConnection);
}

MaskGraphicsScene::~MaskGraphicsScene()
{
    // Fix within #1792
    if (m_proxy)
        m_proxy->setSceneAdaptor(nullptr);
}

void MaskGraphicsScene::setMaskContext(IntensityDataItem* intensityItem,
                                       MaskContainerItem* maskContainerItem)
{
    if (!intensityItem)
        return;

    m_intensityItem = intensityItem;

    if (!maskContainerItem)
        return;

    MaskContainerModel* maskContainerModel = maskContainerItem->model();
    ASSERT(maskContainerModel);

    if (maskContainerModel != m_maskContainerModel) {
        disconnectMaskContainer(m_maskContainerModel);
        m_maskContainerItem = maskContainerItem;
        m_maskContainerModel = maskContainerModel;
        connectMaskContainer(m_maskContainerModel);
        resetScene();
        updateScene();
    }
}

void MaskGraphicsScene::connectMaskContainer(MaskContainerModel* maskContainerModel)
{
    if (!maskContainerModel)
        return;

    connect(maskContainerModel, &QAbstractListModel::modelAboutToBeReset, this,
            &MaskGraphicsScene::resetScene);
    connect(maskContainerModel, &QAbstractListModel::rowsInserted, this,
            &MaskGraphicsScene::onRowsInserted);
    connect(maskContainerModel, &QAbstractListModel::rowsAboutToBeRemoved, this,
            &MaskGraphicsScene::onRowsAboutToBeRemoved);
    connect(maskContainerModel, &QAbstractListModel::rowsRemoved, this,
            &MaskGraphicsScene::updateScene);
    connect(maskContainerModel, &QAbstractListModel::modelReset, this,
            &MaskGraphicsScene::updateScene);
    connect(maskContainerModel, &QAbstractListModel::rowsMoved, this,
            &MaskGraphicsScene::updateScene);
}

void MaskGraphicsScene::disconnectMaskContainer(MaskContainerModel* maskContainerModel)
{
    if (!maskContainerModel)
        return;

    disconnect(maskContainerModel, &QAbstractListModel::modelAboutToBeReset, this,
               &MaskGraphicsScene::resetScene);
    disconnect(maskContainerModel, &QAbstractListModel::rowsInserted, this,
               &MaskGraphicsScene::onRowsInserted);
    disconnect(maskContainerModel, &QAbstractListModel::rowsAboutToBeRemoved, this,
               &MaskGraphicsScene::onRowsAboutToBeRemoved);
    disconnect(maskContainerModel, &QAbstractListModel::rowsRemoved, this,
               &MaskGraphicsScene::updateScene);
    disconnect(maskContainerModel, &QAbstractListModel::modelReset, this,
               &MaskGraphicsScene::updateScene);
    disconnect(maskContainerModel, &QAbstractListModel::rowsMoved, this,
               &MaskGraphicsScene::updateScene);
}

void MaskGraphicsScene::resetContext()
{
    m_intensityItem = nullptr;
    disconnectMaskContainer(m_maskContainerModel);

    m_maskContainerModel = nullptr;
    resetScene();
}

void MaskGraphicsScene::setSelectionModel(QItemSelectionModel* selectionModel)
{
    ASSERT(selectionModel);
    m_selectionModel = selectionModel;
    connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this,
            &MaskGraphicsScene::onSessionSelectionChanged, Qt::UniqueConnection);
}

ColorMap* MaskGraphicsScene::colorMap()
{
    ASSERT(m_proxy);
    return m_proxy->colorMap();
}

void MaskGraphicsScene::onActivityModeChanged(MaskEditorFlags::Activity value)
{
    if (!m_proxy)
        return;

    if (m_context.isActivityRequiresDrawingCancel(value))
        cancelCurrentDrawing();

    m_context.setActivityType(value);
    setInPanAndZoomMode(m_context.isInZoomMode());

    updateCursors();
}

void MaskGraphicsScene::onMaskValueChanged(MaskEditorFlags::MaskValue value)
{
    m_context.setMaskValue(value);
}

void MaskGraphicsScene::onRowsInserted(const QModelIndex&, int, int)
{
    updateScene();
}

void MaskGraphicsScene::onRowsAboutToBeRemoved(const QModelIndex&, int first, int last)
{
    m_block_selection = true;
    for (int irow = first; irow <= last; ++irow) {
        if (MaskItem* maskItem = m_maskContainerModel->maskContainer->at(irow))
            removeItemViewFromScene(maskItem);
    }
    m_block_selection = false;
}

void MaskGraphicsScene::cancelCurrentDrawing()
{
    if (isDrawingInProgress()) {
        ASSERT(m_currentItem);
        m_maskContainerModel->removeMask(dynamic_cast<MaskItem*>(m_currentItem));
        setDrawingInProgress(false);
    }
}

void MaskGraphicsScene::resetScene()
{
    m_block_selection = true;

    clearSelection();

    clear();
    m_ItemToView.clear();
    m_proxy = nullptr;
    m_adaptor.reset(new ColorMapSceneAdaptor);

    m_block_selection = false;
}

//! Main method to update scene on various changes in the model.

void MaskGraphicsScene::updateScene()
{
    if (!m_maskContainerModel)
        return;

    updateProxyWidget();
    updateViews();
    setZValues();
}

//! Propagates selection from model to scene.

void MaskGraphicsScene::onSessionSelectionChanged(const QItemSelection&, const QItemSelection&)
{
    if (m_block_selection)
        return;

    if (!m_selectionModel)
        return;

    m_block_selection = true;

    for (auto it = m_ItemToView.begin(); it != m_ItemToView.end(); ++it) {
        QModelIndex index = m_maskContainerModel->indexOfItem(it.key());
        if (index.isValid())
            it.value()->setSelected(m_selectionModel->isSelected(index));
    }
    m_block_selection = false;
}

//! Propagates selection from scene to model.

void MaskGraphicsScene::onSceneSelectionChanged()
{
    if (m_block_selection)
        return;

    if (!m_selectionModel)
        return;

    m_block_selection = true;

    if (!m_selectionModel)
        return;

    m_selectionModel->clearSelection();

    for (QGraphicsItem* graphicsItem : selectedItems()) {
        if (auto* view = dynamic_cast<IShape2DView*>(graphicsItem)) {
            QModelIndex itemIndex = m_maskContainerModel->indexOfItem(view->parameterizedItem());
            ASSERT(itemIndex.isValid());
            if (!m_selectionModel->isSelected(itemIndex))
                m_selectionModel->select(itemIndex, QItemSelectionModel::Select);
        }
    }
    m_block_selection = false;
}

void MaskGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
    if (Qt::LeftButton)
        m_mouse_is_pressed = true;

    if (event->buttons() & Qt::RightButton) {
        if (isDrawingInProgress())
            cancelCurrentDrawing();
        else
            makeViewAtMousePosSelected(event);
        return;
    }
    if (isValidForPolygonDrawing(event)) {
        processPolygonItem(event);
        return;
    }
    if (isValidForLineDrawing(event)) {
        processLineItem(event);
        return;
    }
    if (isValidForMaskAllDrawing(event)) {
        processMaskAllItem(event);
        return;
    }
    if (isValidForRectangleShapeDrawing(event)) {
        processRectangleOrEllipseItem(event);
        return;
    }
    QGraphicsScene::mousePressEvent(event);
}

void MaskGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
    if (isDrawingInProgress() && m_context.isRectangleShapeMode()) {
        processRectangleOrEllipseItem(event);
        return;
    }
    QGraphicsScene::mouseMoveEvent(event);

    if ((isDrawingInProgress() && m_context.isPolygonMode()) || m_context.isLineMode()) {
        m_currentMousePosition = event->scenePos();
        invalidate();
    }
}

//! Finalizes item drawing or pass events to other items.

void MaskGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
    m_mouse_is_pressed = false;

    if (isDrawingInProgress()) {
        if (m_context.isRectangleShapeMode()) {
            clearSelection();
            if (m_currentItem) {
                // drawing ended up with item drawn, let's make it selected
                if (IShape2DView* view = m_ItemToView[m_currentItem])
                    view->setSelected(true);
            } else {
                // drawing ended without item to be draw (too short mouse move)
                // making item beneath of mouse release position to be selected
                makeViewAtMousePosSelected(event);
            }
            setDrawingInProgress(false);
        }
    } else
        QGraphicsScene::mouseReleaseEvent(event);
}

//! Draws dashed line to the current mouse position in the case of ungoing
//! line or polygon drawing.

void MaskGraphicsScene::drawForeground(QPainter* painter, const QRectF&)
{
    //    if(!isDrawingInProgress())
    //        return;

    if (m_currentMousePosition == QPointF())
        return;

    if (PolygonView* polygon = currentPolygon()) {
        painter->setPen(QPen(Qt::black, 1, Qt::DashLine));
        painter->drawLine(QLineF(polygon->lastAddedPoint(), m_currentMousePosition));
    } else {
        if (m_context.isLineMode()) {
            const QRectF& plot_scene_rectangle = m_adaptor->viewportRectangle();
            if (!plot_scene_rectangle.contains(m_currentMousePosition))
                return;

            painter->setPen(QPen(Qt::black, 1, Qt::DashLine));
            if (m_context.isVerticalLineMode()) {
                QPointF p1(m_currentMousePosition.x(), plot_scene_rectangle.bottom());
                QPointF p2(m_currentMousePosition.x(), plot_scene_rectangle.top());
                painter->drawLine(QLineF(p1, p2));
            }
            if (m_context.isHorizontalLineMode()) {
                QPointF p1(plot_scene_rectangle.left(), m_currentMousePosition.y());
                QPointF p2(plot_scene_rectangle.right(), m_currentMousePosition.y());
                painter->drawLine(QLineF(p1, p2));
            }
        }
    }
}

//! Creates item context menu if there is IMaskView beneath the mouse right click.

void MaskGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
{
    if (isDrawingInProgress())
        return;

    if (dynamic_cast<IShape2DView*>(itemAt(event->scenePos(), QTransform())))
        emit itemContextMenuRequest(event->screenPos());
}

//! Updates proxy widget for intensity data item.

void MaskGraphicsScene::updateProxyWidget()
{
    ASSERT(m_intensityItem);
    if (!m_proxy) {
        m_proxy = new MaskGraphicsProxy; // TODO: check if m_proxy is released at the end
        m_proxy->setParent(this);
        m_proxy->setIntensityItem(m_intensityItem);
        m_proxy->setSceneAdaptor(m_adaptor.data());
        addItem(m_proxy);
    }
}

//! Recutsively runs through the model and creates corresponding views.

void MaskGraphicsScene::updateViews()
{
    ASSERT(m_maskContainerItem);

    IShape2DView* maskView = addViewForItem(m_maskContainerItem);

    for (MaskItem* maskItem : m_maskContainerItem->maskItems()) {
        if (!maskItem)
            continue;

        IShape2DView* itemView = addViewForItem(maskItem);

        if (itemView && maskView) {
            maskView->addView(itemView);

            // Add views for the points of the PolygonItem
            if (auto polygonItem = dynamic_cast<PolygonItem*>(maskItem)) {
                IShape2DView* const polygonView = itemView;
                for (PolygonPointItem* pointItem : polygonItem->points()) {
                    IShape2DView* pointView = addViewForItem(pointItem);
                    polygonView->addView(pointView);
                }
            }
        }
    }
}

//! Creates a view for given item.

IShape2DView* MaskGraphicsScene::addViewForItem(MaskItemObject* item)
{
    ASSERT(item);
    subscribeMaskItem(item);

    IShape2DView* view = m_ItemToView[item];
    if (!view) {
        view = MaskViewFactory::createMaskView(item, m_adaptor.data());
        if (view) {
            m_ItemToView[item] = view;
            addItem(view);
            return view;
        }
    }
    return view;
}

void MaskGraphicsScene::onMaskMove()
{
    if (m_mouse_is_pressed)
        gProjectDocument.value()->setModified(); // manual mask movement
}

//! Removes single view from scene.

void MaskGraphicsScene::removeItemViewFromScene(MaskItemObject* item)
{
    for (auto it = m_ItemToView.begin(); it != m_ItemToView.end(); ++it) {
        if (it.key() == item) {
            // at first, delete views for the points of the PolygonItem
            if (auto* polygonItem = dynamic_cast<PolygonItem*>(item))
                for (PolygonPointItem* pointItem : polygonItem->points())
                    removeItemViewFromScene(pointItem);

            IShape2DView* view = it.value();
            view->setSelected(false);
            m_ItemToView.erase(it);
            delete view;
            break;
        }
    }
}

//! Returns true if left mouse bottom click was inside ColorMap viewport rectangle.

bool MaskGraphicsScene::isValidMouseClick(QGraphicsSceneMouseEvent* event)
{
    if (!m_adaptor)
        return false;
    if (!(event->buttons() & Qt::LeftButton))
        return false;
    if (!m_adaptor->viewportRectangle().contains(event->scenePos()))
        return false;
    return true;
}

//! Returns true if mouse click is valid for rectangular/elliptic/ROI shapes.

bool MaskGraphicsScene::isValidForRectangleShapeDrawing(QGraphicsSceneMouseEvent* event)
{
    if (isDrawingInProgress())
        return false;
    if (!isValidMouseClick(event))
        return false;
    if (!m_context.isRectangleShapeMode())
        return false;
    if (isAreaContains(event, MaskEditorHelper::SIZEHANDLE))
        return false;
    if (m_context.isROIMode()) {
        // only one ROI is allowed
        for (MaskItemObject* item : m_ItemToView.keys())
            if (dynamic_cast<RegionOfInterestItem*>(item))
                return false;
    }
    return true;
}

//! Returns true if mouse click is in context suitable for polygon drawing.

bool MaskGraphicsScene::isValidForPolygonDrawing(QGraphicsSceneMouseEvent* event)
{
    if (!isValidMouseClick(event))
        return false;
    if (!m_context.isPolygonMode())
        return false;
    if (!isDrawingInProgress()) {
        if (isAreaContains(event, MaskEditorHelper::POLYGONPOINT))
            return false;
    }
    return true;
}

//! Returns true if mouse click is in context suitable for line drawing.

bool MaskGraphicsScene::isValidForLineDrawing(QGraphicsSceneMouseEvent* event)
{
    if (!isValidMouseClick(event))
        return false;
    if (isDrawingInProgress())
        return false;
    if (!m_context.isLineMode())
        return false;
    if (QGraphicsItem* graphicsItem = itemAt(event->scenePos(), QTransform())) {
        if (graphicsItem->type() == MaskEditorHelper::VERTICALLINE
            || graphicsItem->type() == MaskEditorHelper::HORIZONTALLINE)
            return false;
    }
    return true;
}

//! Returns true if MaskAllItem can be drawn. Only one item of such type is allowed.

bool MaskGraphicsScene::isValidForMaskAllDrawing(QGraphicsSceneMouseEvent* event)
{
    if (!isValidMouseClick(event))
        return false;
    if (isDrawingInProgress())
        return false;
    if (!m_context.isMaskAllMode())
        return false;

    for (MaskItemObject* item : m_ItemToView.keys())
        if (dynamic_cast<MaskAllItem*>(item))
            return false;
    return true;
}

//! Return true if area beneath the mouse contains views of given type.

bool MaskGraphicsScene::isAreaContains(QGraphicsSceneMouseEvent* event,
                                       MaskEditorHelper::EViewTypes viewType)
{
    for (QGraphicsItem* graphicsItem : this->items(event->scenePos()))
        if (graphicsItem->type() == viewType)
            return true;
    return false;
}

bool MaskGraphicsScene::isDrawingInProgress() const
{
    return m_context.isDrawingInProgress();
}

void MaskGraphicsScene::setDrawingInProgress(bool value)
{
    m_context.setDrawingInProgress(value);
    if (value)
        gProjectDocument.value()->setModified(); // manual mask creation
    else
        m_currentItem = nullptr;
}

//! Sets the state of all views in pan&zoom mode.
//! In pan&zoom mode, the selection is removed, all items cannot receive mouse clicks, and all
//! events are propagated down to ColorMap plot.

void MaskGraphicsScene::setInPanAndZoomMode(bool value)
{
    if (value)
        m_selectionModel->clearSelection();

    Qt::MouseButtons acceptedButton = (value ? Qt::NoButton : Qt::LeftButton);
    for (IShape2DView* view : m_ItemToView.values())
        view->setAcceptedMouseButtons(acceptedButton);

    m_proxy->setInZoomMode(value);
}

//! Change cursor to stress that hovered item is movable (when not in PanZoom mode)

void MaskGraphicsScene::updateCursors()
{
    for (auto it = m_ItemToView.begin(); it != m_ItemToView.end(); ++it) {
        if (dynamic_cast<VerticalLineItem*>(it.key()))
            it.value()->setCursor(m_context.isInZoomMode() ? Qt::ArrowCursor : Qt::SizeHorCursor);
        else if (dynamic_cast<HorizontalLineItem*>(it.key()))
            it.value()->setCursor(m_context.isInZoomMode() ? Qt::ArrowCursor : Qt::SizeVerCursor);
    }
}

void MaskGraphicsScene::makeViewAtMousePosSelected(QGraphicsSceneMouseEvent* event)
{
    if (QGraphicsItem* graphicsItem = itemAt(event->scenePos(), QTransform()))
        graphicsItem->setSelected(true);
}

//! Processes RectangleItem and EllipseItem drawing
//! If the mouse move distance with left button down is larger than certain threshold,
//! new item will be created. Further, this function will update size and position
//! of current rectangle if mouse keep moving.

void MaskGraphicsScene::processRectangleOrEllipseItem(QGraphicsSceneMouseEvent* event)
{
    if (!isDrawingInProgress())
        setDrawingInProgress(true);

    QPointF click_pos = event->buttonDownScenePos(Qt::LeftButton);
    QPointF mouse_pos = event->scenePos();
    QLineF line(mouse_pos, click_pos);

    if (!m_currentItem && line.length() > min_distance_to_create_rect) {

        MaskItem* newMaskItem;
        if (m_context.isRectangleMode())
            newMaskItem = new RectangleItem;
        else if (m_context.isEllipseMode())
            newMaskItem = new EllipseItem;
        else if (m_context.isROIMode())
            newMaskItem = new RegionOfInterestItem;
        else
            ASSERT(false);

        // TODO: What to do for the case when `m_context.isROIMode() = true`?
        m_maskContainerModel->insertMask(0, newMaskItem);

        // new item should be MaskItemObject-based
        m_currentItem = dynamic_cast<MaskItemObject*>(newMaskItem);
        ASSERT(m_currentItem);

        if (!m_context.isROIMode())
            dynamic_cast<MaskItem*>(m_currentItem)->setMaskValue(m_context.getMaskValue());

        m_maskContainerItem->updateMaskNames();
    } else if (!m_currentItem)
        return;

    qreal xmin = std::min(click_pos.x(), mouse_pos.x());
    qreal xmax = std::max(click_pos.x(), mouse_pos.x());
    qreal ymin = std::min(click_pos.y(), mouse_pos.y());
    qreal ymax = std::max(click_pos.y(), mouse_pos.y());

    if (auto* rectItem = dynamic_cast<RectangleItem*>(m_currentItem)) {
        // RectangleItem or RegionOfInterestItem
        rectItem->setXLow(m_adaptor->fromSceneX(xmin));
        rectItem->setYLow(m_adaptor->fromSceneY(ymax));
        rectItem->setXUp(m_adaptor->fromSceneX(xmax));
        rectItem->setYUp(m_adaptor->fromSceneY(ymin));
    } else if (auto* ellItem = dynamic_cast<EllipseItem*>(m_currentItem)) {
        ellItem->setXCenter(m_adaptor->fromSceneX(xmin + (xmax - xmin) / 2.));
        ellItem->setYCenter(m_adaptor->fromSceneY(ymin + (ymax - ymin) / 2.));
        ellItem->setXRadius((m_adaptor->fromSceneX(xmax) - m_adaptor->fromSceneX(xmin)) / 2.);
        ellItem->setYRadius((m_adaptor->fromSceneY(ymin) - m_adaptor->fromSceneY(ymax)) / 2.);
    }

    // produce views for the created shape
    updateViews();
}

void MaskGraphicsScene::processPolygonItem(QGraphicsSceneMouseEvent* event)
{
    ASSERT(m_context.isPolygonMode());

    if (!m_currentItem) {
        setDrawingInProgress(true);
        PolygonItem* new_poly = new PolygonItem;
        m_maskContainerModel->insertMask(0, new_poly);
        new_poly->setMaskValue(m_context.getMaskValue());
        m_currentItem = new_poly;
        m_selectionModel->clearSelection();
        m_selectionModel->select(m_maskContainerModel->indexOfItem(m_currentItem),
                                 QItemSelectionModel::Select);
        m_maskContainerItem->updateMaskNames();
    }
    ASSERT(dynamic_cast<PolygonItem*>(m_currentItem));

    if (PolygonView* polygon = currentPolygon()) {
        if (polygon->closePolygonIfNecessary()) {
            setDrawingInProgress(false);
            m_currentMousePosition = {};
            return;
        }
    }

    QPointF click_pos = event->buttonDownScenePos(Qt::LeftButton);
    double x = m_adaptor->fromSceneX(click_pos.x()), y = m_adaptor->fromSceneY(click_pos.y());
    dynamic_cast<PolygonItem*>(m_currentItem)->addPoint(x, y);
    updateScene();
}

void MaskGraphicsScene::processLineItem(QGraphicsSceneMouseEvent* event)
{
    setDrawingInProgress(true);
    QPointF click_pos = event->buttonDownScenePos(Qt::LeftButton);

    if (m_context.isVerticalLineMode())
        processVerticalLineItem(click_pos);

    if (m_context.isHorizontalLineMode())
        processHorizontalLineItem(click_pos);

    m_selectionModel->clearSelection();
    m_selectionModel->select(m_maskContainerModel->indexOfItem(m_currentItem),
                             QItemSelectionModel::Select);
    m_maskContainerItem->updateMaskNames();
    dynamic_cast<MaskItem*>(m_currentItem)->setMaskValue(m_context.getMaskValue());

    emit lineItemProcessed();

    setDrawingInProgress(false);
}

void MaskGraphicsScene::processVerticalLineItem(const QPointF& pos)
{
    VerticalLineItem* item = new VerticalLineItem;
    m_maskContainerModel->insertMask(0, item);
    m_currentItem = item;
    item->setPosX(m_adaptor->fromSceneX(pos.x()));
}

void MaskGraphicsScene::processHorizontalLineItem(const QPointF& pos)
{
    HorizontalLineItem* item = new HorizontalLineItem;
    m_maskContainerModel->insertMask(0, item);
    m_currentItem = dynamic_cast<MaskItemObject*>(item);
    item->setPosY(m_adaptor->fromSceneY(pos.y()));
}

// TODO: check MaskAllItem
void MaskGraphicsScene::processMaskAllItem(QGraphicsSceneMouseEvent* event)
{
    Q_UNUSED(event);
    setDrawingInProgress(true);
    MaskAllItem* item = new MaskAllItem;
    m_maskContainerModel->insertMask(0, item);
    m_currentItem = item;
    m_selectionModel->clearSelection();
    setDrawingInProgress(false);
}

void MaskGraphicsScene::subscribeMaskItem(MaskItemObject* item)
{
    if (!item)
        return;

    connect(item, &MaskItemObject::maskGeometryChanged, this, &MaskGraphicsScene::lineItemMoved,
            Qt::UniqueConnection);
    connect(item, &MaskItemObject::maskGeometryChanged, this, &MaskGraphicsScene::onMaskMove,
            Qt::UniqueConnection);
    connect(item, &MaskItemObject::maskToBeDestroyed, this, &MaskGraphicsScene::lineItemDeleted,
            Qt::UniqueConnection);
}

//! Update Z-values of all IMaskView to reflect stacking order.

void MaskGraphicsScene::setZValues()
{
    if (!m_maskContainerItem)
        return;

    int z = m_maskContainerItem->maskItems().size();
    for (MaskItem* maskItem : m_maskContainerItem->maskItems()) {
        if (IShape2DView* view = m_ItemToView[maskItem])
            view->setZValue(z);
        --z;
    }
}

//! Returns polygon which is currently under the drawing.

PolygonView* MaskGraphicsScene::currentPolygon() const
{
    PolygonView* result(nullptr);
    if (isDrawingInProgress() && m_context.isPolygonMode()) {
        if (m_currentItem)
            result = dynamic_cast<PolygonView*>(m_ItemToView[m_currentItem]);
    }
    return result;
}
