/* Copyright (c) 1997 The Regents of the University of California.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* a header for canvas objects that hold lists of t_gobjs, such as
*  canvases themselves or graphs
*/

/* --------------------- geometry ---------------------------- */
#define IOWIDTH 7
#define IOMIDDLE 3
#define IOTOPMARGIN 1
#define IOBOTTOMMARGIN 1

/* ----------------------- data ------------------------------- */

EXTERN_STRUCT _rtext;
#define t_rtext struct _rtext

EXTERN_STRUCT _field;
#define t_field struct _field

typedef struct _selection
{
    t_gobj *sel_what;
    struct _selection *sel_next;
} t_selection;

typedef struct _editor
{
    t_rtext *e_rtext;	    	    /* text responder linked list */
    t_selection *e_selection;  	    /* head of the selection list */
    t_rtext *e_textedfor;   	    /* the rtext if any that we are editing */
    t_gobj *e_grab;	    	    /* object being "dragged" */
    t_binbuf *e_connectbuf;	    /* connections to deleted objects */
    t_binbuf *e_deleted;    	    /* last stuff we deleted */
    short e_xwas;   	    	    /* xpos on last mousedown or motion event */
    short e_ywas;   	    	    /* ypos, similarly */
    unsigned int e_onmotion: 3;     /* action to take on motion */
    unsigned int e_lastmoved: 1;    /* one if mouse has moved since click */
    unsigned int e_textdirty: 1;    /* one if e_textedfor has changed */
} t_editor;

#define MA_NONE    0 	/* do nothing on mouse motion */
#define MA_MOVE    1	/* drag the selection around */
#define MA_CONNECT 2	/* make a connection */
#define MA_REGION  3	/* selection region */
#define MA_PASSOUT 4	/* send on to e_grab */

typedef struct _tick	/* where to put ticks on x or y axes */
{
    float k_point;  	/* one point to draw a big tick at */
    float k_inc;    	/* x or y increment per little tick */
    int k_lperb;    	/* little ticks per big; 0 if no ticks to draw */
} t_tick;

typedef struct _glist
{
    t_gobj gl_gobj;
    t_gobj *gl_list;
    struct _glist *gl_owner;
    float gl_px1;   	    	/* bounding rectangle in parent's coords */
    float gl_py1;
    float gl_px2;
    float gl_py2;
    float gl_x1;    	    	/* ... and in our own coordinates */
    float gl_y1;
    float gl_x2;
    float gl_y2;
    t_tick gl_xtick; 	    	/* ticks marking X values */    
    t_tick gl_ytick;	    	    /* ... and Y values */
    int gl_nxlabels;	    	/* X coordinate labels */
    t_symbol **gl_xlabel;
    float gl_xlabely;	    	    /* ... and their Y coordinates */
    int gl_nylabels;    	/* Y coordinate labels */
    t_symbol **gl_ylabel;
    float gl_ylabelx;
    t_editor *gl_editor;    	/* editor structure when visible */
    t_symbol *gl_name;	    	/* symbol bound here */
    int gl_valid;   	    	/* incremented when pointers might be stale */
    struct _gstub *gl_stub;
} t_glist;

#define gl_pd gl_gobj.g_pd


/* a data structure to describe a field in a pure datum */

#define DT_FLOAT 0
#define DT_SYMBOL 1
#define DT_LIST 2
#define DT_ARRAY 3

typedef struct _datatype
{
    int dt_type;
    t_symbol *dt_name;
    t_symbol *dt_arraytemplate;	    /* filled in for arrays only */
} t_datatype;

struct _array
{
    int a_n;
    int a_elemsize; 	/* should just look this up... */
    t_word *a_vec;
    int a_valid;
    t_gpointer a_gp;	/* pointer to scalar or array element we're in */
    t_gstub *a_stub;
};


/* function types used to define graphical behavior for gpbjs, a bit like X
widgets.  These aren't Pd methods because Pd's typechecking can't specify the
types of pointer arguments.  Also it's more convenient this way, since
every "patchable" object can just get the "text" behaviors. */

    	/* Call this to get a gobj's bounding rectangle in pixels */
typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
    int *x1, int *y1, int *x2, int *y2);
    	/* and this to displace a gobj: */
typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
    	/* change color to show selection: */
typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
    	/* change appearance to show activation/deactivation: */
typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
    	/* warn a gobj it's about to be deleted */
typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
    	/*  making visible or invisible */
typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
    	/*  save to a binbuf */
typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
    	/* ... and later, resizing; getting/setting color... */

struct _widgetbehavior
{
    t_getrectfn w_getrectfn;
    t_displacefn w_displacefn;
    t_selectfn w_selectfn;
    t_activatefn w_activatefn;
    t_deletefn w_deletefn;
    t_visfn w_visfn;
    t_savefn w_savefn;
};

/* -----------  behaviors on the parent window ------------- */
    	/* bounding rectangle: */
typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
    t_word *data, t_canvas *template, float basex, float basey,
    int *x1, int *y1, int *x2, int *y2);
    	/* displace it */
typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist, 
    t_word *data, t_canvas *template, float basex, float basey,
    int dx, int dy);
    	/* change color to show selection */
typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
    t_word *data, t_canvas *template, float basex, float basey,
    int state);
    	/* change appearance to show activation/deactivation: */
typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
    t_word *data, t_canvas *template, float basex, float basey,
    int state);
    	/*  making visible or invisible */
typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
    t_word *data, t_canvas *template, float basex, float basey,
    int flag);

