
/* Copyright (C) 1998-2006 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 <goocanvasmm/bounds.h>
#include <goocanvasmm/enums.h>
#include <goocanvasmm/style.h>
#include <cairomm/cairomm.h>
#include <goocanvasitem.h>

_DEFS(goocanvasmm,libgoocanvas)
_PINCLUDE(glibmm/private/interface_p.h)

#ifndef DOXYGEN_SHOULD_SKIP_THIS
extern "C" { typedef union _GooCanvasPathCommand GooCanvasPathCommand; }
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

namespace Goocanvas
{

class Canvas ;
class ItemModel ;

class Item : public Glib::Interface
{
  _CLASS_INTERFACE(Item,GooCanvasItem,GOO_CANVAS_ITEM,GooCanvasItemIface)

public:

  _WRAP_METHOD(Canvas* get_canvas(), goo_canvas_item_get_canvas)
  _WRAP_METHOD(const Canvas* get_canvas() const, goo_canvas_item_get_canvas, constversion)
  // TODO: should this be passed by reference instead of by pointer?
  _WRAP_METHOD(void set_canvas(Canvas* canvas),  goo_canvas_item_set_canvas)

  _WRAP_METHOD(bool is_visible() const, goo_canvas_item_is_visible)

  _WRAP_METHOD(Glib::RefPtr<ItemModel> get_model(), goo_canvas_item_get_model, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const ItemModel> get_model() const, goo_canvas_item_get_model, refreturn, constversion)
  _WRAP_METHOD(void set_model(const Glib::RefPtr<ItemModel>& model), goo_canvas_item_set_model)

  _WRAP_METHOD(Glib::RefPtr<Item> get_parent(), goo_canvas_item_get_parent, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Item> get_parent() const, goo_canvas_item_get_parent, refreturn, constversion)
  _WRAP_METHOD(void set_parent(const Glib::RefPtr<Item>& parent), goo_canvas_item_set_parent)
  _WRAP_METHOD(void remove(), goo_canvas_item_remove)

  _WRAP_METHOD(bool is_container() const, goo_canvas_item_is_container)
  _WRAP_METHOD(int get_n_children() const, goo_canvas_item_get_n_children)
  _WRAP_METHOD(Glib::RefPtr<Item> get_child(int child_num), goo_canvas_item_get_child, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Item> get_child(int child_num) const, goo_canvas_item_get_child, refreturn, constversion)
  _WRAP_METHOD(int find_child(const Glib::RefPtr<Item>& child), goo_canvas_item_find_child)
  _WRAP_METHOD(void add_child(const Glib::RefPtr<Item>& child, int pos), goo_canvas_item_add_child)
  void add_child(const Glib::RefPtr<Item>& child);

  _WRAP_METHOD(void get_child_property_value(const Glib::RefPtr<Item>& child, const Glib::ustring& property_name, Glib::ValueBase& value) const, goo_canvas_item_get_child_property)
  _WRAP_METHOD(void set_child_property_value(const Glib::RefPtr<Item>& child, const Glib::ustring& property_name, const Glib::ValueBase& value), goo_canvas_item_set_child_property)
  _IGNORE(goo_canvas_item_get_child_properties_valist, goo_canvas_item_set_child_properties_valist)
  _IGNORE(goo_canvas_item_get_child_properties, goo_canvas_item_set_child_properties)
  template <class PropertyType>
  void get_child_property(const Glib::RefPtr<Item>& child, const Glib::ustring& the_property_name, PropertyType& value) const;

  template <class PropertyType>
  void set_child_property(const Glib::RefPtr<Item>& child, const Glib::ustring& the_property_name, const PropertyType& value);

  _WRAP_METHOD(void move_child(int old_position, int new_position), goo_canvas_item_move_child)
  _WRAP_METHOD(void remove_child(int child_num), goo_canvas_item_remove_child)

  _WRAP_METHOD(void raise(const Glib::RefPtr<Item>& above), goo_canvas_item_raise)

  /** Raise the item to the top of the stack.
   */
  void raise();

  _WRAP_METHOD(void lower(const Glib::RefPtr<Item>& below), goo_canvas_item_lower)

  /** Lower the item to the bottom of the stack.
   */
  void lower();

  Bounds get_bounds() const;
  _IGNORE(goo_canvas_item_get_bounds)

  _WRAP_METHOD(void request_update(), goo_canvas_item_request_update)
  _WRAP_METHOD(void ensure_updated(), goo_canvas_item_ensure_updated)
  _WRAP_METHOD(void update(bool entire_tree, const Cairo::RefPtr<Cairo::Context>& context, Bounds& bounds), goo_canvas_item_update)
  _WRAP_METHOD(void paint(const Cairo::RefPtr<Cairo::Context>& context, const Bounds& bounds, double scale), goo_canvas_item_paint)
  _WRAP_METHOD(bool get_requested_area(const Cairo::RefPtr<Cairo::Context>& context, Bounds& bounds) const, goo_canvas_item_get_requested_area)
  _WRAP_METHOD(double get_requested_height(const Cairo::RefPtr<Cairo::Context>& context, double width) const, goo_canvas_item_get_requested_height)
  _WRAP_METHOD(void allocate_area(const Cairo::RefPtr<Cairo::Context>& context, const Bounds& requested_area, const Bounds& allocated_area, double x_offset, double y_offset), goo_canvas_item_allocate_area)


  // Note the semantics of the C version: The returned list is the same as the
  // one fed into the function, with possibly some elements added to the head.
