//Author:    Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2012
//Copyright: See COPYING file that comes with this distribution

#include <tqwidget.h>

#include <tqtrla.h>

class TQPixmap;
class TQLabel;
class TQVBoxLayout;
class TQGridLayout;
class TQPushButton;
class TQToolButton;
class TraceWidget;

class TQRectF
{
	public:
		TQRectF();
		TQRectF(double x, double y, double w, double h);

		double x() const;
		double y() const;
		double width() const;
		double height() const;
		bool isNull() const;

		bool operator!() const;
		bool operator==(const TQRectF &r1);
		bool operator!=(const TQRectF &r1);

		void setX(double);
		void setY(double);
		void setWidth(double);
		void setHeight(double);

	private:
		bool m_valid;
		double m_x;
		double m_y;
		double m_w;
		double m_h;
};

typedef TQValueList<int> TraceNumberList;

class TraceData : public TQObject
{
	Q_OBJECT

	public:
		TraceData(TraceWidget* parent, TQWidget* labelParent=0);
		~TraceData();
		void drawTrace(TQPainter* p, int graticule_width, int graticule_height);

	public slots:
		void movePosOneTick();
		void moveNegOneTick();
		void resetVPosition();
		void setVPosition();

	signals:
		void offsetChanged(double offset);

	private:
		TQDoubleArray sampleArray;
		TQDoubleArray positionArray;
		unsigned int numberOfSamples;
		long leftEdgeIndex;
		long rightEdgeIndex;
		double offset;
		TQColor color;
		bool enabled;
		double leftEdge;
		double rightEdge;
		double topEdge;
		double bottomEdge;
		TQString traceName;
		TQString horizontalUnits;
		TQString verticalUnits;
		TQLabel* paramLabel;
		TQLabel* graphStatusLabel;
		TQLabel* graphStatusLabelInner;
		TQToolButton* singleIncrBtn;
		TQToolButton* singleDecrBtn;
		TQToolButton* posResetBtn;
		TQToolButton* posSetBtn;
		TraceWidget* parentWidget;

	friend class TraceWidget;
	friend class GraticuleWidget;
};

typedef TQMemArray<TraceData*> TraceList;

class CursorData : public TQObject
{
	Q_OBJECT

	public:
		CursorData(TraceWidget* parent, TQWidget* labelParent=0);
		~CursorData();
		void drawCursor(TQPainter* p, int graticule_width, int graticule_height);

	public slots:
		void movePosOneTick();
		void moveNegOneTick();
		void movePosMultiTicks();
		void moveNegMultiTicks();

	protected:
		virtual bool eventFilter(TQObject *o, TQEvent *e);

	signals:
		void positionChanged(double newPosition);

	private:
		TQColor color;
		TQColor highlightColor;
		bool highlighted;
		bool enabled;
		TQt::Orientation orientation;
		double position;
		TraceNumberList activeTraceLabelList;
		TQString cursorName;
		TQLabel* paramLabel;
		TQPushButton* singleIncrBtn;
		TQPushButton* singleDecrBtn;
		TQPushButton* multiIncrBtn;
		TQPushButton* multiDecrBtn;
		TraceWidget* parentWidget;

	friend class TraceWidget;
	friend class GraticuleWidget;
};

typedef TQMemArray<CursorData*> CursorList;

class GraticuleWidget : public TQWidget
{
	Q_OBJECT
	
	public:
		GraticuleWidget(TraceWidget*, const char* = 0);
		~GraticuleWidget();

	public:
		virtual TQSizePolicy sizePolicy() const;

	protected:
		virtual void paintEvent(TQPaintEvent*);
		virtual void resizeEvent(TQResizeEvent *);
		virtual void mousePressEvent(TQMouseEvent *);
		virtual void mouseReleaseEvent(TQMouseEvent *);
		virtual void mouseDoubleClickEvent(TQMouseEvent *);
		virtual void mouseMoveEvent(TQMouseEvent *);
		virtual void enterEvent(TQEvent *);
		virtual void leaveEvent(TQEvent *);

	signals:
		void cursorPositionChanged(uint cursorNumber, double newPosition);

	private slots:
		void updateGraticule();

	private:
		TraceWidget* m_base;
		TQPixmap* m_graticulePixmap;
		bool m_leftMouseDown;
		bool m_middleMouseDown;
		int m_closestCursor;
		unsigned int m_closestCursorDistance;
		int m_movingCursor;
		double m_prevCursorPos;
		TQPoint m_prevDownPos;
		TQRectF m_prevCursorRect;

