/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*-
 *
 * Pigment media rendering library
 *
 * Copyright © 2006, 2007, 2008 Fluendo Embedded S.L.
 *
 * 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 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author(s): Loïc Molinari <loic@fluendo.com>
 *            Julien Moutte <julien@fluendo.com>
 */

#ifndef __PGM_DRAWABLE_H__
#define __PGM_DRAWABLE_H__

#include <gst/gst.h>
#include "pgmcommon.h"
#include "pgmlinearalgebra.h"
#include "pgmevents.h"

G_BEGIN_DECLS

#define PGM_TYPE_DRAWABLE \
  (pgm_drawable_get_type ())
#define PGM_DRAWABLE(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj), PGM_TYPE_DRAWABLE, PgmDrawable))
#define PGM_DRAWABLE_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass), PGM_TYPE_DRAWABLE, PgmDrawableClass))
#define PGM_IS_DRAWABLE(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj), PGM_TYPE_DRAWABLE))
#define PGM_IS_DRAWABLE_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE((klass), PGM_TYPE_DRAWABLE))
#define PGM_DRAWABLE_GET_CLASS(obj) \
  (G_TYPE_INSTANCE_GET_CLASS((obj), PGM_TYPE_DRAWABLE, PgmDrawableClass))

typedef struct _PgmDrawable      PgmDrawable;
typedef struct _PgmDrawableClass PgmDrawableClass;

/**
 * PgmDrawableLayer:
 * @PGM_DRAWABLE_UNBOUND: Not bound to a #Canvas.
 * @PGM_DRAWABLE_FAR: Layer of drawables drawn behind the other layers.
 * @PGM_DRAWABLE_MIDDLE: Layer of drawables drawn over the drawables in the
 * far layer and behind the drawables in the near one.
 * @PGM_DRAWABLE_NEAR: Layer of drawables drawn over the other layers.
 *
 * The rendering layers.
 */
typedef enum {
  PGM_DRAWABLE_UNBOUND,
  PGM_DRAWABLE_FAR,
  PGM_DRAWABLE_MIDDLE,
  PGM_DRAWABLE_NEAR
} PgmDrawableLayer;

/* FIXME: These are not all properties (esp. PGM_DRAWABLE_REGENERATE), could be
 *        an idea to change the name from property to something else
 *        (operation?) */
