From 55f0f5d25d7bbc40344d679506676214233d2fa7 Mon Sep 17 00:00:00 2001
From: Jonathan Wilkes <jon.w.wilkes@gmail.com>
Date: Thu, 21 May 2020 00:01:12 -0400
Subject: [PATCH] first shot at l2ork-style graph labels inside the graph

---
 pd/nw/dialog_canvas.html | 12 ++++----
 pd/nw/pdgui.js           | 65 ++++++++++++++++++++++++++++++++++++----
 pd/src/g_array.c         | 11 +++++--
 pd/src/g_graph.c         | 41 +++++++++++++++++--------
 4 files changed, 102 insertions(+), 27 deletions(-)

diff --git a/pd/nw/dialog_canvas.html b/pd/nw/dialog_canvas.html
index b86cf8193..ed9a8b106 100644
--- a/pd/nw/dialog_canvas.html
+++ b/pd/nw/dialog_canvas.html
@@ -630,12 +630,12 @@ function populate_array_form(objects) {
         opt.textContent = "Array #" + (i+1);
         arrays_select.appendChild(opt);
     }
-    // We're permanently hiding the checkbutton for creating a new array
-    // inside an existing graph. It's just a weird interface with very
-    // few benefits. However, patches that already have multiple arrays
-    // inside a graph will continue to work.  (And if users really want
-    // this feature back it's easy to turn it back on.
-    if (!new_array_dialog || 1) {  // to re-enable, remove the "|| 1"
+    // The "array in existing graph" interface is horrible. There should
+    // just be a button in the graph dialog to create an additional array
+    // if the user really wants to do that. Nevertheless, I just added a
+    // color key for multi-array graphs. So I guess it should be "discoverable"
+    // through this horrible interface.
+    if (!new_array_dialog) {
         document.getElementsByClassName("array_in_existing_graph")[0]
             .classList.add("hidden");
     }
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index bbc30f0a3..a24a6f714 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -4759,11 +4759,62 @@ function gui_graph_deleteborder(cid, tag) {
     });
 }
 
