/***************************************************************************
**
**  This file is part of SciFigs.
**
**  This library 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 2.1 of the License, or (at your option) any later version.
**
**  This file 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 library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2003-07-31
**  Copyright: 2003-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef GRAPHICOBJECT_H
#define GRAPHICOBJECT_H

#include <QtGui>
#include <QGpGuiTools.h>
#include <QGpCoreMath.h>

#include "FontScales.h"
#include "SciFigsDLLExport.h"

namespace SciFigs {

  #define MIN_RESOLUTION 16
  #define MAX_RESOLUTION 1200

  class SelectionWidget;
  class GraphicSheet;
  class GraphicObjectGroup;
  class OrderTip;
  class GraphicObjectIdProperties;
  class GraphicObjectGeometryProperties;
  class GraphicObjectPrintProperties;

  class SCIFIGS_EXPORT GraphicObject : public QWidget, public PropertyContext, public PropertyItem, public XMLClass
  {
    Q_OBJECT
    // Overload to mark the beginning of properties to save to XML
    Q_PROPERTY(QString objectName READ objectName WRITE setObjectName STORED true)
    // Kept only to avoid warning on loading old files
    Q_PROPERTY(QString name READ dummyPropertyString WRITE setObjectName STORED false)

    Q_PROPERTY(double printX READ printXAnchor WRITE setPrintXAnchor SCRIPTABLE true)
    Q_PROPERTY(double printY READ printYAnchor WRITE setPrintYAnchor SCRIPTABLE true)
    Q_PROPERTY(QString anchor READ anchorString WRITE setAnchor SCRIPTABLE true)
    Q_PROPERTY(double printWidth READ printWidth WRITE setPrintWidth SCRIPTABLE true)
    Q_PROPERTY(double printHeight READ printHeight WRITE setPrintHeight SCRIPTABLE true)
    Q_PROPERTY(bool constantWidthHeightRatio READ isConstantWidthHeightRatio WRITE setConstantWidthHeightRatio SCRIPTABLE true)
    Q_PROPERTY(bool moveSelection READ isMoveSelection WRITE setMoveSelection SCRIPTABLE true)
    Q_PROPERTY(int printResolution READ printResolution WRITE setPrintResolution SCRIPTABLE true)
    Q_PROPERTY(int transparency READ transparency WRITE setTransparency SCRIPTABLE true)
    Q_PROPERTY(bool transparentMask READ transparentMask WRITE setTransparentMask SCRIPTABLE true)
    Q_PROPERTY(double printLeftMargin READ printLeftMargin WRITE setPrintLeftMargin SCRIPTABLE true)
    Q_PROPERTY(double printRightMargin READ printRightMargin WRITE setPrintRightMargin SCRIPTABLE true)
    Q_PROPERTY(double printTopMargin READ printTopMargin WRITE setPrintTopMargin SCRIPTABLE true)
    Q_PROPERTY(double printBottomMargin READ printBottomMargin WRITE setPrintBottomMargin SCRIPTABLE true)
    DUMMY_PROPERTIES
  public:
    GraphicObject(QWidget * parent=0, Qt::WindowFlags f=Qt::Widget);
    ~GraphicObject();

    virtual const QString& xml_tagName() const {return xmlGraphicObjectTag;}
    static const QString xmlGraphicObjectTag;

    GraphicObject& operator=(const GraphicObject& o);
    virtual void polish();
    virtual QSize sizeHint () const {return QSize(250, 250);}
    virtual void setSheet(GraphicSheet * s) {_sheet=s;}

    // True if normal TopLeft corner
    enum PositionAnchor {XMask=0x3, YMask=0xC,
                         Left=0x2, HCenter=0x1, Right=0x0,
                         Top=0x8, VCenter=0x4, Bottom=0x0,
                         TopLeft=0xA, TopCenter=0x9, TopRight=0x8,
                         CenterLeft=0x6, Center=0x5, CenterRight=0x4,
                         BottomLeft=0x2, BottomCenter=0x1, BottomRight=0x0};

    virtual void setObjectName(QString name);
    double printLeft(double refWidth=0.0) const;
    double printTop(double refHeight=0.0) const;
    double printRight(double refWidth=0.0) const;
    double printBottom(double refHeight=0.0) const;
    double printXAnchor() const {return _printAnchor.x();}
    double printYAnchor() const {return _printAnchor.y();}
    PositionAnchor anchor() const {return _anchor;}
    QString anchorString() const;
    double printWidth() const {return _printWidth;}
    double printHeight() const {return _printHeight;}
    bool isConstantWidthHeightRatio() const {return _constantWidthHeightRatio;}
    bool isMoveSelection() const {return _moveSelection;}
    double printLeftMargin() const {return _printLeftMargin;}
    double printRightMargin() const {return _printRightMargin;}
    double printTopMargin() const {return _printTopMargin;}
    double printBottomMargin() const {return _printBottomMargin;}
    int printResolution() const {return _printResolution;}
    int transparency() const {return _transparency;}
    bool transparentMask() const {return _mask;}

    void setPrintXAnchor(double val);
    void setPrintYAnchor(double val);
    void setPrintAnchor(Point2D pos);
    void setAnchor(PositionAnchor pa, bool preservePosition=false);
    void setAnchor(QString pa);
    void setPrintLeft(double val);
    void setPrintTop(double val);
    void setPrintRight(double val);
    void setPrintBottom(double val);
    void setPrintWidth(double val) {_printWidth=val;}
    void setPrintHeight(double val) {_printHeight=val;}
    void setGeometry(double x, double y, double dx, double dy);
    void setConstantWidthHeightRatio(bool c) {_constantWidthHeightRatio=c;}
    void setMoveSelection(bool m) {_moveSelection=m;}
    void setPrintLeftMargin(double val) {_printLeftMargin=val;}
    void setPrintRightMargin(double val) {_printRightMargin=val;}
    void setPrintTopMargin(double val) {_printTopMargin=val;}
    void setPrintBottomMargin(double val) {_printBottomMargin=val;}
    void setPrintResolution(int val) {_printResolution=val;}
    void setTransparency(int val) {_transparency=val;}
    void setTransparentMask(bool val);

    void setPos();
    void setSize();

    bool isRemovable() {return _isRemovable;}
    void setRemovable(bool r);

    bool isActive() const;
    void setActive(Qt::KeyboardModifiers m);
    void setSelectable(bool s);
    bool isSelectable() const {return _isSelectable;}
    bool isSelected() const;
    SelectionWidget * selectionWidget() const {return _selected;}
    void setSelected(SelectionWidget * s);
    GraphicObject * activeObject(const char * className=0) const;
    void print(QPrinter& printer);

    bool setOrderIndex(int index);
    GraphicSheet * sheet() const {return _sheet;}
    GraphicObject * group();

    void startDragging() {_oldPrintPos=_printAnchor;}
    static QPoint draggingPos() {return _draggingPos;}
    static bool isDragging() {return _draggingOn;}
    void drag(Point2D delta);

    static const QString pixelImageFilter;
    static const QString vectorialImageFilter;
    static const QString allImageFilter;

    // Properties dialog box
    PropertyProxy * proxy() const;
    virtual void addProperties(PropertyProxy * pp);
    virtual void removeProperties(PropertyProxy * pp);
    virtual void properties(PropertyWidget * w) const;
    virtual void setProperty(uint wid, int pid, QVariant val);
    void updateGeometryProperties(PropertyProxy * pp);
    void showProperties(uint category);

    void setToolTip(const QString& t);

    virtual void scaleFonts(FontScales& original, double scale);
    virtual void restoreScaleFonts(const FontScales& original);
    virtual void print(QPainter& p, double dotpercm, int x0Sheet, int y0Sheet, bool mask);
  public slots:
    void keyPopupMenu ();
    virtual void showProperties() {showProperties(_category);}
    void copy();
    void copyImage(int dpi=0);
    void savePage(QString fileName=QString());
    void print(int dpi=0);
    void print(bool outputToFile, QString name, int dpi);
    void exportFile(QString fileName=QString(),
                    QString fileFormat=QString(), int dpi=0);
    void exportImage(QString fileName=QString(),
                     QString imageFormat=QString(), int dpi=0);
    QPixmap image(int dpi=0);
    void copyMakeUp();
    void pasteMakeUp();
    void saveMakeUp(QString fileName=QString());
    void restoreMakeUp(QString fileName=QString());
    void deleteObject();
    virtual void deepUpdate() {update();}
    virtual void update();
    virtual void updateGeometry();
  signals:
    void sizeChanged();
    void positionChanged();
    void wantToBeSelected(GraphicObject *, Qt::KeyboardModifiers);
    void wantToStartDragging();
    void draggedTo(QPoint p);
  protected:
    virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const {qobject_writeProperties(this, this, s, context);}
    virtual XMLMember xml_member(XML_MEMBER_ARGS) {return qobject_member(this, tag, attributes, context);}
    virtual bool xml_setProperty(XML_SETPROPERTY_ARGS) {return qobject_setProperty(this, memberID, tag, attributes, content, context);}
    virtual bool xml_polish(XML_POLISH_ARGS);

    QAction * action(const QString& name);

    void printSvg(const QString& fileName, int dpi);
    virtual void setPrintSize(double dotpercm);
    virtual void paintEvent(QPaintEvent * e);
    virtual void addActions();
    double scaleWidgetFonts(QWidget * w, double scale);
    virtual void paint(QPainter& p, double dotpercm, int w, int h, bool mask);
    // Mouse events
    virtual void mousePressEvent (QMouseEvent * e);
    virtual void mouseReleaseEvent (QMouseEvent * e);
    virtual void mouseMoveEvent (QMouseEvent * e);
    virtual void mouseDoubleClickEvent (QMouseEvent * e);
    virtual void showEvent (QShowEvent * e);
    virtual void enterEvent (QEvent * e);
    virtual void leaveEvent (QEvent * e);

    void updateMask();

    Point2D _printAnchor;
    PositionAnchor _anchor;
    double _printWidth, _printHeight;
    double _printLeftMargin, _printRightMargin, _printTopMargin, _printBottomMargin;
  private:
    friend class SelectionWidget;
    friend class GraphicSheet;

    SelectionWidget * _selected;
    GraphicSheet * _sheet;
    OrderTip * _orderTip;
    bool _isRemovable:1;
    bool _isSelectable:1;
    bool _constantWidthHeightRatio:1;
    bool _mask:1;
    bool _moveSelection:1;
    quint8 _transparency;
    quint16 _printResolution;

    QAction * _propertiesAction;

    static uint _category, _tabId, _tabGeomery, _tabPrint;
    static bool _draggingOn;
    static bool _draggingStarted;
    static QPoint _draggingPos;
    Point2D _oldPrintPos;
  };

} // namespace SciFigs

#endif // GRAPHICOBJECT_H
