/*
 * Analog and Digital Trace Viewing Widget
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * (c) 2012 - 2019 Timothy Pearson
 * Raptor Engineering, LLC
 * http://www.raptorengineering.com
 */

#ifndef REMOTELAB_TRACEWIDGET_H
#define REMOTELAB_TRACEWIDGET_H

#include <tqvbox.h>
#include <tqwidget.h>
#include <tqpushbutton.h>
#include <tqscrollview.h>

#include <tqtrla.h>

class TQPixmap;
class TQLabel;
class TQVBoxLayout;
class TQGridLayout;
class TraceWidgetPushButton;
class TQToolButton;
class TraceWidget;
class TraceLabelLayout;
class TraceCursorLabelLayout;

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

class TraceWidgetPushButton : public TQPushButton
{
	Q_OBJECT

	public:
		TraceWidgetPushButton(TQWidget *parent, const char* name=0);
		TraceWidgetPushButton(const TQString &text, TQWidget *parent, const char* name=0);
		TraceWidgetPushButton(const TQIconSet& icon, const TQString &text, TQWidget *parent, const char* name=0);
		~TraceWidgetPushButton();

	public:
		TQSize sizeHint() const;
};

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, int virtual_width, int virtual_height);

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

	signals:
		void offsetChanged(double offset);

	private:
		TQDoubleArray sampleArray;
		TQDoubleArray positionArray;
		unsigned int numberOfSamples;
		double sampleMax;
		double sampleMin;
		double sampleAverage;
		double minIndex;
		double maxIndex;
		long leftEdgeIndex;
		long rightEdgeIndex;
		double offset;
		double textOffset;
		double verticalMultiplier;
		TQColor color;
		bool enabled;
		double leftEdge;
		double rightEdge;
		double topEdge;
		double bottomEdge;
		TQString traceName;
		TQString horizontalUnits;
		TQString verticalUnits;
		bool m_digitalTraceDrawing;
		unsigned int m_digitalShaderDarkness;
		bool m_suppressNameInCursorText;
		TQLabel* paramLabel;
		TQLabel* leftLabel;
		TQLabel* leftCursorLabel;
		TQLabel* graphStatusLabel;
		TQLabel* graphStatusLabelInner;
		TQToolButton* singleIncrBtn;
		TQToolButton* singleDecrBtn;
		TQToolButton* posResetBtn;
		TQToolButton* posSetBtn;
		TraceWidget* parentWidget;

	friend class TraceWidget;
	friend class GraticuleWidget;
	friend class TraceLabelLayout;
	friend class TraceCursorLabelLayout;
};

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, int virtual_width, int virtual_height, int offset);

	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;
		TraceWidgetPushButton* singleIncrBtn;
		TraceWidgetPushButton* singleDecrBtn;
		TraceWidgetPushButton* multiIncrBtn;
		TraceWidgetPushButton* 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;
		int virtualWidth();
		bool userIsInteractingWithCursor();

	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();
		void horizScrollValueChanged(int value);

	private:
		TraceWidget* m_base;
		TQPixmap* m_graticulePixmap;
		int m_prevWidgetWidth;
		int m_virtualWidth;
		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:
		enum TextDisplayType {
			FullText,
			SummaryText,
			NoText
		};

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

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

		TQDoubleArray& samples(uint traceNumber);
		void setSamples(uint traceNumber, TQDoubleArray&, bool deferUpdate=false);
		TQDoubleArray& positions(uint traceNumber);
		void setPositions(uint traceNumber, TQDoubleArray&, bool deferUpdate=false);
		TQColor traceColor(uint traceNumber);
		void setTraceColor(uint traceNumber, TQColor);
		bool traceEnabled(uint traceNumber);
		void setTraceEnabled(uint traceNumber, bool enabled, TextDisplayType showText=FullText, bool deferUpdate=false);
		TQString traceName(uint traceNumber);
		void setTraceName(uint traceNumber, TQString name, bool deferUpdate=false);
		TQString traceHorizontalUnits(uint traceNumber);
		void setTraceHorizontalUnits(uint traceNumber, TQString units, bool deferUpdate=false);
		TQString traceVerticalUnits(uint traceNumber);
		void setTraceVerticalUnits(uint traceNumber, TQString units, bool deferUpdate=false);
		void setDigitalTraceMode(uint traceNumber, bool enabled, bool deferUpdate=false);
		void suppressNameInCursorText(uint traceNumber, bool suppress, bool deferUpdate=false);

		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 setTraceInfoCursor(uint cursorNumber);
		void setHoverCursor(uint cursorNumber);

		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);

		void showLeftTraceInfoArea(bool show);
		void showLeftCursorTraceInfoArea(bool show);
		void fitLeftTraceInfoArea(bool fit);
		void setLeftTraceInfoAreaFitSpacing(int spacing);

		void showLeftCursorInfoArea(bool show);

		void setMinimumPixelsPerHorizDiv(unsigned int pixels);
		void setHorizCursorDirectClickEnabled(bool enabled);

		double traceOffset(uint traceNumber);
		void setTraceOffset(uint traceNumber, double offset, bool deferUpdate);
		double traceTextOffset(uint traceNumber);
		void setTraceTextOffset(uint traceNumber, double offset, bool deferUpdate);

		double traceVerticalMultiplier(uint traceNumber);
		void setTraceVerticalMultiplier(uint traceNumber, double verticalMultiplier, bool deferUpdate);

		bool horizontalRangeModeAbsolute();
		void setHorizontalRangeModeAbsolute(bool absolute=true);

		bool userIsInteractingWithCursor();

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

		virtual TQSize sizeHint() const;
		virtual TQSize minimumSizeHint() const;

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

	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);
		int horizScrollOffset();

	private:
		unsigned int m_horizDivs;
		unsigned int m_vertDivs;
		unsigned int m_cursorDarkness;
		unsigned int m_zoomBoxDarkness;
		unsigned int m_zoomCursorStartIndex;
		bool m_zoomBoxEnabled;
		bool m_horizCursorDirectClickEnabled;
		TQRectF m_zoomBoxPrev;
		TraceList m_traceArray;
		CursorList m_cursorArray;
		TQGridLayout* m_primaryLayout;
		TQGridLayout* m_rightPaneLayout;
		TQGridLayout* m_leftPaneLayout;
		TQGridLayout* m_traceLabelLayout;
		TQGridLayout* m_infoLabelLayout;
		TQGridLayout* m_cursorLabelLayout;
		TraceLabelLayout* m_traceLeftLabelLayout;
		TraceCursorLabelLayout* m_traceLeftCursorLabelLayout;
		TQVBoxLayout* m_statusLabelLayout;
		TQVBoxLayout* m_statusLabelLayoutInner;
		GraticuleWidget* m_graticuleWidget;
		TQScrollBar* m_horizScrollBar;
		bool m_useAbsoluteHorizontalRange;
		bool m_showLeftTraceInfoArea;
		bool m_showLeftCursorInfoArea;
		unsigned int m_traceInfoCursor;
		int m_hoverCursor;
		bool m_leftTraceInfoLabelsFit;
		int m_leftTraceInfoAreaFitSpacing;
		unsigned int m_minimumPixelsPerHorizDiv;

		friend class GraticuleWidget;
		friend class TraceData;
		friend class CursorData;
		friend class TraceLabelLayout;
		friend class TraceCursorLabelLayout;
		friend class TraceScrollView;
		friend class TraceScrollWidget;
};

class TraceScrollView : public TQScrollView
{
	Q_OBJECT

	public:
		TraceScrollView(TQWidget* = 0, const char* = 0);
		~TraceScrollView();

		TraceWidget* traceWidget();

		virtual TQSize sizeHint() const;
		virtual TQSize minimumSizeHint() const;

	private:
		TraceWidget* m_traceWidget;

		friend class TraceScrollWidget;
};

class TraceScrollWidget : public TQVBox
{
	Q_OBJECT

	public:
		TraceScrollWidget(TQWidget* = 0, const char* = 0);
		~TraceScrollWidget();

		void setHScrollBarMode(TQScrollView::ScrollBarMode);
		void setVScrollBarMode(TQScrollView::ScrollBarMode);

		void setResizePolicy(TQScrollView::ResizePolicy);
		TQScrollView::ResizePolicy resizePolicy() const;

		TraceWidget* traceWidget();

	private:
		TraceScrollView* m_traceScrollView;
		TQScrollBar* m_horizScrollBar;
		TQScrollView::ScrollBarMode m_horizScrollBarMode;
};

#endif