-function gui_graph_label(cid, tag, label_number, font_height, array_name,
-    font, font_size, font_weight, is_selected) {
-    gui(cid).get_elem("patchsvg", function(e) {
-        var y = font_height * label_number * -1;
-        gui_text_new(cid, tag, "graph_label", 0, 0, y, array_name, font_size);
+function gui_graph_label(cid, tag, font_size, font_height, is_selected,
+    legacy_mode, array_of_attr_arrays) {
+    // first let's check if we have any colors other than black. If so we
+    // we will create a little rectangle next to the label to show the color.
+    var show_color_rect = false;
+    array_of_attr_arrays.forEach(function(e) {
+        var c;
+        if (!show_color_rect) {
+            c = attr_array_to_object(e).color;
+            show_color_rect = (c !== "black" && c !== "#000000");
+        }
+    });
+
+    // if the graph only holds a single array, don't display the color
+    if (array_of_attr_arrays.length <= 1) {
+        show_color_rect = false;
+    }
+
+    array_of_attr_arrays.forEach(function(e, i) {
+        var a = attr_array_to_object(e),
+            narrays = array_of_attr_arrays.length;
+        // a.label for the label
+        // a.color for the color
+        gui(cid).get_elem("patchsvg", function(elem) {
+            var x, y;
+            if (!!legacy_mode) { // Pd Vanilla labels go above the box
+                y = -font_height * (narrays - (i + 1)) - 1;
+            } else { // In L2ork they go inside the box
+                // shift the label to the right if we're displaying a small
+                // rectangle to show the color
+                x = show_color_rect ? 17 : 2;
+                y = font_height * (i + 1);
+            }
+            gui_text_new(cid, tag, "graph_label", !!is_selected,
+                x, y, a.label, font_size);
+        })
+        .get_gobj(tag)
+        .append(function(frag) {
+            var colorbar;
+            if (legacy_mode == 0 && show_color_rect) {
+                colorbar = create_item(cid, "rect", {
+                    fill: a.color,
+                    stroke: "black",
+                    "stroke-width": 1,
+                    x: 4,
+                    y: font_height * i + (font_height * 0.5),
+                    width: 10,
+                    height: 10
+                });
+                frag.appendChild(colorbar);
+            }
+            return frag;
+        })
+        .get_elem(tag + "text", function(e) {
+            e.id = tag + "text" + i;
+        });
     });
 }
 
@@ -5089,7 +5140,9 @@ function file_dialog_callback(file_string) {
 exports.file_dialog_callback = file_dialog_callback;
 
 // Used to convert the ["key", "value"...] arrays coming from
-// Pd to a javascript object
+// Pd to a javascript object. This is a hack that I employ because
+// I had already implemented JSON arrays in the Pd->GUI interface
+// and didn't feel like adding object notation.
 function attr_array_to_object(attr_array) {
     var i,
         len = attr_array.length,
diff --git a/pd/src/g_array.c b/pd/src/g_array.c
index ccaaea793..0f270eeb4 100644
--- a/pd/src/g_array.c
+++ b/pd/src/g_array.c
@@ -136,8 +136,8 @@ struct _garray
     char x_hidename;        /* don't print name above graph */
     int x_style;            /* so much simpler to keep it here */
     t_symbol *x_send;       /* send_changed hook */
-    t_symbol *x_fillcolor;       /* color for filled area of the are */
-    t_symbol *x_outlinecolor;    /* color of the outline around the element */
+    t_symbol *x_fillcolor;     /* filled area of bar in bar graph */
+    t_symbol *x_outlinecolor;  /* bar graph: bar outline. Others: line color */
 };
 
 t_pd *garray_arraytemplatecanvas;
@@ -279,6 +279,13 @@ t_scalar *garray_getscalar(t_garray *x)
     return (x->x_scalar);
 }
 
+    /* get a garray's colors and style */
+t_symbol *garray_getlabelcolor(t_garray *x)
+{
+    if (x->x_style == PLOTSTYLE_BARS) return x->x_fillcolor;
+    else return x->x_outlinecolor;
+}
+
     /* helper function for fittograph to see if the same GOP has multiple
         arrays in which case take length of the largest one */
 static int garray_get_largest_array(t_garray *x)
diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
index d2b58b94d..dfbf6739c 100644
--- a/pd/src/g_graph.c
+++ b/pd/src/g_graph.c
@@ -862,6 +862,7 @@ void glist_redraw(t_glist *x)
 /* --------------------------- widget behavior  ------------------- */
 
 int garray_getname(t_garray *x, t_symbol **namep);
+t_symbol *garray_getlabelcolor(t_garray *x);
 
 
     /* Note that some code in here would also be useful for drawing
@@ -977,8 +978,6 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
             (x->gl_ylabelx > 0.5*(x->gl_x1 + x->gl_x2) ? "w" : "e");
         char *xlabelanchor =
             (x->gl_xlabely > 0.5*(x->gl_y1 + x->gl_y2) ? "s" : "n");
-        char tagbuf[MAXPDSTRING];
-        sprintf(tagbuf, "%sR", tag);
         gui_vmess("gui_text_draw_border", "xssiii",
             glist_getcanvas(x->gl_owner),
             tag,
@@ -986,7 +985,23 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
             0,
             x2 - x1,
             y2 - y1);
-            /* write garrays' names along the top */
+            /* write garrays' names along the top. Since we can have multiple
+               arrays inside a single graph, we want to send all the fun
+               label data to the GUI in one message. That way the GUI can do
+               fun stuff like selectively displaying a color key if we have
+               multiple arrays with different colors. */
+        gui_start_vmess("gui_graph_label", "xsiiii",
+            glist_getcanvas(x),
+            tag,
+            sys_hostfontsize(glist_getfont(x)),
+            sys_fontheight(glist_getfont(x)),
+            glist_isselected(x, gr),
+            sys_legacy
+        );
+
+            /* Now start an array to hold each array of label info */
+        gui_start_array();
+
         for (i = 0, g = x->gl_list; g; g = g->g_next, i++)
         {
             //fprintf(stderr,".\n");
@@ -995,18 +1010,18 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
             if (g->g_pd == garray_class &&
                 !garray_getname((t_garray *)g, &arrayname))
             {
-                gui_vmess("gui_graph_label", "xsiissisi",
-                    glist_getcanvas(x),
-                    tag,
-                    i,
-                    sys_fontheight(glist_getfont(x)),
-                    arrayname->s_name,
-                    sys_font,
-                    sys_hostfontsize(glist_getfont(x)),
-                    sys_fontweight,
-                    glist_isselected(x, gr));
+                t_symbol *labelcolor = garray_getlabelcolor((t_garray *)g);
+                    /* Now send an attribute array with the label data */
+                gui_start_array();
+                gui_s("label"); gui_s(arrayname->s_name);
+                gui_s("color"); gui_s(labelcolor->s_name);
+                gui_end_array();
             }
         }
+            /* Finally, end the final array as wel as the call to the GUI */
+        gui_end_array();
+        gui_end_vmess();
+
             /* draw ticks on horizontal borders.  If lperb field is
             zero, this is disabled. */
         if (x->gl_xtick.k_lperb)
-- 
GitLab