From 3cf747978ab5704ac40191e5a03fe96055fc1152 Mon Sep 17 00:00:00 2001
From: user <user@user-ThinkPad-X60.(none)>
Date: Fri, 22 May 2015 12:36:03 -0400
Subject: [PATCH] got a very early working version that does _all_ object text
 editing (arrow keys, selection, etc.) in the GUI. (However, it still depends
 on g_rtext.c for doing everything else.)

---
 pd/nw/pd_canvas.html | 325 +++++++++++++++++++++++++------------------
 pd/nw/pdgui.js       |  41 +++++-
 pd/nw/todo.txt       |  24 ++++
 pd/src/g_canvas.h    |   1 +
 pd/src/g_editor.c    |  24 ++++
 pd/src/g_rtext.c     |  25 +++-
 pd/src/g_text.c      |   6 +-
 7 files changed, 294 insertions(+), 152 deletions(-)

diff --git a/pd/nw/pd_canvas.html b/pd/nw/pd_canvas.html
index 80ab73882..46c16ce03 100644
--- a/pd/nw/pd_canvas.html
+++ b/pd/nw/pd_canvas.html
@@ -43,120 +43,155 @@ function add_keymods(key, evt) {
 
 var canvas_events = (function() {
     var name,
-        mousemove = function(evt) {
-            //pdgui.gui_post("x: " + evt.pageX + " y: " + evt.pageY +
-            //    " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1)));
-            pdgui.pdsend(name +
-            " motion " + evt.pageX + " " + evt.pageY + " " +
-            (evt.shiftKey + (evt.ctrlKey << 1)));
-            evt.stopPropagation();
-            evt.preventDefault();
-            return false;
+        textbox = function () {
+            return document.getElementById('new_object_textentry');
         },
-        mousedown = function(evt) {
-            // tk events are one greater than html5...
-            var b = evt.button + 1;
-            var mod;
-            // For some reason right-click sends a modifier value of "8",
-            // and canvas_doclick in g_editor.c depends on that value to
-            // do the right thing.  So let's hack...
-            if (b === 3) { // right-click
-                mod = 8;
-            } else {
-                mod = (evt.shiftKey + (evt.ctrlKey << 1)); 
-            }
-            pdgui.pdsend(name + " mouse " + evt.pageX + " " + evt.pageY + " " +
-                b + " " + mod);
-            //evt.stopPropagation();
-            evt.preventDefault();
-        },
-        mouseup = function(evt) {
-            //pdgui.gui_post("mouseup: x: " + evt.pageX + " y: " + evt.pageY +
-            //    " button: " + (evt.button + 1));
-            pdgui.pdsend(name +
-                " mouseup " + evt.pageX + " " + evt.pageY + " " +
-                (evt.button + 1));
-            evt.stopPropagation();
-            evt.preventDefault();
-        },
-        keydown = function(evt) {
-            var key_code = evt.keyCode; 
-            var hack = null; // hack for unprintable ascii codes
-            switch(key_code) {
-                case 8:
-                case 9:
-                case 10:
-                case 27:
-                //case 32:
-                case 127: hack = key_code; break;
-                case 37: hack = add_keymods('Left', evt); break;
-                case 38: hack = add_keymods('Up', evt); break;
-                case 39: hack = add_keymods('Right', evt); break;
-                case 40: hack = add_keymods('Down', evt); break;
-                case 33: hack = add_keymods('Prior', evt); break;
-                case 34: hack = add_keymods('Next', evt); break;
-                case 35: hack = add_keymods('End', evt); break;
-                case 36: hack = add_keymods('Home', evt); break;
-
-                // Need to handle Control key, Alt
-
-                case 16: hack = 'Shift'; break;
-                case 17: hack = 'Control'; break;
-                case 18: hack = 'Alt'; break;
-            }
-            if (hack !== null) {
-                pdgui.gui_canvas_sendkey(name, 1, evt, hack);
-                pdgui.set_keymap(key_code, hack);
+        events = {
+            mousemove: function(evt) {
+                //pdgui.gui_post("x: " + evt.pageX + " y: " + evt.pageY +
+                //    " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1)));
+                pdgui.pdsend(name +
+                " motion " + evt.pageX + " " + evt.pageY + " " +
+                (evt.shiftKey + (evt.ctrlKey << 1)));
+                evt.stopPropagation();
+                evt.preventDefault();
+                return false;
+            },
+            mousedown: function(evt) {
+                // tk events are one greater than html5...
+                var b = evt.button + 1;
+                var mod;
+                // For some reason right-click sends a modifier value of "8",
+                // and canvas_doclick in g_editor.c depends on that value to
+                // do the right thing.  So let's hack...
+                if (b === 3) { // right-click
+                    mod = 8;
+                } else {
+                    mod = (evt.shiftKey + (evt.ctrlKey << 1)); 
+                }
+                pdgui.pdsend(name +
+                    " mouse " + evt.pageX + " " + evt.pageY + " " +
+                    b + " " + mod);
+                //evt.stopPropagation();
+                evt.preventDefault();
+            },
+            mouseup: function(evt) {
+                //pdgui.gui_post("mouseup: x: " +
+                //    evt.pageX + " y: " + evt.pageY +
+                //    " button: " + (evt.button + 1));
+                pdgui.pdsend(name +
+                    " mouseup " + evt.pageX + " " + evt.pageY + " " +
+                    (evt.button + 1));
+                evt.stopPropagation();
+                evt.preventDefault();
+            },
+            keydown: function(evt) {
+                var key_code = evt.keyCode; 
+                var hack = null; // hack for unprintable ascii codes
+                switch(key_code) {
+                    case 8:
+                    case 9:
+                    case 10:
+                    case 27:
+                    //case 32:
+                    case 127: hack = key_code; break;
+                    case 37: hack = add_keymods('Left', evt); break;
+                    case 38: hack = add_keymods('Up', evt); break;
+                    case 39: hack = add_keymods('Right', evt); break;
+                    case 40: hack = add_keymods('Down', evt); break;
+                    case 33: hack = add_keymods('Prior', evt); break;
+                    case 34: hack = add_keymods('Next', evt); break;
+                    case 35: hack = add_keymods('End', evt); break;
+                    case 36: hack = add_keymods('Home', evt); break;
+
+                    // Need to handle Control key, Alt
+
+                    case 16: hack = 'Shift'; break;
+                    case 17: hack = 'Control'; break;
+                    case 18: hack = 'Alt'; break;
+                }
+                if (hack !== null) {
+                    pdgui.gui_canvas_sendkey(name, 1, evt, hack);
+                    pdgui.set_keymap(key_code, hack);
+                }
+                pdgui.gui_post("keydown time: keycode is " + evt.keyCode);
+                last_keydown = evt.keyCode;
+                //evt.stopPropagation();
+                //evt.preventDefault();
+            },
+            keypress: function(evt) {
+                pdgui.gui_canvas_sendkey(name, 1, evt, evt.charCode);
+                pdgui.set_keymap(last_keydown, evt.charCode);
+                pdgui.gui_post("keypress time: charcode is " + evt.charCode);
+                // Don't do things like scrolling on space, arrow keys, etc.
+                //evt.stopPropagation();
+                evt.preventDefault();
+            },
+            keyup: function(evt) {
+                var my_char_code = pdgui.get_char_code(evt.keyCode);
+                pdgui.gui_canvas_sendkey(name, 0, evt, my_char_code);
+                pdgui.gui_post("keyup time: charcode is: " + my_char_code);
+                evt.stopPropagation();
+                evt.preventDefault();
+            },
+            text_mousemove: function(evt) { // we may not need this one
+                evt.stopPropagation();    
+                //evt.preventDefault();
+                return false;
+            },
+            text_mousedown: function(evt) {
+                if (textbox() !== evt.target) {
+                    pdgui.gui_post("my content was " + textbox().textContent);
+                    pdgui.pdsend(name + " stringforobj "
+                        + textbox().textContent);
+                    events.mousedown(evt);
+                    canvas_events.normal();
+                }
+                evt.stopPropagation();    
+                //evt.preventDefault();
+                return false;
+            },
+            text_mouseup: function(evt) {
+                pdgui.gui_post("mouseup target is " +
+                    evt.target + " and textbox is " + textbox());
+    //            if (evt.target === textbox) {
+    //                pdgui.gui_post("it's a mouseup in a textbox");
+    //            } else {
+    //                pdgui.gui_post("it's a mouseup outside a textbox");
+    //            }
+    //            evt.stopPropagation();    
+                //evt.preventDefault();
+                return false;
+            },
+            text_keydown: function(evt) {
+                evt.stopPropagation();    
+                //evt.preventDefault();
+                return false;
+            },
+            text_keyup: function(evt) {
+                evt.stopPropagation();    
+                //evt.preventDefault();
+                return false;
+            },
+            text_keypress: function(evt) {
+                evt.stopPropagation();    
+                //evt.preventDefault();
+                return false;
+            },
+            floating_text_click: function(evt) {
+               pdgui.gui_post("leaving floating mode");
+                canvas_events.text();
+                evt.stopPropagation();
+                evt.preventDefault();
+                return false;
+            },
+            floating_text_keypress: function(evt) {
+               pdgui.gui_post("leaving floating mode");
+                canvas_events.text();
+                evt.stopPropagation();
+                evt.preventDefault();
+                return false;
             }
-            pdgui.gui_post("keydown time: keycode is " + evt.keyCode);
-            last_keydown = evt.keyCode;
-            //evt.stopPropagation();
-            //evt.preventDefault();
-        },
-        keypress = function(evt) {
-            pdgui.gui_canvas_sendkey(name, 1, evt, evt.charCode);
-            pdgui.set_keymap(last_keydown, evt.charCode);
-            pdgui.gui_post("keypress time: charcode is " + evt.charCode);
-            // Don't do things like scrolling on space, arrow keys, etc.
-            //evt.stopPropagation();
-            evt.preventDefault();
-        },
-        keyup = function(evt) {
-            var my_char_code = pdgui.get_char_code(evt.keyCode);
-            pdgui.gui_canvas_sendkey(name, 0, evt, my_char_code);
-            pdgui.gui_post("keyup time: charcode is: " + my_char_code);
-            evt.stopPropagation();
-            evt.preventDefault();
-        },
-        text_mousemove = function(evt) {
-            evt.stopPropagation();    
-            //evt.preventDefault();
-            return false;
-        },
-        text_mousedown = function(evt) {
-            evt.stopPropagation();    
-            //evt.preventDefault();
-            return false;
-        },
-        text_mouseup = function(evt) {
-            evt.stopPropagation();    
-            //evt.preventDefault();
-            return false;
-        },
-        text_keydown = function(evt) {
-            evt.stopPropagation();    
-            //evt.preventDefault();
-            return false;
-        },
-        text_keyup = function(evt) {
-            evt.stopPropagation();    
-            //evt.preventDefault();
-            return false;
-        },
-        text_keypress = function(evt) {
-            evt.stopPropagation();    
-            //evt.preventDefault();
-            return false;
         }
     ;
 
@@ -195,7 +230,6 @@ var canvas_events = (function() {
         }, false
     );
 
-
     // closing the Window
     // this isn't actually closing the window yet
     nw.Window.get().on("close", function() {
@@ -203,35 +237,48 @@ var canvas_events = (function() {
     });
 
     return {
+        none: function() {
+            var name;
+            for (var prop in events) {
+                if (events.hasOwnProperty(prop)) {
+                    name = prop.split('_');
+                    name = name[name.length -1];
+                    document.removeEventListener(name, events[prop], false);
+                }
+            }
+        },
         normal: function() {
-            document.removeEventListener("mousemove", text_mousemove, false);
-            document.removeEventListener("keydown", text_keydown, false);
-            document.removeEventListener("keypress", text_keypress, false);
-            document.removeEventListener("keyup", text_keyup, false);
-            document.removeEventListener("mousedown", text_mousedown, false);
-            document.removeEventListener("mouseup", text_mouseup, false);
-
-            document.addEventListener("mousemove", mousemove, false);
-            document.addEventListener("keydown", keydown, false);
-            document.addEventListener("keypress", keypress, false);
-            document.addEventListener("keyup", keyup, false);
-            document.addEventListener("mousedown", mousedown, false);
-            document.addEventListener("mouseup", mouseup, false);
+            pdgui.gui_post("resetting to normal...");
+            this.none();
+
+            document.addEventListener("mousemove", events.mousemove, false);
+            document.addEventListener("keydown", events.keydown, false);
+            document.addEventListener("keypress", events.keypress, false);
+            document.addEventListener("keyup", events.keyup, false);
+            document.addEventListener("mousedown", events.mousedown, false);
+            document.addEventListener("mouseup", events.mouseup, false);
         },
         text: function() {
-            document.removeEventListener("mousemove", mousemove, false);
-            document.removeEventListener("keydown", keydown, false);
-            document.removeEventListener("keypress", keypress, false);
-            document.removeEventListener("keyup", keyup, false);
-            document.removeEventListener("mousedown", mousedown, false);
-            document.removeEventListener("mouseup", mouseup, false);
-
-            document.addEventListener("mousemove", text_mousemove, false);
-            document.addEventListener("keydown", text_keydown, false);
-            document.addEventListener("keypress", text_keypress, false);
-            document.addEventListener("keyup", text_keyup, false);
-            document.addEventListener("mousedown", text_mousedown, false);
-            document.addEventListener("mouseup", mouseup, false);
+            this.none();
+
+            document.addEventListener("mousemove", events.text_mousemove, false);
+            document.addEventListener("keydown", events.text_keydown, false);
+            document.addEventListener("keypress", events.text_keypress, false);
+            document.addEventListener("keyup", events.text_keyup, false);
+            document.addEventListener("mousedown", events.text_mousedown, false);
+            document.addEventListener("mouseup", events.text_mouseup, false);
+        },
+        floating_text: function() {
+            this.none();
+            this.text();
+            document.removeEventListener("mousedown", events.text_mousedown, false);
+            document.removeEventListener("mouseup", events.text_mouseup, false);
+            document.removeEventListener("mousemove", events.text_mousemove, false);
+            document.removeEventListener("keypress", events.text_keypress, false);
+            document.addEventListener("click", events.floating_text_click, false);
+
+            document.addEventListener("keypress", events.floating_text_keypress, false);
+            document.addEventListener("mousemove", events.mousemove, false);
         },
         register: function(n) {
             name = n;
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 2fd515699..fb2202b6b 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -2212,8 +2212,22 @@ function gui_text_displace(name, tag, dx, dy) {
     elem_displace(get_gobj(name, tag), dx, dy);
 }
 
+function textentry_displace(t, dx, dy) {
+    var transform = t.style.getPropertyValue('transform')
+        .split('(')[1]    // get everything after the '('
+        .replace(')', '') // remove trailing ')'
+        .split(',');      // split into x and y
+    var x = +transform[0].trim().replace('px', ''),
+        y = +transform[1].trim().replace('px', '');
+gui_post("x is " + x + " and y is " + y);
+    t.style.setProperty('transform',
+        'translate(' +
+        (x + dx) + 'px, ' +
+        (y + dy) + 'px)');
+}
+
 function gui_canvas_displace_withtag(name, dx, dy) {
-    var pwin = patchwin[name], i;
+    var pwin = patchwin[name], i, textentry;
     var ol = pwin.window.document.getElementsByClassName('selected');
     for (i = 0; i < ol.length; i++) {
         elem_displace(ol[i], dx, dy);
@@ -2223,6 +2237,11 @@ function gui_canvas_displace_withtag(name, dx, dy) {
 //        elem.matrix.e = new_tx;
 //        elem.matrix.f = new_ty;
     }
+    textentry = patchwin[name].window.document.getElementById('new_object_textentry');
+    if (textentry !== null) {
+        textentry_displace(textentry, dx, dy); 
+    }
+
 //        elem.setAttributeNS(null, 'transform',
 //            'translate(' + new_tx + ',' + new_ty + ')');
 //    }
@@ -3396,9 +3415,10 @@ exports.skin = (function () {
     };
 }());
 
-function gui_textarea(cid, tag, x, y, font_size, state) {
+function gui_textarea(cid, tag, x, y, max_char_width, font_size, state) {
     gui_post("x/y is " + x + '/' + y);
-    if (state === 1) {
+    gui_post("state? " + state);
+    if (state !== 0) {
         var p = patchwin[cid].window.document.createElement('p');
         configure_item(p, {
             id: 'new_object_textentry'
@@ -3407,12 +3427,19 @@ function gui_textarea(cid, tag, x, y, font_size, state) {
         p.style.setProperty('left', x + 'px');
         p.style.setProperty('top', y + 'px');
         p.style.setProperty('font-size', font_size + 'px');
-        p.textContent = "Fuck Butts";
+        p.style.setProperty('transform', 'translate(0px, 0px)');
+        p.style.setProperty('max-width',
+            max_char_width === 0 ? '60ch' : max_char_width + 'ch');
+        p.style.setProperty('min-width',
+            max_char_width === 0 ? '3ch' : max_char_width + 'ch');
+//        p.textContent = "Fuck Butts";
         patchwin[cid].window.document.body.appendChild(p);
         p.focus();
-        patchwin[cid].window.canvas_events.text();
-        /* here we need to make sure that events inside the
-           <p> don't propogate down to the svg below... */
+        if (state === 1) {
+            patchwin[cid].window.canvas_events.text();
+        } else {
+            patchwin[cid].window.canvas_events.floating_text();
+        }
     } else {
         var p = patchwin[cid].window.document.getElementById('new_object_textentry');
         if (p !== null) {
diff --git a/pd/nw/todo.txt b/pd/nw/todo.txt
index 5e7d09edc..8bccae975 100644
--- a/pd/nw/todo.txt
+++ b/pd/nw/todo.txt
@@ -1,3 +1,26 @@
+Event settings for edit mode
+----------------------------
+
+1) No box - normal editmode behavior
+   * moving/selecting
+   * setting a bounding rect
+   * mouse cannot select text
+   * text is not editable
+   * clicking a box triggers #2 below
+2) Editing a box in place
+  * x/y is set
+   * can type inside box
+   * can select text with the mouse
+   * mouse motion doesn't change box position
+   * applies to all boxes which already exist and are being edited
+3) Editing a new box before it's anchored
+   * x/y follows mouse
+   * can type new text into the box
+   * a click in the box will anchor the box and trigger #2 above
+
+*need to be able to tell the difference between new obj and retexted
+obj
+
 Problems to put off until all (or most) sys_vgui calls are eliminated:
 1) gui-side parser inside -- pdgui.js.  Currently we're splitting on newlines so we can separate
    gui_vmess from sys_vgui calls.  This makes it very difficult to handle multi-line msg and text
@@ -150,6 +173,7 @@ Everything else: (A [x] means we've fixed it)
     \"%.6lx\". (Not exactly sure what good the "x" does there.)  It's only
     specified in s_inter and in editor_new, so it should be easy to amend
     if need be.
+[ ] make "rtext" textarea <div> static, and turn display on/off
 
 Crashers
 --------
diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h
index 4337d37bd..63c28c0f7 100644
--- a/pd/src/g_canvas.h
+++ b/pd/src/g_canvas.h
@@ -509,6 +509,7 @@ EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag); //5
 EXTERN void rtext_retext(t_rtext *x); //5
 EXTERN char *rtext_gettag(t_rtext *x); //47
 EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize); //9
+EXTERN void rtext_settext(t_rtext *x, char *buf, int bufsize); //1
 EXTERN void rtext_getseltext(t_rtext *x, char **buf, int *bufsize); //4
 
 /* -------------------- functions on canvases ------------------------ */
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index d900479fd..9c4650e9c 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -7613,6 +7613,28 @@ static void canvas_tip(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
     }
 }
 
+static void canvas_stringforobj(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int length;
+    char *buf;
+    t_gobj *y;
+    t_rtext *rtext;
+    if (!x->gl_editor || argc < 1) return;
+    for (y = x->gl_list; y; y = y->g_next)
+    {
+        if (glist_isselected(x, y) && (rtext = glist_findrtext(x, (t_text *)y)))
+        {
+            rtext_gettext(rtext, &buf, &length);
+            t_binbuf *b = binbuf_new();
+            binbuf_add(b, argc, argv);
+            binbuf_gettext(b, &buf, &length);
+            rtext_settext(rtext, buf, length);
+            binbuf_free(b);
+            glist_deselect(x, y);
+        }
+    }
+}
+
 void g_editor_setup(void)
 {
 /* ------------------------ events ---------------------------------- */
@@ -7634,6 +7656,8 @@ void g_editor_setup(void)
     A_GIMME, A_NULL);
     class_addmethod(canvas_class, (t_method)canvas_tip, gensym("echo"),
         A_GIMME, A_NULL);
+    class_addmethod(canvas_class, (t_method)canvas_stringforobj,
+        gensym("stringforobj"), A_GIMME, A_NULL);
 /* ------------------------ menu actions ---------------------------- */
     class_addmethod(canvas_class, (t_method)canvas_menuclose,
         gensym("menuclose"), A_DEFFLOAT, 0);
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c
index c82c9be14..79b54200e 100644
--- a/pd/src/g_rtext.c
+++ b/pd/src/g_rtext.c
@@ -106,6 +106,13 @@ void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
     *bufsize = x->x_bufsize;
 }
 
+void rtext_settext(t_rtext *x, char *buf, int bufsize)
+{
+    freebytes(x->x_buf, x->x_bufsize);
+    x->x_buf = buf;
+    x->x_bufsize = bufsize;
+}
+
 void rtext_getseltext(t_rtext *x, char **buf, int *bufsize)
 {
     *buf = x->x_buf + x->x_selstart;
@@ -553,7 +560,7 @@ post("selected an rtext");
 void rtext_activate(t_rtext *x, int state)
 {
     fprintf(stderr,"rtext_activate state=%d\n", state);
-    int w = 0, h = 0, indx;
+    int w = 0, h = 0, widthspec, indx;
     t_glist *glist = x->x_glist;
     t_canvas *canvas = glist_getcanvas(glist);
     //if (state && x->x_active) printf("duplicate rtext_activate\n");
@@ -578,14 +585,24 @@ void rtext_activate(t_rtext *x, int state)
             glist->gl_editor->e_textedfor = 0;
         x->x_active = 0;
     }
-    /* so I guess the following would need to be commented out
-       if we want to use the textarea junk to feed to Pd... */
     rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
-    gui_vmess("gui_textarea", "xsiiii",
+    /* hack...
+       state = 0 no editing
+       state = 1 editing
+       state = 2 editing a new object
+       State 2 isn't necessary, except that Pd has
+       traditionally had this "floating" state for
+       new objects where the box text also happens
+       to be editable
+    */
+
+    widthspec = x->x_text->te_width; // width if any specified
+    gui_vmess("gui_textarea", "xsiiiii",
         canvas,
         x->x_tag,
         x->x_text->te_xpix,
         x->x_text->te_ypix,
+        widthspec,
         sys_hostfontsize(glist_getfont(glist)),
         state);
 }
diff --git a/pd/src/g_text.c b/pd/src/g_text.c
index 05de05aa4..1b845b50d 100644
--- a/pd/src/g_text.c
+++ b/pd/src/g_text.c
@@ -226,7 +226,8 @@ static void canvas_objtext(t_glist *gl, int xpix, int ypix,
     {
             /* this is called if we've been created from the menu. */
         glist_select(gl, &x->te_g);
-        gobj_activate(&x->te_g, gl, 1);
+        gobj_activate(&x->te_g, gl,
+            2); // <-- hack to signal that we're a new object
     }
     if (pd_class(&x->ob_pd) == vinlet_class)
         canvas_resortinlets(glist_getcanvas(gl));
@@ -357,7 +358,8 @@ void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
         pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
         canvas_objtext(gl,
             connectme ? xpix : xpix - 8,
-            connectme ? ypix : ypix - 8, 0, 1, b);
+            connectme ? ypix : ypix - 8,
+            0, 1, b);
         if (connectme == 1)
         {
             //fprintf(stderr,"canvas_obj calls canvas_connect\n");
-- 
GitLab