Skip to content
Snippets Groups Projects
g_text.c 92 KiB
Newer Older
Miller Puckette's avatar
Miller Puckette committed
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
/* the methods for calling the gui-objects from menu are implemented */
/* all changes are labeled with      iemlib      */

#include <stdlib.h>
#include "m_pd.h"
#include "m_imp.h"
#include "s_stuff.h"
#include "g_canvas.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
Miller Puckette's avatar
Miller Puckette committed
t_class *text_class;
t_class *message_class;
static t_class *gatom_class;
Miller Puckette's avatar
Miller Puckette committed
static void text_vis(t_gobj *z, t_glist *glist, int vis);
static void text_displace(t_gobj *z, t_glist *glist,
    int dx, int dy);
static void text_getrect(t_gobj *z, t_glist *glist,
    int *xp1, int *yp1, int *xp2, int *yp2);
void canvas_howputnew(t_canvas *x, int *connectp, int *xpixp, int *ypixp,
    int *indexp, int *totalp);
Miller Puckette's avatar
Miller Puckette committed

void canvas_startmotion(t_canvas *x);
t_widgetbehavior text_widgetbehavior;

static char *invalid_fill = "$::pd_colors(dash_fill)";
extern void canvas_displaceselection(t_canvas *x, int dx, int dy);
extern void canvas_apply_setundo(t_canvas *x, t_gobj *y);
extern void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
    const char *name);
extern void *canvas_undo_set_create(t_canvas *x);
extern void canvas_undo_create(t_canvas *x, void *z, int action);
extern void glob_preset_node_list_check_loc_and_update(void);
extern void glob_preset_node_list_seek_hub(void);
Miller Puckette's avatar
Miller Puckette committed
/* ----------------- the "text" object.  ------------------ */

    /* add a "text" object (comment) to a glist.  While this one goes for any
    glist, the other 3 below are for canvases only.  (why?)  This is called
    without args if invoked from the GUI; otherwise at least x and y
    are provided.  */

void glist_text(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
Miller Puckette's avatar
Miller Puckette committed
    t_text *x = (t_text *)pd_new(text_class);
    t_atom at;
    x->te_width = 0;                            /* don't know it yet. */
    x->te_type = T_TEXT;
Miller Puckette's avatar
Miller Puckette committed
    x->te_binbuf = binbuf_new();
    if (argc > 1)
    {
        x->te_xpix = atom_getfloatarg(0, argc, argv);
        x->te_ypix = atom_getfloatarg(1, argc, argv);
            binbuf_restore(x->te_binbuf, argc-2, argv+2);
        }
Miller Puckette's avatar
Miller Puckette committed
        else
        {
            SETSYMBOL(&at, gensym("comment"));
            binbuf_restore(x->te_binbuf, 1, &at);
        }
        glist_add(gl, &x->te_g);
    }
    else
    {
        //int xpix, ypix;
        int connectme, xpix, ypix, indx, nobj;
        canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);
Miller Puckette's avatar
Miller Puckette committed
        pd_vmess((t_pd *)glist_getcanvas(gl), gensym("editmode"), "i", 1);
        SETSYMBOL(&at, gensym("comment"));
        glist_noselect(gl);
        //glist_getnextxy(gl, &xpix, &ypix);
        x->te_xpix = xpix;
        x->te_ypix = ypix;
Miller Puckette's avatar
Miller Puckette committed
        binbuf_restore(x->te_binbuf, 1, &at);
        glist_add(gl, &x->te_g);
        glist_noselect(gl);
        glist_select(gl, &x->te_g);
            /* it would be nice to "activate" here, but then the second,
            "put-me-down" click changes the text selection, which is quite
            irritating, so I took this back out.  It's OK in messages
            and objects though since there's no text in them at menu
            creation. */
            /* gobj_activate(&x->te_g, gl, 1); */
        if (!we_are_undoing)
            canvas_undo_add(glist_getcanvas(gl), 9, "create",
                (void *)canvas_undo_set_create(glist_getcanvas(gl)));
            canvas_displaceselection(glist_getcanvas(gl), -8, -8);
            canvas_startmotion(glist_getcanvas(gl));
        }
    glob_preset_node_list_seek_hub();
    glob_preset_node_list_check_loc_and_update();
Miller Puckette's avatar
Miller Puckette committed
}

/* ----------------- the "object" object.  ------------------ */

extern t_pd *newest;
extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv);
Miller Puckette's avatar
Miller Puckette committed
void canvas_getargs(int *argcp, t_atom **argvp);

