// -*- C++ -*-
// --------------------------------------------------------------------
// The Ipe object type.
// --------------------------------------------------------------------
/*

    This file is part of the extensible drawing editor Ipe.
    Copyright (C) 1993-2004  Otfried Cheong

    Ipe 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 2 of the License, or
    (at your option) any later version.

    As a special exception, you have permission to link Ipe with the
    CGAL library and distribute executables, as long as you follow the
    requirements of the Gnu General Public License in regard to all of
    the software in the executable aside from CGAL.

    Ipe 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 Ipe; if not, you can find it at
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef IPEOBJ_H
#define IPEOBJ_H

#include "ipebase.h"
#include "ipegeo.h"
#include "ipecolor.h"
#include "ipexml.h"

class IpeVisitor;
class IpePainter;
class IpeFillable;
class IpeGroup;
class IpeText;
class IpeMark;
class IpePath;
class IpeImage;
class IpeReference;
class IpeStyleSheet;

// --------------------------------------------------------------------

class IPE_EXPORT IpeAllAttributes {
public:
  IpeAllAttributes();

  IpeAttribute iStroke;          //!< Stroke color.
  IpeAttribute iFill;            //!< Fill color.
  IpeAttribute iDashStyle;       //!< Dash style.
  IpeAttribute iLineWidth;       //!< Line width.
  IpeAttribute iTextSize;        //!< Text size.
  IpeAttribute iMarkSize;        //!< Mark size.
  IpeAttribute iArrowSize;       //!< Arrow size.
  bool iForwardArrow;            //!< Arrow forward?
  bool iBackwardArrow;           //!< Arrow backward?
  bool iTransformable;           //!< Text transformable by default?
  int iMarkShape;                //!< Shape of mark objects.
};

// --------------------------------------------------------------------

class IPE_EXPORT IpeObject {
public:
  virtual ~IpeObject() = 0;

  //! Calls VisitXXX method of the visitor.
  virtual void Accept(IpeVisitor &visitor) const = 0;

  //! Make a (shallow) copy of this object.
  virtual IpeObject *Clone() const = 0;

  virtual IpeFillable *AsFillable();
  virtual IpeGroup *AsGroup();
  virtual IpeText *AsText();
  virtual IpeMark *AsMark();
  virtual IpePath *AsPath();
  virtual IpeImage *AsImage();
  virtual IpeReference *AsReference();

  //! Save the object in XML format.
  virtual void SaveAsXml(IpePainter &painter, IpeStream &stream,
			 IpeString layer) const = 0;

  //! Draw the object.
  virtual void Draw(IpePainter &painter) const = 0;

  /*! Return distance of transformed object to point \a v.
    If larger than \a bound, can just return \a bound. */
  virtual double Distance(const IpeVector &v, const IpeMatrix &m,
			  double bound) const = 0;

  //! Extend \a box to include the object transformed by \a m.
  /*! For Ipe objects in a page, don't call this directly.  The
    IpePgObject caches the bounding box, so it is far more efficient
    to call IpePgObject::BBox.

    If called with an empty box, the result of this function is a
    tight bounding box for the object, with a little leeway in case
    the boundary is determined by a spline (it has to be approximated
    to perform this operation). */
  virtual void AddToBBox(IpeRect &box, const IpeMatrix &m) const = 0;

  virtual void AddToGraphicBBox(IpeRect &box, IpeStyleSheet *sheet,
				IpeMatrix &m) const;

  //! Compute possible vertex snapping position for transformed object.
  /*! Looks only for positions closer than \a bound.
    If successful, modify \a pos and \a bound. */
  virtual void SnapVtx(const IpeVector &mouse, const IpeMatrix &m,
		       IpeVector &pos, double &bound) const = 0;

  //! Check symbolic attributes of object.
  virtual void CheckStyle(const IpeStyleSheet *sheet,
			  IpeAttributeSeq &seq) const;

  virtual void SnapBnd(const IpeVector &mouse, const IpeMatrix &m,
		       IpeVector &pos, double &bound) const;

  void SetStroke(IpeAttribute stroke);
  void SetMatrix(const IpeMatrix &matrix);

  inline IpeAttribute Stroke() const;
  inline const IpeMatrix &Matrix() const;

  static bool SnapVertex(const IpeVector &mouse, const IpeVector &v,
			 IpeVector &pos, double &bound);

