// -*- C++ -*-
// --------------------------------------------------------------------
// A page of a document.
// --------------------------------------------------------------------
/*

    This file is part of the extensible drawing editor Ipe.
    Copyright (C) 1993-2007  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 IPEPAGE_H
#define IPEPAGE_H

#include "ipeobj.h"
#include "ipepath.h"
#include "ipetext.h"

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

class IpeStyleSheet;
class IpeDataSource;
class IpeRepository;

struct SSubPath;

class IPE_EXPORT IpeLayer {
public:
  explicit IpeLayer(IpeString name);
  explicit IpeLayer(const IpeXmlAttributes &attr);
  void SaveAsXml(IpeStream &stream) const;
  //! Return name.
  inline IpeString Name() const { return iName; }
  //! Set name.
  inline void SetName(const IpeString &name) { iName = name; }

  //! Is dimmed?
  inline bool IsDimmed() const { return !!(iFlags & EDim); }
  //! Is locked?
  inline bool IsLocked() const { return !!(iFlags & ELocked); }
  //! Is snapping enabled?
  inline bool IsSnapping() const { return !(iFlags & ENoSnapping); }

  void SetDimmed(bool flag);
  void SetLocked(bool flag);
  void SetSnapping(bool flag);

public:
  enum {EDim = 0x01, ELocked = 0x02, ENoSnapping = 0x04 };
  IpeString iName;
  int iFlags;
};

//! Layers of a page.
typedef std::vector<IpeLayer> IpeLayerSeq;

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

class IPE_EXPORT IpeView {
public:
  //! The various fancy effects that Acrobat Reader will show.
  enum TEffect {
    ENormal, ESplitHI, ESplitHO, ESplitVI, ESplitVO,
    EBlindsH, EBlindsV, EBoxI, EBoxO,
    EWipeLR, EWipeBT, EWipeRL, EWipeTB,
    EDissolve, EGlitterLR, EGlitterTB, EGlitterD };

  IpeView();
  IpeView(const IpeXmlAttributes &attr);
  void SaveAsXml(IpeStream &stream) const;
  void PageDictionary(IpeStream &stream) const;

  //! How many layers are visible in this view?
  inline int CountLayers() const { return iLayers.size(); }
  //! Return name of one visible layer.
  inline IpeString Layer(int i) const { return iLayers[i]; }
  bool HasLayer(IpeString name) const;
  void DeleteLayer(IpeString name);
  void AddLayer(IpeString name);
  inline void ClearLayers() { iLayers.clear(); }

  //! The layer active in this view.
  inline IpeString Active() const { return iActive; }
  //! Set active layer.
  inline void SetActive(const IpeString &l) { iActive = l; }
  //! The transition effect when switching to this view.
  inline TEffect Effect() const { return iEffect; }
  //! Set transition effect for switching to this view.
  inline void SetEffect(TEffect e) { iEffect = e; }
  //! How long will this view be shown (in secs)?
  inline int Duration() const { return iDuration; }
  //! Set duration of this view (in secs).
  inline void SetDuration(int secs) { iDuration = secs; }
  //! The transition time for the effect (in secs).
  inline int TransitionTime() const { return iTransitionTime; }
  //! Set transition time for the effect (in secs).
  inline void SetTransitionTime(int secs) { iTransitionTime = secs; }
private:
  std::vector<IpeString> iLayers;
  IpeString iActive;
  TEffect iEffect;
  int iTransitionTime;
  int iDuration;
};

//! View sequence of a page.
typedef std::vector<IpeView> IpeViewSeq;

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

class IPE_EXPORT IpePage : public IpePgObjectSeq {
public:
  explicit IpePage();

  void SaveAsXml(IpePainter &painter, IpeStream &stream) const;

  //! Return number of layers.
  inline int CountLayers() const { return iLayers.size(); }
  //! Return a layer.
  inline const IpeLayer &Layer(int index) const { return iLayers[index]; }
  //! Return a layer.
  inline IpeLayer &Layer(int index) { return iLayers[index]; }
  int FindLayer(IpeString name) const;
  int AddLayer(const IpeLayer &layer, int index = -1);
  int NewLayer(int index);
  void DeleteLayer(int index);
  bool IsLayerActiveInView(int index) const;

  //! Return presentation sequence of this page.
  inline const IpeViewSeq &Views() const {return iViews;}
  //! Return number of views.
  inline int CountViews() const { return iViews.size(); }
  //! Return a view.
  inline const IpeView &View(int index) const { return iViews[index]; }
  //! Return a view.
  inline IpeView &View(int index) { return iViews[index]; }
  void SetView(int index, const IpeView &view);
  void AddView(const IpeView &view, int index = -1);
  void DeleteView(int index);
  void renameLayer(IpeString oldName, IpeString newName);

  IpeRect TextBox(const IpeStyleSheet *sheet) const;

  void SetEdited(bool edited);
  //! Return true if page has been modified since last save.
  inline bool IsEdited() const { return iEdited; }

  //! Return title of this page.
  IpeString title() const;
  void setTitle(IpeString title);
  IpeString section(int level) const;
  void setSection(int level, bool useTitle, IpeString name);
  //! Does this section title reflect the page title?
  bool sectionUsesTitle(int level) const { return iUseTitle[level]; }
  const IpeText *titleText() const;
  void applyTitleStyle(const IpeStyleSheet *sheet);

  void DeselectAll();
  void DeselectLayer(int layer);
  void DeselectNotInView(int view);
  bool HasSelection() const;
  iterator PrimarySelection();
  void EnsurePrimarySelection();
  void ExtractSelection(IpePgObjectSeq &seq);
  bool UpdateCloseSelection(const IpeVector &pos, double d,
			    bool primaryOnly, int view);

  void Copy(IpeStream &stream, const IpeStyleSheet *sheet) const;
  bool Paste(int layer, IpeDataSource &source, IpeRepository *rep);
  void CopyPage(IpeStream &stream, const IpeStyleSheet *sheet) const;

  void MakeLayerTable(std::vector<bool> &layers, int view,
		      bool excludeLocked) const;

  void MoveToLayer(int layer);
  void Delete();
  void SelectAll(int view);
  void SelectAllInLayer(int layer);
  void Group(int layer);
  bool Ungroup(int layer);
  void Front();
  void Back();
  void forward();
  void backward();
  void movePrimaryBeforeSecondary();
  void movePrimaryBehindSecondary();
  void Duplicate(int layer);
  void SetStroke(IpeAttribute color);
  void SetFill(IpeAttribute color);
  void SetLineWidth(IpeAttribute attr);
  void SetDashStyle(IpeAttribute attr);
  void SetArrows(bool forward, bool backward, IpeAttribute size);
  void SetArrowSize(IpeAttribute size);
  void SetMarkShape(int shape);
  void SetMarkSize(IpeAttribute size);
  void SetTextSize(IpeAttribute size);
  void setTransformable(bool transf);
  void setTextStyle(IpeAttribute style);
  void setLabelHorizontalAlignment(IpeText::THorizontalAlignment align);
  void setLabelVerticalAlignment(IpeText::TVerticalAlignment align);
  void setPinned(IpeObject::TPinned pin);
  void setLineJoin(IpeAttribute join);
  void setLineCap(IpeAttribute cap);
  void setWindRule(IpeAttribute rule);

  bool ComposePaths(int layer);
  bool DecomposePath(int layer);
  bool JoinPaths(int layer);

  //! Return grid size for this page (0 if not set).
  inline int GridSize() const { return iGridSize; }
  //! Set grid size.
  inline void SetGridSize(int gs) { iGridSize = gs; }

private:
  IpePath *DoJoinPaths(IpePath *prim, SSubPath *subs, int size);
private:
  bool iEdited;
  IpeViewSeq iViews;
  IpeLayerSeq iLayers;
  int iGridSize;
  IpeString iTitle;
  IpeText iTitleObject;
  bool iUseTitle[2];
  IpeString iSection[2];
};

//! Constructor takes ownership of object.
inline IpePgObject::IpePgObject(TSelect sel, int layer, IpeObject *obj)
  : iSelect(sel), iLayer(layer), iObject(obj)
{
  // nothing
}

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