/**
 * PgmDrawableProperty:
 * @PGM_DRAWABLE_VISIBILITY: %PgmDrawable visibility property.
 * @PGM_DRAWABLE_SIZE: %PgmDrawable size property.
 * @PGM_DRAWABLE_POSITION: %PgmDrawable position property.
 * @PGM_DRAWABLE_TRANSFORMATION_MATRIX: %PgmDrawable transformation matrix
 * property.
 * @PGM_DRAWABLE_BG_COLOR: %PgmDrawable background color property.
 * @PGM_DRAWABLE_FG_COLOR: %PgmDrawable foreground color property.
 * @PGM_DRAWABLE_OPACITY: %PgmDrawable opacity property.
 * @PGM_DRAWABLE_REGENERATE: %PgmDrawable regenerate property.
 * @PGM_IMAGE_DATA_FILE: %PgmImage file data property.
 * @PGM_IMAGE_DATA_BUFFER: %PgmImage buffer data property.
 * @PGM_IMAGE_DATA_GST_BUFFER: %PgmImage GstBuffer data property.
 * @PGM_IMAGE_DATA_PIXBUF: %PgmImage GdkPixbuf data property.
 * @PGM_IMAGE_DATA_SYSTEM_BUFFER: %PgmImage system buffer data property.
 * @PGM_IMAGE_DATA_IMAGE: %PgmImage image data property.
 * @PGM_IMAGE_DATA_EMPTY: %PgmImage empty data property.
 * @PGM_IMAGE_SYSTEM_BUFFER_CONTENT: %PgmImage system buffer content property.
 * @PGM_IMAGE_MAPPING_MATRIX: %PgmImage mapping matrix data property.
 * @PGM_IMAGE_ALIGNMENT: %PgmImage alignment property.
 * @PGM_IMAGE_LAYOUT: %PgmImage layout property.
 * @PGM_IMAGE_INTERP: %PgmImage interpolation property.
 * @PGM_IMAGE_WRAPPING: %PgmImage wrapping property.
 * @PGM_IMAGE_ASPECT_RATIO: %PgmImage aspect-ratio property.
 * @PGM_IMAGE_BORDER_WIDTH: %PgmImage border width property.
 * @PGM_IMAGE_BORDER_INNER_COLOR: %PgmImage border inner color property.
 * @PGM_IMAGE_BORDER_OUTER_COLOR: %PgmImage border outer color property.
 * @PGM_TEXT_LABEL: %PgmText label property.
 * @PGM_TEXT_MARKUP: %PgmText markup property.
 * @PGM_TEXT_FONT_FAMILY: %PgmText font family property.
 * @PGM_TEXT_HEIGHT: %PgmText height property.
 * @PGM_TEXT_ELLIPSIZE: %PgmText ellipsize property.
 * @PGM_TEXT_JUSTIFY: %PgmText justify property.
 * @PGM_TEXT_ALIGNMENT: %PgmText alignment property.
 * @PGM_TEXT_WRAP: %PgmText wrap property.
 * @PGM_TEXT_GRAVITY: %PgmText gravity property.
 * @PGM_TEXT_STRETCH: %PgmText stretch property.
 * @PGM_TEXT_STYLE: %PgmText style property.
 * @PGM_TEXT_VARIANT: %PgmText variant property.
 * @PGM_TEXT_WEIGHT: %PgmText weight property.
 * @PGM_TEXT_MULTILINE: %PgmText multiline property.
 * @PGM_TEXT_LINE_SPACING: %PgmText line spacing property.
 * @PGM_TEXT_COLOR: %PgmText color property.
 * @PGM_TEXT_OUTLINE_COLOR: %PgmText outline color property.
 * @PGM_TEXT_OUTLINE_WIDTH: %PgmText outline width property.
 * @PGM_TEXT_CAST_SHADOW: %PgmText cast shadow property.
 * @PGM_TEXT_SHADOW_POSITION: %PgmText shadow position property.
 * @PGM_TEXT_SHADOW_COLOR: %PgmText shadow color.
 *
 * The different properties of the drawables.
 */
