#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; };