##// END OF EJS Templates
Creates validator interface
Creates validator interface

File last commit:

r1159:4c27015bd9c6
r1193:1e58f6535bdb
Show More
VisualizationSelectionZoneItem.cpp
440 lines | 15.2 KiB | text/x-c | CppLexer
/ gui / src / Visualization / VisualizationSelectionZoneItem.cpp
#include "Visualization/VisualizationSelectionZoneItem.h"
#include "Visualization/VisualizationGraphWidget.h"
#include "Visualization/VisualizationSelectionZoneManager.h"
#include "Visualization/VisualizationWidget.h"
const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
QCustomPlot *m_Plot;
double m_T1 = 0;
double m_T2 = 0;
QColor m_Color;
bool m_IsEditionEnabled = true;
double m_MovedOrinalT1 = 0;
double m_MovedOrinalT2 = 0;
QCPItemStraightLine *m_LeftLine;
QCPItemStraightLine *m_RightLine;
QCPItemText *m_NameLabelItem = nullptr;
enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
EditionMode m_CurrentEditionMode;
QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
: m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
{
}
void updatePosition(VisualizationSelectionZoneItem *item)
{
item->topLeft->setCoords(m_T1, 0);
item->bottomRight->setCoords(m_T2, 1);
}
EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
{
auto distanceLeft = m_LeftLine->selectTest(pos, false);
auto distanceRight = m_RightLine->selectTest(pos, false);
auto distance = zoneItem->selectTest(pos, false);
if (distanceRight <= distance) {
return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
}
else if (distanceLeft <= distance) {
return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
}
return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
}
double pixelSizeToAxisXSize(double pixels)
{
auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
}
bool alignZones(VisualizationSelectionZoneItem *referenceZone,
const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
bool allowResize, bool vertically)
{
auto result = false;
auto referenceTime
= alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
for (auto otherZone : zonesToAlign) {
auto otherZoneRange = otherZone->range();
auto newZoneStart = otherZoneRange.m_TStart;
auto newZoneEnd = otherZoneRange.m_TEnd;
auto alignedTime = referenceTime;
if (vertically) {
auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
}
if (alignOnLeft) {
newZoneStart = alignedTime;
if (!allowResize) {
newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
}
}
else { // align on right
newZoneEnd = alignedTime;
if (!allowResize) {
newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
}
}
if (newZoneStart < newZoneEnd) {
result = true;
otherZone->setRange(newZoneStart, newZoneEnd);
otherZone->parentPlot()->replot();
}
}
return result;
}
};
VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
: QCPItemRect(plot),
impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
{
topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
setSelectable(false);
impl->m_RightLine = new QCPItemStraightLine(plot);
impl->m_RightLine->point1->setParentAnchor(topRight);
impl->m_RightLine->point2->setParentAnchor(bottomRight);
impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
impl->m_RightLine->setSelectable(false);
impl->m_LeftLine = new QCPItemStraightLine(plot);
impl->m_LeftLine->point1->setParentAnchor(topLeft);
impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
impl->m_LeftLine->setSelectable(false);
connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
&QCPItemStraightLine::setSelected);
connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
&QCPItemStraightLine::setSelected);
setColor(QColor(DEFAULT_COLOR));
}
VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
{
}
VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
{
auto parent = impl->m_Plot->parentWidget();
while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
parent = parent->parentWidget();
}
return qobject_cast<VisualizationGraphWidget *>(parent);
}
void VisualizationSelectionZoneItem::setName(const QString &name)
{
if (name.isEmpty() && impl->m_NameLabelItem) {
impl->m_Plot->removeItem(impl->m_NameLabelItem);
impl->m_NameLabelItem = nullptr;
}
else if (!impl->m_NameLabelItem) {
impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
impl->m_NameLabelItem->setText(name);
impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
impl->m_NameLabelItem->setColor(impl->m_Color);
impl->m_NameLabelItem->position->setParentAnchor(top);
}
}
QString VisualizationSelectionZoneItem::name() const
{
if (!impl->m_NameLabelItem) {
return QString();
}
return impl->m_NameLabelItem->text();
}
SqpRange VisualizationSelectionZoneItem::range() const
{
SqpRange range;
range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
return range;
}
void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
{
impl->m_T1 = tstart;
impl->m_T2 = tend;
impl->updatePosition(this);
}
void VisualizationSelectionZoneItem::setStart(double tstart)
{
impl->m_T1 = tstart;
impl->updatePosition(this);
}
void VisualizationSelectionZoneItem::setEnd(double tend)
{
impl->m_T2 = tend;
impl->updatePosition(this);
}
void VisualizationSelectionZoneItem::setColor(const QColor &color)
{
impl->m_Color = color;
auto brushColor = color;
brushColor.setAlpha(80);
setBrush(QBrush(brushColor));
setPen(QPen(Qt::NoPen));
auto selectedBrushColor = brushColor;
selectedBrushColor.setAlpha(150);
setSelectedBrush(QBrush(selectedBrushColor));
setSelectedPen(QPen(Qt::NoPen));
auto linePen = QPen(color);
linePen.setStyle(Qt::SolidLine);
linePen.setWidth(4);
auto selectedLinePen = linePen;
selectedLinePen.setColor(color.darker(120));
selectedLinePen.setWidth(4);
impl->m_LeftLine->setPen(linePen);
impl->m_RightLine->setPen(linePen);
impl->m_LeftLine->setSelectedPen(selectedLinePen);
impl->m_RightLine->setSelectedPen(selectedLinePen);
}
void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
{
impl->m_IsEditionEnabled = value;
setSelectable(value);
if (!value) {
setSelected(false);
impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
}
}
bool VisualizationSelectionZoneItem::isEditionEnabled() const
{
return impl->m_IsEditionEnabled;
}
void VisualizationSelectionZoneItem::moveToTop()
{
moveToLayer(layer(), false);
}
Qt::CursorShape
VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
{
auto mode = impl->m_CurrentEditionMode
== VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
? impl->getEditionMode(position, this)
: impl->m_CurrentEditionMode;
switch (mode) {
case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
return Qt::SizeAllCursor;
case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
return Qt::SizeHorCursor;
default:
return Qt::ArrowCursor;
}
}
void VisualizationSelectionZoneItem::setHovered(bool value)
{
if (value) {
auto linePen = impl->m_LeftLine->pen();
linePen.setStyle(Qt::DotLine);
linePen.setWidth(3);
auto selectedLinePen = impl->m_LeftLine->selectedPen();
;
selectedLinePen.setStyle(Qt::DotLine);
selectedLinePen.setWidth(3);
impl->m_LeftLine->setPen(linePen);
impl->m_RightLine->setPen(linePen);
impl->m_LeftLine->setSelectedPen(selectedLinePen);
impl->m_RightLine->setSelectedPen(selectedLinePen);
}
else {
setColor(impl->m_Color);
}
}
void VisualizationSelectionZoneItem::setAssociatedEditedZones(
const QVector<VisualizationSelectionZoneItem *> &associatedZones)
{
impl->m_AssociatedEditedZones = associatedZones;
impl->m_AssociatedEditedZones.removeAll(this);
}
bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
{
return impl->alignZones(this, zonesToAlign, true, allowResize, true);
}
bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
{
return impl->alignZones(this, zonesToAlign, false, allowResize, true);
}
bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
{
return impl->alignZones(this, zonesToAlign, true, allowResize, false);
}
bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
{
return impl->alignZones(this, zonesToAlign, false, allowResize, false);
}
void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
{
Q_UNUSED(details);
if (isEditionEnabled() && event->button() == Qt::LeftButton) {
impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
impl->m_MovedOrinalT1 = impl->m_T1;
impl->m_MovedOrinalT2 = impl->m_T2;
for (auto associatedZone : impl->m_AssociatedEditedZones) {
associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
}
}
else {
impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
event->ignore();
}
}
void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
{
if (isEditionEnabled()) {
if (!selected()) {
// Force the item to be selected during the edition
parentGraphWidget()->parentVisualizationWidget()->selectionZoneManager().setSelected(
this, true);
}
auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
auto pixelDiff = event->pos().x() - startPos.x();
auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
switch (impl->m_CurrentEditionMode) {
case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
for (auto associatedZone : impl->m_AssociatedEditedZones) {
associatedZone->move(pixelDiff);
}
break;
case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
setStart(impl->m_MovedOrinalT1 + diff);
for (auto associatedZone : impl->m_AssociatedEditedZones) {
impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
? associatedZone->resizeLeft(pixelDiff)
: associatedZone->resizeRight(pixelDiff);
}
break;
case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
setEnd(impl->m_MovedOrinalT2 + diff);
for (auto associatedZone : impl->m_AssociatedEditedZones) {
impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
? associatedZone->resizeRight(pixelDiff)
: associatedZone->resizeLeft(pixelDiff);
}
break;
default:
break;
}
for (auto associatedZone : impl->m_AssociatedEditedZones) {
associatedZone->parentPlot()->replot();
}
}
else {
event->ignore();
}
}
void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
{
Q_UNUSED(startPos);
if (isEditionEnabled()) {
impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
}
else {
event->ignore();
}
impl->m_AssociatedEditedZones.clear();
}
void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
{
auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
setStart(impl->m_MovedOrinalT1 + diff);
}
else {
setEnd(impl->m_MovedOrinalT2 + diff);
}
}
void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
{
auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
setStart(impl->m_MovedOrinalT1 + diff);
}
else {
setEnd(impl->m_MovedOrinalT2 + diff);
}
}
void VisualizationSelectionZoneItem::move(double pixelDiff)
{
auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
}