/* layout.h
 *
 * Copyright(C) 1998-1999 The gtkmm Development Team
 *
 * 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 library 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <glibmm/object.h>
#include <pangomm/font.h>
#include <pangomm/fontdescription.h>
#include <pangomm/context.h>
#include <pangomm/attrlist.h>
#include <pangomm/tabarray.h>
#include <pangomm/layoutline.h>
#include <pangomm/layoutiter.h>
#include <pango/pango-layout.h>

_DEFS(pangomm,pango)
_PINCLUDE(glibmm/private/object_p.h)

namespace Pango
{

_CC_INCLUDE(pango/pango-enum-types.h)
_WRAP_ENUM(Alignment, PangoAlignment, decl_prefix PANGOMM_API)
_WRAP_ENUM(WrapMode, PangoWrapMode, decl_prefix PANGOMM_API)
_WRAP_ENUM(EllipsizeMode, PangoEllipsizeMode, decl_prefix PANGOMM_API)

/** A Pango::Layout represents an entire paragraph of text.
 * It is initialized with a Pango::Context, UTF-8 string and set of attributes for that string.
 * Once that is done, the set of formatted lines can be extracted from the object,
 * the layout can be rendered, and conversion between logical character positions
 * within the layout's text, and the physical position of the resulting glyphs can be made.
 */
class PANGOMM_API Layout : public Glib::Object
{
  _CLASS_GOBJECT(Layout, PangoLayout, PANGO_LAYOUT, Glib::Object, GObject, , , PANGOMM_API)

  _IGNORE(pango_layout_set_text, pango_layout_set_markup, pango_layout_set_markup_with_accel,
    pango_layout_get_log_attrs, pango_layout_get_log_attrs_readonly, pango_layout_get_iter)

protected:
  explicit Layout(const Glib::RefPtr<Context>& context);

public:
  _WRAP_CREATE(const Glib::RefPtr<Context>& context)

 /** Creates a layout object set up to match the current transformation
  * and target surface of the Cairo context.  This layout can then be
  * used for text measurement with functions like
  * get_size() or drawing with methods like show_in_cairo_contet(). 
  * If you change the transformation or target surface for @a context, 
  * you need to call update_from_cairo_context()
  *
  * This is the most convenient way to use Cairo with Pango. 
  * However it is slightly inefficient since it creates a separate
  * Pango Context object for each layout. This might matter in an
  * application that is laying out large amounts of text.
  * 
  * @param context A Cairo context.
  * @return The newly created Pango Layout.
  */
  static Glib::RefPtr<Layout> create(const Cairo::RefPtr<Cairo::Context>& context);

  /** Updates the private Pango Context of a Pango Layout created with
   * create(const Cairo::RefPtr<Cairo::Context>&) to match the current transformation
   * and target surface of a Cairo Context.
   *
   * @param context A Cairo context.
   */
  void update_from_cairo_context(const Cairo::RefPtr<Cairo::Context>& context);


  _WRAP_METHOD(Glib::RefPtr<Layout> copy(), pango_layout_copy)
  _WRAP_METHOD(Glib::RefPtr<Context> get_context() const, pango_layout_get_context, refreturn)
  _WRAP_METHOD(void set_attributes(AttrList& attrs), pango_layout_set_attributes)
  _WRAP_METHOD(AttrList get_attributes() const, pango_layout_get_attributes)

  /** Set the text of the layout.
   * @param text The text for the layout.
   */
  void set_text(const Glib::ustring& text);

  _WRAP_METHOD(Glib::ustring get_text() const, pango_layout_get_text)

  _WRAP_METHOD(int get_character_count() const, pango_layout_get_character_count)

  /** Sets the layout text and attribute list from marked-up text (see markup format).
   * Replaces the current text and attribute list.
   * @param markup Some marked-up text.
   */
  void set_markup(const Glib::ustring& markup);