typedef enum {
  /* PgmDrawable properties */
  PGM_DRAWABLE_VISIBILITY            = 0,
  PGM_DRAWABLE_SIZE                  = 1,
  PGM_DRAWABLE_POSITION              = 2,
  PGM_DRAWABLE_TRANSFORMATION_MATRIX = 3,
  PGM_DRAWABLE_BG_COLOR              = 4,
  PGM_DRAWABLE_FG_COLOR              = 5,
  PGM_DRAWABLE_OPACITY               = 6,
  PGM_DRAWABLE_REGENERATE            = 7,
  /* PgmImage properties */
  PGM_IMAGE_DATA_FILE                = 8,
  PGM_IMAGE_DATA_BUFFER              = 9,
  PGM_IMAGE_DATA_GST_BUFFER          = 10,
  PGM_IMAGE_DATA_PIXBUF              = 11,
  PGM_IMAGE_DATA_SYSTEM_BUFFER       = 12,
  PGM_IMAGE_DATA_IMAGE               = 13,
  PGM_IMAGE_DATA_EMPTY               = 14,
  PGM_IMAGE_SYSTEM_BUFFER_CONTENT    = 15,
  PGM_IMAGE_MAPPING_MATRIX           = 16,
  PGM_IMAGE_ALIGNMENT                = 17,
  PGM_IMAGE_LAYOUT                   = 18,
  PGM_IMAGE_INTERP                   = 19,
  PGM_IMAGE_WRAPPING                 = 20,
  PGM_IMAGE_ASPECT_RATIO             = 21,
  PGM_IMAGE_BORDER_WIDTH             = 22,
  PGM_IMAGE_BORDER_INNER_COLOR       = 23,
  PGM_IMAGE_BORDER_OUTER_COLOR       = 24,
  /* PgmText properties */
  PGM_TEXT_LABEL                     = 25,
  PGM_TEXT_MARKUP                    = 26,
  PGM_TEXT_FONT_FAMILY               = 27,
  PGM_TEXT_HEIGHT                    = 28,
  PGM_TEXT_ELLIPSIZE                 = 29,
  PGM_TEXT_JUSTIFY                   = 30,
  PGM_TEXT_ALIGNMENT                 = 31,
  PGM_TEXT_WRAP                      = 32,
  PGM_TEXT_GRAVITY                   = 33,
  PGM_TEXT_STRETCH                   = 34,
  PGM_TEXT_STYLE                     = 35,
  PGM_TEXT_VARIANT                   = 36,
  PGM_TEXT_WEIGHT                    = 37,
  PGM_TEXT_MULTILINE                 = 38,
  PGM_TEXT_LINE_SPACING              = 39,
  PGM_TEXT_COLOR                     = 40,
  PGM_TEXT_OUTLINE_COLOR             = 41,
  PGM_TEXT_OUTLINE_WIDTH             = 42,
  PGM_TEXT_CAST_SHADOW               = 43,
  PGM_TEXT_SHADOW_POSITION           = 44,
  PGM_TEXT_SHADOW_COLOR              = 45
} PgmDrawableProperty;

/**
 * PgmDrawableFlags:
 * @PGM_DRAWABLE_FLAG_UNPARENTING: Child is being removed from the parent
 * canvas. pgm_canvas_del_drawable() on a child already being removed
 * immediately returns %FALSE.
 * @PGM_DRAWABLE_FLAG_VISIBLE: Drawable is visible.
 * @PGM_DRAWABLE_FLAG_LAST: Offset to define more flags.
 *
 * The standard flags that a drawable may have.
 */
typedef enum {
  PGM_DRAWABLE_FLAG_UNPARENTING = (GST_OBJECT_FLAG_LAST << 0),
  PGM_DRAWABLE_FLAG_VISIBLE     = (GST_OBJECT_FLAG_LAST << 1),
  /* padding */
  PGM_DRAWABLE_FLAG_LAST        = (GST_OBJECT_FLAG_LAST << 16)
} PgmDrawableFlags;

/**
 * PgmDrawablePickingSignal:
 * @PGM_DRAWABLE_PICKING_PRESSED: Pressed signal flag.
 * @PGM_DRAWABLE_PICKING_PRESSURED: Pressured signal flag.
 * @PGM_DRAWABLE_PICKING_RELEASED: Released signal flag.
 * @PGM_DRAWABLE_PICKING_CLICKED: Clicked signal flag.
 * @PGM_DRAWABLE_PICKING_DOUBLE_CLICKED: Double-clicked signal flag.
 * @PGM_DRAWABLE_PICKING_DRAG_BEGIN: Drag-begin signal flag.
 * @PGM_DRAWABLE_PICKING_DRAG_MOTION: Drag-motion signal flag.
 * @PGM_DRAWABLE_PICKING_DRAG_END: Drag-end signal flag.
 * @PGM_DRAWABLE_PICKING_ENTERED: Entered signal flag.
 * @PGM_DRAWABLE_PICKING_SCROLLED: Scrolled signal flag.
 * @PGM_DRAWABLE_PICKING_MOTION: Motion signal flag.
 * @PGM_DRAWABLE_PICKING_MASK: Mask covering all the flags.
 *
 * The mouse picking flags internally used by #PgmViewport.
 */