#m4 _CONVERSION(`const std::vector< Glib::RefPtr<Item> >&',`GList*',`g_list_copy(Glib::ListHandler<Glib::RefPtr<Item> >::vector_to_list($3).data())')
#m4 _CONVERSION(`const std::vector< Glib::RefPtr<const Item> >&',`GList*',`g_list_copy(Glib::ListHandler<Glib::RefPtr<const Item> >::vector_to_list($3).data())')

#m4 _CONVERSION(`GList*',`std::vector< Glib::RefPtr<Item> >',`Glib::ListHandler<Glib::RefPtr<Item> >::list_to_vector($3, Glib::OWNERSHIP_SHALLOW)')
#m4 _CONVERSION(`GList*',`std::vector< Glib::RefPtr<const Item> >',`Glib::ListHandler<Glib::RefPtr<const Item> >::list_to_vector($3, Glib::OWNERSHIP_SHALLOW)')

  _WRAP_METHOD(std::vector< Glib::RefPtr<Item> > get_items_at(double x, double y, const Cairo::RefPtr<Cairo::Context>& context, bool is_pointer_event, bool parent_is_visible, const std::vector< Glib::RefPtr<Item> >& found_items), goo_canvas_item_get_items_at)
  _WRAP_METHOD(std::vector< Glib::RefPtr<const Item> > get_items_at(double x, double y, const Cairo::RefPtr<Cairo::Context>& context, bool is_pointer_event, bool parent_is_visible, const std::vector< Glib::RefPtr<const Item> >& found_items) const, goo_canvas_item_get_items_at)

  // Use this if you don't have a list already:
  std::vector< Glib::RefPtr<Item> > get_items_at(double x, double y, const Cairo::RefPtr<Cairo::Context>& context, bool is_pointer_event, bool parent_is_visible);
  std::vector< Glib::RefPtr<const Item> > get_items_at(double x, double y, const Cairo::RefPtr<Cairo::Context>& context, bool is_pointer_event, bool parent_is_visible) const;

  //TODO: Use Cairo::RefPtr?
  _WRAP_METHOD(bool get_transform(Cairo::Matrix* matrix), goo_canvas_item_get_transform)
  _WRAP_METHOD(void set_transform(const Cairo::Matrix* matrix), goo_canvas_item_set_transform)

  _WRAP_METHOD(void set_simple_transform(double x, double y, double scale, double rotation), goo_canvas_item_set_simple_transform)
  _WRAP_METHOD(bool get_simple_transform(double& x, double& y, double& scale, double& rotation) const, goo_canvas_item_get_simple_transform)
  _WRAP_METHOD(void translate(double tx, double ty), goo_canvas_item_translate)
  _WRAP_METHOD(void scale(double sx, double sy), goo_canvas_item_scale)
  _WRAP_METHOD(void rotate(double degrees, double cx, double cy), goo_canvas_item_rotate)
  _WRAP_METHOD(void skew_x(double degrees, double cx, double cy), goo_canvas_item_skew_x)
  _WRAP_METHOD(void skew_y(double degrees, double cx, double cy), goo_canvas_item_skew_y)

  _WRAP_METHOD(bool get_transform_for_child(const Glib::RefPtr<Item>& child, Cairo::Matrix* transform), goo_canvas_item_get_transform_for_child)

  _WRAP_METHOD(Glib::RefPtr<Style> get_style(), goo_canvas_item_get_style, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Style> get_style() const, goo_canvas_item_get_style, refreturn, constversion)
  _WRAP_METHOD(void set_style(const Glib::RefPtr<Style>& style), goo_canvas_item_set_style)

  _WRAP_METHOD(void animate(double x, double y, double scale, double degrees, bool absolute, int duration, int step_time, GooCanvasAnimateType type), goo_canvas_item_animate)
  _WRAP_METHOD(void stop_animation(), goo_canvas_item_stop_animation)

  _WRAP_METHOD(bool get_is_static() const, goo_canvas_item_get_is_static)
  _WRAP_METHOD(void set_is_static(bool is_static = true), goo_canvas_item_set_is_static)

  //_WRAP_SIGNAL(void child_added(int child_num), "child_added")
  //_WRAP_SIGNAL(void child_moved(int old_position, int new_position), "child_moved")
  //_WRAP_SIGNAL(void child_removed(int child_num), "child_removed")
  //_WRAP_SIGNAL(void changed(bool recompute_bounds), "changed")