  /** Sets the layout text and attribute list from marked-up text (see markup format).
   * Replaces the current text and attribute list.
   *
   * If @a accel_marker is nonzero, the given character will mark the character following
   * it as an accelerator. For example, the accel marker might be an ampersand or
   * underscore. All characters marked as an accelerator will receive a
   * Pango::UNDERLINE_LOW attribute, and the first character so marked will be returned
   * in @a accel_char. Two @a accel_marker characters following each other produce a
   * single literal @a accel_marker character.
   * @param markup Some marked-up text.
   * @param accel_marker Marker for accelerators in the text.
   * @param accel_char Return location for any located accelerators.
   */
  void set_markup(const Glib::ustring& markup, gunichar accel_marker, gunichar& accel_char);

  _WRAP_METHOD(void set_font_description(const FontDescription& desc), pango_layout_set_font_description)
  void unset_font_description();

  _WRAP_METHOD(FontDescription get_font_description() const, pango_layout_get_font_description)

  _WRAP_METHOD(void set_width(int width), pango_layout_set_width)
  _WRAP_METHOD(int get_width() const, pango_layout_get_width)
  _WRAP_METHOD(void set_height(int height), pango_layout_set_height)
  _WRAP_METHOD(int get_height() const, pango_layout_get_height)
  _WRAP_METHOD(void set_wrap(WrapMode wrap), pango_layout_set_wrap)
  _WRAP_METHOD(WrapMode get_wrap() const, pango_layout_get_wrap)
  _WRAP_METHOD(bool is_wrapped() const, pango_layout_is_wrapped)
  _WRAP_METHOD(void set_indent(int indent), pango_layout_set_indent)
  _WRAP_METHOD(int get_indent() const, pango_layout_get_indent)
  _WRAP_METHOD(void set_spacing(int spacing), pango_layout_set_spacing)
  _WRAP_METHOD(int get_spacing() const, pango_layout_get_spacing)
  _WRAP_METHOD(void set_line_spacing(float factor), pango_layout_set_line_spacing)
  _WRAP_METHOD(float get_line_spacing() const, pango_layout_get_line_spacing)
  _WRAP_METHOD(void set_justify(bool justify = true), pango_layout_set_justify)
  _WRAP_METHOD(bool get_justify() const, pango_layout_get_justify)

  _WRAP_METHOD(bool get_auto_dir() const, pango_layout_get_auto_dir)
  _WRAP_METHOD(void set_auto_dir(bool auto_dir = true), pango_layout_set_auto_dir)
  
  _WRAP_METHOD(void set_alignment(Alignment alignment), pango_layout_set_alignment)
  _WRAP_METHOD(Alignment get_alignment() const, pango_layout_get_alignment)

  _WRAP_METHOD(void set_tabs(TabArray& tabs), pango_layout_set_tabs)
  _WRAP_METHOD(TabArray get_tabs() const, pango_layout_get_tabs)

  _WRAP_METHOD(void set_single_paragraph_mode(bool setting = true), pango_layout_set_single_paragraph_mode)
  _WRAP_METHOD(bool get_single_paragraph_mode() const, pango_layout_get_single_paragraph_mode)

  _WRAP_METHOD(void set_ellipsize(EllipsizeMode ellipsize), pango_layout_set_ellipsize)
  _WRAP_METHOD(EllipsizeMode get_ellipsize() const, pango_layout_get_ellipsize)

  _WRAP_METHOD(bool is_ellipsized() const, pango_layout_is_ellipsized)
  _WRAP_METHOD(int get_unknown_glyphs_count() const, pango_layout_get_unknown_glyphs_count)

  _WRAP_METHOD(void context_changed(), pango_layout_context_changed)

  _WRAP_METHOD(guint get_serial() const, pango_layout_get_serial)

  /** Retrieve a vector of logical attributes for each character in the layout.
   *
   * The number of attributes returned will be one more
   * than the total number of characters in the layout, since there
   * need to be attributes corresponding to both the position before
   * the first character and the position after the last character.
   *
   * @return A vector of logical attributes.
   */
  std::vector<LogAttr> get_log_attrs() const;