static void canvas_objtext(t_glist *gl, int xpix, int ypix,
    int width, int selected,
Miller Puckette's avatar
Miller Puckette committed
    t_binbuf *b)
{
    //fprintf(stderr,"canvas_objtext\n");
Miller Puckette's avatar
Miller Puckette committed
    t_text *x;
    int argc;
    t_atom *argv;
    // for hiding arguments
    t_atom *vec;
    int len, i, hidden;
    t_binbuf *hide;
Miller Puckette's avatar
Miller Puckette committed
    newest = 0;
    canvas_setcurrent((t_canvas *)gl);
    canvas_getargs(&argc, &argv);
    binbuf_eval(b, &pd_objectmaker, argc, argv);
    if (binbuf_getnatom(b))
    {
        if (!newest)
        {
            /* let's see if there's a scalar by this name... */
            t_atom *scalar_at = binbuf_getvec(b);
            if (scalar_at->a_type == A_SYMBOL)
            {
                t_symbol *templatesym = 
                    canvas_makebindsym(atom_getsymbol(scalar_at));
                t_template *tmpl = template_findbyname(templatesym);
                if (template_findbyname(templatesym) &&
                    template_cancreate(tmpl) &&
                    template_hasxy(tmpl))
                    //post("Hmm, found a scalar from struct %s... ",
                    //    templatesym->s_name);
                    t_binbuf *scalarbuf = binbuf_new();
                    t_atom coords_at[2];
                    SETFLOAT(coords_at, (t_float)xpix);
                    SETFLOAT(coords_at+1, (t_float)ypix);
                    binbuf_add(scalarbuf, 1, scalar_at);
                    binbuf_add(scalarbuf, 2, coords_at);
                    binbuf_add(scalarbuf, binbuf_getnatom(b)-1, scalar_at+1);
                    t_atom *scalar_create_at = binbuf_getvec(scalarbuf);
                    glist_scalar(gl, gensym("scalar_from_canvas_objtext"),
                        binbuf_getnatom(b)+2, scalar_create_at);
Miller Puckette's avatar
Miller Puckette committed
            binbuf_print(b);
            post("... couldn't create");
            x = 0;
        }
        else if (!(x = pd_checkobject(newest)))
        {
            binbuf_print(b);
            post("... didn't return a patchable object");
        }
    }
    else x = 0;
    if (!x)
    {
        /* LATER make the color reflect this */
        x = (t_text *)pd_new(text_class);
        //fprintf(stderr,"creating blank object %lx\n", x);
    }
    /* special case: an object, like preset_hub, hides its arguments
       beyond the first n, so we modify its binbuf here */
    vec = binbuf_getvec(b);
    len = binbuf_getnatom(b);
    hidden = 0;
    for (i = 0; i < len; i++)
    {
        if (!strcmp("%hidden%", atom_getsymbol(&vec[i])->s_name))
        {
            //fprintf(stderr,"found hidden %d %s\n",
            //    i, atom_getsymbol(&vec[i])->s_name);
            hidden = i;
            break;
        }
    }
    if (hidden)
    {
        hide = binbuf_new();
        binbuf_add(hide, hidden, vec);
        binbuf_free(b);
        b = hide;
    }
    /* done special case */
Miller Puckette's avatar
Miller Puckette committed
    x->te_binbuf = b;
Miller Puckette's avatar
Miller Puckette committed
    x->te_xpix = xpix;
    x->te_ypix = ypix;
Miller Puckette's avatar
Miller Puckette committed
    x->te_type = T_OBJECT;
    /* let's see if iemgui objects did not already set the value to 1,
       otherwise set it explicitly to 0 */
    if (x->te_iemgui != 1)
        x->te_iemgui = 0;
Miller Puckette's avatar
Miller Puckette committed
    glist_add(gl, &x->te_g);
Miller Puckette's avatar
Miller Puckette committed
    if (selected)
    {
            /* this is called if we've been created from the menu. */
        glist_select(gl, &x->te_g);
        gobj_activate(&x->te_g, gl,
            2); // <-- hack to signal that we're a new object
Miller Puckette's avatar
Miller Puckette committed
    }
    if (pd_class(&x->ob_pd) == vinlet_class)
        canvas_resortinlets(glist_getcanvas(gl));
    if (pd_class(&x->ob_pd) == voutlet_class)
        canvas_resortoutlets(glist_getcanvas(gl));
    canvas_unsetcurrent((t_canvas *)gl);

    glob_preset_node_list_seek_hub();
    glob_preset_node_list_check_loc_and_update();

    // here we recreate data buffer inside previously created undo snapshot
    //canvas_undo_create(glist_getcanvas(gl),
    //    glist_getcanvas(gl)->u_last->data, UNDO_FREE);
    //glist_getcanvas(gl)->u_last->data =
    //    canvas_undo_set_create(glist_getcanvas(gl));
    /*if (binbuf_getnatom(x->te_binbuf) && !we_are_undoing) {
        fprintf(stderr,"canvas_objtext calls create undo\n");
        //glist_select(gl, &x->te_g);
        canvas_undo_add(glist_getcanvas(gl), 9, "create",
            (void *)canvas_undo_set_create(glist_getcanvas(gl)));
    }*/
    if ( glist_isvisible( ((t_canvas *)gl) ) )
    {
extern t_gobj *glist_nth(t_glist *x, int n);
extern int glist_getindex(t_glist *x, t_gobj *y);
Miller Puckette's avatar
Miller Puckette committed
    /* utility routine to figure out where to put a new text box from menu
    and whether to connect to it automatically */
void canvas_howputnew(t_canvas *x, int *connectp, int *xpixp, int *ypixp,
Miller Puckette's avatar
Miller Puckette committed
    int *indexp, int *totalp)
{
Mathieu L Bouchard's avatar
Mathieu L Bouchard committed
    int indx = 0, nobj = 0, n2, x1, x2, y1, y2;
    /*
    int connectme = 0;
    if (x->gl_editor->e_selection &&
        !x->gl_editor->e_selection->sel_next &&
        !sys_noautopatch)
    {
        selected = x->gl_editor->e_selection->sel_what;
        t_object *ob = pd_checkobject(&selected->g_pd);
        connectme = (obj_noutlets(ob) ? 1 : 0);
    }*/
    int connectme = (x->gl_editor->e_selection &&
        !x->gl_editor->e_selection->sel_next);
Miller Puckette's avatar
Miller Puckette committed
    if (connectme)
    {
Miller Puckette's avatar
Miller Puckette committed
        t_gobj *g, *selected = x->gl_editor->e_selection->sel_what;
        t_text *t = (t_text *)selected;
        int recreate = 0;
        // if selected object has not yet been activated we need to recreate it first
        if (pd_class(&t->te_pd) == text_class && t->te_type != T_TEXT)
Miller Puckette's avatar
Miller Puckette committed
        {
            glist_noselect(x); // we do this to explicitly activate object
            glist_select(x, glist_nth(x, glist_getindex(x, 0)-1)); // then reselect it
            selected = x->gl_editor->e_selection->sel_what;
            recreate = 1;
Miller Puckette's avatar
Miller Puckette committed
        }
        for (g = x->gl_list, nobj = 0; g; g = g->g_next, nobj++)
            if (g == selected)
            {
                gobj_getrect(g, x, &x1, &y1, &x2, &y2);
                indx = nobj;
                *xpixp = x1;
                *ypixp = y2 + 5;
            }
Miller Puckette's avatar
Miller Puckette committed
        glist_noselect(x);
            /* search back for 'selected' and if it isn't on the list, 
                plan just to connect from the last item on the list. */
        for (g = x->gl_list, n2 = 0; g; g = g->g_next, n2++)
        {
            if (g == selected)
            {
                indx = n2;
                break;
            }
            else if (!g->g_next)
                indx = nobj-1;
        }
        x->gl_editor->e_onmotion = MA_NONE;
Miller Puckette's avatar
Miller Puckette committed
    }
    else
    {
        glist_getnextxy(x, xpixp, ypixp);
        glist_noselect(x);
Miller Puckette's avatar
Miller Puckette committed
    }
    if (sys_noautopatch)
    {
        if (connectme == 1) connectme = -1;
        else connectme = 0;
    }
Miller Puckette's avatar
Miller Puckette committed
    *connectp = connectme;
    *indexp = indx;
    *totalp = nobj;
}

Miller Puckette's avatar
Miller Puckette committed
    /* object creation routine.  These are called without any arguments if
Miller Puckette's avatar
Miller Puckette committed
    they're invoked from the gui; when pasting or restoring from a file, we
    get at least x and y. */
Miller Puckette's avatar
Miller Puckette committed
void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    //fprintf(stderr,"canvas_obj\n");
Miller Puckette's avatar
Miller Puckette committed
    if (argc >= 2)
    {
        t_binbuf *b = binbuf_new();
        binbuf_restore(b, argc-2, argv+2);
        canvas_objtext(gl, atom_getintarg(0, argc, argv),
            atom_getintarg(1, argc, argv), 0, 0, b);
Miller Puckette's avatar
Miller Puckette committed
        /* JMZ: don't go into interactive mode in a closed canvas */
    else if (!glist_isvisible(gl))
        post("unable to create stub object in closed canvas!");
    else
    {
            /* interactively create new obect */
Miller Puckette's avatar
Miller Puckette committed
        t_binbuf *b = binbuf_new();
Miller Puckette's avatar
Miller Puckette committed
        int connectme, xpix, ypix, indx, nobj;
        canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);
Miller Puckette's avatar
Miller Puckette committed
        pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
        canvas_objtext(gl,
            connectme ? xpix : xpix - 8,
            connectme ? ypix : ypix - 8,
            0, 1, b);
        if (connectme == 1)
        {
            //fprintf(stderr,"canvas_obj calls canvas_connect\n");
            connect_exception = 1;
Miller Puckette's avatar
Miller Puckette committed
            canvas_connect(gl, indx, 0, nobj, 0);
            connect_exception = 0;
        }
        else if (connectme == 0)
        {
            //fprintf(stderr,"canvas_obj calls canvas_startmotion\n");
//            canvas_displaceselection(glist_getcanvas(gl), -8, -8);
            canvas_startmotion(glist_getcanvas(gl));
        }
        //canvas_setundo(glist_getcanvas(gl),
        //    canvas_undo_create, canvas_undo_set_create(gl), "create");
        if (!we_are_undoing)
            canvas_undo_add(glist_getcanvas(gl), 9, "create",
                (void *)canvas_undo_set_create(glist_getcanvas(gl)));
extern void glist_setlastxy(t_glist *gl, int xval, int yval);

/* invoked from tcl/tk: abstraction_name x_offset y_offset */
void canvas_obj_abstraction_from_menu(t_glist *gl, t_symbol *s,
    int argc, t_atom *argv)
    //fprintf(stderr,"canvas_abstraction_from_menu\n");
    int connectme, xpix, ypix, indx, nobj;
    canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);
    pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
    if (sys_k12_mode)
        pd_vmess (&gl->gl_pd, gensym("tooltips"), "i", 1);
    canvas_objtext(gl, xpix+atom_getintarg(1, argc, argv),
        ypix+atom_getintarg(2, argc, argv), 0, 1, b);

    // the object is now the last on the glist so we locate it
    // and send it loadbang
    // we know we have at least one object since we just created one
    // so we don't check for y being valid
    y = gl->gl_list;
    while (y->g_next)
        y = y->g_next;
    canvas_loadbang((t_canvas *)y);
        canvas_connect(gl, indx, 0, nobj, 0);
        //glist_setlastxy(glist_getcanvas(gl), xpix, ypix);
        canvas_startmotion(glist_getcanvas(gl));
    }
    canvas_undo_add(glist_getcanvas(gl), 9, "create",
        (void *)canvas_undo_set_create(glist_getcanvas(gl)));
Miller Puckette's avatar
Miller Puckette committed
/* make an object box for an object that's already there. */

/* iemlib */
void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
{
    //fprintf(stderr,"canvas_iemguis\n");
Miller Puckette's avatar
Miller Puckette committed
    t_atom at;
    t_binbuf *b = binbuf_new();
    if(!strcmp(guiobjname->s_name, "cnv"))
        glist_noselect(gl);
    int connectme, xpix, ypix, indx, nobj;
    canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);

    /* NOT NECESSARY ANY MORE: compensate for the iemgui sliders' xyoffset
       in case of autopatch
    if (connectme)
    {
        if(!strcmp(guiobjname->s_name, "hsl"))
            xpix = xpix + 3;
        else if(!strcmp(guiobjname->s_name, "vsl"))
            ypix = ypix + 2;
        else if(!strcmp(guiobjname->s_name, "vu"))
        {
            xpix = xpix + 1;
            ypix = ypix + 2;
        }
    }*/
    
Miller Puckette's avatar
Miller Puckette committed
    pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
    glist_noselect(gl);
    SETSYMBOL(&at, guiobjname);
    binbuf_restore(b, 1, &at);
    canvas_objtext(gl, xpix, ypix, 0, 1, b);
        canvas_connect(gl, indx, 0, nobj, 0);
    //glist_getnextxy(gl, &xpix, &ypix);
    //canvas_objtext(gl, xpix, ypix, 1, b);
        canvas_displaceselection(glist_getcanvas(gl), -8, -8);
        canvas_startmotion(glist_getcanvas(gl));
    }
    //canvas_setundo(glist_getcanvas(gl),
    //    canvas_undo_create, canvas_undo_set_create(gl), "create");
    canvas_undo_add(glist_getcanvas(gl), 9, "create",
        (void *)canvas_undo_set_create(glist_getcanvas(gl)));
Miller Puckette's avatar
Miller Puckette committed
}

void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("bng"));
}

void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("tgl"));
}

void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("vsl"));
}

void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("hsl"));
}

void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("hdl"));
}

void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("vdl"));
}

void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("hradio"));
}

void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("vradio"));
}

void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("vu"));
}

void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("cnv"));
}

void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_iemguis(gl, gensym("nbx"));
}

/* iemlib */

void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv)
{
    x->te_width = 0;                            /* don't know it yet. */
    x->te_type = T_OBJECT;
    x->te_binbuf = binbuf_new();
    x->te_xpix = atom_getfloatarg(0, argc, argv);
    x->te_ypix = atom_getfloatarg(1, argc, argv);
    if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
    glist_add(gl, &x->te_g);
}

/* ---------------------- the "message" text item ------------------------ */

typedef struct _messresponder
{
    t_pd mr_pd;
    t_outlet *mr_outlet;
} t_messresponder;

typedef struct _message
{
    t_text m_text;
    t_messresponder m_messresponder;
    t_glist *m_glist;
    t_clock *m_clock;
} t_message;

static t_class *messresponder_class;
Miller Puckette's avatar
Miller Puckette committed

static void messresponder_bang(t_messresponder *x)
{
    outlet_bang(x->mr_outlet);
}

static void messresponder_float(t_messresponder *x, t_float f)
{
    outlet_float(x->mr_outlet, f);
}

static void messresponder_symbol(t_messresponder *x, t_symbol *s)
{
    outlet_symbol(x->mr_outlet, s);
}

static void messresponder_blob(t_messresponder *x, t_blob *st)
{ /* MP 20070107 blob type */
    outlet_blob(x->mr_outlet, st);
}

Miller Puckette's avatar
Miller Puckette committed
static void messresponder_list(t_messresponder *x, 
    t_symbol *s, int argc, t_atom *argv)
{
    outlet_list(x->mr_outlet, s, argc, argv);
}

