From 65e665e2506907e3e4d0bc94dffcb83f4b6240df Mon Sep 17 00:00:00 2001 From: "B. Bogart" Date: Fri, 20 Feb 2004 20:25:32 +0000 Subject: First release of popup menu external. has some GOP + outlet issues. svn path=/trunk/externals/bbogart/; revision=1322 --- popup/popup.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 popup/popup.c (limited to 'popup/popup.c') diff --git a/popup/popup.c b/popup/popup.c new file mode 100644 index 0000000..a8fce61 --- /dev/null +++ b/popup/popup.c @@ -0,0 +1,456 @@ +/* Popup menu widget for PD */ +/* Based on button from GGEE by Guenter Geiger */ +/* Copyright Ben Bogart 2004 ben@ekran.org */ + + +#include +#include +#include +#include + + + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#if PD_MINOR_VERSION < 37 +#define t_rtext t_text +#endif + +#ifndef IOWIDTH +#define IOWIDTH 4 +#endif + +#define MAX_OPTIONS 100 + +typedef struct _popup +{ + t_object x_obj; + + t_glist * x_glist; + t_outlet* out2; + int x_rect_width; + int x_rect_height; + t_symbol* x_sym; + + int x_height; + int x_width; + + int x_char_width; + int x_num_options; + t_symbol* x_colour; + t_symbol* x_name; + + t_symbol* x_options[MAX_OPTIONS]; + +} t_popup; + +/* widget helper functions */ + +#define DEBUG(x) + + +static void draw_inlets(t_popup *x, t_glist *glist, int firsttime, int nin, int nout) +{ + /* outlets */ + int n = nin; + int nplus, i; + nplus = (n == 1 ? 1 : n-1); + DEBUG(post("draw inlet");) + for (i = 0; i < n; i++) + { + int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus; + if (firsttime) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags {%xo%d %xo}\n", + glist_getcanvas(glist), + onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 2, + onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-1, + x, i, x); + else + sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n", + glist_getcanvas(glist), x, i, + onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 2, + onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-1); + } + /* inlets */ + n = nout; + nplus = (n == 1 ? 1 : n-1); + for (i = 0; i < n; i++) + { + int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus; + if (firsttime) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags {%xi%d %xi}\n", + glist_getcanvas(glist), + onset, text_ypix(&x->x_obj, glist), + onset + IOWIDTH, text_ypix(&x->x_obj, glist)+1, + x, i, x); + else + sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n", + glist_getcanvas(glist), x, i, + onset, text_ypix(&x->x_obj, glist), + onset + IOWIDTH, text_ypix(&x->x_obj, glist)+1); + + } + DEBUG(post("draw inlet end");) +} + + +static void draw_handle(t_popup *x, t_glist *glist, int firsttime) { + int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH+2); + + if (firsttime) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xhandle\n", + glist_getcanvas(glist), + onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12, + onset + IOWIDTH-2, text_ypix(&x->x_obj, glist) + x->x_rect_height-4, + x); + else + sys_vgui(".x%x.c coords %xhandle %d %d %d %d\n", + glist_getcanvas(glist), x, + onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12, + onset + IOWIDTH-2, text_ypix(&x->x_obj, glist) + x->x_rect_height-4); +} + +static void create_widget(t_popup *x, t_glist *glist) +{ + char text[MAXPDSTRING]; + int len,i; + t_canvas *canvas=glist_getcanvas(glist); + x->x_rect_width = x->x_width+10; + x->x_rect_height = x->x_height*20+9; + + /* Create menubutton and empty menu widget -- maybe the menu should be created elseware?*/ + sys_vgui("set %xw .x%x.c.s%x ; menubutton $%xw -relief raised -width \"%d\" -background \"%s\" -text \"%s\" -direction flush -menu $%xw.menu ; menu $%xw.menu -tearoff 0\n", + x,canvas,x,x,x->x_char_width,x->x_colour->s_name,x->x_name->s_name,x,x); + + for(i=0 ; ix_num_options ; i++) + { + sys_vgui(".x%x.c.s%x.menu add command -label \"%s\" -command {.x%x.c.s%x configure -text \"%s\" ; popup_sel%x \"%d\"} \n", + canvas, x, x->x_options[i]->s_name, canvas, x, x->x_options[i]->s_name, x, i); + } + + DEBUG(post("id: .x%x.c.s%x", canvas, x);) +} + +static void popup_drawme(t_popup *x, t_glist *glist, int firsttime) +{ + t_canvas *canvas=glist_getcanvas(glist); + DEBUG(post("drawme %d",firsttime);) + if (firsttime) { + DEBUG(post("glist %x canvas %x",x->x_glist,canvas);) + if (x->x_glist != canvas) { + create_widget(x,glist); + x->x_glist = canvas; + } + sys_vgui(".x%x.c create window %d %d -anchor nw -window .x%x.c.s%x -tags %xS\n", + canvas,text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x->x_glist,x,x); + + } + else { + sys_vgui(".x%x.c coords %xS \ +%d %d\n", + canvas, x, + text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)); + } + draw_inlets(x, glist, firsttime, 2,1); + // draw_handle(x, glist, firsttime); + +} + + +static void popup_erase(t_popup* x,t_glist* glist) +{ + int n; + + DEBUG(post("erase");) + sys_vgui("destroy .x%x.c.s%x\n",glist_getcanvas(glist),x); + + sys_vgui(".x%x.c delete %xS\n",glist_getcanvas(glist), x); + + /* inlets and outlets */ + + sys_vgui(".x%x.c delete %xi\n",glist_getcanvas(glist),x); /* Added tag for all inlets of one instance */ + sys_vgui(".x%x.c delete %xo\n",glist_getcanvas(glist),x); /* Added tag for all outlets of one instance */ + sys_vgui(".x%x.c delete %xhandle\n",glist_getcanvas(glist),x,0); +} + + + +/* ------------------------ popup widgetbehaviour----------------------------- */ + + +static void popup_getrect(t_gobj *z, t_glist *owner, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + int width, height; + t_popup* s = (t_popup*)z; + + width = s->x_rect_width; + height = s->x_rect_height; + *xp1 = text_xpix(&s->x_obj, owner); + *yp1 = text_ypix(&s->x_obj, owner) - 1; + *xp2 = text_xpix(&s->x_obj, owner) + width; + *yp2 = text_ypix(&s->x_obj, owner) + height; +} + +static void popup_displace(t_gobj *z, t_glist *glist, + int dx, int dy) +{ + t_popup *x = (t_popup *)z; + DEBUG(post("displace");) + x->x_obj.te_xpix += dx; + x->x_obj.te_ypix += dy; + if (glist_isvisible(glist)) + { + sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n", + glist_getcanvas(glist), x, + text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)-1, + text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height-2); + + popup_drawme(x, glist, 0); + canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x); + } + DEBUG(post("displace end");) +} + +static void popup_select(t_gobj *z, t_glist *glist, int state) +{ + t_popup *x = (t_popup *)z; + if (state) { + sys_vgui(".x%x.c create rectangle \ +%d %d %d %d -tags %xSEL -outline blue\n", + glist_getcanvas(glist), + text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)-1, + text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height-2, + x); + } + else { + sys_vgui(".x%x.c delete %xSEL\n", + glist_getcanvas(glist), x); + } +} + +static void popup_activate(t_gobj *z, t_glist *glist, int state) +{ +/* What does this do, why commented out? + 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 popup_delete(t_gobj *z, t_glist *glist) +{ + t_text *x = (t_text *)z; + canvas_deletelinesfor(glist_getcanvas(glist), x); +} + + +static void popup_vis(t_gobj *z, t_glist *glist, int vis) +{ + t_popup* s = (t_popup*)z; + t_rtext *y; + DEBUG(post("vis: %d",vis);) + if (vis) { +#ifdef PD_MINOR_VERSION + y = (t_rtext *) rtext_new(glist, (t_text *)z); +#else + y = (t_rtext *) rtext_new(glist, (t_text *)z,0,0); +#endif + popup_drawme(s, glist, 1); + } + else { + y = glist_findrtext(glist, (t_text *)z); + popup_erase(s,glist); + rtext_free(y); + } +} + +static void popup_save(t_gobj *z, t_binbuf *b); + +t_widgetbehavior popup_widgetbehavior = { + w_getrectfn: popup_getrect, + w_displacefn: popup_displace, + w_selectfn: popup_select, + w_activatefn: popup_activate, + w_deletefn: popup_delete, + w_visfn: popup_vis, +#if PD_MINOR_VERSION < 37 + w_savefn: popup_save, +#endif + w_clickfn: NULL, +#if PD_MINOR_VERSION < 37 + w_propertiesfn: NULL, +#endif +}; + +static void popup_output(t_popup* x, t_floatarg popup_index) +{ + outlet_symbol(x->out2, x->x_options[(int)popup_index]); + outlet_float(x->x_obj.ob_outlet, popup_index); +} + + +static void popup_save(t_gobj *z, t_binbuf *b) +{ + int i; + t_popup *x = (t_popup *)z; + + binbuf_addv(b, "ssiisiss", gensym("#X"),gensym("obj"), + x->x_obj.te_xpix, x->x_obj.te_ypix , + gensym("popup"), x->x_char_width, x->x_colour, x->x_name); + /* Loop for menu items */ + for(i=0 ; ix_num_options ; i++) + { + binbuf_addv(b, "s", x->x_options[i]); + } + binbuf_addv(b, ";"); +} + +/* function to change the popup's menu */ +void popup_options(t_popup* x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + + x->x_num_options = argc; + + /* delete old menu items */ + sys_vgui(".x%x.c.s%x.menu delete 0 end \n", x->x_glist, x); + + for(i=0 ; ix_options[i] = atom_getsymbol(argv+i); + sys_vgui(".x%x.c.s%x.menu add command -label \"%s\" -command {.x%x.c.s%x configure -text \"%s\" ; popup_sel%x \"%d\"} \n", + x->x_glist, x, x->x_options[i]->s_name, x->x_glist, x, x->x_options[i]->s_name, x, i); + } +} + +/* function to change width of popup */ +void popup_width(t_popup* x, t_floatarg w) +{ + x->x_char_width = (int)w; + sys_vgui(".x%x.c.s%x configure -width %d\n", x->x_glist, x, x->x_char_width); +} + +/* function to change colour of popup background */ +void popup_bgcolour(t_popup* x, t_symbol* col) +{ + x->x_colour->s_name = col->s_name; + sys_vgui(".x%x.c.s%x configure -background \"%s\"\n", x->x_glist, x, col->s_name); +} + +/* Function to change name of popup */ +static void popup_name(t_popup* x, t_symbol *name) +{ + x->x_name->s_name = name->s_name; + sys_vgui(".x%x.c.s%x configure -text \"%s\"\n", x->x_glist, x, name->s_name); +} + +/* Function to select a menu option by inlet */ +static void popup_iselect(t_popup* x, t_floatarg item) +{ + int i=(int)item; + if( ix_num_options && i>=0) + { + sys_vgui(".x%x.c.s%x configure -text \"%s\" ; popup_sel%x \"%d\" \n", + glist_getcanvas(x->x_glist), x, x->x_options[i]->s_name,x, i); + } else { + post("popup: Valid menu selections are from %d to %d\npopup: You entered %d.", 0, x->x_num_options, i); + } +} + +static t_class *popup_class; + + +static void *popup_new(t_symbol *s, int argc, t_atom *argv) +{ + t_popup *x = (t_popup *)pd_new(popup_class); + int i; + char buf[256]; + + x->x_glist = (t_glist*)NULL; + + + x->x_height = 1; + + if (argc < 4) + { + post("popup: You must enter at least 4 arguments. Default values used."); + x->x_char_width = 10; + x->x_num_options = 1; + x->x_colour = gensym("#ffffff"); + x->x_name = gensym("popup"); + + x->x_options[0] = gensym("option"); + + } else { + /* Copy args into structure */ + x->x_char_width = atom_getint(argv); + x->x_colour = atom_getsymbol(argv+1); + x->x_name = atom_getsymbol(argv+2); + + x->x_num_options = argc-3; + + for(i=0 ; ix_num_options ; i++) + { + x->x_options[i] = atom_getsymbol( argv+(i+3) ); + } + } + + /* TODO .. ask the popup for its width -- "[canvas] itemcget [tags] -width" -- but how to pass the data back?*/ + /* x->x_width = x->x_char_width*10; tuned for OSX */ + x->x_width = x->x_char_width*7; /* tuned for Linux */ + + /* Bind the recieve "popup%p" to the widget outlet*/ + sprintf(buf,"popup%p",x); + x->x_sym = gensym(buf); + pd_bind(&x->x_obj.ob_pd, x->x_sym); + + /* define proc in tcl/tk where "popup%p" is the receive, "output" is the method, and "$index" is an argument. */ + sys_vgui("proc popup_sel%x {index} {\n pd [concat popup%p output $index \\;]\n }\n",x,x); + + outlet_new(&x->x_obj, &s_float); + x->out2 = outlet_new(&x->x_obj, &s_symbol); + return (x); +} + +void popup_setup(void) { + popup_class = class_new(gensym("popup"), (t_newmethod)popup_new, 0, + sizeof(t_popup),0,A_GIMME,0); + + class_addmethod(popup_class, (t_method)popup_output, + gensym("output"), + A_DEFFLOAT, + 0); + + class_addmethod(popup_class, (t_method)popup_width, + gensym("width"), + A_DEFFLOAT, + 0); + + class_addmethod(popup_class, (t_method)popup_name, + gensym("name"), + A_DEFSYMBOL, + 0); + + class_addmethod(popup_class, (t_method)popup_options, + gensym("options"), + A_GIMME, + 0); + + class_addmethod(popup_class, (t_method)popup_bgcolour, + gensym("bgcolour"), + A_DEFSYMBOL, + 0); + class_doaddfloat(popup_class, (t_method)popup_iselect); + + class_setwidget(popup_class,&popup_widgetbehavior); +#if PD_MINOR_VERSION >= 37 + class_setsavefn(popup_class,&popup_save); +#endif + + post("Popup v0 Ben Bogart."); +} + + -- cgit v1.2.1