  /** Convert from an index within the layout to the onscreen position corresponding to the grapheme at that index, which is represented as rectangle.
   * Note that @a x in the returned rectangle is always the leading edge of the grapheme
   * and @a x + @a width the trailing edge of the grapheme.
   * If the directionality of the grapheme is right-to-left, then @a width will be negative.
   * @param index Byte index within layout.
   * @return The position of the grapheme.
   */
  Rectangle index_to_pos(int index) const;
  _IGNORE(pango_layout_index_to_pos)

  _WRAP_METHOD(void index_to_line_x(int index_, bool trailing, int& line, int& x_pos) const, pango_layout_index_to_line_x)

  _WRAP_METHOD(void get_cursor_pos(int index, Rectangle& strong_pos, Rectangle& weak_pos) const, pango_layout_get_cursor_pos)

  /** Given an index within the layout, determine the positions that of the strong cursors if the insertion point is at that index.
   * @param index The byte index of the cursor.
   * @return The strong cursor position.
   */
  Rectangle get_cursor_strong_pos(int index) const;

  /** Given an index within the layout, determine the positions that of the weak cursors if the insertion point is at that index.
   * @param index The byte index of the cursor.
   * @return The weak cursor position.
   */
  Rectangle get_cursor_weak_pos(int index) const;

  _WRAP_METHOD(void move_cursor_visually(bool strong,
     int old_index, int old_trailing, int direction,
     int& new_index, int& new_trailing) const, pango_layout_move_cursor_visually)

  _WRAP_METHOD(bool xy_to_index(int x, int y, int& index, int& trailing) const, pango_layout_xy_to_index)

  _WRAP_METHOD(void get_extents(Rectangle& ink_rect, Rectangle& logical_rect) const, pango_layout_get_extents)

  /** Compute the ink extents of layout.
   * @return The extents of the layout as drawn.
   */
  Rectangle get_ink_extents() const;

  /** Compute the logical extents of layout.
   * @return The logical extents of the layout.
   */
  Rectangle get_logical_extents() const;

  _WRAP_METHOD(void get_pixel_extents(Rectangle& ink_rect, Rectangle& logical_rect) const, pango_layout_get_pixel_extents)

  /** Compute the ink extents of the layout in device units.
   * @return The extents of the layout as drawn.
   */
  Rectangle get_pixel_ink_extents() const;

  /** Compute the logical extents of the layout in device units.
   * @return The logical extents of the layout.
   */
  Rectangle get_pixel_logical_extents() const;

  _WRAP_METHOD(void get_size(int& width, int& height) const, pango_layout_get_size)
  _WRAP_METHOD(void get_pixel_size(int& width, int& height) const, pango_layout_get_pixel_size)

  _WRAP_METHOD(int get_baseline() const, pango_layout_get_baseline)

  _WRAP_METHOD(int get_line_count() const, pango_layout_get_line_count)

  //Note that the const version uses a different (faster) C function:
  /** Retrieves a particular line from a Pango::Layout.
   *
   * Use the faster get_const_line() if you do not plan
   * to modify the contents of the line (glyphs, glyph widths, etc.).
   *
   * @param line The index of a line, which must be between 0 and
   * <tt>get_line_count() - 1</tt>, inclusive.
   * @return The requested Pango::LayoutLine, or an empty RefPtr if the index
   * is out of range. This layout line will become invalid if changes are made
   * to the Pango::Layout.
   */
  _WRAP_METHOD(Glib::RefPtr<LayoutLine> get_line(int line), pango_layout_get_line, refreturn)