static void messresponder_anything(t_messresponder *x,
    t_symbol *s, int argc, t_atom *argv)
{
    outlet_anything(x->mr_outlet, s, argc, argv);
}

static void message_bang(t_message *x)
{
    binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 0, 0);
}

static void message_float(t_message *x, t_float f)
{
    t_atom at;
    SETFLOAT(&at, f);
    binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
}

static void message_symbol(t_message *x, t_symbol *s)
{
    t_atom at;
    SETSYMBOL(&at, s);
    binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
}

static void message_blob(t_message *x, t_blob *st)
{
    t_atom at;
    SETBLOB(&at, st);
    binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
}

Miller Puckette's avatar
Miller Puckette committed
static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
{
    // TODO: here and elsewhere in the message, do we want $0 to be parsed
    // into canvas instance? Makes sense since there is no such argument,
    // but will this break anything?
    //canvas_setcurrent(x->m_glist);
Miller Puckette's avatar
Miller Puckette committed
    binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv);
Miller Puckette's avatar
Miller Puckette committed
}

static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
{
    binbuf_clear(x->m_text.te_binbuf);
    binbuf_add(x->m_text.te_binbuf, argc, argv);
    glist_retext(x->m_glist, &x->m_text);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
{
    binbuf_add(x->m_text.te_binbuf, argc, argv);
    glist_retext(x->m_glist, &x->m_text);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
{
    binbuf_add(x->m_text.te_binbuf, argc, argv);
    binbuf_addsemi(x->m_text.te_binbuf);
    glist_retext(x->m_glist, &x->m_text);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_addcomma(t_message *x)
{
    t_atom a;
    SETCOMMA(&a);
    binbuf_add(x->m_text.te_binbuf, 1, &a);
    glist_retext(x->m_glist, &x->m_text);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_addsemi(t_message *x)
{
    message_add(x, 0, 0, 0);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_adddollar(t_message *x, t_floatarg f)
{
    t_atom a;
    int n = f;
    if (n < 0)
        n = 0;
    SETDOLLAR(&a, n);
    binbuf_add(x->m_text.te_binbuf, 1, &a);
    glist_retext(x->m_glist, &x->m_text);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_adddollsym(t_message *x, t_symbol *s)
{
    t_atom a;
    char buf[MAXPDSTRING];
    buf[0] = '$';
    strncpy(buf+1, s->s_name, MAXPDSTRING-2);
    buf[MAXPDSTRING-1] = 0;
    SETDOLLSYM(&a, gensym(buf));
    binbuf_add(x->m_text.te_binbuf, 1, &a);
    glist_retext(x->m_glist, &x->m_text);
    if (glist_isvisible(glist_getcanvas(x->m_glist)))
Miller Puckette's avatar
Miller Puckette committed
}

static void message_click(t_message *x,
    t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
        t_floatarg ctrl, t_floatarg alt)
{
    message_float(x, 0);
    if (glist_isvisible(x->m_glist))
    {
        t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
user's avatar
user committed
        //sys_vgui(".x%lx.c itemconfigure %sR -strokewidth 5\n", 
        //    glist_getcanvas(x->m_glist), rtext_gettag(y));
        gui_vmess("gui_message_flash", "xsi",
            glist_getcanvas(x->m_glist),
            rtext_gettag(y), 1);
Miller Puckette's avatar
Miller Puckette committed
        clock_delay(x->m_clock, 120);
    }
}

static void message_tick(t_message *x)
{
    if (glist_isvisible(x->m_glist))
    {
        t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
user's avatar
user committed
        //sys_vgui(".x%lx.c itemconfigure %sR -strokewidth 1\n",
        //    glist_getcanvas(x->m_glist), rtext_gettag(y));
        gui_vmess("gui_message_flash", "xsi",
            glist_getcanvas(x->m_glist),
            rtext_gettag(y), 0);
Miller Puckette's avatar
Miller Puckette committed
    }
}

static void message_free(t_message *x)
{
    clock_free(x->m_clock);
}

t_pd *pd_mess_from_responder(t_pd *x)
{
    if (pd_class(x) == messresponder_class)
    {
        /* do pointer math to try to get to the container message struct */
        void *tmp = (void *)x - sizeof(t_text);
        /* if it looks like a message, it must be a message */
        if(((t_text *)tmp)->te_pd == message_class)
            return ((t_pd *)tmp);
    }
    return x;
}

Miller Puckette's avatar
Miller Puckette committed
void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    /*fprintf(stderr,"canvas_msg\n");
    int i = 0;
    while(i < argc)
    {
        if (argv[i].a_type == A_FLOAT)
            fprintf(stderr," %f", atom_getfloatarg(i, argc, argv));
        else
            fprintf(stderr," %s", atom_getsymbolarg(i, argc, argv)->s_name);
        i++;
    }
    fprintf(stderr,"\n");*/
Miller Puckette's avatar
Miller Puckette committed
    t_message *x = (t_message *)pd_new(message_class);
    x->m_messresponder.mr_pd = messresponder_class;
    x->m_messresponder.mr_outlet = outlet_new(&x->m_text, &s_float);
    x->m_text.te_width = 0;                             /* don't know it yet. */
    x->m_text.te_type = T_MESSAGE;
Miller Puckette's avatar
Miller Puckette committed
    x->m_text.te_binbuf = binbuf_new();
    x->m_glist = gl;
    x->m_clock = clock_new(x, (t_method)message_tick);
    if (argc > 1)
    {
        x->m_text.te_xpix = atom_getfloatarg(0, argc, argv);
        x->m_text.te_ypix = atom_getfloatarg(1, argc, argv);
        if (argc > 2) binbuf_restore(x->m_text.te_binbuf, argc-2, argv+2);
        glist_add(gl, &x->m_text.te_g);
    }
Miller Puckette's avatar
Miller Puckette committed
    else if (!glist_isvisible(gl))
        post("unable to create stub message in closed canvas!");
Miller Puckette's avatar
Miller Puckette committed
    else
    {
Miller Puckette's avatar
Miller Puckette committed
        int connectme, xpix, ypix, indx, nobj;
        canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);
        
Miller Puckette's avatar
Miller Puckette committed
        pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
Miller Puckette's avatar
Miller Puckette committed
        x->m_text.te_xpix = xpix;
        x->m_text.te_ypix = ypix;
Miller Puckette's avatar
Miller Puckette committed
        glist_add(gl, &x->m_text.te_g);
        glist_noselect(gl);
        glist_select(gl, &x->m_text.te_g);
        gobj_activate(&x->m_text.te_g, gl,
            2); // <-- hack to signal we're a new message box
Miller Puckette's avatar
Miller Puckette committed
            canvas_connect(gl, indx, 0, nobj, 0);
            canvas_displaceselection(glist_getcanvas(gl), -8, -8);
            canvas_startmotion(glist_getcanvas(gl));
        }
        //canvas_setundo(glist_getcanvas(gl),
        //    canvas_undo_create, canvas_undo_set_create(gl), "create");
        canvas_undo_add(glist_getcanvas(gl), 9, "create",
            (void *)canvas_undo_set_create(glist_getcanvas(gl)));
Miller Puckette's avatar
Miller Puckette committed
    }
}

/* ---------------------- the "atom" text item ------------------------ */

#define ATOMBUFSIZE 40
#define ATOM_LABELLEFT 0
#define ATOM_LABELRIGHT 1
#define ATOM_LABELUP 2
#define ATOM_LABELDOWN 3

typedef struct _gatom
{
    t_text a_text;
    t_atom a_atom;          /* this holds the value and the type */
    t_glist *a_glist;       /* owning glist */
    t_float a_toggle;       /* value to toggle to */
    t_float a_draghi;       /* high end of drag range */
    t_float a_draglo;       /* low end of drag range */
    t_symbol *a_label;      /* symbol to show as label next to box */
    t_symbol *a_symfrom;    /* "receive" name -- bind ourselvs to this */
    t_symbol *a_symto;      /* "send" name -- send to this on output */
    char a_buf[ATOMBUFSIZE];/* string buffer for typing */
    char a_shift;           /* was shift key down when dragging started? */
    char a_wherelabel;      /* 0-3 for left, right, above, below */
    t_symbol *a_expanded_to; /* a_symto after $0, $1, ...  expansion */
} t_gatom;

    /* prepend "-" as necessary to avoid empty strings, so we can
    use them in Pd messages.  A more complete solution would be
    to introduce some quoting mechanism; but then we'd be much more
    complicated. */
static t_symbol *gatom_escapit(t_symbol *s)
{
    if (!*s->s_name)
        return (gensym("-"));
    else if (*s->s_name == '-')
    {
        char shmo[100];
        shmo[0] = '-';
        strncpy(shmo+1, s->s_name, 99);
        shmo[99] = 0;
        return (gensym(shmo));
    }
    else return (iemgui_dollar2raute(s));
}

    /* undo previous operation: strip leading "-" if found. */
static t_symbol *gatom_unescapit(t_symbol *s)
{
    if (*s->s_name == '-')
        return (gensym(s->s_name+1));
    else return (iemgui_raute2dollar(s));
}

static void gatom_redraw(t_gobj *client, t_glist *glist)
{
    t_gatom *x = (t_gatom *)client;
    glist_retext(x->a_glist, &x->a_text);
}

    /* recolor option offers     0 ignore recolor
                                1 recolor */
static void gatom_retext(t_gatom *x, int senditup, int recolor)
{
    t_canvas *canvas = glist_getcanvas(x->a_glist);
    t_rtext *y = glist_findrtext(x->a_glist, &x->a_text);
    if (recolor)
user's avatar
user committed
    {
        //sys_vgui(".x%lx.c itemconfigure %s -fill %s\n", canvas, 
        //    rtext_gettag(y), "$pd_colors(text)");
    }
Miller Puckette's avatar
Miller Puckette committed
    binbuf_clear(x->a_text.te_binbuf);
    binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom);
    if (senditup && glist_isvisible(x->a_glist))
        sys_queuegui(x, x->a_glist, gatom_redraw);
}

static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
{
    t_atom oldatom = x->a_atom;
    int changed = 0;
    if (!argc) return;
    if (x->a_atom.a_type == A_FLOAT)
        x->a_atom.a_w.w_float = atom_getfloat(argv),
            changed = (x->a_atom.a_w.w_float != oldatom.a_w.w_float);
    else if (x->a_atom.a_type == A_SYMBOL)
        x->a_atom.a_w.w_symbol = atom_getsymbol(argv),
            changed = (x->a_atom.a_w.w_symbol != oldatom.a_w.w_symbol);
    if (changed)
    {
        if (x->a_atom.a_type == A_FLOAT && x->a_text.te_width == 1)
            gatom_retext(x, 1, 1);
        else
            gatom_retext(x, 1, 0);
    }
Miller Puckette's avatar
Miller Puckette committed
    x->a_buf[0] = 0;
}

static void gatom_bang(t_gatom *x)
{
    if (x->a_atom.a_type == A_FLOAT)
    {
        if (x->a_text.te_outlet)
            outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float);
        if (*x->a_expanded_to->s_name && x->a_expanded_to->s_thing)
        {
            if (x->a_symto == x->a_symfrom)
                pd_error(x,
                    "%s: atom with same send/receive name (infinite loop)",
                        x->a_symto->s_name);
            else pd_float(x->a_expanded_to->s_thing, x->a_atom.a_w.w_float);
        }
    }
    else if (x->a_atom.a_type == A_SYMBOL)
    {
        if (x->a_text.te_outlet)
            outlet_symbol(x->a_text.te_outlet, x->a_atom.a_w.w_symbol);
        if (*x->a_symto->s_name && x->a_expanded_to->s_thing)
        {
            if (x->a_symto == x->a_symfrom)
                pd_error(x,
                    "%s: atom with same send/receive name (infinite loop)",
                        x->a_symto->s_name);
            else pd_symbol(x->a_expanded_to->s_thing, x->a_atom.a_w.w_symbol);
        }
    }
}

static void gatom_float(t_gatom *x, t_float f)
{
    t_atom at;
    SETFLOAT(&at, f);
    gatom_set(x, 0, 1, &at);
    gatom_bang(x);
}

static void gatom_clipfloat(t_gatom *x, t_float f)
{
    if (x->a_draglo != 0 || x->a_draghi != 0)
    {
        if (f < x->a_draglo)
            f = x->a_draglo;
        if (f > x->a_draghi)
            f = x->a_draghi;
    }
    gatom_float(x, f);
}

static void gatom_symbol(t_gatom *x, t_symbol *s)
{
    t_atom at;
    SETSYMBOL(&at, s);
    gatom_set(x, 0, 1, &at);
    gatom_bang(x);
}

    /* We need a list method because, since there's both an "inlet" and a
    "nofirstin" flag, the standard list behavior gets confused. */
static void gatom_list(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
{
    if (!argc)
        gatom_bang(x);
    else if (argv->a_type == A_FLOAT)
        gatom_float(x, argv->a_w.w_float);
    else if (argv->a_type == A_SYMBOL)
        gatom_symbol(x, argv->a_w.w_symbol);
    else pd_error(x, "gatom_list: need float or symbol");
}

static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy)
{
    t_gatom *x = (t_gatom *)z;
    if (dy == 0) return;
    if (x->a_atom.a_type == A_FLOAT)
    {
        if (x->a_shift)
        {
            double nval = x->a_atom.a_w.w_float - 0.01 * dy;
            double trunc = 0.01 * (floor(100. * nval + 0.5));
            if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
            gatom_clipfloat(x, nval);
        }
        else
        {
            double nval = x->a_atom.a_w.w_float - dy;
            double trunc = 0.01 * (floor(100. * nval + 0.5));
            if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
            trunc = floor(nval + 0.5);
            if (trunc < nval + 0.001 && trunc > nval - 0.001) nval = trunc;
            gatom_clipfloat(x, nval);
        }
    }
}

static void gatom_key(void *z, t_floatarg f)
{
    //fprintf(stderr,"gatom_key %f\n", f);
Miller Puckette's avatar
Miller Puckette committed
    t_gatom *x = (t_gatom *)z;
    int c = f;
    int len = strlen(x->a_buf);
    t_atom at;
    char sbuf[ATOMBUFSIZE + 4];
    if (c == 0)
    {
        /* we're being notified that no more keys will come for this grab */
        if (x->a_buf[0])
Miller Puckette's avatar
Miller Puckette committed
        return;
    }
    else if (c == '\b')
    {
        if (len > 0)
        x->a_buf[len-1] = 0;
        goto redraw;
    }
    else if (c == '\n')
    {
        if (x->a_atom.a_type == A_FLOAT)
            x->a_atom.a_w.w_float = atof(x->a_buf);
        else if (x->a_atom.a_type == A_SYMBOL)
            x->a_atom.a_w.w_symbol = gensym(x->a_buf);
        else bug("gatom_key");
        gatom_bang(x);
Miller Puckette's avatar
Miller Puckette committed
        x->a_buf[0] = 0;
Miller Puckette's avatar
Miller Puckette committed
    }
    else if (len < (ATOMBUFSIZE-1))
    {
            /* for numbers, only let reasonable characters through */
        if ((x->a_atom.a_type == A_SYMBOL) ||
            (c >= '0' && c <= '9' || c == '.' || c == '-'
                || c == 'e' || c == 'E'))
        {
            /* the wchar could expand to up to 4 bytes, which
             * which might overrun our a_buf;
             * therefore we first expand into a temporary buffer, 
             * and only if the resulting utf8 string fits into a_buf
             * we apply it
             */
            char utf8[UTF8_MAXBYTES];
            int utf8len = u8_wc_toutf8(utf8, c);
            if((len+utf8len) < (ATOMBUFSIZE-1))
            {
                int j=0;
                for(j=0; j<utf8len; j++)
                    x->a_buf[len+j] = utf8[j];
                 
                x->a_buf[len+utf8len] = 0;
            }
Miller Puckette's avatar
Miller Puckette committed
            goto redraw;
        }
    }
    return;
redraw:
        /* LATER figure out how to avoid creating all these symbols! */
    sprintf(sbuf, "%s...", x->a_buf);
    SETSYMBOL(&at, gensym(sbuf));
    binbuf_clear(x->a_text.te_binbuf);
    binbuf_add(x->a_text.te_binbuf, 1, &at);
    glist_retext(x->a_glist, &x->a_text);
}

static void gatom_click(t_gatom *x,
    t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
    t_floatarg alt)
{
    if (x->a_text.te_width == 1)
    {
        if (x->a_atom.a_type == A_FLOAT)
            gatom_float(x, (x->a_atom.a_w.w_float == 0));
    }
    else
    {
        if (alt)
        {
            if (x->a_atom.a_type != A_FLOAT) return;
            if (x->a_atom.a_w.w_float != 0)
            {
                x->a_toggle = x->a_atom.a_w.w_float;
                gatom_float(x, 0);
            }
            else gatom_float(x, x->a_toggle);
Miller Puckette's avatar
Miller Puckette committed
        }
        x->a_shift = shift;
        x->a_buf[0] = 0;
        glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key,
            xpos, ypos);
    }
}