typedef enum {
  PGM_DRAWABLE_PICKING_PRESSED        = (1 << 0),
  PGM_DRAWABLE_PICKING_PRESSURED      = (1 << 1),
  PGM_DRAWABLE_PICKING_RELEASED       = (1 << 2),
  PGM_DRAWABLE_PICKING_CLICKED        = (1 << 3),
  PGM_DRAWABLE_PICKING_DOUBLE_CLICKED = (1 << 4),
  PGM_DRAWABLE_PICKING_DRAG_BEGIN     = (1 << 5),
  PGM_DRAWABLE_PICKING_DRAG_MOTION    = (1 << 6),
  PGM_DRAWABLE_PICKING_DRAG_END       = (1 << 7),
  PGM_DRAWABLE_PICKING_ENTERED        = (1 << 8),
  PGM_DRAWABLE_PICKING_SCROLLED       = (1 << 9),
  PGM_DRAWABLE_PICKING_MOTION         = (1 << 10),
  PGM_DRAWABLE_PICKING_MASK           = 0x7FF
} PgmDrawablePickingSignal;

/**
 * PgmDrawable:
 * @transformation_matrix: the drawable transformation matrix.
 * @angle_x: the drawable angle of rotation on the x axis.
 * @angle_y: the drawable angle of rotation on the y axis.
 * @angle_z: the drawable angle of rotation on the z axis.
 * @layer: the layer the drawable belongs to.
 * @x: the drawable position on the x axis.
 * @y: the drawable position on the y axis.
 * @z: the drawable position on the z axis.
 * @orig_x: the drawable original position on the x axis.
 * @orig_y: the drawable original position on the y axis.
 * @width: the drawable width.
 * @height: the drawable height.
 * @orig_width: the drawable original width.
 * @orig_height: the drawable original height.
 * @grid_aligned: the grid aligned boolean.
 * @scale: the drawable scale factor.
 * @fg_r: the drawable foreground red color component.
 * @fg_g: the drawable foreground green color component.
 * @fg_b: the drawable foreground blue color component.
 * @fg_a: the drawable foreground alpha color component.
 * @bg_r: the drawable background red color component.
 * @bg_g: the drawable background green color component.
 * @bg_b: the drawable background blue color component.
 * @bg_a: the drawable background alpha color component.
 * @opacity: the drawable opacity.
 *
 * Pigment drawable abstract base class.
 */
struct _PgmDrawable {
  GstObject parent;

  /*< public >*/
  /* Transformation */
  PgmMat4x4 *transformation_matrix;
  gfloat angle_x, angle_y, angle_z;

  /* Layer */
  PgmDrawableLayer layer;

  /* Position */
  gfloat x, y, z;
  gfloat orig_x, orig_y;

  /* Scale */
  gfloat scale;

  /* Size */
  gfloat width, height;
  gfloat orig_width, orig_height;
  gboolean grid_aligned;

  /* Colors */
  guchar fg_r, fg_g, fg_b, fg_a;
  guchar bg_r, bg_g, bg_b, bg_a;

  /* Opacity */
  guchar opacity;

  /*< private >*/
  /* Position and orientation of the drawable */
  PgmVec3 origin;
  PgmVec3 plane_vector_i;
  PgmVec3 plane_vector_j;

  /* Mouse picking */
  PgmVec3  press_point;
  PgmVec3  viewport_press_point;
  guint32  pressure;
  guint32  release_time;
  gboolean mouse_over;
  guint16  drag_mask;
  guint16  press_mask;
  guint16  release_button;
  guchar   drag_distance;

  /* Flags */
  guint8 flags;
};