  /** Retrieves a particular line from a Pango::Layout.
   *
   * @param line The index of a line, which must be between 0 and
   * <tt>get_line_count() - 1</tt>, inclusive.
   * @return The requested Pango::LayoutLine, or an empty RefPtr if the index
   * is out of range. This layout line will become invalid if changes are made
   * to the Pango::Layout. No changes should be made to the line.
   */
  _WRAP_METHOD(Glib::RefPtr<const LayoutLine> get_line(int line) const, pango_layout_get_line_readonly, refreturn)

  /** Retrieves a particular line from a Pango::Layout.
   *
   * This is a faster alternative to get_line(), but the user is not expected
   * to modify the contents of the line (glyphs, glyph widths, etc.).
   *
   * @newin{2,50}
   *
   * @param line The index of a line, which must be between 0 and
   * <tt>get_line_count() - 1</tt>, inclusive.
   * @return The requested Pango::LayoutLine, or an empty RefPtr if the index
   * is out of range. This layout line will become invalid if changes are made
   * to the Pango::Layout. No changes should be made to the line.
   */
  _WRAP_METHOD(Glib::RefPtr<const LayoutLine> get_const_line(int line) const, pango_layout_get_line_readonly, refreturn)

#m4 _CONVERSION(`GSList*',`std::vector<Glib::RefPtr<LayoutLine>>',`SListHandler_LayoutLine::slist_to_vector($3, Glib::OWNERSHIP_NONE)',)
#m4 _CONVERSION(`GSList*',`std::vector<Glib::RefPtr<const LayoutLine>>',`SListHandler_ConstLayoutLine::slist_to_vector($3, Glib::OWNERSHIP_NONE)')

  //Note that the const version uses a different (faster) C function:
  /** Returns the lines of the layout as a vector.
   *
   * Use the faster get_const_lines() if you do not plan
   * to modify the contents of the lines (glyphs, glyph widths, etc.).
   *
   * @return A std::vector containing
   * the lines in the layout. This points to internal data of the Pango::Layout
   * and must be used with care. It will become invalid on any change to the layout's
   * text or properties.
   */
  _WRAP_METHOD(std::vector<Glib::RefPtr<LayoutLine>> get_lines(), pango_layout_get_lines)

  /** Returns the lines of the layout as a vector.
   *
   * @return A std::vector containing
   * the lines in the layout. This points to internal data of the Pango::Layout and
   * must be used with care. It will become invalid on any change to the layout's
   * text or properties. No changes should be made to the lines.
   */
  _WRAP_METHOD(std::vector<Glib::RefPtr<const LayoutLine>> get_lines() const, pango_layout_get_lines_readonly)

  /** Returns the lines of the layout as a vector.
   *
   * This is a faster alternative to get_lines(), but the user is not expected
   * to modify the contents of the lines (glyphs, glyph widths, etc.).
   *
   * @newin{2,50}
   *
   * @return A std::vector containing
   * the lines in the layout. This points to internal data of the Pango::Layout and
   * must be used with care. It will become invalid on any change to the layout's
   * text or properties. No changes should be made to the lines.
   */
  _WRAP_METHOD(std::vector<Glib::RefPtr<const LayoutLine>> get_const_lines() const, pango_layout_get_lines_readonly)

  /** Gets an iterator to iterate over the visual extents of the layout.
   * @return The iterator.
   *
   * @newin{2,28}
   */
  LayoutIter get_iter();

  /** Adds the text in this LayoutLine to the current path in the
   * specified Cairo @a context. The origin of the glyphs (the left edge
   * of the line) will be at the current point of the cairo context.
   *
   * @param context A Cairo context.
   */
  void add_to_cairo_context(const Cairo::RefPtr<Cairo::Context>& context);

  /** Draws a Layout in the specified Cairo @a context. The top-left
   *  corner of the Layout will be drawn at the current point of the
   *  cairo context.
   *
   * @param context A Cairo context.
   *
   * @newin{2,16}
   */
  void show_in_cairo_context(const Cairo::RefPtr<Cairo::Context>& context);
};

} /* namespace Pango */