EXTERN int glist_getindex(t_glist *x, t_gobj *y);
EXTERN int canvas_apply_restore_original_position(t_canvas *x, int pos);

Miller Puckette's avatar
Miller Puckette committed
    /* message back from dialog window */
static void gatom_param(t_gatom *x, t_symbol *sel, int argc, t_atom *argv)
{
    canvas_apply_setundo(x->a_glist, (t_gobj *)x);
Miller Puckette's avatar
Miller Puckette committed
    t_float width = atom_getfloatarg(0, argc, argv);
    t_float draglo = atom_getfloatarg(1, argc, argv);
    t_float draghi = atom_getfloatarg(2, argc, argv);
    t_symbol *label = gatom_unescapit(atom_getsymbolarg(3, argc, argv));
    t_float wherelabel = atom_getfloatarg(4, argc, argv);
    t_symbol *symfrom = gatom_unescapit(atom_getsymbolarg(5, argc, argv));
    t_symbol *symto = gatom_unescapit(atom_getsymbolarg(6, argc, argv));

    gobj_vis(&x->a_text.te_g, x->a_glist, 0);
    if (!*symfrom->s_name && *x->a_symfrom->s_name)
        inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
    else if (*symfrom->s_name && !*x->a_symfrom->s_name && x->a_text.te_inlet)
    {
        canvas_deletelinesforio(x->a_glist, &x->a_text,
            x->a_text.te_inlet, 0);
        inlet_free(x->a_text.te_inlet);
    }
    if (!*symto->s_name && *x->a_symto->s_name)
        outlet_new(&x->a_text, 0);
    else if (*symto->s_name && !*x->a_symto->s_name && x->a_text.te_outlet)
    {
        canvas_deletelinesforio(x->a_glist, &x->a_text,
            0, x->a_text.te_outlet);
        outlet_free(x->a_text.te_outlet);
    }
    if (draglo >= draghi)
        draglo = draghi = 0;
    x->a_draglo = draglo;
    x->a_draghi = draghi;
    if (width < 0)
        width = 4;
    else if (width > 80)
        width = 80;
    x->a_text.te_width = width;
    x->a_wherelabel = ((int)wherelabel & 3);
    x->a_label = label;
    if (*x->a_symfrom->s_name)
        pd_unbind(&x->a_text.te_pd,
            canvas_realizedollar(x->a_glist, x->a_symfrom));
    x->a_symfrom = symfrom;
    if (*x->a_symfrom->s_name)
        pd_bind(&x->a_text.te_pd,
            canvas_realizedollar(x->a_glist, x->a_symfrom));
    x->a_symto = symto;
    x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
    gobj_vis(&x->a_text.te_g, x->a_glist, 1);
    gobj_select(&x->a_text.te_g, x->a_glist, 1);
    canvas_dirty(x->a_glist, 1);
Miller Puckette's avatar
Miller Puckette committed
    /* glist_retext(x->a_glist, &x->a_text); */
}

    /* ---------------- gatom-specific widget functions --------------- */