/**
 * PgmDrawableClass:
 * @parent_class: the parent class structure.
 * @changed: the "changed" signal.
 * @pressed: the "pressed" signal.
 * @pressured: the "pressured" signal.
 * @released: the "released" signal.
 * @clicked: the "clicked" signal.
 * @double_clicked: the "double-clicked" signal.
 * @scrolled: the "scrolled" signal.
 * @drag_begin: the "drag-begin" signal.
 * @drag_motion: the "drag-motion" signal.
 * @drag_end: the "drag-end" signal.
 * @motion: the "motion" signal.
 * @entered: the "entered" signal.
 * @left: the "left" signal.
 * @hide: the hide virtual method.
 * @show: the show virtual method.
 * @set_size: the set_size virtual method.
 * @set_position: the set_position virtual method.
 * @set_fg_color: the set_fg_color virtual method.
 * @set_bg_color: the set_bg_color virtual method.
 * @set_opacity: the set_opacity virtual method.
 *
 * The #PgmDrawable structure.
 */
struct _PgmDrawableClass {
  GstObjectClass parent_class;

  /*< public >*/

  /* Signals */

  void     (*changed)        (PgmDrawable *drawable,
                              PgmDrawableProperty property);

  gboolean (*pressed)        (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time,
                              guint32 pressure);

  gboolean (*pressured)      (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time,
                              guint32 pressure);

  gboolean (*released)       (PgmDrawable *drawable,
                              PgmButtonType button,
                              guint32 time);

  gboolean (*clicked)        (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time,
                              guint32 pressure);

  gboolean (*double_clicked) (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time);

  gboolean (*scrolled)       (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmScrollDirection direction,
                              guint32 time);

  gboolean (*drag_begin)     (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time,
                              guint32 pressure);

  gboolean (*drag_motion)    (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time,
                              guint32 pressure);

  gboolean (*drag_end)       (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              PgmButtonType button,
                              guint32 time);

  gboolean (*motion)         (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              guint32 time);

  gboolean (*entered)        (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              guint32 time);

  gboolean (*left)           (PgmDrawable *drawable,
                              gfloat x,
                              gfloat y,
                              gfloat z,
                              guint32 time);

  /* virtual methods for subclasses */

  PgmError (*hide)                      (PgmDrawable *drawable);

  PgmError (*show)                      (PgmDrawable *drawable);

  PgmError (*set_size)                  (PgmDrawable *drawable,
                                         gfloat width,
                                         gfloat height);

  PgmError (*set_position)              (PgmDrawable *drawable,
                                         gfloat x,
                                         gfloat y,
                                         gfloat z);

  PgmError (*set_fg_color)              (PgmDrawable *drawable,
                                         guchar r,
                                         guchar g,
                                         guchar b,
                                         guchar a);

  PgmError (*set_bg_color)              (PgmDrawable *drawable,
                                         guchar r,
                                         guchar g,
                                         guchar b,
                                         guchar a);

  PgmError (*set_opacity)               (PgmDrawable *drawable,
                                         guchar opacity);
};

GType    pgm_drawable_get_type          (void);

PgmError pgm_drawable_hide              (PgmDrawable *drawable);
PgmError pgm_drawable_show              (PgmDrawable *drawable);
PgmError pgm_drawable_is_visible        (PgmDrawable *drawable,
                                         gboolean *visible);

PgmError pgm_drawable_set_size          (PgmDrawable *drawable,
                                         gfloat width,
                                         gfloat height);
PgmError pgm_drawable_get_size          (PgmDrawable *drawable,
                                         gfloat *width,
                                         gfloat *height);

PgmError pgm_drawable_set_position      (PgmDrawable *drawable,
                                         gfloat x,
                                         gfloat y,
                                         gfloat z);
PgmError pgm_drawable_get_position      (PgmDrawable *drawable,
                                         gfloat *x,
                                         gfloat *y,
                                         gfloat *z);

PgmError pgm_drawable_set_rotation_x    (PgmDrawable *drawable,
                                         gfloat angle);
PgmError pgm_drawable_get_rotation_x    (PgmDrawable *drawable,
                                         gfloat *angle);

PgmError pgm_drawable_set_rotation_y    (PgmDrawable *drawable,
                                         gfloat angle);
