A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 772 lines 22 kB view raw
1/* Copyright (c) 1997-2002 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. */ 4 5/* this file reads and writes the "data" portions of a canvas to a file. 6See also canvas_saveto(), etc., in g_editor.c. The data portion is a 7collection of "scalar" objects. Routines here can save collections of 8scalars into a file and reload them; also, support is included here for 9*/ 10 11#ifdef ROCKBOX 12#include "plugin.h" 13#include "../../pdbox.h" 14#include "m_pd.h" 15#include "g_canvas.h" 16#else /* ROCKBOX */ 17#include <stdlib.h> 18#include <stdio.h> 19#include "m_pd.h" 20#include "g_canvas.h" 21#include <string.h> 22#endif /* ROCKBOX */ 23 24 /* the following routines read "scalars" from a file into a canvas. */ 25 26static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, 27 int *p_next) 28{ 29#ifdef ROCKBOX 30 int i; 31#else 32 int i, j; 33#endif 34 int indexwas = *p_next; 35 *p_indexout = indexwas; 36 if (indexwas >= natoms) 37 return (0); 38 for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) 39 ; 40 if (i >= natoms) 41 *p_next = i; 42 else *p_next = i + 1; 43 return (i - indexwas); 44} 45 46int glist_readscalar(t_glist *x, int natoms, t_atom *vec, 47 int *p_nextmsg, int selectit); 48 49static void canvas_readerror(int natoms, t_atom *vec, int message, 50 int nline, char *s) 51{ 52#ifdef ROCKBOX 53 (void) natoms; 54#endif 55 error(s); 56 startpost("line was:"); 57 postatom(nline, vec + message); 58 endpost(); 59} 60 61 /* fill in the contents of the scalar into the vector w. */ 62 63static void glist_readatoms(t_glist *x, int natoms, t_atom *vec, 64 int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv) 65{ 66#ifdef ROCKBOX 67 int message, n, i; 68#else 69 int message, nline, n, i; 70#endif 71 72 t_template *template = template_findbyname(templatesym); 73 if (!template) 74 { 75 error("%s: no such template", templatesym->s_name); 76 *p_nextmsg = natoms; 77 return; 78 } 79 word_restore(w, template, argc, argv); 80 n = template->t_n; 81 for (i = 0; i < n; i++) 82 { 83 if (template->t_vec[i].ds_type == DT_ARRAY) 84 { 85#ifndef ROCKBOX 86 int j; 87#endif 88 t_array *a = w[i].w_array; 89 int elemsize = a->a_elemsize, nitems = 0; 90 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; 91 t_template *arraytemplate = 92 template_findbyname(arraytemplatesym); 93 if (!arraytemplate) 94 { 95 error("%s: no such template", arraytemplatesym->s_name); 96 } 97 else while (1) 98 { 99 t_word *element; 100 int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); 101 /* empty line terminates array */ 102 if (!nline) 103 break; 104 array_resize(a, arraytemplate, nitems + 1); 105 element = (t_word *)(((char *)a->a_vec) + 106 nitems * elemsize); 107 glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym, 108 element, nline, vec + message); 109 nitems++; 110 } 111 } 112 else if (template->t_vec[i].ds_type == DT_LIST) 113 { 114 while (1) 115 { 116 if (!glist_readscalar(w->w_list, natoms, vec, 117 p_nextmsg, 0)) 118 break; 119 } 120 } 121 } 122} 123 124int glist_readscalar(t_glist *x, int natoms, t_atom *vec, 125 int *p_nextmsg, int selectit) 126{ 127#ifdef ROCKBOX 128 int message, nline; 129#else 130 int message, i, j, nline; 131#endif 132 t_template *template; 133 t_symbol *templatesym; 134 t_scalar *sc; 135 int nextmsg = *p_nextmsg; 136 int wasvis = glist_isvisible(x); 137 138 if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) 139 { 140 if (nextmsg < natoms) 141 post("stopping early: type %d", vec[nextmsg].a_type); 142 *p_nextmsg = natoms; 143 return (0); 144 } 145 templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol); 146 *p_nextmsg = nextmsg + 1; 147 148 if (!(template = template_findbyname(templatesym))) 149 { 150 error("canvas_read: %s: no such template", templatesym->s_name); 151 *p_nextmsg = natoms; 152 return (0); 153 } 154 sc = scalar_new(x, templatesym); 155 if (!sc) 156 { 157 error("couldn't create scalar \"%s\"", templatesym->s_name); 158 *p_nextmsg = natoms; 159 return (0); 160 } 161 if (wasvis) 162 { 163 /* temporarily lie about vis flag while this is built */ 164 glist_getcanvas(x)->gl_mapped = 0; 165 } 166 glist_add(x, &sc->sc_gobj); 167 168 nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); 169 glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec, 170 nline, vec + message); 171 if (wasvis) 172 { 173 /* reset vis flag as before */ 174 glist_getcanvas(x)->gl_mapped = 1; 175 gobj_vis(&sc->sc_gobj, x, 1); 176 } 177 if (selectit) 178 { 179 glist_select(x, &sc->sc_gobj); 180 } 181 return (1); 182} 183 184void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem) 185{ 186#ifdef ROCKBOX 187 int natoms, nline, message, nextmsg = 0; 188#else 189 t_canvas *canvas = glist_getcanvas(x); 190 int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems; 191#endif 192 t_atom *vec; 193#ifndef ROCKBOX 194 t_gobj *gobj; 195#endif 196 197 natoms = binbuf_getnatom(b); 198 vec = binbuf_getvec(b); 199 200 201 /* check for file type */ 202 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); 203 if (nline != 1 && vec[message].a_type != A_SYMBOL && 204 strcmp(vec[message].a_w.w_symbol->s_name, "data")) 205 { 206 pd_error(x, "%s: file apparently of wrong type", filename); 207 binbuf_free(b); 208 return; 209 } 210 /* read in templates and check for consistency */ 211 while (1) 212 { 213 t_template *newtemplate, *existtemplate; 214 t_symbol *templatesym; 215 t_atom *templateargs = getbytes(0); 216 int ntemplateargs = 0, newnargs; 217 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); 218 if (nline < 2) 219 break; 220 else if (nline > 2) 221 canvas_readerror(natoms, vec, message, nline, 222 "extra items ignored"); 223 else if (vec[message].a_type != A_SYMBOL || 224 strcmp(vec[message].a_w.w_symbol->s_name, "template") || 225 vec[message + 1].a_type != A_SYMBOL) 226 { 227 canvas_readerror(natoms, vec, message, nline, 228 "bad template header"); 229 continue; 230 } 231 templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol); 232 while (1) 233 { 234 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); 235 if (nline != 2 && nline != 3) 236 break; 237 newnargs = ntemplateargs + nline; 238 templateargs = (t_atom *)t_resizebytes(templateargs, 239 sizeof(*templateargs) * ntemplateargs, 240 sizeof(*templateargs) * newnargs); 241 templateargs[ntemplateargs] = vec[message]; 242 templateargs[ntemplateargs + 1] = vec[message + 1]; 243 if (nline == 3) 244 templateargs[ntemplateargs + 2] = vec[message + 2]; 245 ntemplateargs = newnargs; 246 } 247 newtemplate = template_new(templatesym, ntemplateargs, templateargs); 248 t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs); 249 if (!(existtemplate = template_findbyname(templatesym))) 250 { 251 error("%s: template not found in current patch", 252 templatesym->s_name); 253 template_free(newtemplate); 254 return; 255 } 256 if (!template_match(existtemplate, newtemplate)) 257 { 258 error("%s: template doesn't match current one", 259 templatesym->s_name); 260 template_free(newtemplate); 261 return; 262 } 263 template_free(newtemplate); 264 } 265 while (nextmsg < natoms) 266 { 267 glist_readscalar(x, natoms, vec, &nextmsg, selectem); 268 } 269} 270 271static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format, 272 int clearme) 273{ 274 t_binbuf *b = binbuf_new(); 275 t_canvas *canvas = glist_getcanvas(x); 276 int wasvis = glist_isvisible(canvas); 277#ifdef ROCKBOX 278 int cr = 0; 279#else 280 int cr = 0, natoms, nline, message, nextmsg = 0, i, j; 281 t_atom *vec; 282#endif 283 284 if (!strcmp(format->s_name, "cr")) 285 cr = 1; 286 else if (*format->s_name) 287 error("qlist_read: unknown flag: %s", format->s_name); 288 289 if (binbuf_read_via_path(b, filename->s_name, 290 canvas_getdir(canvas)->s_name, cr)) 291 { 292 pd_error(x, "read failed"); 293 binbuf_free(b); 294 return; 295 } 296 if (wasvis) 297 canvas_vis(canvas, 0); 298 if (clearme) 299 glist_clear(x); 300 glist_readfrombinbuf(x, b, filename->s_name, 0); 301 if (wasvis) 302 canvas_vis(canvas, 1); 303 binbuf_free(b); 304} 305 306void glist_read(t_glist *x, t_symbol *filename, t_symbol *format) 307{ 308 glist_doread(x, filename, format, 1); 309} 310 311void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format) 312{ 313 glist_doread(x, filename, format, 0); 314} 315 316 /* read text from a "properties" window, called from a gfxstub set 317 up in scalar_properties(). We try to restore the object; if successful 318 we delete the scalar and put the new thing in its place on the list. */ 319void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) 320{ 321 int ntotal, nnew, scindex; 322 t_gobj *y, *y2 = 0, *newone, *oldone = 0; 323 for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next) 324 { 325 if (y == &sc->sc_gobj) 326 scindex = ntotal, oldone = y; 327 ntotal++; 328 } 329 330 if (scindex == -1) 331 bug("data_properties: scalar disappeared"); 332 glist_readfrombinbuf(x, b, "properties dialog", 0); 333 newone = 0; 334 if (scindex >= 0) 335 { 336 /* take the new object off the list */ 337 if (ntotal) 338 { 339 for(y = x->gl_list, nnew = 1; (y2 = y->g_next); 340 y = y2, nnew++) 341 if (nnew == ntotal) 342 { 343 newone = y2; 344 y->g_next = y2->g_next; 345 break; 346 } 347 } 348 else newone = x->gl_list, x->gl_list = newone->g_next; 349 } 350 if (!newone) 351 error("couldn't update properties (perhaps a format problem?)"); 352 else if (!oldone) 353 bug("data_properties: couldn't find old element"); 354 else 355 { 356 glist_delete(x, oldone); 357 if (scindex > 0) 358 { 359 for (y = x->gl_list, nnew = 1; y; 360 y = y->g_next, nnew++) 361 if (nnew == scindex || !y->g_next) 362 { 363 newone->g_next = y->g_next; 364 y->g_next = newone; 365 goto didit; 366 } 367 bug("data_properties: can't reinsert"); 368 } 369 else newone->g_next = x->gl_list, x->gl_list = newone; 370 } 371didit: 372 ; 373} 374 375 /* ----------- routines to write data to a binbuf ----------- */ 376 377void canvas_doaddtemplate(t_symbol *templatesym, 378 int *p_ntemplates, t_symbol ***p_templatevec) 379{ 380 int n = *p_ntemplates, i; 381 t_symbol **templatevec = *p_templatevec; 382 for (i = 0; i < n; i++) 383 if (templatevec[i] == templatesym) 384 return; 385 templatevec = (t_symbol **)t_resizebytes(templatevec, 386 n * sizeof(*templatevec), (n+1) * sizeof(*templatevec)); 387 templatevec[n] = templatesym; 388 *p_templatevec = templatevec; 389 *p_ntemplates = n+1; 390} 391 392static void glist_writelist(t_gobj *y, t_binbuf *b); 393 394void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, 395 int amarrayelement) 396{ 397#ifndef ROCKBOX 398 t_dataslot *ds; 399#endif 400 t_template *template = template_findbyname(templatesym); 401 t_atom *a = (t_atom *)t_getbytes(0); 402 int i, n = template->t_n, natom = 0; 403 if (!amarrayelement) 404 { 405 t_atom templatename; 406 SETSYMBOL(&templatename, gensym(templatesym->s_name + 3)); 407 binbuf_add(b, 1, &templatename); 408 } 409 if (!template) 410 bug("canvas_writescalar"); 411 /* write the atoms (floats and symbols) */ 412 for (i = 0; i < n; i++) 413 { 414 if (template->t_vec[i].ds_type == DT_FLOAT || 415 template->t_vec[i].ds_type == DT_SYMBOL) 416 { 417 a = (t_atom *)t_resizebytes(a, 418 natom * sizeof(*a), (natom + 1) * sizeof (*a)); 419 if (template->t_vec[i].ds_type == DT_FLOAT) 420 SETFLOAT(a + natom, w[i].w_float); 421 else SETSYMBOL(a + natom, w[i].w_symbol); 422 natom++; 423 } 424 } 425 /* array elements have to have at least something */ 426 if (natom == 0 && amarrayelement) 427 SETSYMBOL(a + natom, &s_bang), natom++; 428 binbuf_add(b, natom, a); 429 binbuf_addsemi(b); 430 t_freebytes(a, natom * sizeof(*a)); 431 for (i = 0; i < n; i++) 432 { 433 if (template->t_vec[i].ds_type == DT_ARRAY) 434 { 435 int j; 436 t_array *a = w[i].w_array; 437 int elemsize = a->a_elemsize, nitems = a->a_n; 438 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; 439 for (j = 0; j < nitems; j++) 440 canvas_writescalar(arraytemplatesym, 441 (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1); 442 binbuf_addsemi(b); 443 } 444 else if (template->t_vec[i].ds_type == DT_LIST) 445 { 446 glist_writelist(w->w_list->gl_list, b); 447 binbuf_addsemi(b); 448 } 449 } 450} 451 452static void glist_writelist(t_gobj *y, t_binbuf *b) 453{ 454 for (; y; y = y->g_next) 455 { 456 if (pd_class(&y->g_pd) == scalar_class) 457 { 458 canvas_writescalar(((t_scalar *)y)->sc_template, 459 ((t_scalar *)y)->sc_vec, b, 0); 460 } 461 } 462} 463 464 /* ------------ routines to write out templates for data ------- */ 465 466static void canvas_addtemplatesforlist(t_gobj *y, 467 int *p_ntemplates, t_symbol ***p_templatevec); 468 469static void canvas_addtemplatesforscalar(t_symbol *templatesym, 470 t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) 471{ 472 t_dataslot *ds; 473 int i; 474 t_template *template = template_findbyname(templatesym); 475 canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec); 476 if (!template) 477 bug("canvas_addtemplatesforscalar"); 478 else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++) 479 { 480 if (ds->ds_type == DT_ARRAY) 481 { 482 int j; 483 t_array *a = w->w_array; 484 int elemsize = a->a_elemsize, nitems = a->a_n; 485 t_symbol *arraytemplatesym = ds->ds_arraytemplate; 486 canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec); 487 for (j = 0; j < nitems; j++) 488 canvas_addtemplatesforscalar(arraytemplatesym, 489 (t_word *)(((char *)a->a_vec) + elemsize * j), 490 p_ntemplates, p_templatevec); 491 } 492 else if (ds->ds_type == DT_LIST) 493 canvas_addtemplatesforlist(w->w_list->gl_list, 494 p_ntemplates, p_templatevec); 495 } 496} 497 498static void canvas_addtemplatesforlist(t_gobj *y, 499 int *p_ntemplates, t_symbol ***p_templatevec) 500{ 501 for (; y; y = y->g_next) 502 { 503 if (pd_class(&y->g_pd) == scalar_class) 504 { 505 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, 506 ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec); 507 } 508 } 509} 510 511 /* write all "scalars" in a glist to a binbuf. */ 512t_binbuf *glist_writetobinbuf(t_glist *x, int wholething) 513{ 514 int i; 515 t_symbol **templatevec = getbytes(0); 516 int ntemplates = 0; 517 t_gobj *y; 518 t_binbuf *b = binbuf_new(); 519 520 for (y = x->gl_list; y; y = y->g_next) 521 { 522 if ((pd_class(&y->g_pd) == scalar_class) && 523 (wholething || glist_isselected(x, y))) 524 { 525 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, 526 ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec); 527 } 528 } 529 binbuf_addv(b, "s;", gensym("data")); 530 for (i = 0; i < ntemplates; i++) 531 { 532 t_template *template = template_findbyname(templatevec[i]); 533 int j, m = template->t_n; 534 /* drop "pd-" prefix from template symbol to print it: */ 535 binbuf_addv(b, "ss;", gensym("template"), 536 gensym(templatevec[i]->s_name + 3)); 537 for (j = 0; j < m; j++) 538 { 539 t_symbol *type; 540 switch (template->t_vec[j].ds_type) 541 { 542 case DT_FLOAT: type = &s_float; break; 543 case DT_SYMBOL: type = &s_symbol; break; 544 case DT_ARRAY: type = gensym("array"); break; 545 case DT_LIST: type = &s_list; break; 546 default: type = &s_float; bug("canvas_write"); 547 } 548 if (template->t_vec[j].ds_type == DT_ARRAY) 549 binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name, 550 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); 551 else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name); 552 } 553 binbuf_addsemi(b); 554 } 555 binbuf_addsemi(b); 556 /* now write out the objects themselves */ 557 for (y = x->gl_list; y; y = y->g_next) 558 { 559 if ((pd_class(&y->g_pd) == scalar_class) && 560 (wholething || glist_isselected(x, y))) 561 { 562 canvas_writescalar(((t_scalar *)y)->sc_template, 563 ((t_scalar *)y)->sc_vec, b, 0); 564 } 565 } 566 return (b); 567} 568 569static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format) 570{ 571#ifdef ROCKBOX 572 int cr = 0; 573#else 574 int cr = 0, i; 575#endif 576 t_binbuf *b; 577 char buf[MAXPDSTRING]; 578#ifndef ROCKBOX 579 t_symbol **templatevec = getbytes(0); 580 int ntemplates = 0; 581 t_gobj *y; 582#endif 583 t_canvas *canvas = glist_getcanvas(x); 584 canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING); 585 if (!strcmp(format->s_name, "cr")) 586 cr = 1; 587 else if (*format->s_name) 588 error("qlist_read: unknown flag: %s", format->s_name); 589 590 b = glist_writetobinbuf(x, 1); 591 if (b) 592 { 593 if (binbuf_write(b, buf, "", cr)) 594 error("%s: write failed", filename->s_name); 595 binbuf_free(b); 596 } 597} 598 599/* ------ routines to save and restore canvases (patches) recursively. ----*/ 600 601 /* save to a binbuf, called recursively; cf. canvas_savetofile() which 602 saves the document, and is only called on root canvases. */ 603static void canvas_saveto(t_canvas *x, t_binbuf *b) 604{ 605 t_gobj *y; 606 t_linetraverser t; 607 t_outconnect *oc; 608 /* subpatch */ 609 if (x->gl_owner && !x->gl_env) 610 { 611 binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"), 612 (t_int)(x->gl_screenx1), 613 (t_int)(x->gl_screeny1), 614 (t_int)(x->gl_screenx2 - x->gl_screenx1), 615 (t_int)(x->gl_screeny2 - x->gl_screeny1), 616 (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")), 617 x->gl_mapped); 618 } 619 /* root or abstraction */ 620 else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"), 621 (t_int)(x->gl_screenx1), 622 (t_int)(x->gl_screeny1), 623 (t_int)(x->gl_screenx2 - x->gl_screenx1), 624 (t_int)(x->gl_screeny2 - x->gl_screeny1), 625 x->gl_font); 626 627 for (y = x->gl_list; y; y = y->g_next) 628 gobj_save(y, b); 629 630 linetraverser_start(&t, x); 631 while((oc = linetraverser_next(&t))) 632 { 633 int srcno = canvas_getindex(x, &t.tr_ob->ob_g); 634 int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g); 635 binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), 636 srcno, t.tr_outno, sinkno, t.tr_inno); 637 } 638 /* unless everything is the default (as in ordinary subpatches) 639 print out a "coords" message to set up the coordinate systems */ 640 if (x->gl_isgraph || x->gl_x1 || x->gl_y1 || 641 x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight) 642 binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"), 643 x->gl_x1, x->gl_y1, 644 x->gl_x2, x->gl_y2, 645 (float)x->gl_pixwidth, (float)x->gl_pixheight, 646 (float)x->gl_isgraph); 647} 648 649 /* call this recursively to collect all the template names for 650 a canvas or for the selection. */ 651static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, 652 t_symbol ***templatevecp, int wholething) 653{ 654 t_gobj *y; 655 656 for (y = x->gl_list; y; y = y->g_next) 657 { 658 if ((pd_class(&y->g_pd) == scalar_class) && 659 (wholething || glist_isselected(x, y))) 660 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, 661 ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp); 662 else if ((pd_class(&y->g_pd) == canvas_class) && 663 (wholething || glist_isselected(x, y))) 664 canvas_collecttemplatesfor((t_canvas *)y, 665 ntemplatesp, templatevecp, 1); 666 } 667} 668 669 /* save the templates needed by a canvas to a binbuf. */ 670static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething) 671{ 672 t_symbol **templatevec = getbytes(0); 673 int i, ntemplates = 0; 674#ifndef ROCKBOX 675 t_gobj *y; 676#endif 677 canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething); 678 for (i = 0; i < ntemplates; i++) 679 { 680 t_template *template = template_findbyname(templatevec[i]); 681 int j, m = template->t_n; 682 if (!template) 683 { 684 bug("canvas_savetemplatesto"); 685 continue; 686 } 687 /* drop "pd-" prefix from template symbol to print */ 688 binbuf_addv(b, "sss", &s__N, gensym("struct"), 689 gensym(templatevec[i]->s_name + 3)); 690 for (j = 0; j < m; j++) 691 { 692 t_symbol *type; 693 switch (template->t_vec[j].ds_type) 694 { 695 case DT_FLOAT: type = &s_float; break; 696 case DT_SYMBOL: type = &s_symbol; break; 697 case DT_ARRAY: type = gensym("array"); break; 698 case DT_LIST: type = &s_list; break; 699 default: type = &s_float; bug("canvas_write"); 700 } 701 if (template->t_vec[j].ds_type == DT_ARRAY) 702 binbuf_addv(b, "sss", type, template->t_vec[j].ds_name, 703 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); 704 else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name); 705 } 706 binbuf_addsemi(b); 707 } 708} 709 710void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except); 711 712 /* save a "root" canvas to a file; cf. canvas_saveto() which saves the 713 body (and which is called recursively.) */ 714static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir) 715{ 716 t_binbuf *b = binbuf_new(); 717 canvas_savetemplatesto(x, b, 1); 718 canvas_saveto(x, b); 719 if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch(); 720 else 721 { 722 /* if not an abstraction, reset title bar and directory */ 723 if (!x->gl_owner) 724 canvas_rename(x, filename, dir); 725 post("saved to: %s/%s", dir->s_name, filename->s_name); 726 canvas_dirty(x, 0); 727 canvas_reload(filename, dir, &x->gl_gobj); 728 } 729 binbuf_free(b); 730} 731 732static void canvas_menusaveas(t_canvas *x) 733{ 734#ifdef ROCKBOX 735 (void) x; 736#else /* ROCKBOX */ 737 t_canvas *x2 = canvas_getrootfor(x); 738 sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2, 739 x2->gl_name->s_name, canvas_getdir(x2)->s_name); 740#endif /* ROCKBOX */ 741} 742 743static void canvas_menusave(t_canvas *x) 744{ 745 t_canvas *x2 = canvas_getrootfor(x); 746 char *name = x2->gl_name->s_name; 747 if (*name && strncmp(name, "Untitled", 8) 748 && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat"))) 749 canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2)); 750 else canvas_menusaveas(x2); 751} 752 753 754void g_readwrite_setup(void) 755{ 756 class_addmethod(canvas_class, (t_method)glist_write, 757 gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL); 758 class_addmethod(canvas_class, (t_method)glist_read, 759 gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL); 760 class_addmethod(canvas_class, (t_method)glist_mergefile, 761 gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL); 762 class_addmethod(canvas_class, (t_method)canvas_savetofile, 763 gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0); 764 class_addmethod(canvas_class, (t_method)canvas_saveto, 765 gensym("saveto"), A_CANT, 0); 766/* ------------------ from the menu ------------------------- */ 767 class_addmethod(canvas_class, (t_method)canvas_menusave, 768 gensym("menusave"), 0); 769 class_addmethod(canvas_class, (t_method)canvas_menusaveas, 770 gensym("menusaveas"), 0); 771} 772