struct _parentwidgetbehavior
{
    t_parentgetrectfn w_parentgetrectfn;
    t_parentdisplacefn w_parentdisplacefn;
    t_parentselectfn w_parentselectfn;
    t_parentactivatefn w_parentactivatefn;
    t_parentvisfn w_parentvisfn;
};

extern t_canvas *canvas_editing;    /* last canvas to start text edting */ 
extern t_class *vinlet_class, *voutlet_class;

/* ------------------- functions on any gobj ----------------------------- */
void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1,
    int *x2, int *y2);
void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy);
void gobj_select(t_gobj *x, t_glist *owner, int state);
void gobj_activate(t_gobj *x, t_glist *owner, int state);
void gobj_delete(t_gobj *x, t_glist *owner);
void gobj_vis(t_gobj *x, t_glist *glist, int flag);
void gobj_save(t_gobj *x, t_binbuf *b);

/* -------------------- functions on glists --------------------- */
void glist_add(t_glist *x, t_gobj *g);
t_canvas *glist_getcanvas(t_glist *x);
void glist_init(t_glist *x);
int glist_isselected(t_glist *x, t_gobj *y);
void glist_select(t_glist *x, t_gobj *y);
void glist_deselect(t_glist *x, t_gobj *y);
void glist_noselect(t_glist *x);
void glist_selectall(t_glist *x);
void glist_delete(t_glist *x, t_gobj *y);
void glist_retext(t_glist *x, t_text *y);
void glist_grab(t_glist *x, t_gobj *y, t_int xpos, t_int ypos);
int  glist_isvisible(t_glist *x);
t_glist *glist_findgraph(t_glist *x, float x1, float x2, float y1, float y2);
int glist_getfont(t_glist *x);

float glist_pixelstox(t_glist *x, float xpix);
float glist_pixelstoy(t_glist *x, float ypix);
float glist_xtopixels(t_glist *x, float xval);
float glist_ytopixels(t_glist *x, float yval);

void glist_redrawitem(t_glist *owner, t_gobj *gobj);
void glist_cleanup(t_glist *x);

/* -------------------- functions on texts ------------------------- */
void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
void text_drawborder(t_text *x, t_glist *glist, char *tag,
    int width, int height, int firsttime);
void text_eraseborder(t_text *x, t_glist *glist, char *tag);

/* -------------------- functions on rtexts ------------------------- */
t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next);
t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
t_rtext *glist_findrtext(t_glist *gl, t_text *who);
int rtext_height(t_rtext *x);
void rtext_displace(t_rtext *x, int dx, int dy);
void rtext_select(t_rtext *x, int state);
void rtext_activate(t_rtext *x, int state);
void rtext_free(t_rtext *x);
void rtext_key(t_rtext *x, int key);
void rtext_retext(t_rtext *x);
int rtext_width(t_rtext *x);
int rtext_height(t_rtext *x);
char *rtext_gettag(t_rtext *x);
void rtext_gettext(t_rtext *x, char **buf, int *bufsize);

/* ---------------------- functions on subcanvases --------------------- */

t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
void canvas_rminlet(t_canvas *x, t_inlet *ip);
t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
void canvas_rmoutlet(t_canvas *x, t_outlet *op);

/* -------------------- functions on canvases ------------------------ */
extern t_class *graph_class, *canvas_class;

void canvas_vistext(t_canvas *x, t_text *y);
void canvas_fixlinesfor(t_canvas *x, t_text *text);
void canvas_deletelinesfor(t_canvas *x, t_text *text);
void canvas_stowconnections(t_canvas *x);
void canvas_restoreconnections(t_canvas *x);
int canvas_template_size(t_canvas *x);
t_field *canvas_find_field(t_canvas *x, t_symbol *name, int *onset);
t_float canvas_getfloat(t_canvas *x, t_symbol *fieldname, t_word *wp, int loud);
void canvas_setfloat(t_canvas *x, t_symbol *fieldname, t_word *wp,
    t_float f, int loud);
t_datatype *canvas_getdatatypes(t_canvas *x, int *nitems);
void canvas_redrawallfortemplate(t_canvas *template);
void canvas_zapallfortemplate(t_canvas *template);
void canvas_setusedastemplate(t_canvas *x);

t_canvas *canvas_getcurrent(void);
t_canvas *canvas_setcurrent(t_canvas *x);
t_canvas *canvas_unsetcurrent(t_canvas *x);
t_canvas *canvas_getrootfor(t_canvas *x);
void canvas_dirty(t_canvas *x, t_int n);
int canvas_isvisible(t_canvas *x);
int canvas_getfont(t_canvas *x);

typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3);

t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn,
    t_int x1, t_int x2, t_int x3);

void canvas_resortinlets(t_canvas *x);
void canvas_resortoutlets(t_canvas *x);

/* -------------------- functions on fields --------------------------- */
extern t_class *field_class;
int field_size(t_field *x);
int field_type(t_field *x); 	    	/* one of DT_FLOAT, etc */
t_symbol *field_arraytemplate(t_field *x);
t_symbol *field_name(t_field *x);

/* --------- functions on garrays (graphical arrays) -------------------- */
t_canvas *garray_template(t_garray *x);

/* -------------------- arrays --------------------- */
t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
void array_resize(t_array *x, t_symbol *templatesym, int n);
void array_free(t_array *x);

/* --------------------- gpointers and stubs ---------------- */
t_gstub *gstub_new(t_glist *gl, t_array *a);
void gstub_cutoff(t_gstub *gs);

/* --------------------- other ------------------------- */
void word_restore(t_word *wp, t_datatype *datatypes, int nitems,
    int argc, t_atom *argv, t_gpointer *gp);

