/*
	QAD - Qt ADvanced

	Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser 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 Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef GRAPHIC_H
#define GRAPHIC_H

#include <QWidget>
#include <QPainter>
#include <QPixmap>
#include <QMouseEvent>
#include <QComboBox>
#include <QDebug>
#include <QGridLayout>
#include <QFileDialog>
#include <QElapsedTimer>
#include <QTranslator>
#include <QGestureEvent>
#include <QMenu>
#include <qmath.h>
#include <float.h>
#include "graphic_conf.h"
#include "evalspinbox.h"
#include "qad_graphic_export.h"


namespace Ui {
	class Graphic;
}


class UGLWidget;
class GraphicPlugin;


Q_DECLARE_METATYPE(QVector<QPointF>)


class QAD_GRAPHIC_EXPORT Graphic: public QFrame
{
	Q_OBJECT
	Q_FLAGS(Buttons)
	Q_ENUMS(Alignment Graduation AxisType FloatingAxisType)

	Q_PROPERTY(QString caption READ caption WRITE setCaption)
	Q_PROPERTY(QString labelX READ labelX WRITE setLabelX)
	Q_PROPERTY(QString labelY READ labelY WRITE setLabelY)
	Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
	Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)

	Q_PROPERTY(int currentGraphic READ currentGraphic WRITE setCurrentGraphic)
	Q_PROPERTY(int graphicsCount READ graphicsCount WRITE setGraphicsCount)
	Q_PROPERTY(QString graphicName READ graphicName WRITE setGraphicName)
	Q_PROPERTY(QPen graphicPen READ graphicPen WRITE setGraphicPen)
	Q_PROPERTY(QColor graphicColor READ graphicColor WRITE setGraphicColor)
	Q_PROPERTY(Qt::PenStyle graphicStyle READ graphicStyle WRITE setGraphicStyle)
	Q_PROPERTY(double graphicLineWidth READ graphicLineWidth WRITE setGraphicLineWidth)
	Q_PROPERTY(double graphicPointWidth READ graphicPointWidth WRITE setGraphicPointWidth)
	Q_PROPERTY(QColor graphicFillColor READ graphicFillColor WRITE setGraphicFillColor)
	Q_PROPERTY(bool graphicLinesEnabled READ graphicLinesEnabled WRITE setGraphicLinesEnabled)
	Q_PROPERTY(bool graphicPointsEnabled READ graphicPointsEnabled WRITE setGraphicPointsEnabled)
	Q_PROPERTY(bool graphicFillEnabled READ graphicFillEnabled WRITE setGraphicFillEnabled)

	Q_PROPERTY(bool gridEnabled READ gridEnabled WRITE setGridEnabled)
	Q_PROPERTY(QPen gridPen READ gridPen WRITE setGridPen)
	Q_PROPERTY(QColor gridColor READ gridColor WRITE setGridColor)
	Q_PROPERTY(Qt::PenStyle gridStyle READ gridStyle WRITE setGridStyle)

	Q_PROPERTY(QPen selectionPen READ selectionPen WRITE setSelectionPen)
	Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor)
	Q_PROPERTY(Qt::PenStyle selectionStyle READ selectionStyle WRITE setSelectionStyle)
	Q_PROPERTY(QBrush selectionBrush READ selectionBrush WRITE setSelectionBrush)

	Q_PROPERTY(Alignment buttonsPosition READ buttonsPosition WRITE setButtonsPosition)
	Q_PROPERTY(Buttons buttons READ buttons WRITE setButtons)
	Q_PROPERTY(bool navigationEnabled READ navigationEnabled WRITE setNavigationEnabled)
	Q_PROPERTY(bool openGL READ openGL WRITE setOpenGL)
	Q_PROPERTY(bool antialiasing READ antialiasing WRITE setAntialiasing)
	Q_PROPERTY(bool autoUpdate READ autoUpdate WRITE setAutoUpdate)
	Q_PROPERTY(bool borderInputsVisible READ borderInputsVisible WRITE setBorderInputsVisible)
	Q_PROPERTY(bool statusVisible READ statusVisible WRITE setStatusVisible)
	Q_PROPERTY(bool legendVisible READ legendVisible WRITE setLegendVisible)
	Q_PROPERTY(bool paused READ paused WRITE setPaused)
	Q_PROPERTY(bool onlyExpandY READ onlyExpandY WRITE setOnlyExpandY)
	Q_PROPERTY(bool onlyExpandX READ onlyExpandX WRITE setOnlyExpandX)
	Q_PROPERTY(bool gesturesNavigation READ gesturesNavigation WRITE setGesturesNavigation)
	Q_PROPERTY(bool LODOptimization READ LODOptimization WRITE setLODOptimization)
	Q_PROPERTY(double historySize READ historySize WRITE setHistorySize)
	Q_PROPERTY(double maxVisibleTime READ maxVisibleTime WRITE setMaxVisibleTime)
	Q_PROPERTY(double autoXIncrement READ autoXIncrement WRITE setAutoXIncrement)
	Q_PROPERTY(QRectF limit READ limit WRITE setLimit)
	Q_PROPERTY(QRect margins READ margins WRITE setMargins)
	Q_PROPERTY(QRectF visualRect READ visualRect WRITE setVisualRect)
	Q_PROPERTY(QRectF defaultRect READ defaultRect WRITE setDefaultRect)
	Q_PROPERTY(int minimumRepaintInterval READ minimumRepaintInterval WRITE setMinimumRepaintInterval)

	Q_PROPERTY(double gridNumbersMultiplierX READ gridNumbersMultiplierX WRITE setGridNumbersMultiplierX)
	Q_PROPERTY(double gridNumbersMultiplierY READ gridNumbersMultiplierY WRITE setGridNumbersMultiplierY)
	Q_PROPERTY(Graduation graduationX READ graduationX WRITE setGraduationX)
	Q_PROPERTY(Graduation graduationY READ graduationY WRITE setGraduationY)
	Q_PROPERTY(double graduationStepX READ graduationStepX WRITE setGraduationStepX)
	Q_PROPERTY(double graduationStepY READ graduationStepY WRITE setGraduationStepY)
	Q_PROPERTY(AxisType axisType READ axisType WRITE setAxisType)
	Q_PROPERTY(FloatingAxisType floatingAxisType READ floatingAxisType WRITE setFloatingAxisType)

	Q_PROPERTY(Graphic::GraphicsData graphicsData READ graphicsData WRITE setGraphicsData)
	Q_PROPERTY(QByteArray graphicsDataRaw READ graphicsDataRaw WRITE setGraphicsDataRaw)

	friend class GraphicPlugin;

public:
	Graphic(QWidget * parent = 0);
	virtual ~Graphic();

	typedef QVector<QVector<QPointF> > GraphicsData;
	enum GraphicAction {gaNone, gaZoomInRect, gaZoomRangeX, gaZoomRangeY, gaMove};
	enum Button {NoButtons   = 0x0,
				AllButtons   = 0xFFFFFFFF,
				Autofit      = 0x01,
				Grid         = 0x02,
				CursorAxis   = 0x04,
				Fullscreen   = 0x20,
				BorderInputs = 0x40,
				Legend       = 0x80,
				Configure    = 0x100,
				Save         = 0x200,
				Export       = 0x400,
				Clear        = 0x800,
				Close        = 0x1000,
				Pause        = 0x2000,
				StandartButtons = 0x2FFF
				};
	enum Alignment {Left, Right};
	enum Graduation {Auto, Fixed};
	enum AxisType {Numeric, DateTime};
	enum FloatingAxisType {Free, TraceXY, TraceX, TraceY};
	Q_DECLARE_FLAGS(Buttons, Button)

	QString caption() const;
	QString labelX() const {return label_x;}
	QString labelY() const {return label_y;}
	QString graphicName() const {return graphics[curGraphic].name;}
	QString graphicName(int index) const {return graphics[index].name;}
	QColor backgroundColor() const {return back_color;}
	QColor textColor() const {return text_color;}
	QColor graphicColor() const {return graphics[curGraphic].pen.color();}
	QColor graphicColor(int index) const {return graphics[index].pen.color();}
	QColor gridColor() const {return grid_pen.color();}
	QColor selectionColor() const {return selpen.color();}
	Qt::PenStyle graphicStyle() const {return graphics[curGraphic].pen.style();}
	Qt::PenStyle graphicStyle(int index) const {return graphics[index].pen.style();}
	Qt::PenStyle gridStyle() const {return grid_pen.style();}
	Qt::PenStyle selectionStyle() const {return selpen.style();}
	double graphicLineWidth() const {return graphics[curGraphic].pen.widthF();}
	double graphicLineWidth(int index) const {return graphics[index].pen.widthF();}
	double graphicPointWidth() const {return graphics[curGraphic].pointWidth;}
	double graphicPointWidth(int index) const {return graphics[index].pointWidth;}
	QColor graphicFillColor() const {return graphics[curGraphic].fill_color;}
	QColor graphicFillColor(int index) const {return graphics[index].fill_color;}
	bool graphicVisible() const {return graphics[curGraphic].visible;}
	bool graphicVisible(int index) const {return graphics[index].visible;}
	bool graphicLinesEnabled() const {return graphics[curGraphic].lines;}
	bool graphicLinesEnabled(int index) const {return graphics[index].lines;}
	bool graphicPointsEnabled() const {return graphics[curGraphic].points;}
	bool graphicPointsEnabled(int index) const {return graphics[index].points;}
	bool graphicFillEnabled() const {return graphics[curGraphic].fill;}
	bool graphicFillEnabled(int index) const {return graphics[index].fill;}
	QPen graphicPen() const {return graphics[curGraphic].pen;}
	QPen graphicPen(int index) const {return graphics[index].pen;}
	QPen gridPen() const {return grid_pen;}
	QPen selectionPen() const {return selpen;}
	QBrush selectionBrush() const {return selbrush;}
	bool navigationEnabled() const {return navigation;}
	bool openGL() const {return isOGL;}
	bool antialiasing() const {return aalias;}
	bool autoUpdate() const {return aupdate;}
	bool gridEnabled() const {return grid;}
	bool borderInputsVisible() const;
	bool statusVisible() const;
	bool legendVisible() const;
	bool paused() const {return pause_;}
	bool onlyExpandY() const {return only_expand_y;}
	bool onlyExpandX() const {return only_expand_x;}
	bool gesturesNavigation() const {return gestures;}
	bool LODOptimization() const {return m_LODOptimization;}
	bool isAutofitted() const {return isFit;}
	int currentGraphic() const {return curGraphic;}
	int currentTraceGraphic() const {return curTrace;}
	int graphicsCount() const {return graphics.size();}
	Graphic::Buttons buttons() const {return buttons_;}
	Graphic::Alignment buttonsPosition() const {return align;}
	double historySize() const {return history;}
	double maxVisibleTime() const {return visible_time;}
	double autoXIncrement() const {return inc_x;}
	QRectF visualRect() const {return selrect;}
	QRectF defaultRect() const {return def_rect;}
	QRectF limit() const {return limit_;}
	QRect margins() const {return margins_;}
	int minimumRepaintInterval() const {return min_repaint_int;}
	double gridNumbersMultiplierX() const {return grid_numbers_x;}
	double gridNumbersMultiplierY() const {return grid_numbers_y;}
	Graduation graduationX() const {return grad_x;}
	Graduation graduationY() const {return grad_y;}
	double graduationStepX() const {return gridx;}
	double graduationStepY() const {return gridy;}
	AxisType axisType() const {return axis_type_x;}
	FloatingAxisType floatingAxisType() const {return floating_axis_type;}
	QVector<QPointF> graphicData() const {return graphics[curGraphic].polyline;}
	QVector<QPointF> graphicData(int index) const {return graphics[index].polyline;}
	GraphicsData graphicsData() const;
	QByteArray graphicsDataRaw() const;
	QWidget * viewport() const {return canvas;}
	QByteArray save();
	void load(QByteArray ba);

	GraphicType graphic(int arg) {if (arg < 0 || arg >= graphics.size()) return GraphicType(); return graphics[arg];}
	const QVector<GraphicType> & allGraphics() const {return graphics;}
	void setAllGraphics(const QVector<GraphicType> & g, bool update = true) {graphics = g; if (update) updateLegend();}

	double canvas2realX(double px) const;
	double canvas2realY(double py) const;
	double real2canvasX(double px) const;
	double real2canvasY(double py) const;
	QPointF canvas2real(QPointF canvas_point) const {return QPointF(canvas2realX(canvas_point.x()), canvas2realY(canvas_point.y()));}
	QPointF real2canvas(QPointF real_point) const {return QPointF(real2canvasX(real_point.x()), real2canvasY(real_point.y()));}
	QPolygonF real2canvas(const QPolygonF & real_polygon) const;
	QPolygonF canvas2real(const QPolygonF & canvas_polygon) const;
	double getScaleX() const {return real2canvasX(1.) - real2canvasX(0.);}
	double getScaleY() const {return real2canvasY(1.) - real2canvasY(0.);}
	QPointF getScale() const {return QPointF(getScaleX(), getScaleY());}

public slots:
	void setCaption(const QString & str);
	void setLabelX(const QString & str) {label_x = str; hasLblX = (str.length() > 0); if (aupdate) update();}
	void setLabelY(const QString & str) {label_y = str; hasLblY = (str.length() > 0); if (aupdate) update();}
	void setGraphicName(const QString & str, int index) {graphics[index].name = str; updateLegend(); if (aupdate) update();}
	void setGraphicName(const QString & str) {graphics[curGraphic].name = str; updateLegend(); if (aupdate) update();}
	void setBackgroundColor(const QColor & color) {back_color = color; if (aupdate) update(); updateLegend();}
	void setTextColor(const QColor & color) {text_color = color; if (aupdate) update();}
	void setGraphicColor(const QColor & color, int index) {graphics[index].pen.setColor(color); updateLegend(); if (aupdate) update();}
	void setGraphicColor(const QColor & color) {setGraphicColor(color, curGraphic);}
	void setGridColor(const QColor & color) {grid_pen.setColor(color); if (aupdate) update();}
	void setSelectionColor(const QColor & color) {selpen.setColor(color);}
	void setGraphicStyle(const Qt::PenStyle & style, int index) {graphics[index].pen.setStyle(style); updateLegend(); if (aupdate) update();}
	void setGraphicStyle(const Qt::PenStyle & style) {setGraphicStyle(style, curGraphic);}
	void setGridStyle(const Qt::PenStyle & style) {grid_pen.setStyle(style); if (aupdate) update();}
	void setSelectionStyle(const Qt::PenStyle & style) {selpen.setStyle(style);}
	void setGraphicVisible(bool visible, int index);
	void setGraphicVisible(bool visible) {setGraphicVisible(visible, curGraphic);}
	void setGraphicLineWidth(double w, int index) {if (qRound(w) == w) graphics[index].pen.setWidth(qRound(w)); else graphics[index].pen.setWidthF(w); updateLegend(); if (aupdate) update();}
	void setGraphicLineWidth(double w) {setGraphicLineWidth(w, curGraphic);}
	void setGraphicPointWidth(double w, int index) {graphics[index].pointWidth = w; updateLegend(); if (aupdate) update();}
	void setGraphicPointWidth(double w) {setGraphicPointWidth(w, curGraphic);}
	void setGraphicFillColor(const QColor & w, int index) {graphics[index].fill_color = w; updateLegend(); if (aupdate) update();}
	void setGraphicFillColor(const QColor & w) {setGraphicFillColor(w, curGraphic);}
	void setGraphicLinesEnabled(bool w, int index) {graphics[index].lines = w; updateLegend(); if (aupdate) update();}
	void setGraphicLinesEnabled(bool w) {setGraphicLinesEnabled(w, curGraphic);}
	void setGraphicPointsEnabled(bool w, int index) {graphics[index].points = w; updateLegend(); if (aupdate) update();}
	void setGraphicPointsEnabled(bool w) {setGraphicPointsEnabled(w, curGraphic);}
	void setGraphicFillEnabled(bool w, int index) {graphics[index].fill = w; updateLegend(); if (aupdate) update();}
	void setGraphicFillEnabled(bool w) {setGraphicFillEnabled(w, curGraphic);}
	void setGraphicPen(const QPen & pen, int index) {graphics[index].pen = pen; updateLegend(); if (aupdate) update();}
	void setGraphicPen(const QPen & pen) {setGraphicPen(pen, curGraphic);}
	void setGridPen(const QPen & pen) {grid_pen = pen; if (aupdate) update();}
	void setSelectionPen(const QPen & pen) {selpen = pen;}
	void setSelectionBrush(const QBrush & brush) {selbrush = brush;}
	void setNavigationEnabled(bool on) {navigation = on;}
	void setLODOptimization(bool yes) {m_LODOptimization = yes;}
	void setOpenGL(bool on);
	void setAntialiasing(bool enabled);
	void setAutoUpdate(bool enabled) {aupdate = enabled;}
	void setGridEnabled(bool enabled);
	void setBorderInputsVisible(bool visible);
	void setStatusVisible(bool visible);
	void setLegendVisible(bool visible);
	void setPaused(bool yes);
	void setButtons(Graphic::Buttons b);
	void setButtonsPosition(Graphic::Alignment a);
	void setHistorySize(double val);
	void setMaxVisibleTime(double val);
	void setAutoXIncrement(double val) {inc_x = val;}
	void setLimit(const QRectF & val) {limit_ = val;}
	void setMargins(const QRect & val) {margins_ = val; update();}
	void setMargins(int left_, int right_, int top_, int bottom_) {setMargins(QRect(left_, bottom_, right_, top_));}
	void setLeftMargin(int value) {margins_.moveLeft(value); setMargins(margins_);}
	void setRightMargin(int value) {margins_.setWidth(value); setMargins(margins_);}
	void setTopMargin(int value) {margins_.setHeight(value); setMargins(margins_);}
	void setBottomMargin(int value) {margins_.moveTop(value); setMargins(margins_);}
	void setMinimumRepaintInterval(const int & val) {min_repaint_int = val;}
	void setOnlyExpandY(bool yes);
	void setOnlyExpandX(bool yes);
	void setGesturesNavigation(bool yes);
	void setGraphicsData(const GraphicsData & gd);
	void setGraphicsDataRaw(const QByteArray & ba);

	void setGridNumbersMultiplierX(double value) {grid_numbers_x = value; updateGraphics();}
	void setGridNumbersMultiplierY(double value) {grid_numbers_y = value; updateGraphics();}
	void setGraduationX(Graduation value) {grad_x = value; if (aupdate) update();;}
	void setGraduationY(Graduation value) {grad_y = value; if (aupdate) update();;}
	void setGraduationStepX(double sx) {gridx = sx; if (aupdate) update();}
	void setGraduationStepY(double sy) {gridy = sy; if (aupdate) update();}
	void setGraduationSteps(double sx, double sy) {gridx = sx; gridy = sy; if (aupdate) update();}
	void setAxisType(AxisType t) {axis_type_x = t; if (aupdate) update();}
	void setFloatingAxisType(FloatingAxisType t) {floating_axis_type = t; setGuidesCursor(); if (aupdate) update();}
	void setFloatingAxisEnabled(bool on);

	void addPoint(const QPointF & p, int graphic, bool update_ = true);
	void addPoint(const QPointF & p, bool update = true) {addPoint(p, curGraphic, update);}
	void addPoint(double x, double y, int graphic, bool update = true) {addPoint(QPointF(x, y), graphic, update);}
	void addPoint(double x, double y, bool update = true) {addPoint(QPointF(x, y), update);}
	void addPoint(double y, int graphic, bool update = true) {if (graphics[graphic].polyline.isEmpty()) addPoint(QPointF(0.0, y), graphic, update); else addPoint(QPointF(graphics[graphic].max_x + inc_x, y), graphic, update);}
	void addPoint(double y, bool update = true) {if (graphics[curGraphic].polyline.isEmpty()) addPoint(QPointF(0.0, y), update); else addPoint(QPointF(graphics[curGraphic].max_x + inc_x, y), update);}
	void addPoints(const QPolygonF & pts, int graphic, bool update_ = true);
	void addPoints(const QPolygonF & pts, bool update = true) {addPoints(pts, curGraphic, update);}
	void addPoints(const QVector<double> & pts, int graphic, bool update_ = true);
	void addPoints(const QVector<double> & pts, bool update = true) {addPoints(pts, curGraphic, update);}
	void setGraphicData(const QVector<QPointF> & g, int graphic, bool update_ = true);
	void setGraphicData(const QVector<QPointF> & g) {setGraphicData(g, curGraphic);}
	void setGraphicProperties(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true) {setGraphicProperties(curGraphic, name, color, style, width, visible);}
	void setGraphicProperties(int graphic, const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true);
	void addGraphic(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true);
	void addGraphic(const GraphicType & gd, bool update = true) {graphics << gd; if (update) updateLegend();}
	void setVisualRect(const QRectF & rect);
	void setDefaultRect(const QRectF & rect);
	void autofit() {on_graphic_buttonAutofit_clicked();}
	void saveImage(QString filename);
	void exportGraphics(QString filename);
	void clear();
	void update(bool force);
	void update() {update(false);}
	void updateGraphics() {findGraphicsRect(); update();}
	void setCurrentGraphic(int arg) {if (arg < 0 || arg >= graphics.size()) return; curGraphic = arg;}
	void setTraceGraphic(int arg) {if (arg < 0 || arg >= graphics.size()) return; curTrace = arg;}
	void setGraphicsCount(int arg, bool update = true);
	void removeGraphic(int arg, bool update = true);

	void zoom(float factor);
	void zoomIn() {zoom(1. / 1.2);}
	void zoomOut() {zoom(1.2);}
	void fullscreen();


protected:
	virtual void changeEvent(QEvent * e);
	virtual void resizeEvent(QResizeEvent * );
	virtual void showEvent(QShowEvent * );
	virtual QSize sizeHint() const {return QSize(400, 300);}
	virtual void timerEvent(QTimerEvent * );
	virtual bool eventFilter(QObject * o, QEvent * e);

	void prepareCanvas(QWidget * w);
	void procGesture(QGesture * g);
	void procZoom(QPointF view_center, double dzoom, Qt::KeyboardModifiers km = Qt::NoModifier);
	void totalUpdate();
	void setCurrentAction(GraphicAction action);
	void findGraphicsRect(double start_x = 0., double end_x = 0., double start_y = 0., double end_y = 0.);
	void tick(int index, bool slide = true, bool update = true);
	void calcLOD(int index);
	void repaintCanvas(bool force = false) {if (tm.elapsed() < min_repaint_int && !force) return; tm.restart(); canvas->update();}
	void drawGraphics();
	void drawGrid();
	void drawGuides();
	void drawPause();
	void drawAction();
	void updateLegend(bool es = true);
	void updateLegendChecks();
	void setCanvasCursor(QCursor cursor);
	void setGuidesCursor();
	void swapToBuffer();
	void swapToNormal() {bufferActive = false;}
	void setRectToLines();
	void checkLines();
	double splitRange(double range, int count = 1);
	double splitRangeDate(double range, int count = 1, QString * format = 0, int step[7] = 0);
	double roundTo(double value, double round_to);
	void roundDateTime(QDateTime & dt, int c[7]);
	void addDateTime(QDateTime & dt, int c[7], int mul = 1);
	QPointF absPoint(QPointF point) {return QPointF(qAbs(point.x()), qAbs(point.y()));}
	QString pointCoords(QPointF point, bool x = true, bool y = true);
	QPair<QString, QString> gridMark(double v) const;

	Ui::Graphic * ui;
	UGLWidget * canvas_gl;
	QWidget * canvas;
	QPixmap buffer;
	QPainter * painter;
	QBrush selbrush;
	QPen grid_pen, selpen;
	QColor back_color, text_color;
	QVector<GraphicType> graphics;
	int curGraphic, curTrace;
	GraphicAction curaction, prevaction;
	QRectF grect, selrect, limit_, def_rect;
	QRect margins_;
	QSize font_sz;
	QPoint startpos, curpos, prevpos, gridborder;
	QPointF startpos_r, curpos_r;
	QString label_x, label_y, ppath, fp_size;
	Graphic::Buttons buttons_;
	Graphic::Alignment align;
	GraphicConf * conf;
	EvalSpinBox line_x_min, line_x_max, line_y_min, line_y_max;
	QElapsedTimer tm;
	QMenu * buttons_menu = nullptr;
#ifdef Q_OS_ANDROID
	QElapsedTimer tm_fscr;
#endif
	QIcon icon_exp_x, icon_exp_y, icon_exp_sx, icon_exp_sy;
	QImage icon_pause_b, icon_pause_f;
	Graduation grad_x, grad_y;
	AxisType axis_type_x;
	FloatingAxisType floating_axis_type;
	double gridx, gridy, history, visible_time, inc_x, grid_numbers_x, grid_numbers_y, LN10;
	double eminx, eminy, emaxx, emaxy, pause_phase, gesture_angle;
	int lastw, lasth, min_repaint_int, timer_pause, thick;
	bool aalias, aupdate, grid, guides, isFit, isOGL, isHover, bufferActive, cancel, pause_, gestures, m_LODOptimization, m_fakeGL, need_createGL;
	bool hasLblX, hasLblY, navigation, only_expand_y, only_expand_x, is_lines_update, leg_update, visible_update, fullscr, need_mouse_pan;

protected slots:
	void canvasPaintEvent();
	void canvasMouseMoveEvent(QMouseEvent * );
	void canvasMousePressEvent(QMouseEvent * );
	void canvasMouseReleaseEvent(QMouseEvent * );
	void canvasMouseDoubleClickEvent(QMouseEvent * );
	void canvasWheelEvent(QWheelEvent * );
	void canvasLeaveEvent(QEvent * );
	void canvasKeyPressEvent(QKeyEvent * );
	void graphicVisibleChange(bool checked);
	void graphicAllVisibleChange(bool checked);
	void lineXMinChanged(double value) {selrect.setLeft(value); checkLines();}
	void lineXMaxChanged(double value) {selrect.setRight(value); checkLines();}
	void lineYMinChanged(double value) {selrect.setBottom(value); checkLines();}
	void lineYMaxChanged(double value) {selrect.setTop(value); checkLines();}
	void on_graphic_buttonClose_clicked() {emit closeRequest(this);}
	void on_graphic_buttonClear_clicked() {clear(); emit cleared();}
	void on_graphic_buttonAutofit_clicked();
	void on_graphic_buttonConfigure_clicked();
	void on_graphic_buttonFullscreen_clicked() {fullscreen();}
	void on_graphic_buttonSave_clicked();
	void on_graphic_buttonExport_clicked();
	void on_graphic_checkGrid_toggled(bool checked) {grid = checked; update();}
	void on_graphic_checkGuides_toggled(bool checked);
	void on_graphic_actionExpandX_triggered(bool checked);
	void on_graphic_actionExpandY_triggered(bool checked);
	void on_graphic_checkBorderInputs_toggled(bool checked) {setBorderInputsVisible(checked);}
	void on_graphic_checkLegend_toggled(bool checked) {setLegendVisible(checked);}
	void on_graphic_checkPause_toggled(bool checked) {setPaused(checked);}
	void actionGuidesTriggered(QAction * a);
	void enterFullscreen();
	void leaveFullscreen();
	void showMenu();

signals:
	void beforeGraphicPaintEvent(QPainter * );
	void graphicPaintEvent(QPainter * );
	void graphicMouseMoveEvent(QPointF point, int buttons);
	void graphicMousePressEvent(QPointF point, int buttons);
	void graphicMouseReleaseEvent(QPointF point, int buttons);
	void graphicWheelEvent(QPointF point, int delta);
	void graphicTraceEvent(int graphic, QPointF point);
	void closeRequest(QWidget * );
	void cleared();
	void visualRectChanged();
	void graphicSettingsChanged();
};


Q_DECLARE_METATYPE(Graphic::GraphicsData)

Q_DECLARE_OPERATORS_FOR_FLAGS(Graphic::Buttons)


inline QDataStream & operator <<(QDataStream & s, const Graphic::Graduation & v) {s << (int)v; return s;}
inline QDataStream & operator >>(QDataStream & s, Graphic::Graduation & v) {s >> *((int*)(&v)); return s;}


class QAD_GRAPHIC_EXPORT __GraphicRegistrator__ {
public:
	__GraphicRegistrator__() {
		qRegisterMetaType<QVector<QPointF> >("QVector<QPointF>");
		qRegisterMetaType<Graphic::GraphicsData>("Graphic::GraphicsData");
#if QT_VERSION_MAJOR <= 5
		qRegisterMetaTypeStreamOperators<Graphic::GraphicsData>("Graphic::GraphicsData");
#endif
	}
};

#endif // GRAPHIC_H
