1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/View/Overlay/IRectangularOverlay.cpp
//! @brief Implements class IRectangularOverlay.
//!
//! @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/Overlay/IRectangularOverlay.h"
#include "Base/Util/Assert.h"
#include <QGraphicsSceneMouseEvent>
namespace {
const double bbox_margins = 5; // additional margins around rectangle to form bounding box
} // namespace
IRectangularOverlay::IRectangularOverlay(ColorMap* plot)
: IMaskOverlay(plot)
, m_active_handle(nullptr)
{
setAcceptHoverEvents(true);
// Create the 8 size handles clockwise starting from top left
for (int i = 0; i < 8; ++i) {
auto h = std::make_unique<SizeHandle>(i, this);
connect(h.get(), &SizeHandle::requestResizing, this, &IRectangularOverlay::setToBeResized);
connect(h.get(), &SizeHandle::requestEnactResize, this, &IRectangularOverlay::enactResize);
m_resize_handles[i] = std::move(h);
}
}
//! triggered by SizeHandle
void IRectangularOverlay::setToBeResized(bool on)
{
if (on) { // triggered by press event
setFlag(QGraphicsItem::ItemIsMovable, false);
m_active_handle = qobject_cast<SizeHandle*>(sender());
ASSERT(m_active_handle);
} else { // triggered by release event
setFlag(QGraphicsItem::ItemIsMovable, true);
m_active_handle = nullptr;
}
}
//! Track if item selected/deselected and show/hide size handles
QVariant IRectangularOverlay::itemChange(QGraphicsItem::GraphicsItemChange change,
const QVariant& value)
{
if (change == QGraphicsItem::ItemSelectedChange)
for (auto& e : m_resize_handles)
e->setVisible(!this->isSelected());
return value;
}
void IRectangularOverlay::enactResize(int i, QPointF pos)
{
QPointF antipode = m_resize_handles.at((i + 4) % 8)->scenePos();
const double xl = std::min(pos.x(), antipode.x());
const double xh = std::max(pos.x(), antipode.x());
const double yl = std::min(pos.y(), antipode.y());
const double yh = std::max(pos.y(), antipode.y());
if (i % 2 == 0) {
resizeX(xl, xh);
resizeY(yl, yh);
} else if (i % 4 == 3)
resizeX(xl, xh);
else if (i % 4 == 1)
resizeY(yl, yh);
update_view();
}
void IRectangularOverlay::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
ASSERT(!m_active_handle);
QGraphicsObject::mousePressEvent(event);
}
void IRectangularOverlay::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
setToBeResized(false);
QGraphicsObject::mouseMoveEvent(event);
}
void IRectangularOverlay::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
ASSERT(!m_active_handle);
setToBeResized(false);
QGraphicsObject::mouseReleaseEvent(event);
}
void IRectangularOverlay::update_view()
{
prepareGeometryChange();
update_bounding_rect();
updatePosition();
}
//! updates view's bounding rectangle using item properties
void IRectangularOverlay::update_bounding_rect()
{
if (parameterizedItem()) {
m_mask_rect = maskRectangle();
if (is_true_mask())
m_bounding_rect = m_mask_rect.marginsAdded(
QMarginsF(bbox_margins, bbox_margins, bbox_margins, bbox_margins));
}
for (auto& e : m_resize_handles)
e->updateHandlePosition(m_mask_rect);
}
|