From ecb92e6da9812b1b47e5c23c01af2c3f1fa66f33 Mon Sep 17 00:00:00 2001
From: Jonathan Wilkes <jon.w.wilkes@gmail.com>
Date: Sun, 5 Jul 2020 23:34:45 -0400
Subject: [PATCH] add hex symbol color syntax for iemgui colors

We're not yet saving the hex colors as that will break in older patches.
But we do print out warning messages in this interim period and will
save the hex colors at a later date. Once that change is made, all the
interim versions will be able to read the new format
---
 pd/src/g_all_guis.c                           | 216 ++++++++++++++++--
 pd/src/g_all_guis.h                           |   6 +-
 pd/src/g_bang.c                               |  18 +-
 pd/src/g_mycanvas.c                           |  16 +-
 pd/src/g_numbox.c                             |  17 +-
 pd/src/g_radio.c                              |  17 +-
 pd/src/g_slider.c                             |  24 +-
 pd/src/g_toggle.c                             |  17 +-
 pd/src/g_vumeter.c                            |  15 +-
 pd/src/s_inter.c                              |   2 +-
 scripts/regression_tests.pd                   |   8 +-
 .../iemgui_color_symbolargs.pd                | 100 ++++++++
 12 files changed, 368 insertions(+), 88 deletions(-)
 create mode 100644 scripts/regression_tests/iemgui_color_symbolargs.pd

diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c
index 1723a986b..d3c483905 100644
--- a/pd/src/g_all_guis.c
+++ b/pd/src/g_all_guis.c
@@ -133,6 +133,45 @@ static void iemgui_init_sym2dollararg(t_iemgui *x, t_symbol **symp,
     }
 }
 
+int color_format_warned;
+static t_symbol *color2symbol(int col)
+{
+    const int compat = (pd_compatibilitylevel < 48) ? 1 : 0;
+    char colname[MAXPDSTRING];
+    colname[0] = colname[MAXPDSTRING-1] = 0;
+
+    if (compat)
+    {       
+        /* compatibility with Pd<=0.47: saves colors as numbers with limited
+           resolution */
+        int col2 = -1 - (((0xfc0000 & col) >> 6)
+                      | ((0xfc00 & col) >> 4)
+                      | ((0xfc & col) >> 2));
+        snprintf(colname, MAXPDSTRING-1, "%d", col2);
+    }
+    else
+    {
+        if (!color_format_warned)
+        {
+            post("warning: saving iemgui colors as hex symbol. These colors "
+                 "are readable in Pd Vanilla since 0.47, but they are not "
+                 "readable in Purr Data version 2.12.0 or earlier. "
+                 "If you need to remain compatible with older versions of Purr "
+                 "Data please run in compatibility mode with Vanilla version "
+                 "0.47 like this:");
+            post("");
+            post("[compatibility 0.47(");
+            post("|");
+            post("[send pd]");
+            post("");
+            color_format_warned = 1;    
+        }
+        snprintf(colname, MAXPDSTRING-1, "#%06x", col);
+    }
+    return gensym(colname);
+}
+
+
 /* get the unexpanded versions of the symbols; initialize them if necessary. */
 void iemgui_all_sym2dollararg(t_iemgui *x, t_symbol **srlsym)
 {
@@ -144,16 +183,107 @@ void iemgui_all_sym2dollararg(t_iemgui *x, t_symbol **srlsym)
     srlsym[2] = x->x_lab_unexpanded;
 }
 
