diff options
Diffstat (limited to 'pd/src/g_text.c')
-rw-r--r-- | pd/src/g_text.c | 1070 |
1 files changed, 1070 insertions, 0 deletions
diff --git a/pd/src/g_text.c b/pd/src/g_text.c new file mode 100644 index 00000000..226ddc7a --- /dev/null +++ b/pd/src/g_text.c @@ -0,0 +1,1070 @@ +/* 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_imp.h" +#include "t_tk.h" +#include "g_canvas.h" +#include <stdio.h> +#include <string.h> +#include <math.h> + +static t_class *text_class; +static t_class *message_class; +static t_class *gatom_class; +void canvas_startmotion(t_canvas *x); +t_widgetbehavior text_widgetbehavior; + +/* ----------------- 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) +{ + 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; + x->te_binbuf = binbuf_new(); + if (argc > 1) + { + 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); + else + { + SETSYMBOL(&at, gensym("comment")); + binbuf_restore(x->te_binbuf, 1, &at); + } + glist_add(gl, &x->te_g); + } + else + { + int xpix, ypix; + 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 = glist_pixelstox(gl, xpix-3); + x->te_ypix = glist_pixelstoy(gl, ypix-3); + binbuf_restore(x->te_binbuf, 1, &at); + glist_add(gl, &x->te_g); + glist_noselect(gl); + glist_select(gl, &x->te_g); + canvas_startmotion(glist_getcanvas(gl)); + } +} + +/* ----------------- the "object" object. ------------------ */ + +extern t_pd *newest; +void canvas_getargs(int *argcp, t_atom **argvp); + +static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected, + t_binbuf *b) +{ + t_text *x; + int argc; + t_atom *argv; + newest = 0; + canvas_setcurrent((t_canvas *)gl); + canvas_getargs(&argc, &argv); + binbuf_eval(b, &pd_objectmaker, argc, argv); + if (binbuf_getnatom(b)) + { + if (!newest) + { + 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); + } + x->te_binbuf = b; + x->te_xpix = xpix; + x->te_ypix = ypix; + x->te_width = 0; + x->te_type = T_OBJECT; + glist_add(gl, &x->te_g); + 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, 1); + } + 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); +} + + /* object creation routine. These are called without any arguments if + they're invoked from the + gui; when pasting or restoring from a file, we get at least x and y. */ + +void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv) +{ + t_text *x; + 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, b); + } + else + { + t_binbuf *b = binbuf_new(); + int xpix, ypix; + pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1); + glist_noselect(gl); + glist_getnextxy(gl, &xpix, &ypix); + canvas_objtext(gl, xpix, ypix, 1, b); + canvas_startmotion(glist_getcanvas(gl)); + } +} + +/* make an object box for an object that's already there. */ + +/* iemlib */ +void canvas_iemguis(t_glist *gl, t_symbol *guiobjname) +{ + t_atom at; + t_binbuf *b = binbuf_new(); + int xpix, ypix; + + pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1); + glist_noselect(gl); + SETSYMBOL(&at, guiobjname); + binbuf_restore(b, 1, &at); + glist_getnextxy(gl, &xpix, &ypix); + canvas_objtext(gl, xpix, ypix, 1, b); + canvas_startmotion(glist_getcanvas(gl)); +} + +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_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 *message_class, *messresponder_class; + +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_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_list(t_message *x, t_symbol *s, int argc, t_atom *argv) +{ + binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv); +} + +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); +} + +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); +} + +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); +} + +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); + sys_vgui(".x%x.c itemconfigure %sR -width 5\n", + glist_getcanvas(x->m_glist), rtext_gettag(y)); + 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); + sys_vgui(".x%x.c itemconfigure %sR -width 1\n", + glist_getcanvas(x->m_glist), rtext_gettag(y)); + } +} + +static void message_free(t_message *x) +{ + clock_free(x->m_clock); +} + +void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv) +{ + 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; + 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); + } + else + { + int xpix, ypix; + pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1); + glist_noselect(gl); + glist_getnextxy(gl, &xpix, &ypix); + x->m_text.te_xpix = xpix-3; + x->m_text.te_ypix = ypix-3; + glist_add(gl, &x->m_text.te_g); + glist_noselect(gl); + glist_select(gl, &x->m_text.te_g); + canvas_startmotion(glist_getcanvas(gl)); + } +} + +/* ---------------------- the "atom" text item ------------------------ */ + +#define ATOMBUFSIZE 40 + +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 */ + char a_buf[ATOMBUFSIZE]; + char a_shift; +} t_gatom; + +static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!argc) return; + if (x->a_atom.a_type == A_FLOAT) + x->a_atom.a_w.w_float = atom_getfloat(argv); + else if (x->a_atom.a_type == A_SYMBOL) + x->a_atom.a_w.w_symbol = atom_getsymbol(argv); + binbuf_clear(x->a_text.te_binbuf); + binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom); + glist_retext(x->a_glist, &x->a_text); + x->a_buf[0] = 0; +} + +static void gatom_bang(t_gatom *x) +{ + if (x->a_atom.a_type == A_FLOAT) + outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float); + else if (x->a_atom.a_type == A_SYMBOL) + outlet_symbol(x->a_text.te_outlet, 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); +} + +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) +{ + t_gatom *x = (t_gatom *)z; + int c = f; + int l = strlen(x->a_buf); + t_atom at; + char sbuf[ATOMBUFSIZE + 4]; + if (c == ' ') return; + else if (c == '\b') + { + if (l > 0) + { + x->a_buf[l-1] = 0; + goto redraw; + } + } + else if (c == '\n') + { + if (x->a_atom.a_type == A_FLOAT) + gatom_float(x, atof(x->a_buf)); + else if (x->a_atom.a_type == A_SYMBOL) + gatom_symbol(x, gensym(x->a_buf)); + else bug("gatom_key"); + } + else if (l < (ATOMBUFSIZE-1)) + { + x->a_buf[l] = c; + x->a_buf[l+1] = 0; + 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); + return; + } + else gatom_float(x, x->a_toggle); + } + 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); + } +} + +static void gatom_param(t_gatom *x, t_floatarg width, t_floatarg draglo, + t_floatarg draghi) +{ + 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; + glist_retext(x->a_glist, &x->a_text); +} + +void canvas_atom(t_glist *gl, t_atomtype type, + t_symbol *s, int argc, t_atom *argv) +{ + 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; + 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; + if (type == A_FLOAT) + { + x->a_atom.a_w.w_float = 0; + x->a_text.te_width = 5; + outlet_new(&x->a_text, &s_float); + SETFLOAT(&at, 0); + } + else + { + x->a_atom.a_w.w_symbol = &s_symbol; + x->a_text.te_width = 10; + outlet_new(&x->a_text, &s_symbol); + SETSYMBOL(&at, &s_symbol); + } + binbuf_add(x->a_text.te_binbuf, 1, &at); + if (argc > 1) + { + 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); + glist_add(gl, &x->a_text.te_g); + } + else + { + int xpix, ypix; + pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1); + glist_noselect(gl); + glist_getnextxy(gl, &xpix, &ypix); + 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); + canvas_startmotion(glist_getcanvas(gl)); + } +} + +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) +{ + gfxstub_deleteforkey(x); +} + +static void gatom_properties(t_gobj *z, t_glist *owner) +{ + t_gatom *x = (t_gatom *)z; + char buf[200]; + sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g\n", + x->a_text.te_width, x->a_draglo, x->a_draghi); + gfxstub_new(&x->a_text.te_pd, x, buf); +} + + +/* -------------------- widget behavior for text objects ------------ */ + +static void text_getrect(t_gobj *z, t_glist *glist, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_text *x = (t_text *)z; + int width, height, iscomment = (x->te_type == T_TEXT); + float x1, y1, x2, y2; + + /* 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) + { + 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 + 1; /* borrowed from TMARGIN, etc, in g_rtext.c */ + } + /* 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_findrtext(glist, x); + width = rtext_width(y); + height = rtext_height(y) - (iscomment << 1); + } + else width = height = 10; + x1 = text_xpix(x, glist); + y1 = text_ypix(x, glist); + x2 = x1 + width; + y2 = y1 + height; + y1 += iscomment; + *xp1 = x1; + *yp1 = y1; + *xp2 = x2; + *yp2 = y2; +} + +static void text_displace(t_gobj *z, t_glist *glist, + int dx, int dy) +{ + 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); + rtext_displace(y, dx, dy); + text_drawborder(x, glist, rtext_gettag(y), + rtext_width(y), rtext_height(y), 0); + canvas_fixlinesfor(glist_getcanvas(glist), x); + } +} + +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); + rtext_select(y, state); + sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist, + rtext_gettag(y), (state? "blue" : "black")); +} + +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); +} + + /* return true if the text box should be drawn. + We don't show object boxes inside graphs. */ +int text_shouldvis(t_text *x, t_glist *glist) +{ + return (glist->gl_havewindow || + (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) || + (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph))); +} + +static void text_vis(t_gobj *z, t_glist *glist, int vis) +{ + t_text *x = (t_text *)z; + if (vis) + { + if (text_shouldvis(x, glist)) + { + t_rtext *y = rtext_new(glist, x, glist->gl_editor->e_rtext, 1); + if (x->te_type == T_ATOM) + glist_retext(glist, x); + text_drawborder(x, glist, rtext_gettag(y), + rtext_width(y), rtext_height(y), 1); + } + else rtext_new(glist, x, glist->gl_editor->e_rtext, 0); + } + else + { + t_rtext *y = glist_findrtext(glist, x); + if (text_shouldvis(x, glist)) + text_eraseborder(x, glist, rtext_gettag(y)); + rtext_free(y); + } +} + +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, 0, (double)alt); + return (1); + } + else return (0); + } + else if (x->te_type == T_ATOM) + { + if (doit) + gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix, + (t_floatarg)shift, 0, (t_floatarg)alt); + 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, 0, (t_floatarg)alt); + return (1); + } + else return (0); +} + +static void text_save(t_gobj *z, t_binbuf *b) +{ + 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)))) + { + mess1(&x->te_pd, gensym("saveto"), b); + binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"), + (t_int)x->te_xpix, (t_int)x->te_ypix); + } + else /* otherwise just save the text */ + { + binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"), + (t_int)x->te_xpix, (t_int)x->te_ypix); + } + binbuf_addbinbuf(b, x->te_binbuf); + binbuf_addv(b, ";"); + } + else if (x->te_type == T_MESSAGE) + { + binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"), + (t_int)x->te_xpix, (t_int)x->te_ypix); + binbuf_addbinbuf(b, x->te_binbuf); + binbuf_addv(b, ";"); + } + else if (x->te_type == T_ATOM) + { + 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"))); + binbuf_addv(b, "ssiiiff", gensym("#X"), sel, + (t_int)x->te_xpix, (t_int)x->te_ypix, (t_int)x->te_width, + (double)((t_gatom *)x)->a_draglo, (double)((t_gatom *)x)->a_draghi); + binbuf_addv(b, ";"); + } + else + { + binbuf_addv(b, "ssii", gensym("#X"), gensym("text"), + (t_int)x->te_xpix, (t_int)x->te_ypix); + binbuf_addbinbuf(b, x->te_binbuf); + binbuf_addv(b, ";"); + } +} + + /* 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_save, + 0, +}; + +static t_widgetbehavior gatom_widgetbehavior = +{ + text_getrect, + text_displace, + text_select, + text_activate, + text_delete, + text_vis, + text_click, + text_save, + gatom_properties, +}; + +/* -------------------- the "text" class ------------ */ + +#ifdef MACOSX +#define EXTRAPIX 2 +#else +#define EXTRAPIX 1 +#endif + + /* 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) +{ + int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i; + int width = x2 - x1; + for (i = 0; i < n; i++) + { + int onset = x1 + (width - IOWIDTH) * i / nplus; + if (firsttime) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %so%d\n", + glist_getcanvas(glist), + onset, y2 - 1, + onset + IOWIDTH, y2, + tag, i); + else + sys_vgui(".x%x.c coords %so%d %d %d %d %d\n", + glist_getcanvas(glist), tag, i, + onset, y2 - 1, + onset + IOWIDTH, y2); + } + 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) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %si%d\n", + glist_getcanvas(glist), + onset, y1, + onset + IOWIDTH, y1 + EXTRAPIX, + tag, i); + else + sys_vgui(".x%x.c coords %si%d %d %d %d %d\n", + glist_getcanvas(glist), tag, i, + onset, y1, + onset + IOWIDTH, y1 + EXTRAPIX); + } +} + +void text_drawborder(t_text *x, t_glist *glist, + char *tag, int width2, int height2, int firsttime) +{ + t_object *ob; + int x1, y1, x2, y2, width, height; + text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2); + width = x2 - x1; + height = y2 - y1; + if (x->te_type == T_OBJECT) + { + if (firsttime) + sys_vgui(".x%x.c create line\ + %d %d %d %d %d %d %d %d %d %d -tags %sR\n", + glist_getcanvas(glist), + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, tag); + else + sys_vgui(".x%x.c coords %sR\ + %d %d %d %d %d %d %d %d %d %d\n", + glist_getcanvas(glist), tag, + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1); + } + else if (x->te_type == T_MESSAGE) + { + if (firsttime) + sys_vgui(".x%x.c create line\ + %d %d %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n", + glist_getcanvas(glist), + x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2, + x1, y2, x1, y1, + tag); + else + sys_vgui(".x%x.c coords %sR\ + %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", + glist_getcanvas(glist), tag, + x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2, + x1, y2, x1, y1); + } + else if (x->te_type == T_ATOM) + { + if (firsttime) + sys_vgui(".x%x.c create line\ + %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n", + glist_getcanvas(glist), + x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1, + tag); + else + sys_vgui(".x%x.c coords %sR\ + %d %d %d %d %d %d %d %d %d %d %d %d\n", + glist_getcanvas(glist), tag, + x1, y1, x2, y1, x2+4, y1+4, x2+4, y2, x1, y2, x1, y1); + } + /* draw inlets/outlets */ + + if (ob = pd_checkobject(&x->te_pd)) + glist_drawiofor(glist, ob, firsttime, tag, x1, y1, x2, y2); +} + +void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag) +{ + int i, n; + n = obj_noutlets(ob); + for (i = 0; i < n; i++) + sys_vgui(".x%x.c delete %so%d\n", + glist_getcanvas(glist), tag, i); + n = obj_ninlets(ob); + for (i = 0; i < n; i++) + sys_vgui(".x%x.c delete %si%d\n", + glist_getcanvas(glist), tag, i); +} + +void text_eraseborder(t_text *x, t_glist *glist, char *tag) +{ + if (x->te_type == T_TEXT) return; + sys_vgui(".x%x.c delete %sR\n", + glist_getcanvas(glist), tag); + glist_eraseiofor(glist, x, tag); +} + + /* change text; if T_OBJECT, remake it. LATER we'll have an undo buffer + which should be filled in here before making the change. */ + +void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize) +{ + if (x->te_type == T_OBJECT) + { + t_binbuf *b = binbuf_new(); + int natom1, natom2; + t_atom *vec1, *vec2; + binbuf_text(b, buf, bufsize); + natom1 = binbuf_getnatom(x->te_binbuf); + vec1 = binbuf_getvec(x->te_binbuf); + natom2 = binbuf_getnatom(b); + vec2 = binbuf_getvec(b); + /* special case: if pd args change just pass the message on. */ + if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL + && !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") && + vec2[0].a_type == A_SYMBOL + && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd")) + { + typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1); + binbuf_free(x->te_binbuf); + x->te_binbuf = b; + } + else /* normally, just destroy the old one and make a new one. */ + { + int xwas = x->te_xpix, ywas = x->te_ypix; + glist_delete(glist, &x->te_g); + canvas_objtext(glist, xwas, ywas, 0, b); + /* if it's an abstraction loadbang it here */ + if (newest && pd_class(newest) == canvas_class) + canvas_loadbang((t_canvas *)newest); + canvas_restoreconnections(glist_getcanvas(glist)); + } + /* if we made a new "pd" or changed a window name, + update window list */ + if (natom2 >= 1 && vec2[0].a_type == A_SYMBOL + && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd")) + canvas_updatewindowlist(); + } + else binbuf_text(x->te_binbuf, buf, bufsize); +} + +void g_text_setup(void) +{ + text_class = class_new(gensym("text"), 0, 0, sizeof(t_text), + CLASS_NOINLET | CLASS_PATCHABLE, 0); + + message_class = class_new(gensym("message"), 0, (t_method)message_free, + sizeof(t_message), CLASS_PATCHABLE, 0); + class_addbang(message_class, message_bang); + class_addfloat(message_class, message_float); + class_addsymbol(message_class, message_symbol); + class_addlist(message_class, message_list); + class_addanything(message_class, message_list); + + class_addmethod(message_class, (t_method)message_click, gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_addmethod(message_class, (t_method)message_set, gensym("set"), + A_GIMME, 0); + class_addmethod(message_class, (t_method)message_add, gensym("add"), + A_GIMME, 0); + class_addmethod(message_class, (t_method)message_add2, gensym("add2"), + A_GIMME, 0); + + messresponder_class = class_new(gensym("messresponder"), 0, 0, + sizeof(t_text), CLASS_PD, 0); + class_addbang(messresponder_class, messresponder_bang); + class_addfloat(messresponder_class, (t_method) messresponder_float); + class_addsymbol(messresponder_class, messresponder_symbol); + class_addlist(messresponder_class, messresponder_list); + class_addanything(messresponder_class, messresponder_anything); + + gatom_class = class_new(gensym("gatom"), 0, (t_method)gatom_free, + sizeof(t_gatom), CLASS_PATCHABLE, 0); + class_addbang(gatom_class, gatom_bang); + class_addfloat(gatom_class, gatom_float); + class_addsymbol(gatom_class, gatom_symbol); + class_addmethod(gatom_class, (t_method)gatom_set, gensym("set"), + A_GIMME, 0); + class_addmethod(gatom_class, (t_method)gatom_click, gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"), + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_setwidget(gatom_class, &gatom_widgetbehavior); +} + + |