diff options
Diffstat (limited to 'text.c')
-rw-r--r-- | text.c | 824 |
1 files changed, 824 insertions, 0 deletions
@@ -0,0 +1,824 @@ +/* text widget for Pd + + Copyright 2003 Guenter Geiger + Copyright 2004 Ben Bogart <ben@ekran.org> + Copyright 2007 Hans-Christoph Steiner <hans@at.or.at> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <stdio.h> +#include <string.h> +#include "shared/tkwidgets.h" + +/* TODO: get Ctrl-A working to select all */ +/* TODO: set message doesnt work with a loadbang */ + + +#define DEFAULT_COLOR "grey70" + +#define TEXT_DEFAULT_WIDTH 130 +#define TEXT_DEFAULT_HEIGHT 60 +#define TEXT_MIN_WIDTH 40 +#define TEXT_MIN_HEIGHT 20 + +#define TOTAL_INLETS 1 +#define TOTAL_OUTLETS 2 + +#define DEBUG(x) x + +typedef struct _textwidget +{ + t_object x_obj; + t_canvas* x_canvas; + t_glist* x_glist; + + t_symbol* x_receive_name; + + int x_height; + int x_width; + int x_resizing; + + t_symbol* x_font_face; + t_int x_font_size; + t_symbol* x_font_weight; + + t_float x_border; + t_symbol* x_relief; + t_int x_have_scrollbar; + t_int x_selected; + + /* IDs for Tk widgets */ + char* tcl_namespace; + char* canvas_id; + char* frame_id; + char* text_id; + char* scrollbar_id; + char* handle_id; + char* window_tag; + char* all_tag; + + t_outlet* x_data_outlet; + t_outlet* x_status_outlet; +} t_textwidget; + +static t_class *textwidget_class; + +static char *tk_options[] = { + "autoseparators", + "background", + "borderwidth", + "cursor", + "exportselection", + "font", + "foreground", + "height", + "highlightbackground", + "highlightcolor", + "highlightthickness", + "insertbackground", + "insertborderwidth", + "insertofftime", + "insertontime", + "insertwidth", + "maxundo", + "padx", + "pady", + "relief", + "selectbackground", + "selectborderwidth", + "selectforeground", + "setgrid", + "spacing1", + "spacing2", + "spacing3", + "state", + "tabs", + "takefocus", + "undo", + "width", + "wrap", + "xscrollcommand", + "yscrollcommand" +}; + + +/* move these to tkwidgets.c */ +static t_symbol *backspace_symbol; +static t_symbol *return_symbol; +static t_symbol *space_symbol; +static t_symbol *tab_symbol; +static t_symbol *escape_symbol; +static t_symbol *left_symbol; +static t_symbol *right_symbol; +static t_symbol *up_symbol; +static t_symbol *down_symbol; + +/* function prototypes */ + +static void textwidget_getrect(t_gobj *z, t_glist *owner, int *xp1, int *yp1, int *xp2, int *yp2); +static void textwidget_displace(t_gobj *z, t_glist *glist, int dx, int dy); +static void textwidget_select(t_gobj *z, t_glist *glist, int state); +static void textwidget_activate(t_gobj *z, t_glist *glist, int state); +static void textwidget_delete(t_gobj *z, t_glist *glist); +static void textwidget_vis(t_gobj *z, t_glist *glist, int vis); +//static int textwidget_click(t_gobj *z, t_glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit); +static void textwidget_save(t_gobj *z, t_binbuf *b); + + +static t_widgetbehavior textwidget_widgetbehavior = { +w_getrectfn: textwidget_getrect, +w_displacefn: textwidget_displace, +w_selectfn: textwidget_select, +w_activatefn: textwidget_activate, +w_deletefn: textwidget_delete, +w_visfn: textwidget_vis, +w_clickfn: NULL, +}; + +/* widget helper functions */ +static void set_tk_widget_ids(t_textwidget *x, t_canvas *canvas) +{ + char buf[MAXPDSTRING]; + + x->x_canvas = canvas; + + /* Tk ID for the current canvas that this object is drawn in */ + sprintf(buf,".x%lx.c", (long unsigned int) canvas); + x->canvas_id = getbytes(strlen(buf)); + strcpy(x->canvas_id, buf); + + /* Tk ID for the "frame" the other things are drawn in */ + sprintf(buf,"%s.frame%lx", x->canvas_id, (long unsigned int)x); + x->frame_id = getbytes(strlen(buf)); + strcpy(x->frame_id, buf); + + sprintf(buf,"%s.text%lx", x->frame_id, (long unsigned int)x); + x->text_id = getbytes(strlen(buf)); + strcpy(x->text_id, buf); /* Tk ID for the "text", the meat! */ + + sprintf(buf,"%s.window%lx", x->canvas_id, (long unsigned int)x); + x->window_tag = getbytes(strlen(buf)); + strcpy(x->window_tag, buf); /* Tk ID for the resizing "window" */ + post(""); + + sprintf(buf,"%s.handle%lx", x->canvas_id, (long unsigned int)x); + x->handle_id = getbytes(strlen(buf)); + strcpy(x->handle_id, buf); /* Tk ID for the resizing "handle" */ + + sprintf(buf,"%s.scrollbar%lx", x->frame_id, (long unsigned int)x); + x->scrollbar_id = getbytes(strlen(buf)); + strcpy(x->scrollbar_id, buf); /* Tk ID for the optional "scrollbar" */ + + sprintf(buf,"all%lx", (long unsigned int)x); + x->all_tag = getbytes(strlen(buf)); + strcpy(x->all_tag, buf); /* Tk ID for the optional "scrollbar" */ +} + +static int calculate_onset(t_textwidget *x, t_glist *glist, + int current_iolet, int total_iolets) +{ + post("calculate_onset"); + return(text_xpix(&x->x_obj, glist) + (x->x_width - IOWIDTH) \ + * current_iolet / (total_iolets == 1 ? 1 : total_iolets - 1)); +} + +static void textwidget_draw_inlets(t_textwidget *x, t_glist *glist, int firsttime, + int total_inlets, int total_outlets) +{ + DEBUG(post("textwidget_draw_inlets in: %d out: %d", total_inlets, total_outlets);); + int i, onset; + + for (i = 0; i < total_inlets; i++) /* inlets */ + { + onset = calculate_onset(x, glist, i, total_inlets); + sys_vgui("%s create rectangle %d %d %d %d -tags {%xi%d %xi %s}\n", + x->canvas_id, onset, text_ypix(&x->x_obj, glist) - 2, + onset + IOWIDTH, text_ypix(&x->x_obj, glist), + x, i, x, x->all_tag); + } + for (i = 0; i < total_outlets; i++) /* outlets */ + { + onset = calculate_onset(x, glist, i, total_outlets); + sys_vgui("%s create rectangle %d %d %d %d -tags {%xo%d %xo %s}\n", + x->canvas_id, onset, text_ypix(&x->x_obj, glist) + x->x_height, + onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_height + 2, + x, i, x, x->all_tag); + } +} + +static void erase_inlets(t_textwidget *x) +{ + DEBUG(post("erase_inlets");); +/* Added tag for all inlets/outlets of one instance */ + sys_vgui("%s delete %xi\n", x->canvas_id, x); + sys_vgui("%s delete %xo\n", x->canvas_id, x); + +} + +static void draw_scrollbar(t_textwidget *x) +{ + sys_vgui("pack %s -side right -fill y -before %s \n", + x->scrollbar_id, x->text_id); + x->x_have_scrollbar = 1; +} + +static void erase_scrollbar(t_textwidget *x) +{ + sys_vgui("pack forget %s \n", x->scrollbar_id); + x->x_have_scrollbar = 0; +} + +static void bind_standard_keys(t_textwidget *x) +{ +#ifdef __APPLE__ + sys_vgui("bind %s <Mod1-Key> {pdtk_canvas_ctrlkey %s %%K 0}\n", + x->text_id, x->canvas_id); + sys_vgui("bind %s <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %s %%K 1}\n", + x->text_id, x->canvas_id); +#else + sys_vgui("bind %s <Control-Key> {pdtk_canvas_ctrlkey %s %%K 0}\n", + x->text_id, x->canvas_id); + sys_vgui("bind %s <Control-Shift-Key> {pdtk_canvas_ctrlkey %s %%K 1}\n", + x->text_id, x->canvas_id); +#endif +} + +static void bind_button_events(t_textwidget *x) +{ + /* mouse buttons */ + sys_vgui("bind %s <Button> {pdtk_canvas_sendclick %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] %%b 0}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); + sys_vgui("bind %s <ButtonRelease> {pdtk_canvas_mouseup %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] %%b}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); + sys_vgui("bind %s <Shift-Button> {pdtk_canvas_click %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] %%b 1}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); + sys_vgui("bind %s <Button-2> {pdtk_canvas_rightclick %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] %%b}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); + sys_vgui("bind %s <Button-3> {pdtk_canvas_rightclick %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] %%b}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); + sys_vgui("bind %s <Control-Button> {pdtk_canvas_rightclick %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] %%b}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); + /* mouse motion */ + sys_vgui("bind %s <Motion> {pdtk_canvas_motion %s \ +[expr %%X - [winfo rootx %s]] [expr %%Y - [winfo rooty %s]] 0}\n", + x->text_id, x->canvas_id, x->canvas_id, x->canvas_id); +} + +static void create_widget(t_textwidget *x) +{ + DEBUG(post("create_widget");); + /* I guess this is for fine-tuning of the rect size based on width and height? */ + + sys_vgui("namespace eval text%lx {} \n", x); + + /* Seems we have to delete the widget in case it already exists (Provided by Guenter)*/ + sys_vgui("destroy %s\n", x->frame_id); + sys_vgui("frame %s \n", x->frame_id); + sys_vgui("text %s -font {%s %d %s} -border 1 \ + -highlightthickness 1 -relief sunken -bg \"%s\" -fg \"%s\" \ + -yscrollcommand {%s set} \n", + x->text_id, + x->x_font_face->s_name, x->x_font_size, x->x_font_weight->s_name, + DEFAULT_COLOR, "black", + x->scrollbar_id); + sys_vgui("scrollbar %s -command {%s yview}\n", + x->scrollbar_id, x->text_id); + sys_vgui("pack %s -side left -fill both -expand 1 \n", x->text_id); + sys_vgui("pack %s -side bottom -fill both -expand 1 \n", x->frame_id); + + bind_standard_keys(x); + bind_button_events(x); + sys_vgui("bind %s <KeyRelease> {+pd %s keyup %%N \\;} \n", + x->text_id, x->x_receive_name->s_name); +} + +static void textwidget_drawme(t_textwidget *x, t_glist *glist, int firsttime) +{ + DEBUG(post("textwidget_drawme: firsttime %d canvas %lx glist %lx", firsttime, x->x_canvas, glist);); + set_tk_widget_ids(x,glist_getcanvas(glist)); + if (firsttime) + { + create_widget(x); + textwidget_draw_inlets(x, glist, firsttime, TOTAL_INLETS, TOTAL_OUTLETS); + if(x->x_have_scrollbar) draw_scrollbar(x); + sys_vgui("%s create window %d %d -anchor nw -window %s \ + -tags {%s %s} -width %d -height %d \n", x->canvas_id, + text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist), + x->frame_id, x->window_tag, x->all_tag, x->x_width, x->x_height); + } + else + { + post("NO MORE COORDS"); +// sys_vgui("%s coords %s %d %d\n", x->canvas_id, x->all_tag, +// text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)); + } +} + + +static void textwidget_erase(t_textwidget* x,t_glist* glist) +{ + DEBUG(post("textwidget_erase: canvas %lx glist %lx", x->x_canvas, glist);); + + set_tk_widget_ids(x,glist_getcanvas(glist)); + erase_inlets(x); + sys_vgui("destroy %s\n", x->frame_id); + sys_vgui("%s delete %s\n", x->canvas_id, x->all_tag); +} + + + +/* ------------------------ text widgetbehaviour----------------------------- */ + + +static void textwidget_getrect(t_gobj *z, t_glist *owner, + int *xp1, int *yp1, int *xp2, int *yp2) +{ +// DEBUG(post("textwidget_getrect");); /* this one is very chatty :D */ + t_textwidget *x = (t_textwidget*)z; + *xp1 = text_xpix(&x->x_obj, owner); + *yp1 = text_ypix(&x->x_obj, owner); + *xp2 = *xp1 + x->x_width; + *yp2 = *yp1 + x->x_height + 2; // add 2 to give space for outlets +} + +static void textwidget_displace(t_gobj *z, t_glist *glist, int dx, int dy) +{ + t_textwidget *x = (t_textwidget *)z; + DEBUG(post("textwidget_displace: canvas %lx glist %lx", x->x_canvas, glist);); + x->x_obj.te_xpix += dx; + x->x_obj.te_ypix += dy; + if (glist_isvisible(glist)) + { + set_tk_widget_ids(x,glist_getcanvas(glist)); + sys_vgui("%s move %s %d %d\n", x->canvas_id, x->all_tag, dx, dy); + sys_vgui("%s move RSZ %d %d\n", x->canvas_id, dx, dy); +/* sys_vgui("%s coords %s %d %d %d %d\n", x->canvas_id, x->all_tag, + text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)-1, + text_xpix(&x->x_obj, glist) + x->x_width, + text_ypix(&x->x_obj, glist) + x->x_height-2);*/ +// textwidget_drawme(x, glist, 0); + canvas_fixlinesfor(glist_getcanvas(glist), (t_text*) x); + } + DEBUG(post("displace end");); +} + +static void textwidget_select(t_gobj *z, t_glist *glist, int state) +{ + t_textwidget *x = (t_textwidget *)z; + DEBUG(post("textwidget_select: canvas %lx glist %lx state %d", x->x_canvas, glist, state);); + + if( (state) && (!x->x_selected)) + { + sys_vgui("%s configure -bg #bdbddd -state disabled -cursor $cursor_editmode_nothing\n", + x->text_id); + x->x_selected = 1; + } + else if (!state) + { + sys_vgui("%s configure -bg grey -state normal -cursor xterm\n", + x->text_id); + /* activatefn never gets called with 0, so destroy here */ + sys_vgui("destroy %s\n", x->handle_id); + x->x_selected = 0; + } +} + +static void textwidget_activate(t_gobj *z, t_glist *glist, int state) +{ + DEBUG(post("textwidget_activate");); + t_textwidget *x = (t_textwidget *)z; + int x1, y1, x2, y2; + + if(state) + { + textwidget_getrect(z, glist, &x1, &y1, &x2, &y2); + sys_vgui("canvas %s -width %d -height %d -bg #ddd -bd 0 \ +-highlightthickness 3 -highlightcolor {#f00} -cursor bottom_right_corner\n", + x->handle_id, TKW_HANDLE_WIDTH, TKW_HANDLE_HEIGHT); + int handle_x1 = x2 - TKW_HANDLE_WIDTH; + int handle_y1 = y2 - (TKW_HANDLE_HEIGHT - TKW_HANDLE_INSET); +// int handle_x2 = x2; +// int handle_y2 = y2 - TKW_HANDLE_INSET; +/* no worky, this should draw MAC OS X style lines on the resize handle */ +/* sys_vgui("%s create line %d %d %d %d -fill black -tags RESIZE_LINES\n", */ +/* x->handle_id, handle_x2, handle_y1, handle_x1, handle_y2); */ + sys_vgui("%s create window %d %d -anchor nw -width %d -height %d -window %s -tags RSZ\n", + x->canvas_id, handle_x1, handle_y1, + TKW_HANDLE_WIDTH, TKW_HANDLE_HEIGHT, + x->handle_id, x->all_tag); + sys_vgui("raise %s\n", x->handle_id); + sys_vgui("bind %s <Button> {pd [concat %s resize_click 1 \\;]}\n", + x->handle_id, x->x_receive_name->s_name); + sys_vgui("bind %s <ButtonRelease> {pd [concat %s resize_click 0 \\;]}\n", + x->handle_id, x->x_receive_name->s_name); + sys_vgui("bind %s <Motion> {pd [concat %s resize_motion %%x %%y \\;]}\n", + x->handle_id, x->x_receive_name->s_name); + } +} + +static void textwidget_delete(t_gobj *z, t_glist *glist) +{ + DEBUG(post("textwidget_delete: glist %lx", glist);); + t_text *x = (t_text *)z; + canvas_deletelinesfor(glist_getcanvas(glist), x); +} + + +static void textwidget_vis(t_gobj *z, t_glist *glist, int vis) +{ + t_textwidget *x = (t_textwidget*)z; + DEBUG(post("textwidget_vis: vis %d canvas %lx glist %lx", vis, x->x_canvas, glist);); + t_rtext *y; + if (vis) { + y = (t_rtext *) rtext_new(glist, (t_text *)z); + textwidget_drawme(x, glist, 1); + } + else { + y = glist_findrtext(glist, (t_text *)z); + textwidget_erase(x, glist); + rtext_free(y); + } +} + +/* the clickfn is only called in run mode +static int textwidget_click(t_gobj *z, t_glist *glist, int xpix, int ypix, + int shift, int alt, int dbl, int doit) +{ + t_textwidget *x = (t_textwidget *)z; + DEBUG(post("textwidget_click x:%d y:%d edit: %d", xpix, ypix, x->x_canvas->gl_edit);); + return 0; +} +*/ + +static void textwidget_append(t_textwidget* x, t_symbol *s, int argc, t_atom *argv) +{ + DEBUG(post("textwidget_append");); + int i; + t_symbol *tmp_symbol = s; /* <-- this gets rid of the unused variable warning */ + t_float tmp_float; + + for(i=0; i<argc ; i++) + { + tmp_symbol = atom_getsymbolarg(i, argc, argv); + if(tmp_symbol == &s_) + { + tmp_float = atom_getfloatarg(i, argc , argv); + sys_vgui("lappend ::%s::list %g \n", x->tcl_namespace, tmp_float ); + } + else + { + sys_vgui("lappend ::%s::list %s \n", x->tcl_namespace, tmp_symbol->s_name ); + } + } + sys_vgui("append ::%s::list \" \"\n", x->tcl_namespace); + sys_vgui("%s insert end $::%s::list ; unset ::%s::list \n", + x->text_id, x->tcl_namespace, x->tcl_namespace ); + sys_vgui("%s yview end-2char \n", x->text_id ); +} + +static void textwidget_key(t_textwidget* x, t_symbol *s, int argc, t_atom *argv) +{ + DEBUG(post("textwidget_key");); + t_symbol *tmp_symbol = s; /* <-- this gets rid of the unused variable warning */ + t_int tmp_int; + + tmp_symbol = atom_getsymbolarg(0, argc, argv); + if(tmp_symbol == &s_) + { + tmp_int = (t_int) atom_getfloatarg(0, argc , argv); + if(tmp_int < 10) + { + sys_vgui("%s insert end %d\n", x->text_id, tmp_int); + } + else if(tmp_int == 10) + { + sys_vgui("%s insert end {\n}\n", x->text_id); + } + else + { + sys_vgui("%s insert end [format \"%c\" %d]\n", x->text_id, tmp_int); + } + } + else + { + sys_vgui("%s insert end %s\n", x->text_id, tmp_symbol->s_name ); + } + sys_vgui("%s yview end-2char \n", x->text_id ); +} + +/* Clear the contents of the text widget */ +static void textwidget_clear(t_textwidget* x) +{ + sys_vgui("%s delete 0.0 end \n", x->text_id); +} + +/* Function to reset the contents of the textwidget box */ +static void textwidget_set(t_textwidget* x, t_symbol *s, int argc, t_atom *argv) +{ + DEBUG(post("textwidget_set");); + + textwidget_clear(x); + textwidget_append(x, s, argc, argv); +} + +static void textwidget_output(t_textwidget* x, t_symbol *s, int argc, t_atom *argv) +{ + outlet_list(x->x_data_outlet, s, argc, argv ); +} + +/* Pass the contents of the text widget onto the textwidget_output fuction above */ +static void textwidget_bang_output(t_textwidget* x) +{ + /* With "," and ";" escaping thanks to JMZ */ + sys_vgui("pd [concat %s output [string map {\",\" \"\\\\,\" \";\" \"\\\\;\"} \ + [%s get 0.0 end]] \\;]\n", + x->x_receive_name->s_name, x->text_id); +} + +static void textwidget_keyup_callback(t_textwidget *x, t_float f) +{ +/* DEBUG(post("textwidget_keyup_callback");); */ + int keycode = (int) f; + char buf[10]; + t_symbol *output_symbol; + + if( (keycode > 32 ) && (keycode < 65288) ) + { + snprintf(buf, 2, "%c", keycode); + output_symbol = gensym(buf); + } else + switch(keycode) + { + case 32: /* space */ + output_symbol = space_symbol; + break; + case 65293: /* return */ + output_symbol = return_symbol; + break; + case 65288: /* backspace */ + output_symbol = backspace_symbol; + break; + case 65289: /* tab */ + output_symbol = tab_symbol; + break; + case 65307: /* escape */ + output_symbol = escape_symbol; + break; + case 65361: /* left */ + output_symbol = left_symbol; + break; + case 65363: /* right */ + output_symbol = right_symbol; + break; + case 65362: /* up */ + output_symbol = up_symbol; + break; + case 65364: /* down */ + output_symbol = down_symbol; + break; + default: + snprintf(buf, 10, "key_%d", keycode); + DEBUG(post("keyup: %d", keycode);); + output_symbol = gensym(buf); + } + outlet_symbol(x->x_status_outlet, output_symbol); +} + +static void textwidget_save(t_gobj *z, t_binbuf *b) +{ + t_textwidget *x = (t_textwidget *)z; + + binbuf_addv(b, "ssiisii;", &s__X, gensym("obj"), + x->x_obj.te_xpix, x->x_obj.te_ypix, + atom_getsymbol(binbuf_getvec(x->x_obj.te_binbuf)), + x->x_width, x->x_height); +} + +static void textwidget_option(t_textwidget *x, t_symbol *s, int argc, t_atom *argv) +{ + if(s != &s_list) + { + t_binbuf *argument_binbuf = binbuf_new(); + char *argument_buffer; + int buffer_length; + + binbuf_add(argument_binbuf, argc, argv); + binbuf_gettext(argument_binbuf, &argument_buffer, &buffer_length); + binbuf_free(argument_binbuf); + argument_buffer[buffer_length] = 0; + post("argument_buffer: %s", argument_buffer); + sys_vgui("%s configure -%s {%s} \n", + x->text_id, s->s_name, argument_buffer); + } +} + +static void textwidget_scrollbar(t_textwidget *x, t_float f) +{ + if(f > 0) + draw_scrollbar(x); + else + erase_scrollbar(x); +} + +static void textwidget_fontsize(t_textwidget *x, t_float font_size) +{ + DEBUG(post("textwidget_fontsize");); + if(font_size > 8) + { + x->x_font_size = (t_int)font_size; + sys_vgui("%s configure -font {%s %d %s} \n", + x->text_id, + x->x_font_face->s_name, x->x_font_size, + x->x_font_weight->s_name); + } + else + pd_error(x,"textwidget: invalid font size: %f",font_size); +} + +static void textwidget_size(t_textwidget *x, t_float width, t_float height) +{ + DEBUG(post("textwidget_size");); + x->x_height = height; + x->x_width = width; + if(glist_isvisible(x->x_glist)) + { + sys_vgui("%s itemconfigure %s -width %d -height %d\n", + x->canvas_id, x->window_tag, x->x_width, x->x_height); + erase_inlets(x); + textwidget_draw_inlets(x, x->x_glist, 1, TOTAL_INLETS, TOTAL_OUTLETS); + canvas_fixlinesfor(x->x_glist, (t_text *)x); // 2nd inlet + } +} + +/* callback functions */ +static void textwidget_click_callback(t_textwidget *x, t_floatarg f) +{ + if( (x->x_glist->gl_edit) && (x->x_glist == x->x_canvas) ) + { + textwidget_select((t_gobj *)x, x->x_glist, f); + } +} + +static void textwidget_resize_click_callback(t_textwidget *x, t_floatarg f) +{ + t_canvas *canvas = (glist_isvisible(x->x_glist) ? x->x_canvas : 0); + int newstate = (int)f; + if (x->x_resizing && newstate == 0) + { + if (canvas) + { + textwidget_draw_inlets(x, canvas, 1, TOTAL_INLETS, TOTAL_OUTLETS); + canvas_fixlinesfor(x->x_glist, (t_text *)x); // 2nd inlet + } + } + else if (!x->x_resizing && newstate) + { + erase_inlets(x); + } + x->x_resizing = newstate; +} + +static void textwidget_resize_motion_callback(t_textwidget *x, t_floatarg f1, t_floatarg f2) +{ + DEBUG(post("textwidget_resize_motion_callback");); + if (x->x_resizing) + { + int dx = (int)f1, dy = (int)f2; + if (glist_isvisible(x->x_glist)) + { + x->x_width += dx; + x->x_height += dy; + sys_vgui("%s itemconfigure %s -width %d -height %d\n", + x->canvas_id, x->window_tag, + x->x_width, x->x_height); + sys_vgui("%s move RSZ %d %d\n", + x->canvas_id, dx, dy); + } + } +} + +static void textwidget_free(t_textwidget *x) +{ + pd_unbind(&x->x_obj.ob_pd, x->x_receive_name); +} + +static void *textwidget_new(t_symbol *s, int argc, t_atom *argv) +{ + DEBUG(post("textwidget_new");); + t_textwidget *x = (t_textwidget *)pd_new(textwidget_class); + char buf[MAXPDSTRING]; + + x->x_height = 1; + x->x_font_face = gensym("helvetica"); + x->x_font_size = 10; + x->x_font_weight = gensym("normal"); + x->x_have_scrollbar = 0; + x->x_selected = 0; + + if (argc < 4) + { + post("textwidget: You must enter at least 4 arguments. Default values used."); + x->x_width = TEXT_DEFAULT_WIDTH; + x->x_height = TEXT_DEFAULT_HEIGHT; + + } else { + /* Copy args into structure */ + x->x_width = atom_getint(argv); + x->x_height = atom_getint(argv+1); + } + + x->x_data_outlet = outlet_new(&x->x_obj, &s_float); + x->x_status_outlet = outlet_new(&x->x_obj, &s_symbol); + + sprintf(buf,"text%lx",(long unsigned int)x); + x->tcl_namespace = getbytes(strlen(buf)); + strcpy(x->tcl_namespace, buf); + + sprintf(buf,"#%s", x->tcl_namespace); + x->x_receive_name = gensym(buf); + pd_bind(&x->x_obj.ob_pd, x->x_receive_name); + + x->x_glist = canvas_getcurrent(); + set_tk_widget_ids(x, x->x_glist); + + int i; + int option_argc = sizeof(tk_options)/sizeof(char *); + post("total options: %d", option_argc); + for(i = 0; i < option_argc; i++) + { + post("option %d: %s", i, tk_options[i]); + } + + return (x); +} + +void text_setup(void) { + textwidget_class = class_new(gensym("text"), (t_newmethod)textwidget_new, + (t_method)textwidget_free,sizeof(t_textwidget), + 0, A_GIMME, 0); + + class_addbang(textwidget_class, (t_method)textwidget_bang_output); + class_addanything(textwidget_class, (t_method)textwidget_option); + + + class_addmethod(textwidget_class, (t_method)textwidget_scrollbar, + gensym("scrollbar"), A_DEFFLOAT, 0); + class_addmethod(textwidget_class, (t_method)textwidget_size, + gensym("size"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(textwidget_class, (t_method)textwidget_fontsize, + gensym("fontsize"), A_DEFFLOAT, 0); + class_addmethod(textwidget_class, (t_method)textwidget_output, + gensym("output"), A_GIMME, 0); + class_addmethod(textwidget_class, (t_method)textwidget_set, + gensym("set"), A_GIMME, 0); + class_addmethod(textwidget_class, (t_method)textwidget_append, + gensym("append"), A_GIMME, 0); + class_addmethod(textwidget_class, (t_method)textwidget_key, + gensym("key"), A_GIMME, 0); + class_addmethod(textwidget_class, (t_method)textwidget_clear, + gensym("clear"), 0); +/* callbacks */ + class_addmethod(textwidget_class, (t_method)textwidget_keyup_callback, + gensym("keyup"), A_DEFFLOAT, 0); + class_addmethod(textwidget_class, (t_method)textwidget_click_callback, + gensym("click"), A_FLOAT, 0); + class_addmethod(textwidget_class, (t_method)textwidget_resize_click_callback, + gensym("resize_click"), A_FLOAT, 0); + class_addmethod(textwidget_class, (t_method)textwidget_resize_motion_callback, + gensym("resize_motion"), A_FLOAT, A_FLOAT, 0); + + class_setwidget(textwidget_class,&textwidget_widgetbehavior); + class_setsavefn(textwidget_class,&textwidget_save); + +/* commonly used symbols */ + backspace_symbol = gensym("backspace"); + return_symbol = gensym("return"); + space_symbol = gensym("space"); + tab_symbol = gensym("tab"); + escape_symbol = gensym("escape"); + left_symbol = gensym("left"); + right_symbol = gensym("right"); + up_symbol = gensym("up"); + down_symbol = gensym("down"); +} + + |