/* NOTE: include this file by including gdambufferviewport.h.
 *       do not include this file directly!
 */

#if defined(__GDAM_BUFFER_VIEWPORT_RENDER_H_) || \
   !defined(__GDAM_BUFFER_VIEWPORT_H_)
#error "gdambufferviewport-render.h should not be included directly"
#endif
#define __GDAM_BUFFER_VIEWPORT_RENDER_H_

typedef struct _GdamBufferViewportAdornment GdamBufferViewportAdornment;
typedef struct _GdamBufferViewportBeatInfo GdamBufferViewportBeatInfo;
typedef struct _GdamBufferViewportBeatArray GdamBufferViewportBeatArray;
typedef struct _GdamBufferViewportMarker GdamBufferViewportMarker;
typedef struct _GdamBufferViewportMarkerData GdamBufferViewportMarkerData;

/* --- generic waveform rendering --- */
typedef struct _GdamBufferViewportRenderInfo GdamBufferViewportRenderInfo;
struct _GdamBufferViewportRenderInfo
{
  GdkDrawable        *drawable;
  gpointer            data;
  GdamBufferViewport *viewport;
  gboolean            is_double;
  guint               num_columns;
  guint               num_rows;
  guint		      valid_output_start;
  guint		      valid_output_end;
  gpointer            values;
  guint               x;
  guint               y;
  guint               width;
  guint               height;
  guint               draw_width;
  guint               draw_height;
  gboolean            has_selection;
  gint                selection_start;
  gint                selection_end;
};
typedef gpointer (*GdamBufferViewportRenderInitFunc)
  					(GdamBufferViewportRenderInfo*);
typedef void     (*GdamBufferViewportRenderFunc)(GdamBufferViewportRenderInfo*,
						 gpointer render_data);

void  gdam_buffer_viewport_set_render_func    (GdamBufferViewport *viewport,
					       const char *mode_name,
					       GdamBufferViewportRenderInitFunc,
                                               GdamBufferViewportRenderFunc bg,
                                               GdamBufferViewportRenderFunc fg,
					       GDestroyNotify render_data_done,
                                               gpointer            render_data,
                                               GDestroyNotify      destroy);

/* --- specific waveform rendering modes --- */
void  gdam_buffer_viewport_set_render_waveform(GdamBufferViewport *viewport,
                                               GdkGC              *fg_gc,
                                               GdkGC              *bg_gc);
void  gdam_buffer_viewport_set_render_2d_tmp  (GdamBufferViewport *viewport);

/* --- an entirely external "helper" function --- */
void  gdam_buffer_viewport_render_to_drawable (GdkDrawable        *drawable,
					       GdkGC              *fg_gc,
					       GdkGC              *bg_gc,
					       gboolean            is_double,
					       guint               num_samples,
					       gpointer            samples,
                                               guint               x,
                                               guint               y,
                                               guint               width,
                                               guint               height,
                                               guint               draw_width,
                                               guint               draw_height,
                                               gboolean            has_selection,
                                               gint                selection_start,
                                               gint                selection_end);

/* --- methods for dealing with generic "adornments" --- */
typedef struct _GdamBufferViewportAdornFuncs GdamBufferViewportAdornFuncs;

typedef struct _GdamBufferViewportDragInfo GdamBufferViewportDragInfo;
struct _GdamBufferViewportDragInfo
{
  gint start_x, start_y;
  gdouble start_time;
  gint last_x, last_y;
  gdouble last_time;
  gint end_x, end_y;
  gdouble end_time;
  gint button;
  GdkModifierType modifiers;
};

struct _GdamBufferViewportAdornFuncs
{
  /* drawing */
  gboolean       (*render)        (GdamBufferViewport *viewport,
                                   GdkDrawable        *drawable,
                                   gpointer            data,
                                   guint               x,
                                   guint               y,
                                   guint               width,
                                   guint               height);
  GdamCursorType (*get_cursor)    (GdamBufferViewport *viewport,
				   gpointer            data);

  /* dragging */
  gboolean       (*start_drag)    (GdamBufferViewportAdornment *adorn,
				   GdamBufferViewportDragInfo *drag_info);
  gboolean       (*keep_dragging) (GdamBufferViewportAdornment *adorn,
				   GdamBufferViewportDragInfo *drag_info);
  gboolean       (*end_drag)      (GdamBufferViewportAdornment *adorn,
				   GdamBufferViewportDragInfo *drag_info);

  /* lifetime */
  void     (*destroy)       (gpointer            data);
};

