#pragma once
#include "FractoriumPch.h"
///
/// CurvesGraphicsView and EllipseItem classes.
///
class EllipseItem;
///
/// Enumeration used for setting values on a specific curve.
///
enum class CurveIndex : et
{
ALL,
RED,
GREEN,
BLUE
};
///
/// Derivation to display points on bezier cuves for the user to drag.
/// Selection logic and updating is handled by the base class.
/// Changes here will affect the current ember and vice versa.
/// The points, axis lines and pens are kept as members and the curves
/// themselves are drawn on the fly during each paint event.
/// Pointers to these are kept in arrays to make manipulating them in loops easier.
/// Note that this must work off a fixed rect size, hence why the control is not resizeable.
///
class CurvesGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
CurvesGraphicsView(QWidget* parent = nullptr);
void PointChanged(int curveIndex, int pointIndex, const QPointF& point);
QPointF Get(int curveIndex, int pointIndex);
void Set(int curveIndex, int pointIndex, const QPointF& point);
void Set(Curves& curves);
void SetTop(CurveIndex curveIndex);
size_t SelectedCurveIndex() const { return m_Index; }
Q_SIGNALS:
void PointChangedSignal(int curveIndex, int pointIndex, const QPointF& point);
void PointAddedSignal(size_t curveIndex, const QPointF& point);
void PointRemovedSignal(size_t curveIndex, int pointIndex);
protected:
virtual void paintEvent(QPaintEvent* e) override;
virtual void mousePressEvent(QMouseEvent* e) override;
size_t m_Index = 0;
QPen m_APen;
QPen m_RPen;
QPen m_GPen;
QPen m_BPen;
QPen m_AxisPen;
std::vector m_AllP;
std::vector m_RedP;
std::vector m_GrnP;
std::vector m_BluP;
QGraphicsLineItem* m_XLine;
QGraphicsLineItem* m_YLine;
std::array m_Pens;
QGraphicsScene m_Scene;
QRectF m_OriginalRect;
std::array, 4> m_Points;
};
///
/// Derivation for draggable points needed to trigger an event whenever the item is changed.
/// Custom drawing is also done to omit drawing a selection rectangle.
///
class EllipseItem : public QGraphicsEllipseItem
{
public:
///
/// Construct the point and specify the curve index it's part of, as well as the
/// point index within the curve.
///
/// Pass to the parent
/// The curve's index this point is a part of, 0-3.
/// The point index within the curve
/// The graphics view this point is displayed on
/// The parent widget of this item
EllipseItem(const QRectF& rect, int curveIndex, int pointIndex, CurvesGraphicsView* viewParent, QGraphicsItem* parent = nullptr)
: QGraphicsEllipseItem(rect, parent)
{
m_CurveIndex = curveIndex;
m_PointIndex = pointIndex;
m_ViewParent = viewParent;
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemIsMovable);
setPen(Qt::NoPen);
}
///
/// Set whether this item is selectable, which means this curve is the current one.
///
/// True if selected, else false.
void SetCurrent(bool b)
{
setFlag(QGraphicsItem::ItemIsMovable, b);
setZValue(b ? 2 : 1);
}
///
/// Index properties, getters only.
///
int CurveIndex() const { return m_CurveIndex; }
int PointIndex() const { return m_PointIndex; }
protected:
///
/// Overridden paint event to disable the selection rectangle.
///
/// Unused and just passed to QGraphicsEllipseItem::paint()
/// Drawing options used which will have the QStyle::State_Selected flag unset
/// Unused and just passed to QGraphicsEllipseItem::paint()
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override
{
QStyleOptionGraphicsItem myOption(*option);
myOption.state &= ~QStyle::State_Selected;
QGraphicsEllipseItem::paint(painter, &myOption, widget);
}
///
/// Overridden itemChange event to notify the parent control that it has moved.
/// Movement is also restricted to the scene rect.
///
/// Action is only taken if this value equals ItemPositionChange
/// The new position. This will be clamped to the scene rect.
/// The new position
virtual QVariant itemChange(GraphicsItemChange change, const QVariant& value) override
{
if ((change == ItemPositionChange) && scene())
{
//Value is the new position.
QPointF newPos = value.toPointF();
QRectF rect = scene()->sceneRect();
if (!rect.contains(newPos))
{
//Keep the item inside the scene rect.
newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
}
m_ViewParent->PointChanged(m_CurveIndex, m_PointIndex, newPos);
return newPos;
}
return QGraphicsEllipseItem::itemChange(change, value);
}
int m_CurveIndex;
int m_PointIndex;
CurvesGraphicsView* m_ViewParent;
};