1 /* Copyright (c) 1997-2001 Miller Puckette and others.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
7 #include "../../pdbox.h"
22 void glist_readfrombinbuf(t_glist
*x
, t_binbuf
*b
, char *filename
,
25 void open_via_helppath(const char *name
, const char *dir
);
26 char *class_gethelpdir(t_class
*c
);
28 /* ------------------ forward declarations --------------- */
29 static void canvas_doclear(t_canvas
*x
);
30 static void glist_setlastxy(t_glist
*gl
, int xval
, int yval
);
31 static void glist_donewloadbangs(t_glist
*x
);
32 static t_binbuf
*canvas_docopy(t_canvas
*x
);
33 static void canvas_dopaste(t_canvas
*x
, t_binbuf
*b
);
34 static void canvas_paste(t_canvas
*x
);
35 static void canvas_clearline(t_canvas
*x
);
36 static t_binbuf
*copy_binbuf
;
38 /* ---------------- generic widget behavior ------------------------- */
40 void gobj_getrect(t_gobj
*x
, t_glist
*glist
, int *x1
, int *y1
,
43 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_getrectfn
)
44 (*x
->g_pd
->c_wb
->w_getrectfn
)(x
, glist
, x1
, y1
, x2
, y2
);
47 void gobj_displace(t_gobj
*x
, t_glist
*glist
, int dx
, int dy
)
49 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_displacefn
)
50 (*x
->g_pd
->c_wb
->w_displacefn
)(x
, glist
, dx
, dy
);
53 void gobj_select(t_gobj
*x
, t_glist
*glist
, int state
)
55 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_selectfn
)
56 (*x
->g_pd
->c_wb
->w_selectfn
)(x
, glist
, state
);
59 void gobj_activate(t_gobj
*x
, t_glist
*glist
, int state
)
61 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_activatefn
)
62 (*x
->g_pd
->c_wb
->w_activatefn
)(x
, glist
, state
);
65 void gobj_delete(t_gobj
*x
, t_glist
*glist
)
67 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_deletefn
)
68 (*x
->g_pd
->c_wb
->w_deletefn
)(x
, glist
);
71 void gobj_vis(t_gobj
*x
, struct _glist
*glist
, int flag
)
73 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_visfn
)
74 (*x
->g_pd
->c_wb
->w_visfn
)(x
, glist
, flag
);
77 int gobj_click(t_gobj
*x
, struct _glist
*glist
,
78 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
80 if (x
->g_pd
->c_wb
&& x
->g_pd
->c_wb
->w_clickfn
)
81 return ((*x
->g_pd
->c_wb
->w_clickfn
)(x
,
82 glist
, xpix
, ypix
, shift
, alt
, dbl
, doit
));
86 /* ------------------------ managing the selection ----------------- */
88 void glist_selectline(t_glist
*x
, t_outconnect
*oc
, int index1
,
89 int outno
, int index2
, int inno
)
94 x
->gl_editor
->e_selectedline
= 1;
95 x
->gl_editor
->e_selectline_index1
= index1
;
96 x
->gl_editor
->e_selectline_outno
= outno
;
97 x
->gl_editor
->e_selectline_index2
= index2
;
98 x
->gl_editor
->e_selectline_inno
= inno
;
99 x
->gl_editor
->e_selectline_tag
= oc
;
101 sys_vgui(".x%x.c itemconfigure l%x -fill blue\n",
102 x
, x
->gl_editor
->e_selectline_tag
);
107 void glist_deselectline(t_glist
*x
)
111 x
->gl_editor
->e_selectedline
= 0;
113 sys_vgui(".x%x.c itemconfigure l%x -fill black\n",
114 x
, x
->gl_editor
->e_selectline_tag
);
119 int glist_isselected(t_glist
*x
, t_gobj
*y
)
124 for (sel
= x
->gl_editor
->e_selection
; sel
; sel
= sel
->sel_next
)
125 if (sel
->sel_what
== y
) return (1);
130 /* call this for unselected objects only */
131 void glist_select(t_glist
*x
, t_gobj
*y
)
135 t_selection
*sel
= (t_selection
*)getbytes(sizeof(*sel
));
136 if (x
->gl_editor
->e_selectedline
)
137 glist_deselectline(x
);
138 /* LATER #ifdef out the following check */
139 if (glist_isselected(x
, y
)) bug("glist_select");
140 sel
->sel_next
= x
->gl_editor
->e_selection
;
142 x
->gl_editor
->e_selection
= sel
;
143 gobj_select(y
, x
, 1);
147 /* call this for selected objects only */
148 void glist_deselect(t_glist
*x
, t_gobj
*y
)
151 static int reenter
= 0;
156 t_selection
*sel
, *sel2
;
158 if (!glist_isselected(x
, y
)) bug("glist_deselect");
159 if (x
->gl_editor
->e_textedfor
)
161 t_rtext
*fuddy
= glist_findrtext(x
, (t_text
*)y
);
162 if (x
->gl_editor
->e_textedfor
== fuddy
)
164 if (x
->gl_editor
->e_textdirty
)
167 canvas_stowconnections(glist_getcanvas(x
));
169 gobj_activate(y
, x
, 0);
171 if (zgetfn(&y
->g_pd
, gensym("dsp")))
174 if ((sel
= x
->gl_editor
->e_selection
)->sel_what
== y
)
176 x
->gl_editor
->e_selection
= x
->gl_editor
->e_selection
->sel_next
;
177 gobj_select(sel
->sel_what
, x
, 0);
178 freebytes(sel
, sizeof(*sel
));
182 for(sel
= x
->gl_editor
->e_selection
; (sel2
= sel
->sel_next
);
185 if (sel2
->sel_what
== y
)
187 sel
->sel_next
= sel2
->sel_next
;
188 gobj_select(sel2
->sel_what
, x
, 0);
189 freebytes(sel2
, sizeof(*sel2
));
199 rtext_gettext(z
, &buf
, &bufsize
);
200 text_setto((t_text
*)y
, x
, buf
, bufsize
);
201 canvas_fixlinesfor(glist_getcanvas(x
), (t_text
*)y
);
202 x
->gl_editor
->e_textedfor
= 0;
210 void glist_noselect(t_glist
*x
)
214 while (x
->gl_editor
->e_selection
)
215 glist_deselect(x
, x
->gl_editor
->e_selection
->sel_what
);
216 if (x
->gl_editor
->e_selectedline
)
217 glist_deselectline(x
);
221 void glist_selectall(t_glist
*x
)
228 t_selection
*sel
= (t_selection
*)getbytes(sizeof(*sel
));
229 t_gobj
*y
= x
->gl_list
;
230 x
->gl_editor
->e_selection
= sel
;
232 gobj_select(y
, x
, 1);
233 while((y
= y
->g_next
))
235 t_selection
*sel2
= (t_selection
*)getbytes(sizeof(*sel2
));
236 sel
->sel_next
= sel2
;
239 gobj_select(y
, x
, 1);
246 /* get the index of a gobj in a glist. If y is zero, return the
247 total number of objects. */
248 int glist_getindex(t_glist
*x
, t_gobj
*y
)
253 for (y2
= x
->gl_list
, indx
= 0; y2
&& y2
!= y
; y2
= y2
->g_next
)
258 /* get the index of the object, among selected items, if "selected"
259 is set; otherwise, among unselected ones. If y is zero, just
260 counts the selected or unselected objects. */
261 int glist_selectionindex(t_glist
*x
, t_gobj
*y
, int selected
)
266 for (y2
= x
->gl_list
, indx
= 0; y2
&& y2
!= y
; y2
= y2
->g_next
)
267 if (selected
== glist_isselected(x
, y2
))
272 static t_gobj
*glist_nth(t_glist
*x
, int n
)
276 for (y
= x
->gl_list
, indx
= 0; y
; y
= y
->g_next
, indx
++)
282 /* ------------------- support for undo/redo -------------------------- */
284 static t_undofn canvas_undo_fn
; /* current undo function if any */
285 static int canvas_undo_whatnext
; /* whether we can now UNDO or REDO */
286 static void *canvas_undo_buf
; /* data private to the undo function */
287 static t_canvas
*canvas_undo_canvas
; /* which canvas we can undo on */
288 static const char *canvas_undo_name
;
290 void canvas_setundo(t_canvas
*x
, t_undofn undofn
, void *buf
,
294 /* blow away the old undo information. In one special case the
295 old undo info is re-used; if so we shouldn't free it here. */
296 if (canvas_undo_fn
&& canvas_undo_buf
&& (buf
!= canvas_undo_buf
))
298 (*canvas_undo_fn
)(canvas_undo_canvas
, canvas_undo_buf
, UNDO_FREE
);
301 canvas_undo_canvas
= x
;
302 canvas_undo_fn
= undofn
;
303 canvas_undo_buf
= buf
;
304 canvas_undo_whatnext
= UNDO_UNDO
;
305 canvas_undo_name
= name
;
307 if (x
&& glist_isvisible(x
) && glist_istoplevel(x
))
308 /* enable undo in menu */
309 sys_vgui("pdtk_undomenu .x%x %s no\n", x
, name
);
311 sys_vgui("pdtk_undomenu nobody no no\n");
315 /* clear undo if it happens to be for the canvas x.
316 (but if x is 0, clear it regardless of who owns it.) */
317 void canvas_noundo(t_canvas
*x
)
319 if (!x
|| (x
== canvas_undo_canvas
))
320 canvas_setundo(0, 0, 0, "foo");
323 static void canvas_undo(t_canvas
*x
)
325 if (x
!= canvas_undo_canvas
)
326 bug("canvas_undo 1");
327 else if (canvas_undo_whatnext
!= UNDO_UNDO
)
328 bug("canvas_undo 2");
332 (*canvas_undo_fn
)(canvas_undo_canvas
, canvas_undo_buf
, UNDO_UNDO
);
333 /* enable redo in menu */
335 if (glist_isvisible(x
) && glist_istoplevel(x
))
336 sys_vgui("pdtk_undomenu .x%x no %s\n", x
, canvas_undo_name
);
338 canvas_undo_whatnext
= UNDO_REDO
;
342 static void canvas_redo(t_canvas
*x
)
344 if (x
!= canvas_undo_canvas
)
345 bug("canvas_undo 1");
346 else if (canvas_undo_whatnext
!= UNDO_REDO
)
347 bug("canvas_undo 2");
351 (*canvas_undo_fn
)(canvas_undo_canvas
, canvas_undo_buf
, UNDO_REDO
);
352 /* enable undo in menu */
354 if (glist_isvisible(x
) && glist_istoplevel(x
))
355 sys_vgui("pdtk_undomenu .x%x %s no\n", x
, canvas_undo_name
);
357 canvas_undo_whatnext
= UNDO_UNDO
;
361 /* ------- specific undo methods: 1. connect and disconnect -------- */
363 typedef struct _undo_connect
371 static void *canvas_undo_set_disconnect(t_canvas
*x
,
372 int index1
, int outno
, int index2
, int inno
)
377 t_undo_connect
*buf
= (t_undo_connect
*)getbytes(sizeof(*buf
));
378 buf
->u_index1
= index1
;
379 buf
->u_outletno
= outno
;
380 buf
->u_index2
= index2
;
381 buf
->u_inletno
= inno
;
385 void canvas_disconnect(t_canvas
*x
,
386 float index1
, float outno
, float index2
, float inno
)
390 linetraverser_start(&t
, x
);
391 while((oc
= linetraverser_next(&t
)))
393 int srcno
= canvas_getindex(x
, &t
.tr_ob
->ob_g
);
394 int sinkno
= canvas_getindex(x
, &t
.tr_ob2
->ob_g
);
395 if (srcno
== index1
&& t
.tr_outno
== outno
&&
396 sinkno
== index2
&& t
.tr_inno
== inno
)
399 sys_vgui(".x%x.c delete l%x\n", x
, oc
);
401 obj_disconnect(t
.tr_ob
, t
.tr_outno
, t
.tr_ob2
, t
.tr_inno
);
407 static void canvas_undo_disconnect(t_canvas
*x
, void *z
, int action
)
409 t_undo_connect
*buf
= z
;
410 if (action
== UNDO_UNDO
)
412 canvas_connect(x
, buf
->u_index1
, buf
->u_outletno
,
413 buf
->u_index2
, buf
->u_inletno
);
415 else if (action
== UNDO_REDO
)
417 canvas_disconnect(x
, buf
->u_index1
, buf
->u_outletno
,
418 buf
->u_index2
, buf
->u_inletno
);
420 else if (action
== UNDO_FREE
)
421 t_freebytes(buf
, sizeof(*buf
));
424 /* connect just calls disconnect actions backward... */
425 static void *canvas_undo_set_connect(t_canvas
*x
,
426 int index1
, int outno
, int index2
, int inno
)
428 return (canvas_undo_set_disconnect(x
, index1
, outno
, index2
, inno
));
431 static void canvas_undo_connect(t_canvas
*x
, void *z
, int action
)
434 if (action
== UNDO_UNDO
)
435 myaction
= UNDO_REDO
;
436 else if (action
== UNDO_REDO
)
437 myaction
= UNDO_UNDO
;
438 else myaction
= action
;
439 canvas_undo_disconnect(x
, z
, myaction
);
442 /* ---------- ... 2. cut, clear, and typing into objects: -------- */
444 #define UCUT_CUT 1 /* operation was a cut */
445 #define UCUT_CLEAR 2 /* .. a clear */
446 #define UCUT_TEXT 3 /* text typed into a box */
448 typedef struct _undo_cut
450 t_binbuf
*u_objectbuf
; /* the object cleared or typed into */
451 t_binbuf
*u_reconnectbuf
; /* connections into and out of object */
452 t_binbuf
*u_redotextbuf
; /* buffer to paste back for redo if TEXT */
453 int u_mode
; /* from flags above */
456 static void *canvas_undo_set_cut(t_canvas
*x
, int mode
)
464 int nnotsel
= glist_selectionindex(x
, 0, 0);
465 buf
= (t_undo_cut
*)getbytes(sizeof(*buf
));
467 buf
->u_redotextbuf
= 0;
469 /* store connections into/out of the selection */
470 buf
->u_reconnectbuf
= binbuf_new();
471 linetraverser_start(&t
, x
);
472 while((oc
= linetraverser_next(&t
)))
474 int issel1
= glist_isselected(x
, &t
.tr_ob
->ob_g
);
475 int issel2
= glist_isselected(x
, &t
.tr_ob2
->ob_g
);
476 if (issel1
!= issel2
)
478 binbuf_addv(buf
->u_reconnectbuf
, "ssiiii;",
479 gensym("#X"), gensym("connect"),
480 (issel1
? nnotsel
: 0)
481 + glist_selectionindex(x
, &t
.tr_ob
->ob_g
, issel1
),
483 (issel2
? nnotsel
: 0) +
484 glist_selectionindex(x
, &t
.tr_ob2
->ob_g
, issel2
),
488 if (mode
== UCUT_TEXT
)
490 buf
->u_objectbuf
= canvas_docopy(x
);
492 else if (mode
== UCUT_CUT
)
494 buf
->u_objectbuf
= 0;
496 else if (mode
== UCUT_CLEAR
)
498 buf
->u_objectbuf
= canvas_docopy(x
);
503 static void canvas_undo_cut(t_canvas
*x
, void *z
, int action
)
506 int mode
= buf
->u_mode
;
507 if (action
== UNDO_UNDO
)
509 if (mode
== UCUT_CUT
)
510 canvas_dopaste(x
, copy_binbuf
);
511 else if (mode
== UCUT_CLEAR
)
512 canvas_dopaste(x
, buf
->u_objectbuf
);
513 else if (mode
== UCUT_TEXT
)
517 for(y1
= x
->gl_list
; (y2
= y1
->g_next
); y1
= y2
)
521 if (!buf
->u_redotextbuf
)
525 buf
->u_redotextbuf
= canvas_docopy(x
);
530 canvas_dopaste(x
, buf
->u_objectbuf
);
532 pd_bind(&x
->gl_pd
, gensym("#X"));
533 binbuf_eval(buf
->u_reconnectbuf
, 0, 0, 0);
534 pd_unbind(&x
->gl_pd
, gensym("#X"));
536 else if (action
== UNDO_REDO
)
538 if (mode
== UCUT_CUT
|| mode
== UCUT_CLEAR
)
540 else if (mode
== UCUT_TEXT
)
543 for(y1
= x
->gl_list
; (y2
= y1
->g_next
); y1
= y2
)
547 canvas_dopaste(x
, buf
->u_redotextbuf
);
548 pd_bind(&x
->gl_pd
, gensym("#X"));
549 binbuf_eval(buf
->u_reconnectbuf
, 0, 0, 0);
550 pd_unbind(&x
->gl_pd
, gensym("#X"));
553 else if (action
== UNDO_FREE
)
555 if (buf
->u_objectbuf
)
556 binbuf_free(buf
->u_objectbuf
);
557 if (buf
->u_reconnectbuf
)
558 binbuf_free(buf
->u_reconnectbuf
);
559 if (buf
->u_redotextbuf
)
560 binbuf_free(buf
->u_redotextbuf
);
561 t_freebytes(buf
, sizeof(*buf
));
565 /* --------- 3. motion, including "tidy up" and stretching ----------- */
567 typedef struct _undo_move_elem
574 typedef struct _undo_move
576 t_undo_move_elem
*u_vec
;
580 static int canvas_undo_already_set_move
;
582 static void *canvas_undo_set_move(t_canvas
*x
, int selected
)
584 int x1
, y1
, x2
, y2
, i
, indx
;
586 t_undo_move
*buf
= (t_undo_move
*)getbytes(sizeof(*buf
));
587 buf
->u_n
= selected
? glist_selectionindex(x
, 0, 1) : glist_getindex(x
, 0);
588 buf
->u_vec
= (t_undo_move_elem
*)getbytes(sizeof(*buf
->u_vec
) *
589 (selected
? glist_selectionindex(x
, 0, 1) : glist_getindex(x
, 0)));
592 for (y
= x
->gl_list
, i
= indx
= 0; y
; y
= y
->g_next
, indx
++)
593 if (glist_isselected(x
, y
))
595 gobj_getrect(y
, x
, &x1
, &y1
, &x2
, &y2
);
596 buf
->u_vec
[i
].e_index
= indx
;
597 buf
->u_vec
[i
].e_xpix
= x1
;
598 buf
->u_vec
[i
].e_ypix
= y1
;
604 for (y
= x
->gl_list
, indx
= 0; y
; y
= y
->g_next
, indx
++)
606 gobj_getrect(y
, x
, &x1
, &y1
, &x2
, &y2
);
607 buf
->u_vec
[indx
].e_index
= indx
;
608 buf
->u_vec
[indx
].e_xpix
= x1
;
609 buf
->u_vec
[indx
].e_ypix
= y1
;
612 canvas_undo_already_set_move
= 1;
616 static void canvas_undo_move(t_canvas
*x
, void *z
, int action
)
618 t_undo_move
*buf
= z
;
619 if (action
== UNDO_UNDO
|| action
== UNDO_REDO
)
622 for (i
= 0; i
< buf
->u_n
; i
++)
624 int x1
, y1
, x2
, y2
, newx
, newy
;
626 newx
= buf
->u_vec
[i
].e_xpix
;
627 newy
= buf
->u_vec
[i
].e_ypix
;
628 y
= glist_nth(x
, buf
->u_vec
[i
].e_index
);
631 gobj_getrect(y
, x
, &x1
, &y1
, &x2
, &y2
);
632 gobj_displace(y
, x
, newx
-x1
, newy
- y1
);
633 buf
->u_vec
[i
].e_xpix
= x1
;
634 buf
->u_vec
[i
].e_ypix
= y1
;
638 else if (action
== UNDO_FREE
)
640 t_freebytes(buf
->u_vec
, buf
->u_n
* sizeof(*buf
->u_vec
));
641 t_freebytes(buf
, sizeof(*buf
));
645 /* --------- 4. paste (also duplicate) ----------- */
647 typedef struct _undo_paste
649 int u_index
; /* index of first object pasted */
652 static void *canvas_undo_set_paste(t_canvas
*x
)
654 t_undo_paste
*buf
= (t_undo_paste
*)getbytes(sizeof(*buf
));
655 buf
->u_index
= glist_getindex(x
, 0);
659 static void canvas_undo_paste(t_canvas
*x
, void *z
, int action
)
661 t_undo_paste
*buf
= z
;
662 if (action
== UNDO_UNDO
)
666 for (y
= glist_nth(x
, buf
->u_index
); y
; y
= y
->g_next
)
670 else if (action
== UNDO_REDO
)
673 canvas_dopaste(x
, copy_binbuf
);
674 /* if it was "duplicate" have to re-enact the displacement. */
675 if (canvas_undo_name
&& canvas_undo_name
[0] == 'd')
676 for (sel
= x
->gl_editor
->e_selection
; sel
; sel
= sel
->sel_next
)
677 gobj_displace(sel
->sel_what
, x
, 10, 10);
679 else if (action
== UNDO_FREE
)
680 t_freebytes(buf
, sizeof(*buf
));
683 /* recursively check for abstractions to reload as result of a save.
684 Don't reload the one we just saved ("except") though. */
685 /* LATER try to do the same trick for externs. */
686 static void glist_doreload(t_glist
*gl
, t_symbol
*name
, t_symbol
*dir
,
690 int i
, nobj
= glist_getindex(gl
, 0); /* number of objects */
691 for (g
= gl
->gl_list
, i
= 0; g
&& i
< nobj
; i
++)
693 if (g
!= except
&& pd_class(&g
->g_pd
) == canvas_class
&&
694 canvas_isabstraction((t_canvas
*)g
) &&
695 ((t_canvas
*)g
)->gl_name
== name
&&
696 canvas_getdir((t_canvas
*)g
) == dir
)
698 /* we're going to remake the object, so "g" will go stale.
699 Get its index here, and afterward restore g. Also, the
700 replacement will be at teh end of the list, so we don't
701 do g = g->g_next in this case. */
702 int j
= glist_getindex(gl
, g
);
703 if (!gl
->gl_havewindow
)
704 canvas_vis(glist_getcanvas(gl
), 1);
707 canvas_setundo(gl
, canvas_undo_cut
,
708 canvas_undo_set_cut(gl
, UCUT_CLEAR
), "clear");
712 g
= glist_nth(gl
, j
);
716 if (g
!= except
&& pd_class(&g
->g_pd
) == canvas_class
)
717 glist_doreload((t_canvas
*)g
, name
, dir
, except
);
723 /* call canvas_doreload on everyone */
724 void canvas_reload(t_symbol
*name
, t_symbol
*dir
, t_gobj
*except
)
727 /* find all root canvases */
728 for (x
= canvas_list
; x
; x
= x
->gl_next
)
729 glist_doreload(x
, name
, dir
, except
);
732 /* ------------------------ event handling ------------------------ */
734 #define CURSOR_RUNMODE_NOTHING 0
735 #define CURSOR_RUNMODE_CLICKME 1
736 #define CURSOR_RUNMODE_THICKEN 2
737 #define CURSOR_RUNMODE_ADDPOINT 3
738 #define CURSOR_EDITMODE_NOTHING 4
739 #define CURSOR_EDITMODE_CONNECT 5
740 #define CURSOR_EDITMODE_DISCONNECT 6
742 static char *cursorlist
[] = {
744 "right_ptr", /* CURSOR_RUNMODE_NOTHING */
746 "left_ptr", /* CURSOR_RUNMODE_NOTHING */
748 "arrow", /* CURSOR_RUNMODE_CLICKME */
749 "sb_v_double_arrow", /* CURSOR_RUNMODE_THICKEN */
750 "plus", /* CURSOR_RUNMODE_ADDPOINT */
751 "hand2", /* CURSOR_EDITMODE_NOTHING */
752 "circle", /* CURSOR_EDITMODE_CONNECT */
753 "X_cursor" /* CURSOR_EDITMODE_DISCONNECT */
756 void canvas_setcursor(t_canvas
*x
, unsigned int cursornum
)
758 static t_canvas
*xwas
;
759 static unsigned int cursorwas
;
760 if (cursornum
>= sizeof(cursorlist
)/sizeof *cursorlist
)
762 bug("canvas_setcursor");
765 if (xwas
!= x
|| cursorwas
!= cursornum
)
768 sys_vgui(".x%x configure -cursor %s\n", x
, cursorlist
[cursornum
]);
771 cursorwas
= cursornum
;
775 /* check if a point lies in a gobj. */
776 int canvas_hitbox(t_canvas
*x
, t_gobj
*y
, int xpos
, int ypos
,
777 int *x1p
, int *y1p
, int *x2p
, int *y2p
)
781 if ((ob
= pd_checkobject(&y
->g_pd
)) &&
782 !text_shouldvis(ob
, x
))
784 gobj_getrect(y
, x
, &x1
, &y1
, &x2
, &y2
);
785 if (xpos
>= x1
&& xpos
<= x2
&& ypos
>= y1
&& ypos
<= y2
)
796 /* find the last gobj, if any, containing the point. */
797 static t_gobj
*canvas_findhitbox(t_canvas
*x
, int xpos
, int ypos
,
798 int *x1p
, int *y1p
, int *x2p
, int *y2p
)
800 t_gobj
*y
, *rval
= 0;
801 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
803 if (canvas_hitbox(x
, y
, xpos
, ypos
, x1p
, y1p
, x2p
, y2p
))
809 /* right-clicking on a canvas object pops up a menu. */
810 static void canvas_rightclick(t_canvas
*x
, int xpos
, int ypos
, t_gobj
*y
)
812 int canprop
, canopen
;
813 canprop
= (!y
|| (y
&& class_getpropertiesfn(pd_class(&y
->g_pd
))));
814 canopen
= (y
&& zgetfn(&y
->g_pd
, gensym("menu-open")));
820 sys_vgui("pdtk_canvas_popup .x%x %d %d %d %d\n",
821 x
, xpos
, ypos
, canprop
, canopen
);
825 /* tell GUI to create a properties dialog on the canvas. We tell
826 the user the negative of the "pixel" y scale to make it appear to grow
827 naturally upward, whereas pixels grow downward. */
828 static void canvas_properties(t_glist
*x
)
834 sprintf(graphbuf
, "pdtk_canvas_dialog %%s %g %g %g %g \n",
835 glist_dpixtodx(x
, 1), -glist_dpixtody(x
, 1),
836 (float)glist_isgraph(x
), (float)x
->gl_stretch
);
837 gfxstub_new(&x
->gl_pd
, x
, graphbuf
);
842 void canvas_setgraph(t_glist
*x
, int flag
)
844 if (!flag
&& glist_isgraph(x
))
846 if (x
->gl_owner
&& !x
->gl_loading
&& glist_isvisible(x
->gl_owner
))
847 gobj_vis(&x
->gl_gobj
, x
->gl_owner
, 0);
849 if (x
->gl_owner
&& !x
->gl_loading
&& glist_isvisible(x
->gl_owner
))
851 gobj_vis(&x
->gl_gobj
, x
->gl_owner
, 1);
852 canvas_fixlinesfor(x
->gl_owner
, &x
->gl_obj
);
855 else if (flag
&& !glist_isgraph(x
))
857 if (x
->gl_pixwidth
<= 0)
858 x
->gl_pixwidth
= GLIST_DEFGRAPHWIDTH
;
860 if (x
->gl_pixheight
<= 0)
861 x
->gl_pixheight
= GLIST_DEFGRAPHHEIGHT
;
863 if (x
->gl_owner
&& !x
->gl_loading
&& glist_isvisible(x
->gl_owner
))
864 gobj_vis(&x
->gl_gobj
, x
->gl_owner
, 0);
866 /* if (x->gl_owner && glist_isvisible(x->gl_owner))
868 if (x
->gl_loading
&& x
->gl_owner
&& glist_isvisible(x
->gl_owner
))
869 canvas_create_editor(x
, 1);
870 if (x
->gl_owner
&& !x
->gl_loading
&& glist_isvisible(x
->gl_owner
))
872 gobj_vis(&x
->gl_gobj
, x
->gl_owner
, 1);
873 canvas_fixlinesfor(x
->gl_owner
, &x
->gl_obj
);
878 /* called from the gui when "OK" is selected on the canvas properties
879 dialog. Again we negate "y" scale. */
880 static void canvas_donecanvasdialog(t_glist
*x
, t_floatarg xperpix
,
881 t_floatarg yperpix
, t_floatarg fgraphme
)
883 int graphme
= (fgraphme
!= 0), redraw
= 0;
889 canvas_setgraph(x
, graphme
);
890 if (!x
->gl_isgraph
&& (xperpix
!= glist_dpixtodx(x
, 1)))
899 x
->gl_x1
= -xperpix
* (x
->gl_screenx2
- x
->gl_screenx1
);
900 x
->gl_x2
= x
->gl_x1
+ xperpix
;
904 if (!x
->gl_isgraph
&& (yperpix
!= glist_dpixtody(x
, 1)))
913 x
->gl_y1
= -yperpix
* (x
->gl_screeny2
- x
->gl_screeny1
);
914 x
->gl_y2
= x
->gl_y1
+ yperpix
;
922 /* called from the gui when a popup menu comes back with "properties,"
923 "open," or "help." */
924 static void canvas_done_popup(t_canvas
*x
, float which
, float xpos
, float ypos
)
927 char namebuf
[MAXPDSTRING
];
929 char pathbuf
[MAXPDSTRING
], namebuf
[MAXPDSTRING
];
932 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
935 if (canvas_hitbox(x
, y
, xpos
, ypos
, &x1
, &y1
, &x2
, &y2
))
937 if (which
== 0) /* properties */
939 if (!class_getpropertiesfn(pd_class(&y
->g_pd
)))
941 (*class_getpropertiesfn(pd_class(&y
->g_pd
)))(y
, x
);
944 else if (which
== 1) /* open */
946 if (!zgetfn(&y
->g_pd
, gensym("menu-open")))
948 vmess(&y
->g_pd
, gensym("menu-open"), "");
954 if (pd_class(&y
->g_pd
) == canvas_class
&&
955 canvas_isabstraction((t_canvas
*)y
))
957 t_object
*ob
= (t_object
*)y
;
958 int ac
= binbuf_getnatom(ob
->te_binbuf
);
959 t_atom
*av
= binbuf_getvec(ob
->te_binbuf
);
962 atom_string(av
, namebuf
, MAXPDSTRING
);
963 dir
= canvas_getdir((t_canvas
*)y
)->s_name
;
967 strcpy(namebuf
, class_gethelpname(pd_class(&y
->g_pd
)));
968 dir
= class_gethelpdir(pd_class(&y
->g_pd
));
970 if (strcmp(namebuf
+ strlen(namebuf
) - 3, ".pd"))
971 strcat(namebuf
, ".pd");
972 open_via_helppath(namebuf
, dir
);
978 canvas_properties(x
);
982 strcpy(pathbuf
, sys_libdir
->s_name
);
983 strcat(pathbuf
, "/doc/5.reference/0.INTRO.txt");
984 sys_vgui("menu_opentext %s\n", pathbuf
);
995 /* on one-button-mouse machines, you can use double click to
996 mean right click (which gets the popup menu.) Do this for Mac. */
998 #define SIMULATERIGHTCLICK
1001 #ifdef SIMULATERIGHTCLICK
1002 static double canvas_upclicktime
;
1003 static int canvas_upx
, canvas_upy
;
1004 #define DCLICKINTERVAL 0.25
1008 void canvas_doclick(t_canvas
*x
, int xpos
, int ypos
, int which
,
1012 int shiftmod
, runmode
, altmod
, rightclick
;
1013 int x1
, y1
, x2
, y2
, clickreturned
= 0;
1025 shiftmod
= (mod
& SHIFTMOD
);
1026 runmode
= ((mod
& CTRLMOD
) || (!x
->gl_edit
));
1027 altmod
= (mod
& ALTMOD
);
1028 rightclick
= (mod
& RIGHTCLICK
);
1030 canvas_undo_already_set_move
= 0;
1032 /* if keyboard was grabbed, notify grabber and cancel the grab */
1033 if (doit
&& x
->gl_editor
->e_grab
&& x
->gl_editor
->e_keyfn
)
1035 (* x
->gl_editor
->e_keyfn
) (x
->gl_editor
->e_grab
, 0);
1036 glist_grab(x
, 0, 0, 0, 0, 0);
1039 #ifdef SIMULATERIGHTCLICK
1040 if (doit
&& !runmode
&& xpos
== canvas_upx
&& ypos
== canvas_upy
&&
1041 sys_getrealtime() - canvas_upclicktime
< DCLICKINTERVAL
)
1045 x
->gl_editor
->e_lastmoved
= 0;
1048 x
->gl_editor
->e_grab
= 0;
1049 x
->gl_editor
->e_onmotion
= MA_NONE
;
1051 /* post("click %d %d %d %d", xpos, ypos, which, mod); */
1053 if (x
->gl_editor
->e_onmotion
!= MA_NONE
)
1056 x
->gl_editor
->e_xwas
= xpos
;
1057 x
->gl_editor
->e_ywas
= ypos
;
1059 if (runmode
&& !rightclick
)
1061 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
1063 /* check if the object wants to be clicked */
1064 if (canvas_hitbox(x
, y
, xpos
, ypos
, &x1
, &y1
, &x2
, &y2
)
1065 && (clickreturned
= gobj_click(y
, x
, xpos
, ypos
,
1066 shiftmod
, altmod
, 0, doit
)))
1072 canvas_setcursor(x
, clickreturned
);
1073 else canvas_setcursor(x
, CURSOR_RUNMODE_NOTHING
);
1077 /* if not a runmode left click, fall here. */
1078 if((y
= canvas_findhitbox(x
, xpos
, ypos
, &x1
, &y1
, &x2
, &y2
)))
1080 t_object
*ob
= pd_checkobject(&y
->g_pd
);
1081 /* check you're in the rectangle */
1082 ob
= pd_checkobject(&y
->g_pd
);
1084 canvas_rightclick(x
, xpos
, ypos
, y
);
1090 if (ob
&& (rt
= x
->gl_editor
->e_textedfor
) &&
1091 rt
== glist_findrtext(x
, ob
))
1093 rtext_mouse(rt
, xpos
- x1
, ypos
- y1
, RTEXT_SHIFT
);
1094 x
->gl_editor
->e_onmotion
= MA_DRAGTEXT
;
1095 x
->gl_editor
->e_xwas
= x1
;
1096 x
->gl_editor
->e_ywas
= y1
;
1100 if (glist_isselected(x
, y
))
1101 glist_deselect(x
, y
);
1102 else glist_select(x
, y
);
1108 /* look for an outlet */
1110 if (ob
&& (noutlet
= obj_noutlets(ob
)) && ypos
>= y2
-4)
1112 int width
= x2
- x1
;
1113 int nout1
= (noutlet
> 1 ? noutlet
- 1 : 1);
1114 int closest
= ((xpos
-x1
) * (nout1
) + width
/2)/width
;
1116 (width
- IOWIDTH
) * closest
/ (nout1
);
1117 if (closest
< noutlet
&&
1118 xpos
>= (hotspot
-1) && xpos
<= hotspot
+ (IOWIDTH
+1))
1123 int issignal
= obj_issignaloutlet(ob
, closest
);
1125 x
->gl_editor
->e_onmotion
= MA_CONNECT
;
1126 x
->gl_editor
->e_xwas
= xpos
;
1127 x
->gl_editor
->e_ywas
= ypos
;
1130 ".x%x.c create line %d %d %d %d -width %d -tags x\n",
1131 x
, xpos
, ypos
, xpos
, ypos
,
1132 (issignal
? 2 : 1));
1135 else canvas_setcursor(x
, CURSOR_EDITMODE_CONNECT
);
1138 goto nooutletafterall
;
1140 /* not in an outlet; select and move */
1144 /* check if the box is being text edited */
1146 if (ob
&& (rt
= x
->gl_editor
->e_textedfor
) &&
1147 rt
== glist_findrtext(x
, ob
))
1149 rtext_mouse(rt
, xpos
- x1
, ypos
- y1
, RTEXT_DOWN
);
1150 x
->gl_editor
->e_onmotion
= MA_DRAGTEXT
;
1151 x
->gl_editor
->e_xwas
= x1
;
1152 x
->gl_editor
->e_ywas
= y1
;
1156 /* otherwise select and drag to displace */
1157 if (!glist_isselected(x
, y
))
1162 x
->gl_editor
->e_onmotion
= MA_MOVE
;
1165 else canvas_setcursor(x
, CURSOR_EDITMODE_NOTHING
);
1169 /* if right click doesn't hit any boxes, call rightclick
1172 canvas_rightclick(x
, xpos
, ypos
, 0);
1174 /* if not an editing action, and if we didn't hit a
1175 box, set cursor and return */
1176 if (runmode
|| rightclick
)
1178 canvas_setcursor(x
, CURSOR_RUNMODE_NOTHING
);
1181 /* having failed to find a box, we try lines now. */
1182 if (!runmode
&& !altmod
&& !shiftmod
)
1186 float fx
= xpos
, fy
= ypos
;
1187 t_glist
*glist2
= glist_getcanvas(x
);
1188 linetraverser_start(&t
, glist2
);
1189 while((oc
= linetraverser_next(&t
)))
1191 float lx1
= t
.tr_lx1
, ly1
= t
.tr_ly1
,
1192 lx2
= t
.tr_lx2
, ly2
= t
.tr_ly2
;
1193 float area
= (lx2
- lx1
) * (fy
- ly1
) -
1194 (ly2
- ly1
) * (fx
- lx1
);
1195 float dsquare
= (lx2
-lx1
) * (lx2
-lx1
) + (ly2
-ly1
) * (ly2
-ly1
);
1196 if (area
* area
>= 50 * dsquare
) continue;
1197 if ((lx2
-lx1
) * (fx
-lx1
) + (ly2
-ly1
) * (fy
-ly1
) < 0) continue;
1198 if ((lx2
-lx1
) * (lx2
-fx
) + (ly2
-ly1
) * (ly2
-fy
) < 0) continue;
1201 glist_selectline(glist2
, oc
,
1202 canvas_getindex(glist2
, &t
.tr_ob
->ob_g
), t
.tr_outno
,
1203 canvas_getindex(glist2
, &t
.tr_ob2
->ob_g
), t
.tr_inno
);
1205 canvas_setcursor(x
, CURSOR_EDITMODE_DISCONNECT
);
1209 canvas_setcursor(x
, CURSOR_EDITMODE_NOTHING
);
1212 if (!shiftmod
) glist_noselect(x
);
1214 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags x\n",
1215 x
, xpos
, ypos
, xpos
, ypos
);
1217 x
->gl_editor
->e_xwas
= xpos
;
1218 x
->gl_editor
->e_ywas
= ypos
;
1219 x
->gl_editor
->e_onmotion
= MA_REGION
;
1223 void canvas_mousedown(t_canvas
*x
, t_floatarg xpos
, t_floatarg ypos
,
1224 t_floatarg which
, t_floatarg mod
)
1226 canvas_doclick(x
, xpos
, ypos
, which
, mod
, 1);
1229 int canvas_isconnected (t_canvas
*x
, t_text
*ob1
, int n1
,
1230 t_text
*ob2
, int n2
)
1234 linetraverser_start(&t
, x
);
1235 while((oc
= linetraverser_next(&t
)))
1236 if (t
.tr_ob
== ob1
&& t
.tr_outno
== n1
&&
1237 t
.tr_ob2
== ob2
&& t
.tr_inno
== n2
)
1242 void canvas_doconnect(t_canvas
*x
, int xpos
, int ypos
, int which
, int doit
)
1244 int x11
, y11
, x12
, y12
;
1246 int x21
, y21
, x22
, y22
;
1248 int xwas
= x
->gl_editor
->e_xwas
,
1249 ywas
= x
->gl_editor
->e_ywas
;
1252 #endif /* ROCKBOX */
1254 if (doit
) sys_vgui(".x%x.c delete x\n", x
);
1255 else sys_vgui(".x%x.c coords x %d %d %d %d\n",
1256 x
, x
->gl_editor
->e_xwas
,
1257 x
->gl_editor
->e_ywas
, xpos
, ypos
);
1258 #endif /* ROCKBOX */
1260 if ((y1
= canvas_findhitbox(x
, xwas
, ywas
, &x11
, &y11
, &x12
, &y12
))
1261 && (y2
= canvas_findhitbox(x
, xpos
, ypos
, &x21
, &y21
, &x22
, &y22
)))
1263 t_object
*ob1
= pd_checkobject(&y1
->g_pd
);
1264 t_object
*ob2
= pd_checkobject(&y2
->g_pd
);
1265 int noutlet1
, ninlet2
;
1266 if (ob1
&& ob2
&& ob1
!= ob2
&&
1267 (noutlet1
= obj_noutlets(ob1
))
1268 && (ninlet2
= obj_ninlets(ob2
)))
1270 int width1
= x12
- x11
, closest1
, hotspot1
;
1271 int width2
= x22
- x21
, closest2
, hotspot2
;
1272 int lx1
, lx2
, ly1
, ly2
;
1277 closest1
= ((xwas
-x11
) * (noutlet1
-1) + width1
/2)/width1
;
1279 (width1
- IOWIDTH
) * closest1
/ (noutlet1
-1);
1281 else closest1
= 0, hotspot1
= x11
;
1285 closest2
= ((xpos
-x21
) * (ninlet2
-1) + width2
/2)/width2
;
1287 (width2
- IOWIDTH
) * closest2
/ (ninlet2
-1);
1289 else closest2
= 0, hotspot2
= x21
;
1291 if (closest1
>= noutlet1
)
1292 closest1
= noutlet1
- 1;
1293 if (closest2
>= ninlet2
)
1294 closest2
= ninlet2
- 1;
1296 if (canvas_isconnected (x
, ob1
, closest1
, ob2
, closest2
))
1298 canvas_setcursor(x
, CURSOR_EDITMODE_NOTHING
);
1301 if (obj_issignaloutlet(ob1
, closest1
) &&
1302 !obj_issignalinlet(ob2
, closest2
))
1305 error("can't connect signal outlet to control inlet");
1306 canvas_setcursor(x
, CURSOR_EDITMODE_NOTHING
);
1311 oc
= obj_connect(ob1
, closest1
, ob2
, closest2
);
1312 lx1
= x11
+ (noutlet1
> 1 ?
1313 ((x12
-x11
-IOWIDTH
) * closest1
)/(noutlet1
-1) : 0)
1316 lx2
= x21
+ (ninlet2
> 1 ?
1317 ((x22
-x21
-IOWIDTH
) * closest2
)/(ninlet2
-1) : 0)
1321 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
1324 (obj_issignaloutlet(ob1
, closest1
) ? 2 : 1), oc
);
1325 #endif /* ROCKBOX */
1326 canvas_setundo(x
, canvas_undo_connect
,
1327 canvas_undo_set_connect(x
,
1328 canvas_getindex(x
, &ob1
->ob_g
), closest1
,
1329 canvas_getindex(x
, &ob2
->ob_g
), closest2
),
1332 else canvas_setcursor(x
, CURSOR_EDITMODE_CONNECT
);
1336 canvas_setcursor(x
, CURSOR_EDITMODE_NOTHING
);
1339 void canvas_selectinrect(t_canvas
*x
, int lox
, int loy
, int hix
, int hiy
)
1342 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
1345 gobj_getrect(y
, x
, &x1
, &y1
, &x2
, &y2
);
1346 if (hix
>= x1
&& lox
<= x2
&& hiy
>= y1
&& loy
<= y2
1347 && !glist_isselected(x
, y
))
1352 static void canvas_doregion(t_canvas
*x
, int xpos
, int ypos
, int doit
)
1356 int lox
, loy
, hix
, hiy
;
1357 if (x
->gl_editor
->e_xwas
< xpos
)
1358 lox
= x
->gl_editor
->e_xwas
, hix
= xpos
;
1359 else hix
= x
->gl_editor
->e_xwas
, lox
= xpos
;
1360 if (x
->gl_editor
->e_ywas
< ypos
)
1361 loy
= x
->gl_editor
->e_ywas
, hiy
= ypos
;
1362 else hiy
= x
->gl_editor
->e_ywas
, loy
= ypos
;
1363 canvas_selectinrect(x
, lox
, loy
, hix
, hiy
);
1365 sys_vgui(".x%x.c delete x\n", x
);
1367 x
->gl_editor
->e_onmotion
= 0;
1370 else sys_vgui(".x%x.c coords x %d %d %d %d\n",
1371 x
, x
->gl_editor
->e_xwas
,
1372 x
->gl_editor
->e_ywas
, xpos
, ypos
);
1376 void canvas_mouseup(t_canvas
*x
,
1377 t_floatarg fxpos
, t_floatarg fypos
, t_floatarg fwhich
)
1381 int xpos
= fxpos
, ypos
= fypos
, which
= fwhich
;
1389 #ifdef SIMULATERIGHTCLICK
1390 canvas_upclicktime
= sys_getrealtime();
1395 if (x
->gl_editor
->e_onmotion
== MA_CONNECT
)
1396 canvas_doconnect(x
, xpos
, ypos
, which
, 1);
1397 else if (x
->gl_editor
->e_onmotion
== MA_REGION
)
1398 canvas_doregion(x
, xpos
, ypos
, 1);
1399 else if (x
->gl_editor
->e_onmotion
== MA_MOVE
)
1401 /* after motion, if there's only one item selected, activate it */
1402 if (x
->gl_editor
->e_selection
&&
1403 !(x
->gl_editor
->e_selection
->sel_next
))
1404 gobj_activate(x
->gl_editor
->e_selection
->sel_what
,
1407 else if (x
->gl_editor
->e_onmotion
== MA_PASSOUT
)
1408 x
->gl_editor
->e_onmotion
= 0;
1409 x
->gl_editor
->e_onmotion
= MA_NONE
;
1413 /* GG misused the (unused) dbl parameter to tell if mouseup */
1415 for (y
= x
->gl_list
; y
; y
= y
->g_next
) {
1416 int x1
, y1
, x2
, y2
, clickreturned
= 0;
1418 /* check if the object wants to be clicked */
1419 if (canvas_hitbox(x
, y
, xpos
, ypos
, &x1
, &y1
, &x2
, &y2
)
1420 && (clickreturned
= gobj_click(y
, x
, xpos
, ypos
,
1429 /* displace the selection by (dx, dy) pixels */
1430 static void canvas_displaceselection(t_canvas
*x
, int dx
, int dy
)
1433 int resortin
= 0, resortout
= 0;
1434 if (!canvas_undo_already_set_move
)
1436 canvas_setundo(x
, canvas_undo_move
, canvas_undo_set_move(x
, 1),
1438 canvas_undo_already_set_move
= 1;
1440 for (y
= x
->gl_editor
->e_selection
; y
; y
= y
->sel_next
)
1442 t_class
*cl
= pd_class(&y
->sel_what
->g_pd
);
1443 gobj_displace(y
->sel_what
, x
, dx
, dy
);
1444 if (cl
== vinlet_class
) resortin
= 1;
1445 else if (cl
== voutlet_class
) resortout
= 1;
1447 if (resortin
) canvas_resortinlets(x
);
1448 if (resortout
) canvas_resortoutlets(x
);
1452 /* this routine is called whenever a key is pressed or released. "x"
1453 may be zero if there's no current canvas. The first argument is true or
1454 fals for down/up; the second one is either a symbolic key name (e.g.,
1455 "Right" or an Ascii key number. */
1456 void canvas_key(t_canvas
*x
, t_symbol
*s
, int ac
, t_atom
*av
)
1458 static t_symbol
*keynumsym
, *keyupsym
, *keynamesym
;
1460 t_symbol
*gotkeysym
;
1475 canvas_undo_already_set_move
= 0;
1476 down
= (atom_getfloat(av
) != 0); /* nonzero if it's a key down */
1477 shift
= (atom_getfloat(av
+2) != 0); /* nonzero if shift-ed */
1478 if (av
[1].a_type
== A_SYMBOL
)
1479 gotkeysym
= av
[1].a_w
.w_symbol
;
1480 else if (av
[1].a_type
== A_FLOAT
)
1484 snprintf(buf
, sizeof(buf
), "%c", (int) (av
[1].a_w
.w_float
));
1486 sprintf(buf
, "%c", (int)(av
[1].a_w
.w_float
));
1487 #endif /* ROCKBOX */
1488 gotkeysym
= gensym(buf
);
1490 else gotkeysym
= gensym("?");
1491 fflag
= (av
[0].a_type
== A_FLOAT
? av
[0].a_w
.w_float
: 0);
1492 keynum
= (av
[1].a_type
== A_FLOAT
? av
[1].a_w
.w_float
: 0);
1493 if (keynum
== '\\' || keynum
== '{' || keynum
== '}')
1495 post("%c: dropped", (int)keynum
);
1498 if (keynum
== '\r') keynum
= '\n';
1499 if (av
[1].a_type
== A_SYMBOL
&&
1500 !strcmp(av
[1].a_w
.w_symbol
->s_name
, "Return"))
1504 keynumsym
= gensym("#key");
1505 keyupsym
= gensym("#keyup");
1506 keynamesym
= gensym("#keyname");
1510 keynum
= 0, gotkeysym
= gensym("Up");
1511 else if (keynum
== 31)
1512 keynum
= 0, gotkeysym
= gensym("Down");
1513 else if (keynum
== 28)
1514 keynum
= 0, gotkeysym
= gensym("Left");
1515 else if (keynum
== 29)
1516 keynum
= 0, gotkeysym
= gensym("Right");
1518 if (keynumsym
->s_thing
&& down
)
1519 pd_float(keynumsym
->s_thing
, (float)keynum
);
1520 if (keyupsym
->s_thing
&& !down
)
1521 pd_float(keyupsym
->s_thing
, (float)keynum
);
1522 if (keynamesym
->s_thing
)
1527 SETSYMBOL(at
+1, gotkeysym
);
1528 pd_list(keynamesym
->s_thing
, 0, 2, at
);
1530 if (!x
->gl_editor
) /* if that 'invis'ed the window, we'd better stop. */
1534 /* if an object has "grabbed" keys just send them on */
1535 if (x
->gl_editor
->e_grab
1536 && x
->gl_editor
->e_keyfn
&& keynum
)
1537 (* x
->gl_editor
->e_keyfn
)
1538 (x
->gl_editor
->e_grab
, (float)keynum
);
1539 /* if a text editor is open send it on */
1540 else if (x
->gl_editor
->e_textedfor
)
1542 if (!x
->gl_editor
->e_textdirty
)
1544 canvas_setundo(x
, canvas_undo_cut
,
1545 canvas_undo_set_cut(x
, UCUT_TEXT
), "typing");
1547 rtext_key(x
->gl_editor
->e_textedfor
,
1548 (int)keynum
, gotkeysym
);
1549 if (x
->gl_editor
->e_textdirty
)
1552 /* check for backspace or clear */
1553 else if (keynum
== 8 || keynum
== 127)
1555 if (x
->gl_editor
->e_selectedline
)
1556 canvas_clearline(x
);
1557 else if (x
->gl_editor
->e_selection
)
1559 canvas_setundo(x
, canvas_undo_cut
,
1560 canvas_undo_set_cut(x
, UCUT_CLEAR
), "clear");
1564 /* check for arrow keys */
1565 else if (!strcmp(gotkeysym
->s_name
, "Up"))
1566 canvas_displaceselection(x
, 0, shift
? -10 : -1);
1567 else if (!strcmp(gotkeysym
->s_name
, "Down"))
1568 canvas_displaceselection(x
, 0, shift
? 10 : 1);
1569 else if (!strcmp(gotkeysym
->s_name
, "Left"))
1570 canvas_displaceselection(x
, shift
? -10 : -1, 0);
1571 else if (!strcmp(gotkeysym
->s_name
, "Right"))
1572 canvas_displaceselection(x
, shift
? 10 : 1, 0);
1576 void canvas_motion(t_canvas
*x
, t_floatarg xpos
, t_floatarg ypos
,
1579 /* post("motion %d %d", xpos, ypos); */
1586 glist_setlastxy(x
, xpos
, ypos
);
1587 if (x
->gl_editor
->e_onmotion
== MA_MOVE
)
1589 canvas_displaceselection(x
,
1590 xpos
- x
->gl_editor
->e_xwas
, ypos
- x
->gl_editor
->e_ywas
);
1591 x
->gl_editor
->e_xwas
= xpos
;
1592 x
->gl_editor
->e_ywas
= ypos
;
1594 else if (x
->gl_editor
->e_onmotion
== MA_REGION
)
1595 canvas_doregion(x
, xpos
, ypos
, 0);
1596 else if (x
->gl_editor
->e_onmotion
== MA_CONNECT
)
1597 canvas_doconnect(x
, xpos
, ypos
, 0, 0);
1598 else if (x
->gl_editor
->e_onmotion
== MA_PASSOUT
)
1600 if (!x
->gl_editor
->e_motionfn
)
1602 (*x
->gl_editor
->e_motionfn
)(&x
->gl_editor
->e_grab
->g_pd
,
1603 xpos
- x
->gl_editor
->e_xwas
,
1604 ypos
- x
->gl_editor
->e_ywas
);
1605 x
->gl_editor
->e_xwas
= xpos
;
1606 x
->gl_editor
->e_ywas
= ypos
;
1608 else if (x
->gl_editor
->e_onmotion
== MA_DRAGTEXT
)
1610 t_rtext
*rt
= x
->gl_editor
->e_textedfor
;
1612 rtext_mouse(rt
, xpos
- x
->gl_editor
->e_xwas
,
1613 ypos
- x
->gl_editor
->e_ywas
, RTEXT_DRAG
);
1615 else canvas_doclick(x
, xpos
, ypos
, 0, mod
, 0);
1617 x
->gl_editor
->e_lastmoved
= 1;
1620 void canvas_startmotion(t_canvas
*x
)
1623 if (!x
->gl_editor
) return;
1624 glist_getnextxy(x
, &xval
, &yval
);
1625 if (xval
== 0 && yval
== 0) return;
1626 x
->gl_editor
->e_onmotion
= MA_MOVE
;
1627 x
->gl_editor
->e_xwas
= xval
;
1628 x
->gl_editor
->e_ywas
= yval
;
1631 /* ----------------------------- window stuff ----------------------- */
1633 void canvas_print(t_canvas
*x
, t_symbol
*s
)
1639 if (*s
->s_name
) sys_vgui(".x%x.c postscript -file %s\n", x
, s
->s_name
);
1640 else sys_vgui(".x%x.c postscript -file x.ps\n", x
);
1641 #endif /* ROCKBOX */
1644 void canvas_menuclose(t_canvas
*x
, t_floatarg force
)
1648 else if ((force
!= 0) || (!x
->gl_dirty
))
1651 else sys_vgui("pdtk_check {This window has been modified. Close anyway?}\
1652 {.x%x menuclose 1;\n}\n", x
);
1656 /* put up a dialog which may call canvas_font back to do the work */
1657 static void canvas_menufont(t_canvas
*x
)
1663 t_canvas
*x2
= canvas_getrootfor(x
);
1664 gfxstub_deleteforkey(x2
);
1665 sprintf(buf
, "pdtk_canvas_dofont %%s %d\n", x2
->gl_font
);
1666 gfxstub_new(&x2
->gl_pd
, &x2
->gl_pd
, buf
);
1667 #endif /* ROCKBOX */
1670 static int canvas_find_index1
, canvas_find_index2
;
1671 static t_binbuf
*canvas_findbuf
;
1672 int binbuf_match(t_binbuf
*inbuf
, t_binbuf
*searchbuf
);
1674 /* find an atom or string of atoms */
1675 static int canvas_dofind(t_canvas
*x
, int *myindex1p
)
1678 int myindex1
= *myindex1p
, myindex2
;
1679 if (myindex1
>= canvas_find_index1
)
1681 for (y
= x
->gl_list
, myindex2
= 0; y
;
1682 y
= y
->g_next
, myindex2
++)
1685 if((ob
= pd_checkobject(&y
->g_pd
)))
1687 if (binbuf_match(ob
->ob_binbuf
, canvas_findbuf
))
1689 if (myindex1
> canvas_find_index1
||
1690 (myindex1
== canvas_find_index1
&&
1691 myindex2
> canvas_find_index2
))
1693 canvas_find_index1
= myindex1
;
1694 canvas_find_index2
= myindex2
;
1697 canvas_editmode(x
, 1.);
1705 for (y
= x
->gl_list
, myindex2
= 0; y
; y
= y
->g_next
, myindex2
++)
1707 if (pd_class(&y
->g_pd
) == canvas_class
)
1710 if (canvas_dofind((t_canvas
*)y
, myindex1p
))
1717 static void canvas_find(t_canvas
*x
, t_symbol
*s
, int ac
, t_atom
*av
)
1719 int myindex1
= 0, i
;
1723 for (i
= 0; i
< ac
; i
++)
1725 if (av
[i
].a_type
== A_SYMBOL
)
1727 if (!strcmp(av
[i
].a_w
.w_symbol
->s_name
, "_semi_"))
1729 else if (!strcmp(av
[i
].a_w
.w_symbol
->s_name
, "_comma_"))
1733 if (!canvas_findbuf
)
1734 canvas_findbuf
= binbuf_new();
1735 binbuf_clear(canvas_findbuf
);
1736 binbuf_add(canvas_findbuf
, ac
, av
);
1737 canvas_find_index1
= 0;
1738 canvas_find_index2
= -1;
1739 canvas_whichfind
= x
;
1740 if (!canvas_dofind(x
, &myindex1
))
1742 binbuf_print(canvas_findbuf
);
1743 post("... couldn't find");
1747 static void canvas_find_again(t_canvas
*x
)
1753 if (!canvas_findbuf
|| !canvas_whichfind
)
1755 if (!canvas_dofind(canvas_whichfind
, &myindex1
))
1757 binbuf_print(canvas_findbuf
);
1758 post("... couldn't find");
1762 static void canvas_find_parent(t_canvas
*x
)
1765 canvas_vis(glist_getcanvas(x
->gl_owner
), 1);
1768 static int glist_dofinderror(t_glist
*gl
, void *error_object
)
1771 for (g
= gl
->gl_list
; g
; g
= g
->g_next
)
1773 if ((void *)g
== error_object
)
1775 /* got it... now show it. */
1777 canvas_vis(glist_getcanvas(gl
), 1);
1778 canvas_editmode(glist_getcanvas(gl
), 1.);
1779 glist_select(gl
, g
);
1782 else if (g
->g_pd
== canvas_class
)
1784 if (glist_dofinderror((t_canvas
*)g
, error_object
))
1791 void canvas_finderror(void *error_object
)
1794 /* find all root canvases */
1795 for (x
= canvas_list
; x
; x
= x
->gl_next
)
1797 if (glist_dofinderror(x
, error_object
))
1800 post("... sorry, I couldn't find the source of that error.");
1803 void canvas_stowconnections(t_canvas
*x
)
1805 t_gobj
*selhead
= 0, *seltail
= 0, *nonhead
= 0, *nontail
= 0, *y
, *y2
;
1808 if (!x
->gl_editor
) return;
1809 /* split list to "selected" and "unselected" parts */
1810 for (y
= x
->gl_list
; y
; y
= y2
)
1813 if (glist_isselected(x
, y
))
1817 seltail
->g_next
= y
;
1823 selhead
= seltail
= y
;
1824 seltail
->g_next
= 0;
1831 nontail
->g_next
= y
;
1837 nonhead
= nontail
= y
;
1838 nontail
->g_next
= 0;
1842 /* move the selected part to the end */
1843 if (!nonhead
) x
->gl_list
= selhead
;
1844 else x
->gl_list
= nonhead
, nontail
->g_next
= selhead
;
1846 /* add connections to binbuf */
1847 binbuf_clear(x
->gl_editor
->e_connectbuf
);
1848 linetraverser_start(&t
, x
);
1849 while((oc
= linetraverser_next(&t
)))
1851 int s1
= glist_isselected(x
, &t
.tr_ob
->ob_g
);
1852 int s2
= glist_isselected(x
, &t
.tr_ob2
->ob_g
);
1854 binbuf_addv(x
->gl_editor
->e_connectbuf
, "ssiiii;",
1855 gensym("#X"), gensym("connect"),
1856 glist_getindex(x
, &t
.tr_ob
->ob_g
), t
.tr_outno
,
1857 glist_getindex(x
, &t
.tr_ob2
->ob_g
), t
.tr_inno
);
1861 void canvas_restoreconnections(t_canvas
*x
)
1863 pd_bind(&x
->gl_pd
, gensym("#X"));
1864 binbuf_eval(x
->gl_editor
->e_connectbuf
, 0, 0, 0);
1865 pd_unbind(&x
->gl_pd
, gensym("#X"));
1868 static t_binbuf
*canvas_docopy(t_canvas
*x
)
1873 t_binbuf
*b
= binbuf_new();
1874 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
1876 if (glist_isselected(x
, y
))
1879 linetraverser_start(&t
, x
);
1880 while((oc
= linetraverser_next(&t
)))
1882 if (glist_isselected(x
, &t
.tr_ob
->ob_g
)
1883 && glist_isselected(x
, &t
.tr_ob2
->ob_g
))
1885 binbuf_addv(b
, "ssiiii;", gensym("#X"), gensym("connect"),
1886 glist_selectionindex(x
, &t
.tr_ob
->ob_g
, 1), t
.tr_outno
,
1887 glist_selectionindex(x
, &t
.tr_ob2
->ob_g
, 1), t
.tr_inno
);
1893 static void canvas_copy(t_canvas
*x
)
1895 if (!x
->gl_editor
|| !x
->gl_editor
->e_selection
)
1897 binbuf_free(copy_binbuf
);
1898 copy_binbuf
= canvas_docopy(x
);
1901 static void canvas_clearline(t_canvas
*x
)
1903 if (x
->gl_editor
->e_selectedline
)
1905 canvas_disconnect(x
, x
->gl_editor
->e_selectline_index1
,
1906 x
->gl_editor
->e_selectline_outno
,
1907 x
->gl_editor
->e_selectline_index2
,
1908 x
->gl_editor
->e_selectline_inno
);
1909 canvas_setundo(x
, canvas_undo_disconnect
,
1910 canvas_undo_set_disconnect(x
,
1911 x
->gl_editor
->e_selectline_index1
,
1912 x
->gl_editor
->e_selectline_outno
,
1913 x
->gl_editor
->e_selectline_index2
,
1914 x
->gl_editor
->e_selectline_inno
),
1919 extern t_pd
*newest
;
1920 static void canvas_doclear(t_canvas
*x
)
1925 dspstate
= canvas_suspend_dsp();
1926 if (x
->gl_editor
->e_selectedline
)
1928 canvas_disconnect(x
, x
->gl_editor
->e_selectline_index1
,
1929 x
->gl_editor
->e_selectline_outno
,
1930 x
->gl_editor
->e_selectline_index2
,
1931 x
->gl_editor
->e_selectline_inno
);
1932 canvas_setundo(x
, canvas_undo_disconnect
,
1933 canvas_undo_set_disconnect(x
,
1934 x
->gl_editor
->e_selectline_index1
,
1935 x
->gl_editor
->e_selectline_outno
,
1936 x
->gl_editor
->e_selectline_index2
,
1937 x
->gl_editor
->e_selectline_inno
),
1940 /* if text is selected, deselecting it might remake the
1941 object. So we deselect it and hunt for a "new" object on
1942 the glist to reselect. */
1943 if (x
->gl_editor
->e_textedfor
)
1949 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
1950 if (&y
->g_pd
== newest
) glist_select(x
, y
);
1953 while (1) /* this is pretty wierd... should rewrite it */
1955 for (y
= x
->gl_list
; y
; y
= y2
)
1958 if (glist_isselected(x
, y
))
1962 if (y2
) post("cut 5 %x %x", y2
, y2
->g_next
);
1972 canvas_resume_dsp(dspstate
);
1976 static void canvas_cut(t_canvas
*x
)
1978 if (x
->gl_editor
&& x
->gl_editor
->e_selectedline
)
1979 canvas_clearline(x
);
1980 else if (x
->gl_editor
&& x
->gl_editor
->e_selection
)
1982 canvas_setundo(x
, canvas_undo_cut
,
1983 canvas_undo_set_cut(x
, UCUT_CUT
), "cut");
1989 static int paste_onset
;
1990 static t_canvas
*paste_canvas
;
1992 static void glist_donewloadbangs(t_glist
*x
)
1997 for (sel
= x
->gl_editor
->e_selection
; sel
; sel
= sel
->sel_next
)
1998 if (pd_class(&sel
->sel_what
->g_pd
) == canvas_class
)
1999 canvas_loadbang((t_canvas
*)(&sel
->sel_what
->g_pd
));
2003 static void canvas_dopaste(t_canvas
*x
, t_binbuf
*b
)
2008 t_gobj
*newgobj
, *last
, *g2
;
2009 #endif /* ROCKBOX */
2010 int dspstate
= canvas_suspend_dsp(), nbox
, count
;
2012 canvas_editmode(x
, 1.);
2014 for (g2
= x
->gl_list
, nbox
= 0; g2
; g2
= g2
->g_next
) nbox
++;
2019 pd_bind(&x
->gl_pd
, gensym("#X"));
2020 binbuf_eval(b
, 0, 0, 0);
2021 pd_unbind(&x
->gl_pd
, gensym("#X"));
2022 for (g2
= x
->gl_list
, count
= 0; g2
; g2
= g2
->g_next
, count
++)
2024 glist_select(x
, g2
);
2026 canvas_resume_dsp(dspstate
);
2028 glist_donewloadbangs(x
);
2031 static void canvas_paste(t_canvas
*x
)
2033 canvas_setundo(x
, canvas_undo_paste
, canvas_undo_set_paste(x
), "paste");
2034 canvas_dopaste(x
, copy_binbuf
);
2037 static void canvas_duplicate(t_canvas
*x
)
2039 if (x
->gl_editor
->e_onmotion
== MA_NONE
)
2043 canvas_setundo(x
, canvas_undo_paste
, canvas_undo_set_paste(x
),
2045 canvas_dopaste(x
, copy_binbuf
);
2046 for (y
= x
->gl_editor
->e_selection
; y
; y
= y
->sel_next
)
2047 gobj_displace(y
->sel_what
, x
,
2053 static void canvas_selectall(t_canvas
*x
)
2057 canvas_editmode(x
, 1);
2058 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
2060 if (!glist_isselected(x
, y
))
2065 void canvas_connect(t_canvas
*x
, t_floatarg fwhoout
, t_floatarg foutno
,
2066 t_floatarg fwhoin
, t_floatarg finno
)
2068 int whoout
= fwhoout
, outno
= foutno
, whoin
= fwhoin
, inno
= finno
;
2069 t_gobj
*src
= 0, *sink
= 0;
2070 t_object
*objsrc
, *objsink
;
2072 int nin
= whoin
, nout
= whoout
;
2073 if (paste_canvas
== x
) whoout
+= paste_onset
, whoin
+= paste_onset
;
2074 for (src
= x
->gl_list
; whoout
; src
= src
->g_next
, whoout
--)
2075 if (!src
->g_next
) goto bad
; /* bug fix thanks to Hannes */
2076 for (sink
= x
->gl_list
; whoin
; sink
= sink
->g_next
, whoin
--)
2077 if (!sink
->g_next
) goto bad
;
2078 if (!(objsrc
= pd_checkobject(&src
->g_pd
)) ||
2079 !(objsink
= pd_checkobject(&sink
->g_pd
)))
2081 if (!(oc
= obj_connect(objsrc
, outno
, objsink
, inno
))) goto bad
;
2082 if (glist_isvisible(x
))
2085 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
2086 glist_getcanvas(x
), 0, 0, 0, 0,
2087 (obj_issignaloutlet(objsrc
, outno
) ? 2 : 1),oc
);
2089 canvas_fixlinesfor(x
, objsrc
);
2094 post("%s %d %d %d %d (%s->%s) connection failed",
2095 x
->gl_name
->s_name
, nout
, outno
, nin
, inno
,
2096 (src
? class_getname(pd_class(&src
->g_pd
)) : "???"),
2097 (sink
? class_getname(pd_class(&sink
->g_pd
)) : "???"));
2100 #define XTOLERANCE 4
2101 #define YTOLERANCE 3
2104 /* LATER might have to speed this up */
2105 static void canvas_tidy(t_canvas
*x
)
2110 t_gobj
*y
, *y2
, *y3
;
2111 #endif /* ROCKBOX */
2112 int ax1
, ay1
, ax2
, ay2
, bx1
, by1
, bx2
, by2
;
2113 int histogram
[NHIST
], *ip
, i
, besthist
, bestdist
;
2114 /* if nobody is selected, this means do it to all boxes;
2115 othewise just the selection */
2116 int all
= (x
->gl_editor
? (x
->gl_editor
->e_selection
== 0) : 1);
2118 canvas_setundo(x
, canvas_undo_move
, canvas_undo_set_move(x
, !all
),
2121 /* tidy horizontally */
2122 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
2123 if (all
|| glist_isselected(x
, y
))
2125 gobj_getrect(y
, x
, &ax1
, &ay1
, &ax2
, &ay2
);
2127 for (y2
= x
->gl_list
; y2
; y2
= y2
->g_next
)
2128 if (all
|| glist_isselected(x
, y2
))
2130 gobj_getrect(y2
, x
, &bx1
, &by1
, &bx2
, &by2
);
2131 if (by1
<= ay1
+ YTOLERANCE
&& by1
>= ay1
- YTOLERANCE
&&
2136 for (y2
= x
->gl_list
; y2
; y2
= y2
->g_next
)
2137 if (all
|| glist_isselected(x
, y2
))
2139 gobj_getrect(y2
, x
, &bx1
, &by1
, &bx2
, &by2
);
2140 if (by1
<= ay1
+ YTOLERANCE
&& by1
>= ay1
- YTOLERANCE
2142 gobj_displace(y2
, x
, 0, ay1
-by1
);
2146 /* tidy vertically. First guess the user's favorite vertical spacing */
2147 for (i
= NHIST
, ip
= histogram
; i
--; ip
++) *ip
= 0;
2148 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
2149 if (all
|| glist_isselected(x
, y
))
2151 gobj_getrect(y
, x
, &ax1
, &ay1
, &ax2
, &ay2
);
2152 for (y2
= x
->gl_list
; y2
; y2
= y2
->g_next
)
2153 if (all
|| glist_isselected(x
, y2
))
2155 gobj_getrect(y2
, x
, &bx1
, &by1
, &bx2
, &by2
);
2156 if (bx1
<= ax1
+ XTOLERANCE
&& bx1
>= ax1
- XTOLERANCE
)
2158 int distance
= by1
-ay2
;
2159 if (distance
>= 0 && distance
< NHIST
)
2160 histogram
[distance
]++;
2164 for (i
= 1, besthist
= 0, bestdist
= 4, ip
= histogram
+ 1;
2165 i
< (NHIST
-1); i
++, ip
++)
2167 int hit
= ip
[-1] + 2 * ip
[0] + ip
[1];
2174 post("best vertical distance %d", bestdist
);
2175 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
2176 if (all
|| glist_isselected(x
, y
))
2179 gobj_getrect(y
, x
, &ax1
, &ay1
, &ax2
, &ay2
);
2180 for (y2
= x
->gl_list
; y2
; y2
= y2
->g_next
)
2181 if (all
|| glist_isselected(x
, y2
))
2183 gobj_getrect(y2
, x
, &bx1
, &by1
, &bx2
, &by2
);
2184 if (bx1
<= ax1
+ XTOLERANCE
&& bx1
>= ax1
- XTOLERANCE
&&
2185 ay1
>= by2
- 10 && ay1
< by2
+ NHIST
)
2191 for (y2
= x
->gl_list
; y2
; y2
= y2
->g_next
)
2192 if (all
|| glist_isselected(x
, y2
))
2194 gobj_getrect(y2
, x
, &bx1
, &by1
, &bx2
, &by2
);
2195 if (bx1
<= ax1
+ XTOLERANCE
&& bx1
>= ax1
- XTOLERANCE
&&
2196 by1
> ay1
&& by1
< ay2
+ NHIST
)
2198 int vmove
= ay2
+ bestdist
- by1
;
2199 gobj_displace(y2
, x
, ax1
-bx1
, vmove
);
2212 static void canvas_texteditor(t_canvas
*x
)
2217 if((foo
= x
->gl_editor
->e_textedfor
))
2218 rtext_gettext(foo
, &buf
, &bufsize
);
2219 else buf
= "", bufsize
= 0;
2221 sys_vgui("pdtk_pd_texteditor {%.*s}\n", bufsize
, buf
);
2225 void glob_key(void *dummy
, t_symbol
*s
, int ac
, t_atom
*av
)
2230 /* canvas_editing can be zero; canvas_key checks for that */
2231 canvas_key(canvas_editing
, s
, ac
, av
);
2234 void canvas_editmode(t_canvas
*x
, t_floatarg fyesplease
)
2236 int yesplease
= fyesplease
;
2237 if (yesplease
&& x
->gl_edit
)
2239 x
->gl_edit
= !x
->gl_edit
;
2240 if (x
->gl_edit
&& glist_isvisible(x
) && glist_istoplevel(x
))
2241 canvas_setcursor(x
, CURSOR_EDITMODE_NOTHING
);
2245 if (glist_isvisible(x
) && glist_istoplevel(x
))
2246 canvas_setcursor(x
, CURSOR_RUNMODE_NOTHING
);
2249 sys_vgui("pdtk_canvas_editval .x%x %d\n",
2250 glist_getcanvas(x
), x
->gl_edit
);
2254 /* called by canvas_font below */
2255 static void canvas_dofont(t_canvas
*x
, t_floatarg font
, t_floatarg xresize
,
2260 if (xresize
!= 1 || yresize
!= 1)
2262 canvas_setundo(x
, canvas_undo_move
, canvas_undo_set_move(x
, 0),
2264 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
2266 int x1
, x2
, y1
, y2
, nx1
, ny1
;
2267 gobj_getrect(y
, x
, &x1
, &y1
, &x2
, &y2
);
2268 nx1
= x1
* xresize
+ 0.5;
2269 ny1
= y1
* yresize
+ 0.5;
2270 gobj_displace(y
, x
, nx1
-x1
, ny1
-y1
);
2273 if (glist_isvisible(x
))
2275 for (y
= x
->gl_list
; y
; y
= y
->g_next
)
2276 if (pd_class(&y
->g_pd
) == canvas_class
2277 && !canvas_isabstraction((t_canvas
*)y
))
2278 canvas_dofont((t_canvas
*)y
, font
, xresize
, yresize
);
2281 /* canvas_menufont calls up a TK dialog which calls this back */
2282 static void canvas_font(t_canvas
*x
, t_floatarg font
, t_floatarg resize
,
2283 t_floatarg whichresize
)
2285 float realresize
, realresx
= 1, realresy
= 1;
2286 t_canvas
*x2
= canvas_getrootfor(x
);
2287 if (!resize
) realresize
= 1;
2290 if (resize
< 20) resize
= 20;
2291 if (resize
> 500) resize
= 500;
2292 realresize
= resize
* 0.01;
2294 if (whichresize
!= 3) realresx
= realresize
;
2295 if (whichresize
!= 2) realresy
= realresize
;
2296 canvas_dofont(x2
, font
, realresx
, realresy
);
2298 sys_defaultfont
= font
;
2302 static t_glist
*canvas_last_glist
;
2303 static int canvas_last_glist_x
, canvas_last_glist_y
;
2305 void glist_getnextxy(t_glist
*gl
, int *xpix
, int *ypix
)
2307 if (canvas_last_glist
== gl
)
2308 *xpix
= canvas_last_glist_x
, *ypix
= canvas_last_glist_y
;
2309 else *xpix
= *ypix
= 40;
2312 static void glist_setlastxy(t_glist
*gl
, int xval
, int yval
)
2314 canvas_last_glist
= gl
;
2315 canvas_last_glist_x
= xval
;
2316 canvas_last_glist_y
= yval
;
2320 void g_editor_setup(void)
2322 /* ------------------------ events ---------------------------------- */
2323 class_addmethod(canvas_class
, (t_method
)canvas_mousedown
, gensym("mouse"),
2324 A_FLOAT
, A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2325 class_addmethod(canvas_class
, (t_method
)canvas_mouseup
, gensym("mouseup"),
2326 A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2327 class_addmethod(canvas_class
, (t_method
)canvas_key
, gensym("key"),
2329 class_addmethod(canvas_class
, (t_method
)canvas_motion
, gensym("motion"),
2330 A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2332 /* ------------------------ menu actions ---------------------------- */
2333 class_addmethod(canvas_class
, (t_method
)canvas_menuclose
,
2334 gensym("menuclose"), A_DEFFLOAT
, 0);
2335 class_addmethod(canvas_class
, (t_method
)canvas_cut
,
2336 gensym("cut"), A_NULL
);
2337 class_addmethod(canvas_class
, (t_method
)canvas_copy
,
2338 gensym("copy"), A_NULL
);
2339 class_addmethod(canvas_class
, (t_method
)canvas_paste
,
2340 gensym("paste"), A_NULL
);
2341 class_addmethod(canvas_class
, (t_method
)canvas_duplicate
,
2342 gensym("duplicate"), A_NULL
);
2343 class_addmethod(canvas_class
, (t_method
)canvas_selectall
,
2344 gensym("selectall"), A_NULL
);
2345 class_addmethod(canvas_class
, (t_method
)canvas_undo
,
2346 gensym("undo"), A_NULL
);
2347 class_addmethod(canvas_class
, (t_method
)canvas_redo
,
2348 gensym("redo"), A_NULL
);
2349 class_addmethod(canvas_class
, (t_method
)canvas_tidy
,
2350 gensym("tidy"), A_NULL
);
2351 class_addmethod(canvas_class
, (t_method
)canvas_texteditor
,
2352 gensym("texteditor"), A_NULL
);
2353 class_addmethod(canvas_class
, (t_method
)canvas_editmode
,
2354 gensym("editmode"), A_DEFFLOAT
, A_NULL
);
2355 class_addmethod(canvas_class
, (t_method
)canvas_print
,
2356 gensym("print"), A_SYMBOL
, A_NULL
);
2357 class_addmethod(canvas_class
, (t_method
)canvas_menufont
,
2358 gensym("menufont"), A_NULL
);
2359 class_addmethod(canvas_class
, (t_method
)canvas_font
,
2360 gensym("font"), A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2361 class_addmethod(canvas_class
, (t_method
)canvas_find
,
2362 gensym("find"), A_GIMME
, A_NULL
);
2363 class_addmethod(canvas_class
, (t_method
)canvas_find_again
,
2364 gensym("findagain"), A_NULL
);
2365 class_addmethod(canvas_class
, (t_method
)canvas_find_parent
,
2366 gensym("findparent"), A_NULL
);
2367 class_addmethod(canvas_class
, (t_method
)canvas_done_popup
,
2368 gensym("done-popup"), A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2369 class_addmethod(canvas_class
, (t_method
)canvas_donecanvasdialog
,
2370 gensym("donecanvasdialog"), A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2371 class_addmethod(canvas_class
, (t_method
)glist_arraydialog
,
2372 gensym("arraydialog"), A_SYMBOL
, A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2374 /* -------------- connect method used in reading files ------------------ */
2375 class_addmethod(canvas_class
, (t_method
)canvas_connect
,
2376 gensym("connect"), A_FLOAT
, A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2378 class_addmethod(canvas_class
, (t_method
)canvas_disconnect
,
2379 gensym("disconnect"), A_FLOAT
, A_FLOAT
, A_FLOAT
, A_FLOAT
, A_NULL
);
2380 /* -------------- copy buffer ------------------ */
2381 copy_binbuf
= binbuf_new();