GdamBufferViewportAdornment *
    gdam_buffer_viewport_add_adornment (GdamBufferViewport           *viewport,
					gboolean                      is_shown,
					gboolean                      is_under,
                                        GdamBufferViewportAdornFuncs *funcs,
                                        gpointer                    adorn_data);


/* adornment change notification */

/* TODO: need hints or something for optimization
 * (i.e. small change optimizations)
 */
typedef gboolean (*GdamBufferViewportAdornmentChange) 
                                (GdamBufferViewportAdornment *adornment,
                                 gpointer                     data);
void gdam_buffer_viewport_trap_adornment_changed
                                  (GdamBufferViewportAdornment *adornment,
                                   GdamBufferViewportAdornmentChange func,
                                   gpointer                     data,
                                   GDestroyNotify               destroy);
void gdam_buffer_viewport_adornment_changed
                                  (GdamBufferViewportAdornment *adornment);
void gdam_buffer_viewport_adornment_changed_part
                                  (GdamBufferViewportAdornment *adornment,
				   guint                        x,
				   guint                        y,
				   guint                        width,
				   guint                        height);

/* --- return a list of GdamBufferViewportAdornment's of a specific type --- */
GSList *gdam_buffer_viewport_get_adornments_by_func
                                    (GdamBufferViewport           *viewport,
                                     GdamBufferViewportAdornFuncs *funcs);

/*< private >*/
/* The contents of some opaque structures. */

/* A notification hook for an adornment. */
typedef struct _GdamBufferViewportAdornHook GdamBufferViewportAdornHook;
struct _GdamBufferViewportAdornHook
{
  GdamBufferViewportAdornmentChange func;
  gpointer                          data;
  GDestroyNotify                    destroy;
  GdamBufferViewportAdornHook      *next;
};


/* a node in the list of adornments */
struct _GdamBufferViewportAdornment
{
  GdamBufferViewport *viewport;
  GdamBufferViewportAdornFuncs *funcs;
  gpointer data;

  /* private */
  gboolean is_shown;
  gboolean is_under;

  GdamBufferViewportAdornment *prev;
  GdamBufferViewportAdornment *next;

  GdamBufferViewportAdornHook *first_hook;
  GdamBufferViewportAdornHook *last_hook;
};

/* data for the beat-info adornment */
struct _GdamBufferViewportBeatInfo
{
  /* Beat lines. */
  gboolean              is_draggable;
  int                   dragging_beat_line;
  int                   num_beats;
  gdouble               start;
  gdouble               beat_period;
  GdkGC                *beat_line_gc;
};

GdamBufferViewportAdornment *gdam_buffer_viewport_add_beat_info
                                        (GdamBufferViewport    *viewport,
					 gboolean               is_shown,
					 gboolean               is_under,
                                         gboolean               is_draggable,
                                         guint                  num_beats,
                                         gdouble                start_beat,
                                         gdouble                beat_period,
                                         GdkGC                 *beat_line_gc);
GdamBufferViewportAdornment *gdam_buffer_viewport_add_beat_array
                                        (GdamBufferViewport    *viewport,
					 gboolean               is_shown,
					 gboolean               is_under,
                                         gboolean               is_draggable,
                                         guint                  num_beats,
                                         const gdouble         *beats,
                                         GdkGC                 *beat_line_gc);
GdamBufferViewportAdornment * gdam_buffer_viewport_add_markers
                                        (GdamBufferViewport    *viewport,
				         gboolean               is_shown,
					 gboolean               is_under,
                                         GdkFont               *marker_font,
                                         GdkGC                 *marker_gc,
                                         GdkColor              *marker_color,
                                         const char            *marker_format,
                                         gdouble                marker_unit);

/* data for the beat-array adornment */
struct _GdamBufferViewportBeatArray
{
  /* Beat lines. */
  gboolean              is_draggable;
  int                   dragging_beat;
  int                   num_beats;
  gdouble              *beats;
  GdkGC                *beat_gc;
  gint                  beat_radius;
};

/* data for the marker adornment */
struct _GdamBufferViewportMarker
{
  int            draw_x;
  int            draw_y;
  int            draw_width;
  char          *text;
};

struct _GdamBufferViewportMarkerData
{
  guint                     num_markers;
  GdamBufferViewportMarker *markers;

  /* For figuring if the markers have to be recomputed. */
  gdouble                   old_time_start;
  gdouble                   old_time_length;
  gint                      old_draw_width;

  /* Marker drawing information. */
  GdkFont                  *marker_font;
  GdkGC                    *marker_gc;
  GdkColor                 *marker_color;
  char                     *marker_format;
  gdouble                   marker_unit;
};