#m4 _CONVERSION(`GooCanvasItem*',`const Glib::RefPtr<Item>&',`Glib::wrap($3, true)')
  _WRAP_SIGNAL(bool enter_notify_event(const Glib::RefPtr<Item>& target, GdkEventCrossing* event), "enter_notify_event")
  _WRAP_SIGNAL(bool leave_notify_event(const Glib::RefPtr<Item>& target, GdkEventCrossing* event), "leave_notify_event")
  _WRAP_SIGNAL(bool motion_notify_event(const Glib::RefPtr<Item>& target, GdkEventMotion* event), "motion_notify_event")
  _WRAP_SIGNAL(bool button_press_event(const Glib::RefPtr<Item>& target, GdkEventButton* event), "button_press_event")
  _WRAP_SIGNAL(bool button_release_event(const Glib::RefPtr<Item>& target, GdkEventButton* event), "button_release_event")
  _WRAP_SIGNAL(bool focus_in_event(const Glib::RefPtr<Item>& target, GdkEventFocus* event), "focus_in_event")
  _WRAP_SIGNAL(bool focus_out_event(const Glib::RefPtr<Item>& target, GdkEventFocus* event), "focus_out_event")
  _WRAP_SIGNAL(bool key_press_event(const Glib::RefPtr<Item>& target, GdkEventKey* event), "key_press_event")
  _WRAP_SIGNAL(bool key_release_event(const Glib::RefPtr<Item>& target, GdkEventKey* event), "key_release_event")
  _WRAP_SIGNAL(bool grab_broken_event(const Glib::RefPtr<Item>& target, GdkEventGrabBroken* event), "grab_broken_event")
  _WRAP_SIGNAL(void child_notify(GParamSpec* pspec), "child_notify")
  _WRAP_SIGNAL(void animation_finished(bool stopped), "animation_finished")
  _WRAP_SIGNAL(bool scroll_event(const Glib::RefPtr<Item>& target, GdkEventScroll* event), "scroll_event")

  _WRAP_PROPERTY("parent", Glib::RefPtr<Item>)
  _WRAP_PROPERTY("visibility", ItemVisibility)
  _WRAP_PROPERTY("visibility-threshold", double)
  _WRAP_PROPERTY("transform", Cairo::Matrix*)
  _WRAP_PROPERTY("pointer-events", PointerEvents)
  _WRAP_PROPERTY("title", Glib::ustring)
  _WRAP_PROPERTY("description", Glib::ustring)
  _WRAP_PROPERTY("can-focus", bool)

  //These properties are not really in GooCanvasItem, but they are actually 
  //implemented in all derived GooCanvasItem classes individually. 
  //That is a GooCanvas design error, but the patch to fix it has 
  //not yet been accepted: http://bugzilla.gnome.org/show_bug.cgi?id=555097 
  _WRAP_PROPERTY("x", double)
  _WRAP_PROPERTY("y", double)
  _WRAP_PROPERTY("width", double)
  _WRAP_PROPERTY("height", double)