user's avatar
user committed
static void gatom_getwherelabel(t_gatom *x, t_glist *glist, int *xp, int *yp)
{
    int x1, y1, x2, y2;
    text_getrect(&x->a_text.te_g, glist, &x1, &y1, &x2, &y2);
    if (x->a_wherelabel == ATOM_LABELLEFT)
    {
user's avatar
user committed
        *xp = -3 -
user's avatar
user committed
            strlen(canvas_realizedollar(x->a_glist, x->a_label)->s_name) *
            sys_fontwidth(glist_getfont(glist));
user's avatar
user committed
        *yp = y2 - y1 - 4;
user's avatar
user committed
    }
    else if (x->a_wherelabel == ATOM_LABELRIGHT)
    {
user's avatar
user committed
        *xp = x2 - x1 + 3;
        *yp = y2 - y1 - 4;
user's avatar
user committed
    }
    else if (x->a_wherelabel == ATOM_LABELUP)
    {
        *xp = -1;
user's avatar
user committed
        *yp = -3;
user's avatar
user committed
    }
    else
    {
        *xp = -1;
user's avatar
user committed
        *yp = y2 - y1 + sys_fontheight(glist_getfont(glist));
Miller Puckette's avatar
Miller Puckette committed
static void gatom_displace(t_gobj *z, t_glist *glist,
    int dx, int dy)
{
    //fprintf(stderr,"gatom_displace\n");
    t_gatom *x = (t_gatom*)z;
    text_displace(z, glist, dx, dy);
    if (glist_isvisible(glist))
    {
user's avatar
user committed
        //sys_vgui(".x%lx.c move %lx.l %d %d\n", glist_getcanvas(glist), 
        //    x, dx, dy);
user's avatar
user committed
/* for gatom's label */
Miller Puckette's avatar
Miller Puckette committed
static void gatom_vis(t_gobj *z, t_glist *glist, int vis)
{
    //fprintf(stderr,"gatom_vis\n");
Miller Puckette's avatar
Miller Puckette committed
    t_gatom *x = (t_gatom*)z;
    text_vis(z, glist, vis);
    if (*x->a_label->s_name)
    {
        if (vis)
        {
            int x1, y1;
user's avatar
user committed
            t_rtext *y = glist_findrtext(x->a_glist, &x->a_text);
Miller Puckette's avatar
Miller Puckette committed
            gatom_getwherelabel(x, glist, &x1, &y1);
user's avatar
user committed
            //sys_vgui("pdtk_text_new .x%lx.c %lx.l %f %f {%s} %d %s\n",
            //    glist_getcanvas(glist), x,
            //    (double)x1, (double)y1,
            //    canvas_realizedollar(x->a_glist, x->a_label)->s_name,
            //    sys_hostfontsize(glist_getfont(glist)),
            //    "$pd_colors(text)");
            gui_vmess("gui_text_new", "xssiiisi",
                glist_getcanvas(glist),
user's avatar
user committed
                rtext_gettag(y),
                "gatom",
                0,
                x1, // left margin
                y1, // top margin
Miller Puckette's avatar
Miller Puckette committed
                canvas_realizedollar(x->a_glist, x->a_label)->s_name,
user's avatar
user committed
                sys_hostfontsize(glist_getfont(glist))
            );


        else
        {
            /* We're just deleting the parent gobj in the GUI, which takes
               care of removing all the children. So we don't need to send
               a message here */
            //sys_vgui(".x%lx.c delete %lx.l\n", glist_getcanvas(glist), x);
        }
Miller Puckette's avatar
Miller Puckette committed
    }
    if (!vis)
        sys_unqueuegui(x);
}

void canvas_atom(t_glist *gl, t_atomtype type,
    t_symbol *s, int argc, t_atom *argv)
{
    //fprintf(stderr,"canvas_atom\n");
Miller Puckette's avatar
Miller Puckette committed
    t_gatom *x = (t_gatom *)pd_new(gatom_class);
    t_atom at;
    x->a_text.te_width = 0;                        /* don't know it yet. */
    x->a_text.te_type = T_ATOM;
Miller Puckette's avatar
Miller Puckette committed
    x->a_text.te_binbuf = binbuf_new();
    x->a_glist = gl;
    x->a_atom.a_type = type;
    x->a_toggle = 1;
    x->a_draglo = 0;
    x->a_draghi = 0;
    x->a_wherelabel = 0;
    x->a_label = &s_;
    x->a_symfrom = &s_;
    x->a_symto = x->a_expanded_to = &s_;
    if (type == A_FLOAT)
    {
        x->a_atom.a_w.w_float = 0;
        x->a_text.te_width = 5;
        SETFLOAT(&at, 0);
    }
    else
    {
        x->a_atom.a_w.w_symbol = &s_symbol;
        x->a_text.te_width = 10;
        SETSYMBOL(&at, &s_symbol);
    }
    binbuf_add(x->a_text.te_binbuf, 1, &at);
    if (argc > 1)
        /* create from file. x, y, width, low-range, high-range, flags,
            label, receive-name, send-name */
    {
        x->a_text.te_xpix = atom_getfloatarg(0, argc, argv);
        x->a_text.te_ypix = atom_getfloatarg(1, argc, argv);
        x->a_text.te_width = atom_getintarg(2, argc, argv);
            /* sanity check because some very old patches have trash in this
            field... remove this in 2003 or so: */
        if (x->a_text.te_width < 0 || x->a_text.te_width > 500)
            x->a_text.te_width = 4;
        x->a_draglo = atom_getfloatarg(3, argc, argv);
        x->a_draghi = atom_getfloatarg(4, argc, argv);
        x->a_wherelabel = (((int)atom_getfloatarg(5, argc, argv)) & 3);
        x->a_label = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
        x->a_symfrom = gatom_unescapit(atom_getsymbolarg(7, argc, argv));
        if (*x->a_symfrom->s_name)
            pd_bind(&x->a_text.te_pd,
                canvas_realizedollar(x->a_glist, x->a_symfrom));

        x->a_symto = gatom_unescapit(atom_getsymbolarg(8, argc, argv));
        x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
        if (x->a_symto == &s_)
            outlet_new(&x->a_text,
                x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
        if (x->a_symfrom == &s_)
            inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
        glist_add(gl, &x->a_text.te_g);
    }
    else
    {
Miller Puckette's avatar
Miller Puckette committed
        int connectme, xpix, ypix, indx, nobj;
        canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);
Miller Puckette's avatar
Miller Puckette committed
        outlet_new(&x->a_text,
            x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
        inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
        pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
        x->a_text.te_xpix = xpix;
        x->a_text.te_ypix = ypix;
        glist_add(gl, &x->a_text.te_g);
        glist_noselect(gl);
        glist_select(gl, &x->a_text.te_g);
Miller Puckette's avatar
Miller Puckette committed
            canvas_connect(gl, indx, 0, nobj, 0);
            canvas_displaceselection(glist_getcanvas(gl), -8, -8);
            canvas_startmotion(glist_getcanvas(gl));
        }
        //canvas_setundo(glist_getcanvas(gl),
        //    canvas_undo_create, canvas_undo_set_create(gl), "create");
        canvas_undo_add(glist_getcanvas(gl), 9, "create",
            (void *)canvas_undo_set_create(glist_getcanvas(gl)));
    glob_preset_node_list_seek_hub();
    glob_preset_node_list_check_loc_and_update();    
Miller Puckette's avatar
Miller Puckette committed
}

void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_atom(gl, A_FLOAT, s, argc, argv);
}

void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
{
    canvas_atom(gl, A_SYMBOL, s, argc, argv);
}

static void gatom_free(t_gatom *x)
{
    if (*x->a_symfrom->s_name)
        pd_unbind(&x->a_text.te_pd,
            canvas_realizedollar(x->a_glist, x->a_symfrom));
    gfxstub_deleteforkey(x);
}

static void gatom_properties(t_gobj *z, t_glist *owner)
{
    t_gatom *x = (t_gatom *)z;
user's avatar
user committed
    //char buf[200];
    //sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g %d {%s} {%s} {%s}\n",
    //    x->a_text.te_width, x->a_draglo, x->a_draghi,
    //        x->a_wherelabel, gatom_escapit(x->a_label)->s_name,
    //            gatom_escapit(x->a_symfrom)->s_name,
    //                gatom_escapit(x->a_symto)->s_name);
    //gfxstub_new(&x->a_text.te_pd, x, buf);
    gui_start_vmess("gui_gatom_dialog", "s",
        gfxstub_new2(&x->a_text.te_pd, x));
    gui_start_array();
    gui_s("width");    gui_i(x->a_text.te_width);
    gui_s("draglo");   gui_f(x->a_draglo);
    gui_s("draghi");   gui_f(x->a_draghi);
    gui_s("labelpos"); gui_i(x->a_wherelabel);
    gui_s("label");    gui_s(gatom_escapit(x->a_label)->s_name);
    gui_s("receive-symbol");  gui_s(gatom_escapit(x->a_symfrom)->s_name);
    gui_s("send-symbol");     gui_s(gatom_escapit(x->a_symto)->s_name);
user's avatar
user committed
    gui_end_array();
    gui_end_vmess();
Miller Puckette's avatar
Miller Puckette committed
}

/* -------------------- widget behavior for text objects ------------ */

/* variant of the glist_findrtext found in g_rtext.c 
   that does not throw a consistency check */
extern t_rtext *glist_tryfindrtext(t_glist *gl, t_text *who);

Miller Puckette's avatar
Miller Puckette committed
static void text_getrect(t_gobj *z, t_glist *glist,
    int *xp1, int *yp1, int *xp2, int *yp2)
{
    //fprintf(stderr,"text_getrect\n");
Miller Puckette's avatar
Miller Puckette committed
    t_text *x = (t_text *)z;
    int width = 0, height = 0, iscomment = (x->te_type == T_TEXT);
    t_float x1, y1, x2, y2;
Miller Puckette's avatar
Miller Puckette committed

        /* for number boxes, we know width and height a priori, and should
        report them here so that graphs can get swelled to fit. */
    
    if (x->te_type == T_ATOM && x->te_width > 0)
    {
Miller Puckette's avatar
Miller Puckette committed
        int font = glist_getfont(glist);
        int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
        width = (x->te_width > 0 ? x->te_width : 6) * fontwidth + 2;
        height = fontheight + 3; /* borrowed from TMARGIN, etc, in g_rtext.c */
    // jsarlo
    else if (strcmp("magicGlass", class_getname(x->ob_pd)) == 0)
    {
        width = 0;
        height = 0;
    }
    // end jsarlo
    else if (x->te_type == T_TEXT)
    {
        t_rtext *y = glist_findrtext(glist, x);
        if (y)
        {
            width = rtext_width(y);
            height = rtext_height(y);
        }
        else
        {
            width = height = 10;
        }
        //fprintf(stderr,"T_TEXT width=%d height=%d\n", width, height);
Miller Puckette's avatar
Miller Puckette committed
    }
        /* if we're invisible we don't know our size so we just lie about
        it.  This is called on invisible boxes to establish order of inlets
        and possibly other reasons.
           To find out if the box is visible we can't just check the "vis"
        flag because we might be within the vis() routine and not have set
        that yet.  So we check directly whether the "rtext" list has been
        built.  LATER reconsider when "vis" flag should be on and off? */
    else if (glist->gl_editor && glist->gl_editor->e_rtext)
    {
        t_rtext *y = glist_tryfindrtext(glist, x);
        if (y)
        {
            width = rtext_width(y);
            height = rtext_height(y) - (iscomment << 1);
        }
        //fprintf(stderr,"rtext width=%d height=%d\n", width, height);

        /*  now find if we have more inlets or outlets than
            what can comfortably fit and adjust accordingly
            NB: textless GOPs are unaffected and are treated
            as GUI objects
        */

        //fprintf(stderr,"isgraph %d\n", ((t_glist *)z)->gl_isgraph);
        //if (!((t_glist *)z)->gl_isgraph) {

        t_object *ob = pd_checkobject(&x->te_pd);
        int no = obj_noutlets(ob);
        int ni = obj_ninlets(ob);

        /*
        // debug chunk
        char *bufdbg;
        int bufsizedbg;
        if (y) rtext_gettext(y, &bufdbg, &bufsizedbg);
        if (!strncmp(bufdbg, "gate", 4) || strlen(bufdbg) == 0)
            fprintf(stderr,"text_getrect nlets %d %d <%s>\n", ni, no, ( y ? bufdbg : "null" ));
        */

        int m = ( ni > no ? ni : no);
        //let's see if the object has more nlets than
        //its text width and resize them accordingly
        //UNLESS we are gop in which case it is user's choice
        //how big/small they want the object
        if (pd_class(&z->g_pd) != canvas_class || 
                pd_class(&z->g_pd) == canvas_class &&
                    !((t_glist *)z)->gl_isgraph)
        {
            if (width < (IOWIDTH * m) * 2 - IOWIDTH)
            {
                //we have to resize the object
                width = (IOWIDTH * m) * 2 - IOWIDTH;
            }
        }
Miller Puckette's avatar
Miller Puckette committed
        height = rtext_height(y) - (iscomment << 1);
    }
        width = height = 10;
        //fprintf(stderr,"    default\n");
    }
Miller Puckette's avatar
Miller Puckette committed
    x1 = text_xpix(x, glist);
    y1 = text_ypix(x, glist);
    x2 = x1 + width;
    y2 = y1 + height;
    //y1 += iscomment*6;
Miller Puckette's avatar
Miller Puckette committed
    *xp1 = x1;
    *yp1 = y1;
    *xp2 = x2;
    *yp2 = y2;
}

static void text_displace(t_gobj *z, t_glist *glist,
    int dx, int dy)
{
    //fprintf(stderr,"text_displace\n");
Miller Puckette's avatar
Miller Puckette committed
    t_text *x = (t_text *)z;
    x->te_xpix += dx;
    x->te_ypix += dy;
    if (glist_isvisible(glist))
    {
        t_rtext *y = glist_findrtext(glist, x);
        gui_vmess("gui_text_displace", "xsii",
            glist, rtext_gettag(y), dx, dy);
//        t_rtext *y = glist_findrtext(glist, x);
//        rtext_displace(y, dx, dy);
//        text_drawborder(x, glist, rtext_gettag(y),
//            rtext_width(y), rtext_height(y), 0);
Miller Puckette's avatar
Miller Puckette committed
        canvas_fixlinesfor(glist_getcanvas(glist), x);
    }
}

static void text_displace_withtag(t_gobj *z, t_glist *glist,
    int dx, int dy)
{
    //fprintf(stderr,"text_displace_withtag\n");
    t_text *x = (t_text *)z;
    x->te_xpix += dx;
    x->te_ypix += dy;
    if (glist_isvisible(glist))
    {
Mathieu L Bouchard's avatar
Mathieu L Bouchard committed
        //t_rtext *y = glist_findrtext(glist, x);
        //text_drawborder_withtag(x, glist, rtext_gettag(y),
        //    rtext_width(y), rtext_height(y), 0);
        canvas_fixlinesfor(glist_getcanvas(glist), x);
        /* if this is a subpatcher in which case we may be
           possibly moving nlets around
           which in turn requires that we redraw parent's nlets */

/*        if (glist->gl_owner && glist_isvisible(glist->gl_owner))
          {
            int resortin = 0, resortout = 0;
            t_class *cl = pd_class(&z->g_pd);
            if (cl == vinlet_class) resortin = 1;
            else if (cl == voutlet_class) resortout = 1;
            fprintf(stderr,"vinlet=%d voutlet=%d\n", resortin, resortout);
            if (resortin) canvas_resortinlets(glist->gl_owner);
            if (resortout) canvas_resortoutlets(glist->gl_owner);

            char *buf;
            char name[6];
            int bufsize, i;
            rtext_gettext(y, &buf, &bufsize);
            for (i = 0; i < 5; i++)
            {
                name[i] = buf[i];
            }
            name[5] = '\0';
            //fprintf(stderr,"yes, this is a subpatch with visible parent %s\n",
            //    name);
            if (!strcmp(name, "inlet") ||
                !strcmp(name, "outle"))
            {
                
                //fprintf(stderr,"yes, we're moving nlets around\n");    
                glist_redraw(glist->gl_owner);
            }
        }*/
    }    
}

static void gatom_displace_withtag(t_gobj *z, t_glist *glist,
    int dx, int dy)
{
Mathieu L Bouchard's avatar
Mathieu L Bouchard committed
    //t_gatom *x = (t_gatom*)z;
    text_displace_withtag(z, glist, dx, dy);
    //sys_vgui(".x%lx.c move %lx.l %d %d\n", glist_getcanvas(glist), 
    //    x, dx, dy);
Miller Puckette's avatar
Miller Puckette committed
static void text_select(t_gobj *z, t_glist *glist, int state)
{
    t_text *x = (t_text *)z;
    t_rtext *y = glist_findrtext(glist, x);
    char *outline;
Miller Puckette's avatar
Miller Puckette committed
    rtext_select(y, state);
    //fprintf(stderr,"text_select %s %d\n", rtext_gettag(y), state);
    // text_class is either a comment or an object that failed to create
    // so we distinguish between it and comment using T_TEXT type check
    if (pd_class(&x->te_pd) == text_class && x->te_type != T_TEXT)
        outline = "$pd_colors(dash_outline)";
    else if (z->g_pd == gatom_class)
        outline = "$pd_colors(atom_box_border)";
    else
        outline = "$pd_colors(box_border)";
    //fprintf(stderr,"text_select isvisible=%d shouldvis=%d istoplevel=%d\n",
    //    glist_isvisible(glist), gobj_shouldvis(&x->te_g, glist),
    //    glist_istoplevel(glist));
    if (gobj_shouldvis(&x->te_g, glist))
    {
        if (glist_istoplevel(glist))
        {
            //sys_vgui(".x%lx.c itemconfigure %sR -stroke %s\n",
            //    glist_getcanvas(glist), rtext_gettag(y),
            //    (state? "$pd_colors(selection)" : outline));
            gui_vmess("gui_text_select_color", "xs",
                glist_getcanvas(glist), rtext_gettag(y));
                //sys_vgui(".x%lx.c itemconfigure %lx.l -fill %s\n",
                //    glist_getcanvas(glist), x,
                //    (state? "$pd_colors(selection)" : "$pd_colors(text)"));
            }
        }
        if (z->g_pd->c_wb && z->g_pd->c_wb->w_displacefnwtag)
        {
Mathieu L Bouchard's avatar
Mathieu L Bouchard committed
            int i;
                    /* Since the label is a child of the parent gobj, we
                       only need to select the gobj to displace it */
                    //sys_vgui(".x%lx.c addtag selected withtag %lx.l\n",
                    //    glist_getcanvas(glist), x);                    
                //sys_vgui(".x%lx.c addtag selected withtag %sR \n",
                //    glist_getcanvas(glist), rtext_gettag(y));
                gui_vmess("gui_gobj_select", "xs",
                    glist_getcanvas(glist), rtext_gettag(y));
                if (pd_class(&x->te_pd) == text_class &&
                             x->te_type != T_TEXT &&
                             glist_istoplevel(glist))
                {
                    /* Not sure yet what this is doing... */
                    sys_vgui(".x%lx.c itemconfigure %sR -strokewidth 1 "
                             "-strokedasharray {} "
                             "-fill $pd_colors(box)\n",
                        glist_getcanvas(glist), rtext_gettag(y));

                t_object *ob = pd_checkobject(&x->te_pd);
                int no = obj_noutlets(ob);
                int ni = obj_ninlets(ob);

                for (i = 0; i < no; i++)
                {
                    /* Not necessary since xlet rect is child of gobj */
                    //sys_vgui(".x%lx.c addtag selected withtag %so%d \n",
                    //                glist_getcanvas(glist), rtext_gettag(y), i);
                    /* Not necessary since xlet rect is child of gobj */
                    //sys_vgui(".x%lx.c addtag selected withtag %si%d \n",
                    //    glist_getcanvas(glist), rtext_gettag(y), i);
                    //sys_vgui(".x%lx.c dtag %lx.l selected\n",
                    //    glist_getcanvas(glist), x);                    
                //sys_vgui(".x%lx.c dtag %sR selected\n",
                //    glist_getcanvas(glist), rtext_gettag(y));
                gui_vmess("gui_gobj_deselect", "xs",
                    rtext_gettag(y));
                if (pd_class(&x->te_pd) == text_class &&
                    x->te_type != T_TEXT)
                {
                    /* This might be for broken objects... */
                    sys_vgui(".x%lx.c itemconfigure %sR -strokewidth 2 "
                        "-strokelinecap projecting -strokedasharray {2 3} "
                        "-fill %s\n",
                        glist_getcanvas(glist), 
                        rtext_gettag(y), invalid_fill);

                t_object *ob = pd_checkobject(&x->te_pd);
                int no = obj_noutlets(ob);
                int ni = obj_ninlets(ob);

                for (i = 0; i < no; i++)
                {
                    //sys_vgui(".x%lx.c dtag %so%d selected\n",
                    //    glist_getcanvas(glist), rtext_gettag(y), i);
                    //sys_vgui(".x%lx.c dtag %si%d selected\n",
                    //    glist_getcanvas(glist), rtext_gettag(y), i);
Miller Puckette's avatar
Miller Puckette committed
}

static void text_activate(t_gobj *z, t_glist *glist, int state)
{
    t_text *x = (t_text *)z;
    t_rtext *y = glist_findrtext(glist, x);
    if (z->g_pd != gatom_class) rtext_activate(y, state);
}

static void text_delete(t_gobj *z, t_glist *glist)
{
    t_text *x = (t_text *)z;
    canvas_deletelinesfor(glist, x);
}

static void text_get_typestring(int type, char *buf)
{
    if (type == T_OBJECT)
        sprintf(buf, "%s", "obj");
    else if (type == T_MESSAGE)
        sprintf(buf, "%s", "msg");
    else if (type == T_TEXT)
        sprintf(buf, "%s", "comment");
    else
        sprintf(buf, "%s", "atom");
}

Miller Puckette's avatar
Miller Puckette committed
static void text_vis(t_gobj *z, t_glist *glist, int vis)
{
    //fprintf(stderr,"text_vis %d\n", vis);
Miller Puckette's avatar
Miller Puckette committed
    t_text *x = (t_text *)z;
    int x1, y1, x2, y2;
    char type[8];
    text_get_typestring(x->te_type, type);
    //if we are in k12 mode and this is hub with level 1 (global)
    //don't draw it and make its width/height 0
    int exception = 0;
    if (pd_class(&x->te_pd) == preset_hub_class && sys_k12_mode)
    {
        //fprintf(stderr,"text_vis reports preset_hub_class detected\n");
        t_preset_hub *h = (t_preset_hub *)z;
        if (h->ph_invis)
        {
            exception = 1;
            x->te_width = 0;
        }
    }
    if (!exception)
    {
        if (vis)
        {
            if (gobj_shouldvis(&x->te_g, glist))
            {
                //fprintf(stderr,"    draw it\n");
                t_rtext *y = glist_findrtext(glist, x);

                // make a group
                text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
                gui_vmess("gui_text_create_gobj", "xssiii",
                    glist_getcanvas(glist),
                    rtext_gettag(y), type, x1, y1, glist_istoplevel(glist));
                if (x->te_type == T_ATOM)
                    glist_retext(glist, x);
                text_drawborder(x, glist, rtext_gettag(y),
                    rtext_width(y), rtext_height(y), 1);
                rtext_draw(y);
            }
        }
        else
        {
            t_rtext *y = glist_findrtext(glist, x);
            if (gobj_shouldvis(&x->te_g, glist))
            {
                //fprintf(stderr,"    erase it %lx %lx\n", x, glist);
                text_erase_gobj(x, glist, rtext_gettag(y));
                //text_eraseborder(x, glist, rtext_gettag(y));
                //rtext_erase(y);
Miller Puckette's avatar
Miller Puckette committed
}

static int text_click(t_gobj *z, struct _glist *glist,
    int xpix, int ypix, int shift, int alt, int dbl, int doit)
{
    t_text *x = (t_text *)z;
    if (x->te_type == T_OBJECT)
    {
        t_symbol *clicksym = gensym("click");
        if (zgetfn(&x->te_pd, clicksym))
        {
            if (doit)
                pd_vmess(&x->te_pd, clicksym, "fffff",
                    (double)xpix, (double)ypix,
                        (double)shift, (double)0, (double)alt);
            return (1);
        }
        else return (0);
    }
    else if (x->te_type == T_ATOM)
    {
        t_canvas *canvas = glist_getcanvas(glist);
        t_rtext *y = glist_findrtext(glist, x);
        if (doit)
        {
            //fprintf(stderr,"atom click\n");
            /* Change the gatom blue when it's clicked? Need to test... */
            sys_vgui(".x%lx.c itemconfigure %s -fill %s\n", canvas, 
                rtext_gettag(y), "$pd_colors(selection)");
            gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,
                (t_floatarg)shift, (t_floatarg)0, (t_floatarg)alt);
Miller Puckette's avatar
Miller Puckette committed
        return (1);
    }
    else if (x->te_type == T_MESSAGE)
    {
        if (doit)
            message_click((t_message *)x, (t_floatarg)xpix, (t_floatarg)ypix,
                (t_floatarg)shift, (t_floatarg)0, (t_floatarg)alt);
        return (1);
    }
    else return (0);
}

void text_save(t_gobj *z, t_binbuf *b)
{
    //fprintf(stderr, "text_save\n");
Miller Puckette's avatar
Miller Puckette committed
    t_text *x = (t_text *)z;
    if (x->te_type == T_OBJECT)
    {
            /* if we have a "saveto" method, and if we don't happen to be
            a canvas that's an abstraction, the saveto method does the work */
        if (zgetfn(&x->te_pd, gensym("saveto")) &&
            !((pd_class(&x->te_pd) == canvas_class) && 
                (canvas_isabstraction((t_canvas *)x)
                    || canvas_istable((t_canvas *)x))))
        {  
Miller Puckette's avatar
Miller Puckette committed
            mess1(&x->te_pd, gensym("saveto"), b);
            binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"),
                (int)x->te_xpix, (int)x->te_ypix);
        }
        else    /* otherwise just save the text */
        {
            //fprintf(stderr, "is this gop?\n");
Miller Puckette's avatar
Miller Puckette committed
            binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"),
                (int)x->te_xpix, (int)x->te_ypix);
        }
        //fprintf(stderr, "this must be it\n");
Miller Puckette's avatar
Miller Puckette committed
        binbuf_addbinbuf(b, x->te_binbuf);
        //fprintf(stderr, "DONE this must be it\n");
Miller Puckette's avatar
Miller Puckette committed
    }
    else if (x->te_type == T_MESSAGE)
    {
Miller Puckette's avatar
Miller Puckette committed
        binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"),
            (int)x->te_xpix, (int)x->te_ypix);
        binbuf_addbinbuf(b, x->te_binbuf);
    }
    else if (x->te_type == T_ATOM)
    {
Miller Puckette's avatar
Miller Puckette committed
        t_atomtype t = ((t_gatom *)x)->a_atom.a_type;
        t_symbol *sel = (t == A_SYMBOL ? gensym("symbolatom") :
            (t == A_FLOAT ? gensym("floatatom") : gensym("intatom")));
        t_symbol *label = gatom_escapit(((t_gatom *)x)->a_label);
        t_symbol *symfrom = gatom_escapit(((t_gatom *)x)->a_symfrom);
        t_symbol *symto = gatom_escapit(((t_gatom *)x)->a_symto);
        binbuf_addv(b, "ssiiifffsss", gensym("#X"), sel,
            (int)x->te_xpix, (int)x->te_ypix, (int)x->te_width,
            (double)((t_gatom *)x)->a_draglo,
            (double)((t_gatom *)x)->a_draghi,
            (double)((t_gatom *)x)->a_wherelabel,
            label, symfrom, symto);
    }           
        //fprintf(stderr,"comment\n");
        int natom = binbuf_getnatom(x->te_binbuf);
        t_atom *a = binbuf_getvec(x->te_binbuf);
        int i;
                //fprintf(stderr,"%d is a symbol\n", i);
                s = a[i].a_w.w_symbol;
                if (s != NULL && s->s_name != NULL)
                {
                    for(c = s->s_name; c != NULL && *c != '\0'; c++)
                    {
                        if(*c == '\n')
                        {
Miller Puckette's avatar
Miller Puckette committed
        binbuf_addv(b, "ssii", gensym("#X"), gensym("text"),
            (int)x->te_xpix, (int)x->te_ypix);
        binbuf_addbinbuf(b, x->te_binbuf);
    if (x->te_width)
        binbuf_addv(b, ",si", gensym("f"), (int)x->te_width);
    binbuf_addv(b, ";");
Miller Puckette's avatar
Miller Puckette committed
}

    /* this one is for everyone but "gatoms"; it's imposed in m_class.c */
t_widgetbehavior text_widgetbehavior =
{
    text_getrect,
    text_displace,
    text_select,
    text_activate,
    text_delete,
    text_vis,
    text_click,
    text_displace_withtag,
Miller Puckette's avatar
Miller Puckette committed
};

static t_widgetbehavior gatom_widgetbehavior =
{
    text_getrect,
    gatom_displace,
    text_select,
    text_activate,
    text_delete,
    gatom_vis,
    text_click,
    gatom_displace_withtag,
Miller Puckette's avatar
Miller Puckette committed
};

/* -------------------- the "text" class  ------------ */

#define EXTRAPIX 2

    /* draw inlets and outlets for a text object or for a graph. */
void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
    char *tag, int x1, int y1, int x2, int y2)
{
    t_rtext *y = glist_findrtext(glist, ob);
    //if this is a comment or we are drawing inside gop on one of
    //our parents return
    if (pd_class(&ob->te_pd) == text_class || glist_getcanvas(glist) != glist)
        return;
    //fprintf(stderr,"glist_drawiofor\n");
Miller Puckette's avatar
Miller Puckette committed
    int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
    int width = x2 - x1;
    int issignal;
    int selected = glist_isselected(glist, (t_gobj*)ob);
Miller Puckette's avatar
Miller Puckette committed
    for (i = 0; i < n; i++)
    {
        int onset = x1 + (width - IOWIDTH) * i / nplus;
        if (firsttime)
            //fprintf(stderr,"glist_drawiofor o firsttime\n");
            issignal = obj_issignaloutlet(ob,i);
            //sys_vgui(".x%lx.c create prect %d %d %d %d \
            //          -fill %s -stroke %s -tags {%so%d %lx outlet %s %s}\n",
            //    glist_getcanvas(glist), onset, y2 - 2, onset + IOWIDTH, y2,
            //    (issignal ? "$pd_colors(signal_nlet)" :
            //       "$pd_colors(control_nlet)"),
            //    (issignal ? "$pd_colors(signal_cord)" :
            //        "$pd_colors(control_cord)"),
            //    tag, i, tag,
            //    (issignal ? "signal" : "control"),
            //    (selected ? "selected" : ""));

/* need to send issignal and is_iemgui here... */


            gui_vmess("gui_canvas_drawio", "xssiiiiiisiii",
                glist_getcanvas(glist), rtext_gettag(y), tag,
                onset, y2 - 2, onset + IOWIDTH, y2, x1, y1, "o", i,
                issignal, 0);
            //fprintf(stderr,"glist_drawiofor o redraw\n");
            //sys_vgui(".x%lx.c coords %so%d %d %d %d %d\n",
            //    glist_getcanvas(glist), tag, i,
            //    onset, y2 - 2,
            //    onset + IOWIDTH, y2);
                // jsarlo
                /*sys_vgui(".x%x.c raise %so%d\n",
                         glist_getcanvas(glist),
                         tag,
                         i);*/
                // end jsarlo
            gui_vmess("gui_canvas_redraw_io", "xssiisiii",
                glist_getcanvas(glist), rtext_gettag(y), tag,
                onset, y2 - 2, "o", i, x1, y1);
Miller Puckette's avatar
Miller Puckette committed
    }
    n = obj_ninlets(ob);
    nplus = (n == 1 ? 1 : n-1);
    for (i = 0; i < n; i++)
    {
        int onset = x1 + (width - IOWIDTH) * i / nplus;
        if (firsttime)
            //fprintf(stderr,"glist_drawiofor i firsttime\n");
            issignal = obj_issignalinlet(ob,i);
            //sys_vgui(".x%lx.c create prect %d %d %d %d \
            //          -fill %s -stroke %s -tags {%si%d %lx inlet %s %s}\n",
            //    glist_getcanvas(glist), onset, y1,
            //    onset + IOWIDTH, y1 + EXTRAPIX,
            //    (issignal ? "$pd_colors(signal_nlet)" :
            //        "$pd_colors(control_nlet)"),
            //    (issignal ? "$pd_colors(signal_cord)" :
            //        "$pd_colors(control_cord)"),
            //    tag, i, tag,
            //    (issignal ? "signal" : "control"),
            //    (selected ? "selected" : ""));
            gui_vmess("gui_canvas_drawio", "xssiiiiiisiii",
                glist_getcanvas(glist), rtext_gettag(y), tag,
                onset, y1, onset + IOWIDTH, y1 + EXTRAPIX, x1, y1, "i", i,
                issignal, 0);
            //fprintf(stderr,"glist_drawiofor i firsttime\n");
            //sys_vgui(".x%lx.c coords %si%d %d %d %d %d\n",
            //    glist_getcanvas(glist), tag, i,
            //    onset, y1,
            //    onset + IOWIDTH, y1 + EXTRAPIX);
                // jsarlo   
                /*sys_vgui(".x%x.c raise %si%d\n",
                         glist_getcanvas(glist),
                         tag,
                         i);*/
                // end jsarlo
            gui_vmess("gui_canvas_redraw_io", "xssiisiii",
                glist_getcanvas(glist), rtext_gettag(y), tag,
                onset, y1, "i", i, x1, y1);
    /* draw inlets and outlets for a text object or for a graph. */
void glist_drawiofor_withtag(t_glist *glist, t_object *ob, int firsttime,
    char *tag, int x1, int y1, int x2, int y2)
{
    if (pd_class(&ob->te_pd) == text_class)
        return;
    //fprintf(stderr,"drawiofor_withtag\n");
    int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
    int width = x2 - x1;
    int issignal;
    for (i = 0; i < n; i++)
    {
        int onset = x1 + (width - IOWIDTH) * i / nplus;
        if (firsttime)
        {
            //fprintf(stderr,"drawiofor_withtag o firsttime\n");
            issignal = obj_issignaloutlet(ob,i);
            /* Hm, I can't seem to find a case where this is needed
               yet.  All the xlets in nw.js port load and get created
               correctly without it... */
            sys_vgui(".x%lx.c create prect %d %d %d %d \
                      -fill %s -stroke %s -tags {%so%d %lx outlet}\n",
                glist_getcanvas(glist), onset, y2 - 2, onset + IOWIDTH, y2,
                (issignal ? "$pd_colors(signal_nlet)" :
                    "$pd_colors(control_nlet)"),
                (issignal ? "$pd_colors(signal_cord)" :
                    "$pd_colors(control_cord)"),
        else
        {
            sys_vgui(".x%lx.c addtag selected withtag %so%d \n",
                glist_getcanvas(glist), tag, i);
        }
    //fprintf(stderr,"drawiofor_withtag n=%d\n", n);
    nplus = (n == 1 ? 1 : n-1);
    for (i = 0; i < n; i++)
    {
        int onset = x1 + (width - IOWIDTH) * i / nplus;
        if (firsttime)
        {
            //fprintf(stderr,"drawiofor_withtag i firsttime\n");
            issignal = obj_issignalinlet(ob,i);
            sys_vgui(".x%lx.c create prect %d %d %d %d \
                      -fill %s -stroke %s -tags {%si%d %lx inlet}\n",
                glist_getcanvas(glist), onset, y1,
                onset + IOWIDTH, y1 + EXTRAPIX,
                (issignal ? "$pd_colors(signal_nlet)" :
                    "$pd_colors(control_nlet)"),
                (issignal ? "$pd_colors(signal_cord)" :
                    "$pd_colors(control_cord)"),
/*        else
        {
            //sys_vgui(".x%lx.c addtag selected withtag %si%d \n",
            //    glist_getcanvas(glist), tag, i);
            fprintf(stderr,"drawiofor_withtag i redraw\n");
            issignal = obj_issignalinlet(ob,i);
            sys_vgui(".x%lx.c itemconfigure %si%d \
                      -fill %s -outline %s\n",
                glist_getcanvas(glist), tag, i,
                (issignal ? "$pd_colors(signal_nlet)" :
                    "$pd_colors(control_nlet)"),
                (issignal ? "$pd_colors(signal_cord)" :
                    "$pd_colors(control_cord)"));
        }
Miller Puckette's avatar
Miller Puckette committed
void text_drawborder(t_text *x, t_glist *glist,
    char *tag, int width2, int height2, int firsttime)
{
Miller Puckette's avatar
Miller Puckette committed
    t_object *ob;
Mathieu L Bouchard's avatar
Mathieu L Bouchard committed
    int x1, y1, x2, y2;
    int broken;
    int selected = glist_isselected(glist, (t_gobj*)x);

    /* if this is gop patcher, the getrect should be equal to gop-ed window
       rather than just the size of text */
    if (pd_class(&x->te_pd) == canvas_class &&
        ((t_glist *)x)->gl_isgraph &&
        ((t_glist *)x)->gl_goprect &&
        !(((t_glist *)x)->gl_havewindow) )
    {
        int gop_width = ((t_glist *)x)->gl_pixwidth;
        int gop_height = ((t_glist *)x)->gl_pixheight;
        text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
        /*fprintf(stderr,"text = %d %d %d %d     gop = %d %d\n",
            x1, y1, x2, y2, gop_width, gop_height); */
        if (gop_width > (x2-x1)) x2 = x1 + gop_width;
        if (gop_height > (y2-y1)) y2 = y1 + gop_height;
    }
    else
    {
        text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
    }
Miller Puckette's avatar
Miller Puckette committed
    if (x->te_type == T_OBJECT)
    {
        char *pattern; char *outline; char *fill;
        /* tag to identify broken boxes from tcl/tk */
        char *box_tag;
        if (pd_class(&x->te_pd) == text_class)
        {
            pattern = "-";
            outline = "$pd_colors(dash_outline) -strokewidth 2 -strokelinecap projecting -strokedasharray {2 3}"; //-strokedasharray {4 1}
            fill = invalid_fill;
            box_tag = "broken box";
            broken = 1;
        }
        else
        {
            pattern = "\"\"";
            outline = "$pd_colors(box_border)";
            broken = 0;
Miller Puckette's avatar
Miller Puckette committed
        if (firsttime)
            sys_vgui(".x%lx.c create ppolygon %d %d %d %d %d %d %d %d %d %d \
                    -stroke %s -fill %s -tags {%sR %lx text %s %s}\n", 
                    glist_getcanvas(glist),
                    x1, y1,  x2, y1,  x2, y2,  x1, y2,  x1, y1,  
                    (selected ? "$pd_colors(selection)" : outline),
                    fill, tag, tag, box_tag,
                    (selected ? "selected" : ""));
            gui_vmess("gui_text_drawborder", "xssiiiii",
                glist_getcanvas(glist), tag, "none",
Loading
Loading full blame...