PgmError pgm_drawable_get_rotation_y    (PgmDrawable *drawable,
                                         gfloat *angle);

PgmError pgm_drawable_set_rotation_z    (PgmDrawable *drawable,
                                         gfloat angle);
PgmError pgm_drawable_get_rotation_z    (PgmDrawable *drawable,
                                         gfloat *angle);

PgmError pgm_drawable_set_scale         (PgmDrawable *drawable,
                                         gfloat scale);
PgmError pgm_drawable_get_scale         (PgmDrawable *drawable,
                                         gfloat *scale);

PgmError pgm_drawable_set_fg_color      (PgmDrawable *drawable,
                                         guchar r,
                                         guchar g,
                                         guchar b,
                                         guchar a);
PgmError pgm_drawable_get_fg_color      (PgmDrawable *drawable,
                                         guchar *r,
                                         guchar *g,
                                         guchar *b,
                                         guchar *a);

PgmError pgm_drawable_set_bg_color      (PgmDrawable *drawable,
                                         guchar r,
                                         guchar g,
                                         guchar b,
                                         guchar a);
PgmError pgm_drawable_get_bg_color      (PgmDrawable *drawable,
                                         guchar *r,
                                         guchar *g,
                                         guchar *b,
                                         guchar *a);

PgmError pgm_drawable_set_opacity       (PgmDrawable *drawable,
                                         guchar opacity);
PgmError pgm_drawable_get_opacity       (PgmDrawable *drawable,
                                         guchar *opacity);

PgmError pgm_drawable_set_grid_aligned  (PgmDrawable *drawable,
                                         gboolean aligned);
PgmError pgm_drawable_get_grid_aligned  (PgmDrawable *drawable,
                                         gboolean *aligned);

PgmError pgm_drawable_set_drag_distance (PgmDrawable *drawable,
                                         guchar distance);
PgmError pgm_drawable_get_drag_distance (PgmDrawable *drawable,
                                         guchar *distance);

PgmError pgm_drawable_regenerate        (PgmDrawable *drawable);

PgmError pgm_drawable_from_canvas       (PgmDrawable *drawable,
                                         gfloat *x_drawable,
                                         gfloat *y_drawable,
                                         gfloat  x_canvas,
                                         gfloat  y_canvas,
                                         gfloat  z_canvas);

PgmError pgm_drawable_to_canvas         (PgmDrawable *drawable,
                                         gfloat *x_canvas,
                                         gfloat *y_canvas,
                                         gfloat *z_canvas,
                                         gfloat  x_drawable,
                                         gfloat  y_drawable);


/* Protected methods */

void _pgm_drawable_emit_changed      (PgmDrawable *drawable,
                                      PgmDrawableProperty property);

void _pgm_drawable_do_press_event    (PgmDrawable *drawable,
                                      PgmEventButton *event,
                                      PgmVec3 *p1,
                                      PgmVec3 *p2,
                                      guint16 *emission_mask);

void _pgm_drawable_do_pressure_event (PgmDrawable *drawable,
                                      PgmEventButton *event,
                                      PgmVec3 *p1,
                                      PgmVec3 *p2,
                                      guint16 *emission_mask);

void _pgm_drawable_do_release_event  (PgmDrawable *drawable,
                                      PgmEventButton *event,
                                      PgmVec3 *p1,
                                      PgmVec3 *p2,
                                      guint16 *emission_mask);

void _pgm_drawable_do_motion_event   (PgmDrawable *drawable,
                                      PgmEventMotion *event,
                                      PgmVec3 *p1,
                                      PgmVec3 *p2,
                                      guint16 *emission_mask);

void _pgm_drawable_do_scroll_event   (PgmDrawable *drawable,
                                      PgmEventScroll *event,
                                      PgmVec3 *p1,
                                      PgmVec3 *p2,
                                      guint16 *emission_mask);

G_END_DECLS

#endif /* __PGM_DRAWABLE_H__ */