protected:
  explicit IpeObject();
  explicit IpeObject(const IpeAllAttributes &attr);
  explicit IpeObject(IpeRepository *rep, const IpeXmlAttributes &attr);
  IpeObject(const IpeObject &rhs);

  void SaveAttributesAsXml(IpePainter &painter, IpeStream &stream,
			   IpeString layer) const;
  static void CheckSymbol(IpeAttribute attr, const IpeStyleSheet *sheet,
			  IpeAttributeSeq &seq);

private:
  IpeAttribute iStroke;
  IpeMatrix iMatrix;
};

class IPE_EXPORT IpeFillable : public IpeObject {
public:
  virtual IpeFillable *AsFillable();

  virtual void CheckStyle(const IpeStyleSheet *sheet,
			  IpeAttributeSeq &seq) const;

  void SetFill(IpeAttribute fill);
  void SetLineWidth(IpeAttribute lw);
  void SetDashStyle(IpeAttribute dash);
  void SetStrokeStyle(IpeStrokeStyle attr);

  inline IpeAttribute Fill() const;
  inline IpeAttribute LineWidth() const;
  inline IpeAttribute DashStyle() const;
  inline IpeStrokeStyle StrokeStyle() const;

protected:
  explicit IpeFillable();
  explicit IpeFillable(const IpeAllAttributes &attr);
  explicit IpeFillable(IpeRepository *rep, const IpeXmlAttributes &attr);
  IpeFillable(const IpeFillable &rhs);
  void SaveFillAttributesAsXml(IpePainter &painter, IpeStream &stream) const;
  void ApplyAttributes(IpePainter &painter) const;

private:
  IpeAttribute iFill;
  IpeAttribute iDashStyle;
  IpeAttribute iLineWidth;
  IpeStrokeStyle iStrokeStyle;
};

// --------------------------------------------------------------------

class IPE_EXPORT IpePgObject {
public:
  //! Selection status of an object on the page
  enum TSelect { ENone = 0, EPrimary, ESecondary };

  inline explicit IpePgObject(TSelect sel, int layer, IpeObject *obj);
  IpePgObject(const IpePgObject &rhs);
  IpePgObject &operator=(const IpePgObject &rhs);
  ~IpePgObject();

  //! Return IpeObject.
  inline IpeObject *Object() { return iObject; }
  //! Return IpeObject (const version).
  inline const IpeObject *Object() const { return iObject; }
  //! Return selection status.
  inline TSelect Select() const { return iSelect; }
  //! Return layer.
  inline int Layer() const { return iLayer; }

  //! Set selection status.
  inline void SetSelect(TSelect sel) { iSelect = sel; }
  //! Set layer.
  inline void SetLayer(int layer) { iLayer = layer; }
  void ReplaceObject(IpeObject *obj);

  IpeRect BBox() const;

  void Transform(const IpeMatrix &m);
  double Distance(const IpeVector &v, double bound) const;
  void SnapVtx(const IpeVector &mouse, IpeVector &pos, double &bound) const;
  void SnapBnd(const IpeVector &mouse, IpeVector &pos, double &bound) const;
  void InvalidateBBox() const;

private:
  TSelect iSelect;
  int iLayer;
  mutable IpeRect iBBox;
  IpeObject *iObject;
};

/*! \relates IpePgObject
  List of objects on a page.
*/
typedef std::list<IpePgObject> IpePgObjectSeq;

// --------------------------------------------------------------------

//! Return object stroke color.
inline IpeAttribute IpeObject::Stroke() const
{
  return iStroke;
}

//! Return transformation matrix.
inline const IpeMatrix &IpeObject::Matrix() const
{
  return iMatrix;
}

//! Return object fill color.
inline IpeAttribute IpeFillable::Fill() const
{
  return iFill;
}

//! Return object line width.
inline IpeAttribute IpeFillable::LineWidth() const
{
  return iLineWidth;
}

//! Return object line style.
inline IpeAttribute IpeFillable::DashStyle() const
{
  return iDashStyle;
}

//! Return line cap, join.
inline IpeStrokeStyle IpeFillable::StrokeStyle() const
{
  return iStrokeStyle;
}

// --------------------------------------------------------------------
#endif