-static int col2save(int col) {
-    return -1-(((0xfc0000 & col) >> 6)|((0xfc00 & col) >> 4)|((0xfc & col) >> 2));
+void iemgui_all_col2save(t_iemgui *x, t_symbol **bflcol)
+{
+    bflcol[0] = color2symbol(x->x_bcol);
+    bflcol[1] = color2symbol(x->x_fcol);
+    bflcol[2] = color2symbol(x->x_lcol);
 }
-void iemgui_all_col2save(t_iemgui *x, int *bflcol)
+
+static void expand_shorthex(char *source, char *doubled)
 {
-    bflcol[0] = col2save(x->x_bcol);
-    bflcol[1] = col2save(x->x_fcol);
-    bflcol[2] = col2save(x->x_lcol);
+    while(*source)
+    {
+        *doubled++ = *source;
+        *doubled++ = *source++;
+    }
 }
 
+static int iemgui_getcolorarg(t_iemgui *x, int index, int argc, t_atom *argv)
+{
+    char *classname;
+    if (index < 0 || index >= argc || !argc)
+        return 0;
+
+    if (IS_A_FLOAT(argv, index))
+        return atom_getfloatarg(index, argc, argv);
+
+    classname = class_getname(pd_class(&x->x_obj.te_pd));
+    if (IS_A_SYMBOL(argv, index))
+    {
+        t_symbol *s = atom_getsymbolarg(index, argc, argv);
+        if ('#' == s->s_name[0])
+        {
+            char *start = s->s_name + 1, *end;
+            char expanded[6];
+            int len = strlen(start);
+            if (len == 3)
+            {
+                expand_shorthex(start, expanded);
+                start = expanded;
+                len = 6;
+            }
+            if (len == 6)
+            {
+                int col = (int)strtol(start, &end, 16);
+                if (end != start)
+                    return col;
+            }
+        }
+        if (s == &s_)
+            pd_error(x, "%s: empty symbol detected in hex color argument. "
+                "Falling back to black. (Hit the sack.:)",
+                classname);
+        else
+            pd_error(x, "%s: expected '#fff' or '#ffffff' hex color format "
+                "but got '%s'. Falling back to black.",
+                classname, s->s_name);
+        return 0;
+    }
+    pd_error(x, "%s: color method only accepts symbol or float arguments. "
+        "Falling back to black.",
+        classname);
+    return 0;
+}
+
+static int colfromatomload(t_iemgui *x, t_atom *colatom)
+{
+    int color;
+    /* old-fashioned color argument, either a number or symbol
+       evaluating to an integer */
+    if (colatom->a_type == A_FLOAT)
+        color = atom_getfloat(colatom);
+    else if (colatom->a_type == A_SYMBOL &&
+        (isdigit(colatom->a_w.w_symbol->s_name[0]) ||
+         colatom->a_w.w_symbol->s_name[0] == '-'))
+            color = atoi(colatom->a_w.w_symbol->s_name);
+
+    /* symbolic color */
+    else return (iemgui_getcolorarg(x, 0, 1, colatom));
+
+    if (color < 0)
+    {
+        color = -1 - color;
+        color = ((color & 0x3f000) << 6)|((color & 0xfc0) << 4)|
+        ((color & 0x3f) << 2);
+    }
+    else
+    {
+        color = iemgui_modulo_color(color);
+        color = iemgui_color_hex[color];
+    }
+    return (color);
+}
+
+void iemgui_all_loadcolors(t_iemgui *x, t_atom *bcol, t_atom *fcol,
+    t_atom *lcol)
+{
+    if (bcol) x->x_bcol = colfromatomload(x, bcol);
+    if (fcol) x->x_fcol = colfromatomload(x, fcol);
+    if (lcol) x->x_lcol = colfromatomload(x, lcol);
+}
+
+
 static int colfromload(int col) {
     if(col)
     {
@@ -170,13 +300,26 @@ void iemgui_all_colfromload(t_iemgui *x, int *bflcol)
     x->x_lcol = colfromload(bflcol[2]);
 }
 
-static int iemgui_compatible_col(int i)
+int iemgui_compatible_colorarg(t_iemgui *x, int index, int argc, t_atom* argv)
 {
-    if(i >= 0)
-        return(iemgui_color_hex[(iemgui_modulo_color(i))]);
-    return((-1-i)&0xffffff);
+    if (index < 0 || index >= argc || !argc)
+        return 0;
+        /* old style, lossy int values */
+    if (IS_A_FLOAT(argv, index))
+    {
+        int col = atom_getfloatarg(index, argc, argv);
+        if (col >= 0)
+        {
+            int idx = iemgui_modulo_color(col);
+            return(iemgui_color_hex[(idx)]);
+        }
+        else
+            return((-1 - col) & 0xffffff);
+    }
+    return iemgui_getcolorarg(x, index, argc, argv);
 }
 
+
 void iemgui_all_raute2dollar(t_symbol **srlsym)
 {
     srlsym[0] = iemgui_raute2dollar(srlsym[0]);
@@ -478,20 +621,51 @@ void iemgui_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
         iemgui_shouldvis(x, IEM_GUI_DRAW_MODE_MOVE);
 }
 
-void iemgui_color(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
+int iemgui_old_color_args(int argc, t_atom *argv)
 {
-    x->x_bcol = iemgui_compatible_col(atom_getintarg(0, ac, av));
-    if(ac > 2)
+    int gotsym = 0, gotfloat = 0;
+    gotsym += atom_getsymbolarg(0, argc, argv) != &s_;
+    gotsym += atom_getsymbolarg(1, argc, argv) != &s_;
+    gotsym += atom_getsymbolarg(2, argc, argv) != &s_;
+    
+    gotfloat += argc >=1 && argv[0].a_type == A_FLOAT;
+    gotfloat += argc >=2 && argv[1].a_type == A_FLOAT;
+    gotfloat += argc >=2 && argv[2].a_type == A_FLOAT;
+
+    if (gotfloat && gotsym)
     {
-        x->x_fcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
-        x->x_lcol = iemgui_compatible_col(atom_getintarg(2, ac, av));
+        post("warning: unexpected mixing of symbol args with deprecated "
+             "float color syntax.");
+        return 1;
     }
-    else
-        x->x_lcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
-    if (glist_isvisible(x->x_glist))
+    else if (gotfloat) return 1;
+    else return 0;
+}
+
+void iemgui_color(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
+{
+    if (ac)
     {
-        x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
-        iemgui_label_draw_config(x);
+        if (ac >= 1)
+            x->x_bcol = iemgui_compatible_colorarg(x, 0, ac, av);
+        if (ac >= 2)
+        {
+                /* if there are only two args, the old style was to make
+                   the 2nd argument the label color. So here we check for the
+                   old-style float args and use that format if they are
+                   present. */
+            if (ac == 2 && iemgui_old_color_args(ac, av))
+                x->x_lcol = iemgui_compatible_colorarg(x, 1, ac, av);
+            else
+                x->x_fcol = iemgui_compatible_colorarg(x, 1, ac, av);
+        }
+        if (ac >= 3)
+            x->x_lcol = iemgui_compatible_colorarg(x, 2, ac, av);
+        if (glist_isvisible(x->x_glist))
+        {
+            x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+            iemgui_label_draw_config(x);
+        }
     }
 }
 
@@ -561,7 +735,7 @@ void iemgui_vis(t_gobj *z, t_glist *glist, int vis)
     }
 }
 
-void iemgui_save(t_iemgui *x, t_symbol **srl, int *bflcol)
+void iemgui_save(t_iemgui *x, t_symbol **srl, t_symbol **bflcol)
 {
     if (srl) {
        srl[0] = x->x_snd;
diff --git a/pd/src/g_all_guis.h b/pd/src/g_all_guis.h
index a9d6768a0..19d2d46db 100644
--- a/pd/src/g_all_guis.h
+++ b/pd/src/g_all_guis.h
@@ -204,7 +204,11 @@ EXTERN void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui);
 EXTERN t_symbol *iemgui_getfloatsym(t_atom *a);
 EXTERN t_symbol *iemgui_getfloatsymarg(int i, int argc, t_atom *argv);
 EXTERN void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv);
+    /* old interface, in case we have old externals calling it */
 EXTERN void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol);
+    /* new interface for handling colors */
+EXTERN void iemgui_all_loadcolors(t_iemgui *x, t_atom *bcol, t_atom *fcol,
+    t_atom*lcol);
 EXTERN void iemgui_send(t_iemgui *x, t_symbol *s);
 EXTERN void iemgui_receive(t_iemgui *x, t_symbol *s);
 EXTERN void iemgui_label(t_iemgui *x, t_symbol *s);
@@ -221,7 +225,7 @@ EXTERN void iemgui_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy);
 EXTERN void iemgui_select(t_gobj *z, t_glist *glist, int selected);
 EXTERN void iemgui_delete(t_gobj *z, t_glist *glist);
 EXTERN void iemgui_vis(t_gobj *z, t_glist *glist, int vis);