protected:

#m4 _CONVERSION(`Glib::RefPtr<Item>', `GooCanvasItem*', `(($3) ? ($3)->gobj() : 0)')
#m4 _CONVERSION(`GooCanvasItem*', `Glib::RefPtr<Item>', `Glib::wrap($3, true)')
/* Virtual methods that group items must implement. */
  _WRAP_VFUNC(int get_n_children() const, get_n_children)
  _WRAP_VFUNC(Glib::RefPtr<Item> get_child(int child_num) const, get_child)
  _WRAP_VFUNC(void request_update(), request_update)
  _WRAP_VFUNC(Canvas* get_canvas() const, get_canvas)
  _WRAP_VFUNC(void set_canvas(Canvas* canvas), set_canvas)

  /* Virtual methods that group items may implement. */

  _WRAP_VFUNC(void add_child(const Glib::RefPtr<Item>& child, int position), add_child)
  _WRAP_VFUNC(void move_child(int old_position, int new_position), move_child)
  _WRAP_VFUNC(void remove_child(int child_num), remove_child)
  _WRAP_VFUNC(void get_child_property(const Glib::RefPtr<Item>& child, guint property_id, Glib::ValueBase& value, GParamSpec* pspec) const, get_child_property)
  _WRAP_VFUNC(void set_child_property(const Glib::RefPtr<Item>& child, guint property_id, const Glib::ValueBase& value, GParamSpec* pspec), set_child_property)
  _WRAP_VFUNC(bool get_transform_for_child(const Glib::RefPtr<Item>& child, Cairo::Matrix* transform) const, get_transform_for_child)

  /* Virtual methods that all canvas items must implement. */

  _WRAP_VFUNC(Glib::RefPtr<Item> get_parent() const, get_parent)
  _WRAP_VFUNC(void set_parent(const Glib::RefPtr<Item>& parent), set_parent)

#ifdef GLIBMM_VFUNCS_ENABLED
  // Hand code, since Bounds can only copy a GooCanvasBounds* but not ref one.
  virtual void get_bounds_vfunc(Bounds& bounds) const;
  virtual std::vector<Glib::RefPtr<Item> > get_items_at_vfunc(double x, double y, const Cairo::RefPtr<Cairo::Context>& context, bool is_pointer_event, bool is_parent_visible, const std::vector<Glib::RefPtr<Item> >& found_items);
#endif

#m4begin
  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
  klass->get_bounds = &get_bounds_vfunc_callback;
  klass->get_items_at = &get_items_at_vfunc_callback;
  _SECTION(SECTION_PH_VFUNCS)
  static void get_bounds_vfunc_callback(GooCanvasItem* self, GooCanvasBounds* bounds);
  static GList* get_items_at_vfunc_callback(GooCanvasItem* self, gdouble x, gdouble y, cairo_t* cr, gboolean is_pointer_event, gboolean parent_is_visible, GList* found_items);
  _POP()