	friend class TraceWidget;
	friend class TraceData;
	friend class CursorData;
};

class TraceWidget : public TQWidget
{
	Q_OBJECT
	
	public:
		TraceWidget(TQWidget* = 0, const char* = 0);
		~TraceWidget();

		void setNumberOfSamples(uint traceNumber, unsigned int samples);
		void setNumberOfHorizontalDivisions(unsigned int divisions);
		void setNumberOfVerticalDivisions(unsigned int divisions);
		void setDisplayLimits(uint traceNumber, TQRectF limits);
		TQRectF displayLimits(uint traceNumber);
		void setNumberOfTraces(uint traceNumber);
		void setNumberOfCursors(uint traceNumber);

		TQDoubleArray& samples(uint traceNumber);
		void setSamples(uint traceNumber, TQDoubleArray&);
		TQDoubleArray& positions(uint traceNumber);
		void setPositions(uint traceNumber, TQDoubleArray&);
		TQColor traceColor(uint traceNumber);
		void setTraceColor(uint traceNumber, TQColor);
		bool traceEnabled(uint traceNumber);
		void setTraceEnabled(uint traceNumber, bool enabled, bool showText=true);
		TQString traceName(uint traceNumber);
		void setTraceName(uint traceNumber, TQString name);
		TQString traceHorizontalUnits(uint traceNumber);
		void setTraceHorizontalUnits(uint traceNumber, TQString units);
		TQString traceVerticalUnits(uint traceNumber);
		void setTraceVerticalUnits(uint traceNumber, TQString units);

		double cursorPosition(uint cursorNumber);
		void setCursorPosition(uint cursorNumber, double position);
		TQColor cursorColor(uint cursorNumber);
		void setCursorColor(uint cursorNumber, TQColor);
		TQColor cursorHighlightColor(uint cursorNumber);
		void setCursorHighlightColor(uint cursorNumber, TQColor);
		void setCursorActiveTraceList(uint cursorNumber, TraceNumberList list);
		bool cursorEnabled(uint cursorNumber);
		void setCursorEnabled(uint cursorNumber, bool enabled);
		TQString cursorName(uint cursorNumber);
		void setCursorName(uint cursorNumber, TQString name);
		TQt::Orientation cursorOrientation(uint cursorNumber);
		void setCursorOrientation(uint cursorNumber, TQt::Orientation orient);

		void setForegroundColor(const TQColor color);
		void setBackgroundColor(const TQColor color);

		TQRectF zoomBox();
		void setZoomBoxEnabled(bool enabled);
		TQRectF zoomCursorBox();
		void setZoomCursorBox(const TQRectF rect);
		unsigned int zoomCursorStartIndex();
		void setZoomCursorStartIndex(unsigned int index);

		double traceOffset(uint traceNumber);

		static TQString prettyFormat(double value, double rangeDetectValue, TQString baseUnits, unsigned int precision=3);

	public slots:
		void setTraceOffset(uint traceNumber, double offset);

	private slots:
		void updateTraceText();
		void updateCursorText();
		void processChangedOffset(double offset);
		void processChangedCursor(uint cursorNumber, double newPosition);
		void processChangedCusorPosition(double position);

	signals:
		void zoomBoxChanged(const TQRectF&);
		void offsetChanged(uint traceNumber, double offset);
		void cursorPositionChanged(uint cursorNumber, double newPosition);
		void cursorDragged(uint cursorNumber, double newPosition);

	private:
		void resizeTraceArray(uint newsize);
		void resizeCursorArray(uint newsize);

	private:
		unsigned int m_horizDivs;
		unsigned int m_vertDivs;
		unsigned int m_cursorDarkness;
		unsigned int m_zoomBoxDarkness;
		unsigned int m_zoomCursorStartIndex;
		bool m_zoomBoxEnabled;
		TQRectF m_zoomBoxPrev;
		TraceList m_traceArray;
		CursorList m_cursorArray;
		TQGridLayout* m_primaryLayout;
		TQGridLayout* m_rightPaneLayout;
		TQGridLayout* m_traceLabelLayout;
		TQGridLayout* m_infoLabelLayout;
		TQGridLayout* m_cursorLabelLayout;
		TQVBoxLayout* m_statusLabelLayout;
		TQVBoxLayout* m_statusLabelLayoutInner;
		GraticuleWidget* m_graticuleWidget;
		bool m_useAbsoluteHorizontalRange;

		friend class GraticuleWidget;
		friend class TraceData;
		friend class CursorData;
};