-EXTERN void iemgui_save(t_iemgui *x, t_symbol **srl, int *bflcol);
+EXTERN void iemgui_save(t_iemgui *x, t_symbol **srl, t_symbol **bflcol);
 EXTERN void iemgui_properties(t_iemgui *x, t_symbol **srl);
 EXTERN int iemgui_dialog(t_iemgui *x, int argc, t_atom *argv);
 
diff --git a/pd/src/g_bang.c b/pd/src/g_bang.c
index bedbb664d..3667629de 100644
--- a/pd/src/g_bang.c
+++ b/pd/src/g_bang.c
@@ -196,11 +196,11 @@ static void bng_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1,
 static void bng_save(t_gobj *z, t_binbuf *b)
 {
     t_bng *x = (t_bng *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
 
     iemgui_save(&x->x_gui, srl, bflcol);
-    binbuf_addv(b, "ssiisiiiisssiiiiiii;", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiiiisssiiiisss;", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         gensym("bng"), x->x_gui.x_w,
         x->x_flashtime_hold, x->x_flashtime_break,
@@ -430,7 +430,6 @@ static void bng_tick_lck(t_bng *x)
 static void *bng_new(t_symbol *s, int argc, t_atom *argv)
 {
     t_bng *x = (t_bng *)pd_new(bng_class);
-    int bflcol[]={-262144, -1, -1};
     int a=IEM_GUI_DEFAULTSIZE;
     int ldx=17, ldy=7;
     int fs=10;
@@ -440,6 +439,10 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv)
     iem_inttosymargs(&x->x_gui, 0);
     iem_inttofstyle(&x->x_gui, 0);
 
+    x->x_gui.x_bcol = 0xFCFCFC;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x00;
+
     if((argc == 14)&&IS_A_FLOAT(argv,0)
        &&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
        &&IS_A_FLOAT(argv,3)
@@ -447,10 +450,8 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv)
        &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
        &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
        &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
-       &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
-       &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13))
+       &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10))
     {
-
         a = atom_getintarg(0, argc, argv);
         fthold = atom_getintarg(1, argc, argv);
         ftbreak = atom_getintarg(2, argc, argv);
@@ -460,9 +461,7 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(8, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(9, argc, argv));
         fs = maxi(atom_getintarg(10, argc, argv),4);
-        bflcol[0] = atom_getintarg(11, argc, argv);
-        bflcol[1] = atom_getintarg(12, argc, argv);
-        bflcol[2] = atom_getintarg(13, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+11, argv+12, argv+13);
     }
     else iemgui_new_getnames(&x->x_gui, 4, 0);
 
