// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WPAINTDEVICE_H_
#define WPAINTDEVICE_H_

#include <Wt/WLength>
#include <Wt/WString>
#include <Wt/WGlobal>

namespace Wt {

class WFontMetrics;
class WPainter;
class WPainterPath;
class WRectF;

/*! \class WTextItem Wt/WPaintDevice Wt/WPaintDevice
 *  \brief The result of a font metrics computation.
 *
 * \sa WPaintDevice::measureText()
 */
class WT_API WTextItem
{
public:
  /*! \brief Constructor.
   */
  WTextItem(const WString& text, double width, double nextWidth = -1);

  /*! \brief Returns the measured text.
   *
   * If the item was measured with word breaking enabled, then the text may
   * contain trailing whitespace that is not included in the width().
   */
  WString text() const { return text_; }

  /*! \brief Returns the measured width.
   *
   * Returns the text width, in device local coordinates (pixels).
   */
  double width() const { return width_; }

  /*! \brief Returns the width for a next line-break boundary.
   *
   * Returns the width until the next line-break boundary, or -1 if the
   * underlying word boundary analysis does not support this.
   */
  double nextWidth() const { return nextWidth_; }

private:
  WString text_;
  double width_, nextWidth_;
};

/*! \class WPaintDevice Wt/WPaintDevice Wt/WPaintDevice
 *  \brief The abstract base class for a paint device
 *
 * A %WPaintDevice is a device on which may be painted using a
 * WPainter. You should never paint directly on a paint device.
 *
 * The device defines the size of the drawing area, using width() and
 * height(). These dimensions must be defined in pixel units. In the
 * future, additional information will be included to convert these pixel
 * units to lengths (using DPI information).
 *
 * You should reimplement this class if you wish to extend the %Wt
 * paint system to paint on other devices than the ones provided by
 * the library.
 *
 * <i>Note: this interface is subject to changes to increase
 * optimization possibilities for the painting using different
 * devices.</i>
 *
 * \sa WPainter
 *
 * \ingroup painting
 */
class WT_API WPaintDevice
{
public:
  /*! \brief Enumeration to communicate painter state changes.
   *
   * \sa setChanged(WFlags<ChangeFlag>)
   */
  enum ChangeFlag {
    Pen = 0x1,         //!< Properties of the pen have changed
    Brush = 0x2,       //!< Properties of the brush have changed
    Font = 0x4,        //!< Properties of the font have changed
    Hints = 0x8,       //!< Some render hints have changed
    Transform = 0x10,  //!< The transformation has changed
    Clipping = 0x20,   //!< The clipping has changed
    Shadow = 0x40      //!< Properties of the shadow have changed
  };

  /*! \brief Enumeration to indicate paint device features.
   *
   * \sa features()
   */
  enum FeatureFlag {
    CanWordWrap = 0x1,    //!< Implements drawText() with Wt::TextWordWrap
    HasFontMetrics = 0x2  //!< Implements fontMetrics() and measureText()
  };

  /*! \brief Destructor.
   *
   * Frees all resources associated with this device.
   */
  virtual ~WPaintDevice();

  /*! \brief Returns device features.
   */
  virtual WFlags<FeatureFlag> features() const = 0;

  /*! \brief Returns the device width.
   *
   * The device width, in pixels, establishes the width of the device
   * coordinate system.
   */
  virtual WLength width() const = 0;

  /*! \brief Returns the device height.
   *
   * The device height, in pixels, establishes the height of the device
   * coordinate system.
   */
  virtual WLength height() const = 0;

  /*! \brief Indicates changes in painter state.
   *
   * The \p flags argument is the logical OR of one or more change flags.
   *
   * \sa ChangeFlag
   */
  virtual void setChanged(WFlags<ChangeFlag> flags) = 0;

  /*! \brief Draws an arc.
   *
   * The arc is defined as in 
   * WPainter::drawArc(const WRectF& rectangle, int startAngle, int spanAngle)
   *
   * The arc must be stroked, filled, and transformed using the
   * current painter settings.
   */
  virtual void drawArc(const WRectF& rect, double startAngle, double spanAngle)
    = 0;

  /*! \brief Draws an image.
   *
   * Draws <i>sourceRect</i> from the image with URL \p imageUri
   * and original dimensions <i>imgWidth</i> and \p imgHeight to
   * the location, into the rectangle defined by \p rect.
   *
   * The image is transformed using the current painter settings.
   */
  virtual void drawImage(const WRectF& rect, const std::string& imageUri,
			 int imgWidth, int imgHeight,
			 const WRectF& sourceRect) = 0;

  /*! \brief Draws a line.
   *
   * The line must be stroked and transformed using the current
   * painter settings.
   */
  virtual void drawLine(double x1, double y1, double x2, double y2) = 0;

  /*! \brief Draws a path.
   *
   * The path must be stroked, filled, and transformed using the
   * current painter settings.
   */
  virtual void drawPath(const WPainterPath& path) = 0;

  /*! \brief Draws text.
   *
   * The text must be rendered, stroked and transformed using the
   * current painter settings.
   */
  virtual void drawText(const WRectF& rect, 
			WFlags<AlignmentFlag> alignmentFlags,
			TextFlag textFlag,
			const WString& text) = 0;

  /*! \brief Measures rendered text size.
   *
   * Returns the bounding rect of the given text when rendered using the
   * current font.
   *
   * If \p maxWidth != -1, then the text is truncated to fit in the
   * width.
   *
   * If \p wordWrap = \c true then text is truncated only at word
   * boundaries. Note that in this case the whitespace at the
   * truncated position is included in the text but not accounted for
   * by the returned width (since usually you will not render the
   * whitespace at the end of a line).
   *
   * Throws a std::logic_error if the underlying device does not
   * provide font metrics.
   */
  virtual WTextItem measureText(const WString& text, double maxWidth = -1,
				bool wordWrap = false) = 0;

  /*! \brief Returns font metrics.
   *
   * This returns font metrics for the current font.
   *
   * Throws a std::logic_error if the underlying device does not
   * provide font metrics.
   */
  virtual WFontMetrics fontMetrics() = 0;

  /*! \brief Initializes the device for painting.
   *
   * This method is called when a WPainter starts painting.
   *
   * \sa WPainter::begin(WPaintDevice *), painter()
   */
  virtual void init() = 0;

  /*! \brief Finishes painting on the device.
   *
   * This method is called when a WPainter stopped painting.
   *
   * \sa WPainter::end()
   */
  virtual void done() = 0;

  /*! \brief Returns whether painting is active.
   *
   * \sa init(), painter()
   */
  virtual bool paintActive() const = 0;

protected:
  /*! \brief Returns the painter that is currently painting on the device.
   *
   * \sa init()
   */
  virtual WPainter *painter() const = 0;

  /*! \brief Sets the painter.
   */
  virtual void setPainter(WPainter *painter) = 0;

  friend class WPainter;
  friend class WPaintedWidget;
};

W_DECLARE_OPERATORS_FOR_FLAGS(WPaintDevice::ChangeFlag)
W_DECLARE_OPERATORS_FOR_FLAGS(WPaintDevice::FeatureFlag)

}

#endif // WPAINTDEVICE_H_