#m4end

#m4 _CONVERSION(`cairo_t*',`const Cairo::RefPtr<Cairo::Context>&',`Cairo::RefPtr<Cairo::Context>(new Cairo::Context($3, false /* has_reference */))')
  _WRAP_VFUNC(void update(bool entire_tree, const Cairo::RefPtr<Cairo::Context>& cr, Bounds& bounds), update)

#m4 _CONVERSION(`const GooCanvasBounds*', `const Bounds&', `Glib::wrap($3)')
  _WRAP_VFUNC(void paint(const Cairo::RefPtr<Cairo::Context>& cr, const Bounds& bounds, double scale), paint)

  _WRAP_VFUNC(bool get_requested_area(const Cairo::RefPtr<Cairo::Context>& cr, GooCanvasBounds* requested_area) const, get_requested_area)
  _WRAP_VFUNC(void allocate_area(const Cairo::RefPtr<Cairo::Context>& cr, const Bounds& requested_area, const Bounds& allocated_area, double x_offset, double y_offset), allocate_area)


  /* Virtual methods that canvas items may implement. */

  _WRAP_VFUNC(bool get_transform(Cairo::Matrix* transform) const, get_transform)
  _WRAP_VFUNC(void set_transform(const Cairo::Matrix* transform), set_transform)

#m4 _CONVERSION(`Glib::RefPtr<Style>', `GooCanvasStyle*', `(($3) ? ($3)->gobj() : 0)')
#m4 _CONVERSION(`GooCanvasStyle*', `Glib::RefPtr<Style>', `Glib::wrap($3, true)')
#m4 _CONVERSION(`GooCanvasStyle*', `const Glib::RefPtr<Style>&', `Glib::wrap($3, true)')
  _WRAP_VFUNC(Glib::RefPtr<Style> get_style() const, get_style)
  _WRAP_VFUNC(void set_style(const Glib::RefPtr<Style>& style), set_style)
  _WRAP_VFUNC(bool is_visible() const, is_visible)
  _WRAP_VFUNC(double get_requested_height(const Cairo::RefPtr<Cairo::Context>& cr, double width), get_requested_height)
  _WRAP_VFUNC(bool get_is_static() const, get_is_static)
  _WRAP_VFUNC(void set_is_static(bool is_static), set_is_static)


  /* Virtual methods that model/view items must implement. */
#m4 _CONVERSION(`Glib::RefPtr<ItemModel>', `GooCanvasItemModel*', `(($3) ? ($3)->gobj() : 0)')
#m4 _CONVERSION(`GooCanvasItemModel*', `Glib::RefPtr<ItemModel>', `Glib::wrap($3, true)')
#m4 _CONVERSION(`GooCanvasItemModel*', `const Glib::RefPtr<ItemModel>&', `Glib::wrap($3, true)')
  _WRAP_VFUNC(Glib::RefPtr<ItemModel> get_model() const, get_model)
  _WRAP_VFUNC(void set_model(const Glib::RefPtr<ItemModel>& model), set_model)

};

#ifndef DOXYGEN_SHOULD_SKIP_THIS

template <class PropertyType>
void Item::get_child_property(const Glib::RefPtr<Item>& child, const Glib::ustring& the_property_name, PropertyType& value) const
{
  Glib::Value<PropertyType> property_value;
  property_value.init(Glib::Value<PropertyType>::value_type());

  this->get_child_property_value(child, the_property_name, property_value);

  value = property_value.get();
}

template <class PropertyType>
void Item::set_child_property(const Glib::RefPtr<Item>& child, const Glib::ustring& the_property_name, const PropertyType& value)
{
  Glib::Value<PropertyType> property_value;
  property_value.init(Glib::Value<PropertyType>::value_type());
  property_value.set(value);

  this->set_child_property_value(child, the_property_name, property_value);
}


#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} //namespace Goocanvas