@@ -479,7 +478,6 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv)
     x->x_gui.x_w = iemgui_clip_size(a);
     x->x_gui.x_h = x->x_gui.x_w;
     bng_check_minmax(x, ftbreak, fthold);
-    iemgui_all_colfromload(&x->x_gui, bflcol);
     x->x_gui.x_locked = 0;
     iemgui_verify_snd_ne_rcv(&x->x_gui);
     x->x_clock_hld = clock_new(x, (t_method)bng_tick_hld);
diff --git a/pd/src/g_mycanvas.c b/pd/src/g_mycanvas.c
index 638ef318d..7ee35eaec 100644
--- a/pd/src/g_mycanvas.c
+++ b/pd/src/g_mycanvas.c
@@ -151,10 +151,10 @@ static void my_canvas_getrect(t_gobj *z, t_glist *glist,
 static void my_canvas_save(t_gobj *z, t_binbuf *b)
 {
     t_my_canvas *x = (t_my_canvas *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
     iemgui_save(&x->x_gui, srl, bflcol);
-    binbuf_addv(b, "ssiisiiisssiiiiiii;", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiiisssiiiissi;", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         gensym("cnv"), x->x_gui.x_w, x->x_vis_w, x->x_vis_h,
         srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy,
@@ -277,7 +277,6 @@ static void my_canvas_vis_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
 static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
 {
     t_my_canvas *x = (t_my_canvas *)pd_new(my_canvas_class);
-    int bflcol[]={-233017, -1, -66577};
     int a=IEM_GUI_DEFAULTSIZE, w=100, h=60;
     int ldx=20, ldy=12, i=0;
     int fs=14;
@@ -285,6 +284,10 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
     iem_inttosymargs(&x->x_gui, 0);
     iem_inttofstyle(&x->x_gui, 0);
 
+    x->x_gui.x_bcol = 0xE0E0E0;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x404040;
+
     if(((argc >= 10)&&(argc <= 13))
        &&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2))
     {
@@ -308,8 +311,7 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
     if(((argc >= 10)&&(argc <= 13))
        &&(IS_A_SYMBOL(argv,i+3)||IS_A_FLOAT(argv,i+3))&&IS_A_FLOAT(argv,i+4)
        &&IS_A_FLOAT(argv,i+5)&&IS_A_FLOAT(argv,i+6)
-       &&IS_A_FLOAT(argv,i+7)&&IS_A_FLOAT(argv,i+8)
-       &&IS_A_FLOAT(argv,i+9))
+       &&IS_A_FLOAT(argv,i+7))
     {
             /* disastrously, the "label" sits in a different part of the
             message.  So we have to track its location separately (in
@@ -320,8 +322,7 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(i+5, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(i+6, argc, argv));
         fs = atom_getintarg(i+7, argc, argv);
-        bflcol[0] = atom_getintarg(i+8, argc, argv);
-        bflcol[2] = atom_getintarg(i+9, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+i+8, 0, argv+i+9);
     }
     if((argc == 13)&&IS_A_FLOAT(argv,i+10))
     {
@@ -340,7 +341,6 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
     if(fs < 4)
         fs = 4;
     x->x_gui.x_fontsize = fs;
-    iemgui_all_colfromload(&x->x_gui, bflcol);
     x->x_at[0].a_type = A_FLOAT;
     x->x_at[1].a_type = A_FLOAT;
     iemgui_verify_snd_ne_rcv(&x->x_gui);
diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c
index 96976df41..80d3a66f9 100644
--- a/pd/src/g_numbox.c
+++ b/pd/src/g_numbox.c
@@ -387,7 +387,7 @@ static void my_numbox_getrect(t_gobj *z, t_glist *glist,
 static void my_numbox_save(t_gobj *z, t_binbuf *b)
 {
     t_my_numbox *x = (t_my_numbox *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
 
     iemgui_save(&x->x_gui, srl, bflcol);
@@ -398,7 +398,7 @@ static void my_numbox_save(t_gobj *z, t_binbuf *b)
         x->x_gui.x_changed = 1;
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
     }
-    binbuf_addv(b, "ssiisiiffiisssiiiiiiifii;", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiiffiisssiiiisssfii;", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         gensym("nbx"), x->x_gui.x_w, x->x_gui.x_h,
         (t_float)x->x_min, (t_float)x->x_max,
@@ -759,13 +759,16 @@ static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
 static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
 {
     t_my_numbox *x = (t_my_numbox *)pd_new(my_numbox_class);
-    int bflcol[]={-262144, -1, -1};
     int w=5, h=14;
     int lilo=0, ldx=0, ldy=-8;
     int fs=10;
     int log_height=256;
     double min=-1.0e+37, max=1.0e+37,v=0.0;
 
+    x->x_gui.x_bcol = 0xFCFCFC;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x00;
+
     if((argc >= 17)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
        &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
        &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
@@ -773,8 +776,7 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
        &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
        &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
        &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
-       &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
-       &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+       &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,16))
     {
         w = maxi(atom_getintarg(0, argc, argv),1);
         h = maxi(atom_getintarg(1, argc, argv),8);
@@ -787,9 +789,7 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(10, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(11, argc, argv));
         fs = maxi(atom_getintarg(12, argc, argv),4);
-        bflcol[0] = atom_getintarg(13, argc, argv);
-        bflcol[1] = atom_getintarg(14, argc, argv);
-        bflcol[2] = atom_getintarg(15, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+13, argv+14, argv+15);
         v = atom_getfloatarg(16, argc, argv);
     }
     else iemgui_new_getnames(&x->x_gui, 6, 0);
@@ -814,7 +814,6 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
     x->x_buf[0] = 0;
     x->x_numwidth = my_numbox_calc_fontwidth(x);
     my_numbox_check_minmax(x, min, max);
-    iemgui_all_colfromload(&x->x_gui, bflcol);
     iemgui_verify_snd_ne_rcv(&x->x_gui);
     x->x_clock_reset = clock_new(x, (t_method)my_numbox_tick_reset);
     x->x_clock_wait = clock_new(x, (t_method)my_numbox_tick_wait);
diff --git a/pd/src/g_radio.c b/pd/src/g_radio.c
index eaf924e87..1c119aae8 100644
--- a/pd/src/g_radio.c
+++ b/pd/src/g_radio.c
@@ -203,7 +203,7 @@ static void radio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1,
 static void radio_save(t_gobj *z, t_binbuf *b)
 {
     t_radio *x = (t_radio *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
     t_class *c = pd_class((t_pd *)x);
     t_symbol *cname =
@@ -212,7 +212,7 @@ static void radio_save(t_gobj *z, t_binbuf *b)
         x->x_orient ? gensym("vradio") : gensym("hradio");
     
     iemgui_save(&x->x_gui, srl, bflcol);
-    binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiiiisssiiiisssi", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         cname, x->x_gui.x_w,
         x->x_change, iem_symargstoint(&x->x_gui), x->x_number,
@@ -458,19 +458,21 @@ static void *radio_new(t_symbol *s, int argc, t_atom *argv)
         s==gensym("vdl") ? vradio_old_class :
         s==gensym("vradio") ? vradio_class : hradio_class);
     x->x_orient = s==gensym("vdl") || s==gensym("vradio");
-    int bflcol[]={-262144, -1, -1};
     int a=IEM_GUI_DEFAULTSIZE, on=0, ldx=0, ldy=-8, chg=1, num=8, fs=10;
     iem_inttosymargs(&x->x_gui, 0);
     iem_inttofstyle(&x->x_gui, 0);
 
+    x->x_gui.x_bcol = 0xFCFCFC;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x00;
+
     if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
        &&IS_A_FLOAT(argv,3)
        &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
        &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
        &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
        &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
-       &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
-       &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
+       &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,14))
     {
         a = atom_getintarg(0, argc, argv);
         chg = atom_getintarg(1, argc, argv);
@@ -481,9 +483,7 @@ static void *radio_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(8, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(9, argc, argv));
         fs = maxi(atom_getintarg(10, argc, argv),4);
-        bflcol[0] = atom_getintarg(11, argc, argv);
-        bflcol[1] = atom_getintarg(12, argc, argv);
-        bflcol[2] = atom_getintarg(13, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+11, argv+12, argv+13);
         on = mini(maxi(atom_getintarg(14, argc, argv),0),num-1);
     }
     else iemgui_new_getnames(&x->x_gui, 4, 0);
@@ -502,7 +502,6 @@ static void *radio_new(t_symbol *s, int argc, t_atom *argv)
     x->x_gui.x_w = iemgui_clip_size(a);
     x->x_gui.x_h = x->x_gui.x_w;
     iemgui_verify_snd_ne_rcv(&x->x_gui);
-    iemgui_all_colfromload(&x->x_gui, bflcol);
     outlet_new(&x->x_gui.x_obj, &s_list);
 
     x->x_gui.x_handle = scalehandle_new((t_object *)x,x->x_gui.x_glist,1,radio__clickhook,radio__motionhook);
diff --git a/pd/src/g_slider.c b/pd/src/g_slider.c
index 320a45a99..46f12dd62 100644
--- a/pd/src/g_slider.c
+++ b/pd/src/g_slider.c
@@ -189,10 +189,10 @@ static void slider_getrect(t_gobj *z, t_glist *glist,
 static void slider_save(t_gobj *z, t_binbuf *b)
 {
     t_slider *x = (t_slider *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
     iemgui_save(&x->x_gui, srl, bflcol);
-    binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiiffiisssiiiisssii", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         gensym(x->x_orient ? "vsl" : "hsl"), x->x_gui.x_w, x->x_gui.x_h,
         (t_float)x->x_min, (t_float)x->x_max,
@@ -489,7 +489,7 @@ static void *slider_new(t_symbol *s, int argc, t_atom *argv)
     int orient = s==gensym("vsl") || s==gensym("vslider");
     t_slider *x = (t_slider *)pd_new(orient ? vslider_class : hslider_class);
     x->x_orient = orient;
-    int bflcol[]={-262144, -1, -1};
+//    int bflcol[]={-262144, -1, -1};
     int lilo=0;
     int w,h,ldx,ldy,fs=10, v=0, steady=1;
     if (orient) {
@@ -502,6 +502,11 @@ static void *slider_new(t_symbol *s, int argc, t_atom *argv)
     iem_inttosymargs(&x->x_gui, 0);
     iem_inttofstyle(&x->x_gui, 0);
 
+    x->x_gui.x_bcol = 0xFCFCFC;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x00;
+
+
     if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
        &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
        &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
@@ -509,8 +514,7 @@ static void *slider_new(t_symbol *s, int argc, t_atom *argv)
        &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
        &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
        &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
-       &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
-       &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+       &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,16))
     {
         w = atom_getintarg(0, argc, argv);
         h = atom_getintarg(1, argc, argv);
@@ -523,9 +527,10 @@ static void *slider_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(10, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(11, argc, argv));
         fs = maxi(atom_getintarg(12, argc, argv),4);
-        bflcol[0] = (int)atom_getintarg(13, argc, argv);
-        bflcol[1] = (int)atom_getintarg(14, argc, argv);
-        bflcol[2] = (int)atom_getintarg(15, argc, argv);
+//        bflcol[0] = (int)atom_getintarg(13, argc, argv);
+//        bflcol[1] = (int)atom_getintarg(14, argc, argv);
+//        bflcol[2] = (int)atom_getintarg(15, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+13, argv+14, argv+15);
         v = atom_getintarg(16, argc, argv);
     }
     else iemgui_new_getnames(&x->x_gui, 6, 0);
@@ -554,7 +559,7 @@ static void *slider_new(t_symbol *s, int argc, t_atom *argv)
         slider_check_length(x, w);
     }
     slider_check_minmax(x, min, max);
-    iemgui_all_colfromload(&x->x_gui, bflcol);
+//    iemgui_all_colfromload(&x->x_gui, bflcol);
     x->x_thick = 0;
     iemgui_verify_snd_ne_rcv(&x->x_gui);
     outlet_new(&x->x_gui.x_obj, &s_float);
@@ -573,7 +578,6 @@ static void *slider_new(t_symbol *s, int argc, t_atom *argv)
         x->x_gui.legacy_y = 1;
     }
 
-
     return (x);
 }
 
diff --git a/pd/src/g_toggle.c b/pd/src/g_toggle.c
index 6286b9c6e..195887fc5 100644
--- a/pd/src/g_toggle.c
+++ b/pd/src/g_toggle.c
@@ -178,10 +178,10 @@ static void toggle_getrect(t_gobj *z, t_glist *glist,
 static void toggle_save(t_gobj *z, t_binbuf *b)
 {
     t_toggle *x = (t_toggle *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
     iemgui_save(&x->x_gui, srl, bflcol);
-    binbuf_addv(b, "ssiisiisssiiiiiiiff;", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiisssiiiisssff;", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         gensym("tgl"), x->x_gui.x_w, iem_symargstoint(&x->x_gui),
         srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy,
@@ -349,7 +349,6 @@ static void toggle_nonzero(t_toggle *x, t_floatarg f)
 static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
 {
     t_toggle *x = (t_toggle *)pd_new(toggle_class);
-    int bflcol[]={-262144, -1, -1};
     int a=IEM_GUI_DEFAULTSIZE;
     int ldx=17, ldy=7;
     int fs=10;
@@ -358,14 +357,17 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
     iem_inttosymargs(&x->x_gui, 0);
     iem_inttofstyle(&x->x_gui, 0);
 
+    x->x_gui.x_bcol = 0xFCFCFC;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x00;
+
     if(((argc == 13)||(argc == 14))&&IS_A_FLOAT(argv,0)
        &&IS_A_FLOAT(argv,1)
        &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
        &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
        &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
        &&IS_A_FLOAT(argv,5)&&IS_A_FLOAT(argv,6)
-       &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)
-       &&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12))
+       &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,12))
     {
         a = atom_getintarg(0, argc, argv);
         iem_inttosymargs(&x->x_gui, atom_getintarg(1, argc, argv));
@@ -374,9 +376,7 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(6, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(7, argc, argv));
         fs = maxi(atom_getintarg(8, argc, argv),4);
-        bflcol[0] = atom_getintarg(9, argc, argv);
-        bflcol[1] = atom_getintarg(10, argc, argv);
-        bflcol[2] = atom_getintarg(11, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+9, argv+10, argv+11);
         on = atom_getfloatarg(12, argc, argv);
     }
     else iemgui_new_getnames(&x->x_gui, 2, 0);
@@ -399,7 +399,6 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
     x->x_gui.x_fontsize = fs;
     x->x_gui.x_w = iemgui_clip_size(a);
     x->x_gui.x_h = x->x_gui.x_w;
-    iemgui_all_colfromload(&x->x_gui, bflcol);
     iemgui_verify_snd_ne_rcv(&x->x_gui);
     outlet_new(&x->x_gui.x_obj, &s_float);
 
diff --git a/pd/src/g_vumeter.c b/pd/src/g_vumeter.c
index d1693a08a..0b1a8076e 100644
--- a/pd/src/g_vumeter.c
+++ b/pd/src/g_vumeter.c
@@ -428,10 +428,10 @@ static void vu_getrect(t_gobj *z, t_glist *glist,
 static void vu_save(t_gobj *z, t_binbuf *b)
 {
     t_vu *x = (t_vu *)z;
-    int bflcol[3];
+    t_symbol *bflcol[3];
     t_symbol *srl[3];
     iemgui_save(&x->x_gui, srl, bflcol);
-    binbuf_addv(b, "ssiisiissiiiiiiii;", gensym("#X"),gensym("obj"),
+    binbuf_addv(b, "ssiisiissiiiissii;", gensym("#X"),gensym("obj"),
         (int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix,
         gensym("vu"), x->x_gui.x_w, x->x_gui.x_h,
         srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy,
@@ -648,19 +648,22 @@ static void vu_bang(t_vu *x)
 static void *vu_new(t_symbol *s, int argc, t_atom *argv)
 {
     t_vu *x = (t_vu *)pd_new(vu_class);
-    int bflcol[] = {-66577, -1, -1};
     int w = IEM_GUI_DEFAULTSIZE, h = IEM_VU_STEPS*IEM_VU_DEFAULTSIZE;
     int ldx = -1, ldy = -8, fs = 10, scale = 1;
 
     iem_inttosymargs(&x->x_gui, 0);
     iem_inttofstyle(&x->x_gui, 0);
 
+    x->x_gui.x_bcol = 0x404040;
+    x->x_gui.x_fcol = 0x00;
+    x->x_gui.x_lcol = 0x00;
+
     if((argc >= 11)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
        &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
        &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
        &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
        &&IS_A_FLOAT(argv,6)&&IS_A_FLOAT(argv,7)
-       &&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10))
+       &&IS_A_FLOAT(argv,10))
     {
         w = atom_getintarg(0, argc, argv);
         h = atom_getintarg(1, argc, argv);
@@ -669,8 +672,7 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv)
         ldy = atom_getintarg(5, argc, argv);
         iem_inttofstyle(&x->x_gui, atom_getintarg(6, argc, argv));
         fs = maxi(atom_getintarg(7, argc, argv),4);
-        bflcol[0] = atom_getintarg(8, argc, argv);
-        bflcol[2] = atom_getintarg(9, argc, argv);
+        iemgui_all_loadcolors(&x->x_gui, argv+8, NULL, argv+9);
         scale = !!atom_getintarg(10, argc, argv);
     }
     else iemgui_new_getnames(&x->x_gui, 1, 0);
@@ -688,7 +690,6 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv)
     x->x_gui.x_fontsize = fs;
     x->x_gui.x_w = iemgui_clip_size(w);
     vu_check_height(x, h);
-    iemgui_all_colfromload(&x->x_gui, bflcol);
     x->x_scale = scale;
     x->x_peak = 0;
     x->x_rms = 0;
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index c9add24e4..e05e112d8 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -21,7 +21,7 @@ that didn't really belong anywhere. */
  * extract the nw binary to purr-data/pd/nw/nw
  */
 
-#define GUIDIR "" /* "/home/user/purr-data/pd/nw" */
+#define GUIDIR "/home/user/purr-data/pd/nw"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
diff --git a/scripts/regression_tests.pd b/scripts/regression_tests.pd
index 640fb3785..e65a2e3b1 100644
--- a/scripts/regression_tests.pd
+++ b/scripts/regression_tests.pd
@@ -1,7 +1,7 @@
-#N canvas 126 96 749 571 12;
+#N canvas 586 253 749 571 12;
 #X obj 465 281 r \$0-result;
-#X obj 212 239 bng 31 250 50 0 empty empty Run_all 39 13 0 12 -262144
--1 -1;
+#X obj 212 239 bng 31 250 50 0 empty empty Run_all 39 13 0 12 #fcfcfc
+#000000 #000000;
 #X obj 56 25 r init;
 #X obj 345 191 route dollarzero;
 #X obj 198 281 rtest msg_dollarzero;
@@ -52,6 +52,7 @@ is handy for some binbuf tests.;
 #X obj 127 172 print Done;
 #X obj 198 1701 rtest wrap~_compatibility_bug;
 #X obj 198 1756 rtest select_bang;
+#X obj 198 1811 rtest iemgui_color_symbolargs;
 #X connect 0 0 27 0;
 #X connect 1 0 4 0;
 #X connect 2 0 42 0;
@@ -89,3 +90,4 @@ is handy for some binbuf tests.;
 #X connect 42 3 3 0;
 #X connect 43 0 44 0;
 #X connect 45 0 46 0;
+#X connect 46 0 47 0;
diff --git a/scripts/regression_tests/iemgui_color_symbolargs.pd b/scripts/regression_tests/iemgui_color_symbolargs.pd
new file mode 100644
index 000000000..d355ce23c
--- /dev/null
+++ b/scripts/regression_tests/iemgui_color_symbolargs.pd
@@ -0,0 +1,100 @@
+#N canvas 1 24 1329 701 12;
+#X obj 877 305 bng 15 250 50 0 empty empty empty 17 7 0 10 #ff66ff
+#000000 #fcccfc;
+#X msg 812 124 color #ff66ff;
+#X text 782 82 accept the common 6-digit hex syntas;
+#X obj 838 209 unpost;
+#X obj 812 163 trigger bang anything bang;
+#X obj 813 268 list;
+#X obj 607 305 bng 15 250 50 0 empty empty empty 17 7 0 10 #ff66ff
+#000000 #fcccfc;
+#X obj 568 209 unpost;
+#X obj 542 163 trigger bang anything bang;
+#X obj 543 268 list;
+#X msg 542 124 color #f6f;
+#X obj 107 365 bng 15 250 50 0 empty empty empty 17 7 0 10 #000000
+#000000 #fcccfc;
+#X obj 68 269 unpost;
+#X obj 42 223 trigger bang anything bang;
+#X obj 43 328 list;
+#X text 53 122 reject any non-standard symbols;
+#X msg 42 154 symbol;
+#X obj 43 387 list length;
+#X obj 813 327 list length;
+#X obj 813 422 list append iemgui color method should accept 6-digit
+hex format;
+#X msg 42 184 color \$1 \, color # \, color #a \, color #ffffff0 \,
+color foo \, color ffff99, f 34;
+#X obj 43 585 list append iemgui color method should reject empty symbol
+and non-standard hex notation arguments;
+#X obj 543 327 list length;
+#X obj 543 469 list append iemgui color method should accept short
+3-digit hex notation;
+#X obj 43 630 outlet;
+#X obj 42 34 inlet;
+#X obj 42 63 trigger bang bang bang bang;
+#X obj 302 181 canvasinfo;
+#X msg 302 149 pointer;
+#X obj 367 385 bng 15 250 50 0 empty empty empty 17 7 0 10 #000000
+#000000 #fcccfc;
+#X obj 328 289 unpost;
+#X obj 302 243 trigger bang anything bang;
+#X obj 303 348 list;
+#X obj 303 407 list length;
+#X text 302 115 reject gpointer;
+#X obj 303 536 list append iemgui color method should only accept symbol
+and float arguments;
+#X msg 302 210 color \$1;
+#X text 503 75 accept the "short" hex notation;
+#X obj 813 356 == 0;
+#X obj 543 356 == 0;
+#X obj 303 436 != 0;
+#X obj 43 416 != 0;
+#X connect 1 0 4 0;
+#X connect 3 0 5 1;
+#X connect 3 1 0 0;
+#X connect 4 0 5 0;
+#X connect 4 1 3 0;
+#X connect 4 2 5 1;
+#X connect 5 0 18 0;
+#X connect 7 0 9 1;
+#X connect 7 1 6 0;
+#X connect 8 0 9 0;
+#X connect 8 1 7 0;
+#X connect 8 2 9 1;
+#X connect 9 0 22 0;
+#X connect 10 0 8 0;
+#X connect 12 0 14 1;
+#X connect 12 1 11 0;
+#X connect 13 0 14 0;
+#X connect 13 1 12 0;
+#X connect 13 2 14 1;
+#X connect 14 0 17 0;
+#X connect 16 0 20 0;
+#X connect 17 0 41 0;
+#X connect 18 0 38 0;
+#X connect 19 0 24 0;
+#X connect 20 0 13 0;
+#X connect 21 0 24 0;
+#X connect 22 0 39 0;
+#X connect 23 0 24 0;
+#X connect 25 0 26 0;
+#X connect 26 0 16 0;
+#X connect 26 1 28 0;
+#X connect 26 2 10 0;
+#X connect 26 3 1 0;
+#X connect 27 0 36 0;
+#X connect 28 0 27 0;
+#X connect 30 0 32 1;
+#X connect 30 1 29 0;
+#X connect 31 0 32 0;
+#X connect 31 1 30 0;
+#X connect 31 2 32 1;
+#X connect 32 0 33 0;
+#X connect 33 0 40 0;
+#X connect 35 0 24 0;
+#X connect 36 0 31 0;
+#X connect 38 0 19 0;
+#X connect 39 0 23 0;
+#X connect 40 0 35 0;
+#X connect 41 0 21 0;
-- 
GitLab