Commit 3cf74797 authored by user's avatar user
Browse files

got a very early working version that does _all_ object text editing (arrow...

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.)
parent 3fb7aab2
...@@ -43,120 +43,155 @@ function add_keymods(key, evt) { ...@@ -43,120 +43,155 @@ function add_keymods(key, evt) {
var canvas_events = (function() { var canvas_events = (function() {
var name, var name,
mousemove = function(evt) { textbox = function () {
//pdgui.gui_post("x: " + evt.pageX + " y: " + evt.pageY + return document.getElementById('new_object_textentry');
// " 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) { events = {
// tk events are one greater than html5... mousemove: function(evt) {
var b = evt.button + 1; //pdgui.gui_post("x: " + evt.pageX + " y: " + evt.pageY +
var mod; // " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1)));
// For some reason right-click sends a modifier value of "8", pdgui.pdsend(name +
// and canvas_doclick in g_editor.c depends on that value to " motion " + evt.pageX + " " + evt.pageY + " " +
// do the right thing. So let's hack... (evt.shiftKey + (evt.ctrlKey << 1)));
if (b === 3) { // right-click evt.stopPropagation();
mod = 8; evt.preventDefault();
} else { return false;
mod = (evt.shiftKey + (evt.ctrlKey << 1)); },
} mousedown: function(evt) {
pdgui.pdsend(name + " mouse " + evt.pageX + " " + evt.pageY + " " + // tk events are one greater than html5...
b + " " + mod); var b = evt.button + 1;
//evt.stopPropagation(); var mod;
evt.preventDefault(); // For some reason right-click sends a modifier value of "8",
}, // and canvas_doclick in g_editor.c depends on that value to
mouseup = function(evt) { // do the right thing. So let's hack...
//pdgui.gui_post("mouseup: x: " + evt.pageX + " y: " + evt.pageY + if (b === 3) { // right-click
// " button: " + (evt.button + 1)); mod = 8;
pdgui.pdsend(name + } else {
" mouseup " + evt.pageX + " " + evt.pageY + " " + mod = (evt.shiftKey + (evt.ctrlKey << 1));
(evt.button + 1)); }
evt.stopPropagation(); pdgui.pdsend(name +
evt.preventDefault(); " mouse " + evt.pageX + " " + evt.pageY + " " +
}, b + " " + mod);
keydown = function(evt) { //evt.stopPropagation();
var key_code = evt.keyCode; evt.preventDefault();
var hack = null; // hack for unprintable ascii codes },
switch(key_code) { mouseup: function(evt) {
case 8: //pdgui.gui_post("mouseup: x: " +
case 9: // evt.pageX + " y: " + evt.pageY +
case 10: // " button: " + (evt.button + 1));
case 27: pdgui.pdsend(name +
//case 32: " mouseup " + evt.pageX + " " + evt.pageY + " " +
case 127: hack = key_code; break; (evt.button + 1));
case 37: hack = add_keymods('Left', evt); break; evt.stopPropagation();
case 38: hack = add_keymods('Up', evt); break; evt.preventDefault();
case 39: hack = add_keymods('Right', evt); break; },
case 40: hack = add_keymods('Down', evt); break; keydown: function(evt) {
case 33: hack = add_keymods('Prior', evt); break; var key_code = evt.keyCode;
case 34: hack = add_keymods('Next', evt); break; var hack = null; // hack for unprintable ascii codes
case 35: hack = add_keymods('End', evt); break; switch(key_code) {
case 36: hack = add_keymods('Home', evt); break; case 8:
case 9:
// Need to handle Control key, Alt case 10:
case 27:
case 16: hack = 'Shift'; break; //case 32:
case 17: hack = 'Control'; break; case 127: hack = key_code; break;
case 18: hack = 'Alt'; break; case 37: hack = add_keymods('Left', evt); break;
} case 38: hack = add_keymods('Up', evt); break;
if (hack !== null) { case 39: hack = add_keymods('Right', evt); break;
pdgui.gui_canvas_sendkey(name, 1, evt, hack); case 40: hack = add_keymods('Down', evt); break;
pdgui.set_keymap(key_code, hack); 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() { ...@@ -195,7 +230,6 @@ var canvas_events = (function() {
}, false }, false
); );
// closing the Window // closing the Window
// this isn't actually closing the window yet // this isn't actually closing the window yet
nw.Window.get().on("close", function() { nw.Window.get().on("close", function() {
...@@ -203,35 +237,48 @@ var canvas_events = (function() { ...@@ -203,35 +237,48 @@ var canvas_events = (function() {
}); });
return { 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() { normal: function() {
document.removeEventListener("mousemove", text_mousemove, false); pdgui.gui_post("resetting to normal...");
document.removeEventListener("keydown", text_keydown, false); this.none();
document.removeEventListener("keypress", text_keypress, false);
document.removeEventListener("keyup", text_keyup, false); document.addEventListener("mousemove", events.mousemove, false);
document.removeEventListener("mousedown", text_mousedown, false); document.addEventListener("keydown", events.keydown, false);
document.removeEventListener("mouseup", text_mouseup, false); document.addEventListener("keypress", events.keypress, false);
document.addEventListener("keyup", events.keyup, false);
document.addEventListener("mousemove", mousemove, false); document.addEventListener("mousedown", events.mousedown, false);
document.addEventListener("keydown", keydown, false); document.addEventListener("mouseup", events.mouseup, false);
document.addEventListener("keypress", keypress, false);
document.addEventListener("keyup", keyup, false);
document.addEventListener("mousedown", mousedown, false);
document.addEventListener("mouseup", mouseup, false);
}, },
text: function() { text: function() {
document.removeEventListener("mousemove", mousemove, false); this.none();
document.removeEventListener("keydown", keydown, false);
document.removeEventListener("keypress", keypress, false); document.addEventListener("mousemove", events.text_mousemove, false);
document.removeEventListener("keyup", keyup, false); document.addEventListener("keydown", events.text_keydown, false);
document.removeEventListener("mousedown", mousedown, false); document.addEventListener("keypress", events.text_keypress, false);
document.removeEventListener("mouseup", mouseup, false); document.addEventListener("keyup", events.text_keyup, false);
document.addEventListener("mousedown", events.text_mousedown, false);
document.addEventListener("mousemove", text_mousemove, false); document.addEventListener("mouseup", events.text_mouseup, false);
document.addEventListener("keydown", text_keydown, false); },
document.addEventListener("keypress", text_keypress, false); floating_text: function() {
document.addEventListener("keyup", text_keyup, false); this.none();
document.addEventListener("mousedown", text_mousedown, false); this.text();
document.addEventListener("mouseup", mouseup, false); 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) { register: function(n) {
name = n; name = n;
......
...@@ -2212,8 +2212,22 @@ function gui_text_displace(name, tag, dx, dy) { ...@@ -2212,8 +2212,22 @@ function gui_text_displace(name, tag, dx, dy) {
elem_displace(get_gobj(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) { 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'); var ol = pwin.window.document.getElementsByClassName('selected');
for (i = 0; i < ol.length; i++) { for (i = 0; i < ol.length; i++) {
elem_displace(ol[i], dx, dy); elem_displace(ol[i], dx, dy);
...@@ -2223,6 +2237,11 @@ function gui_canvas_displace_withtag(name, dx, dy) { ...@@ -2223,6 +2237,11 @@ function gui_canvas_displace_withtag(name, dx, dy) {
// elem.matrix.e = new_tx; // elem.matrix.e = new_tx;
// elem.matrix.f = new_ty; // 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', // elem.setAttributeNS(null, 'transform',
// 'translate(' + new_tx + ',' + new_ty + ')'); // 'translate(' + new_tx + ',' + new_ty + ')');
// } // }
...@@ -3396,9 +3415,10 @@ exports.skin = (function () { ...@@ -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); 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'); var p = patchwin[cid].window.document.createElement('p');
configure_item(p, { configure_item(p, {
id: 'new_object_textentry' id: 'new_object_textentry'
...@@ -3407,12 +3427,19 @@ function gui_textarea(cid, tag, x, y, font_size, state) { ...@@ -3407,12 +3427,19 @@ function gui_textarea(cid, tag, x, y, font_size, state) {
p.style.setProperty('left', x + 'px'); p.style.setProperty('left', x + 'px');
p.style.setProperty('top', y + 'px'); p.style.setProperty('top', y + 'px');
p.style.setProperty('font-size', font_size + '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); patchwin[cid].window.document.body.appendChild(p);
p.focus(); p.focus();
patchwin[cid].window.canvas_events.text(); if (state === 1) {
/* here we need to make sure that events inside the patchwin[cid].window.canvas_events.text();
<p> don't propogate down to the svg below... */ } else {
patchwin[cid].window.canvas_events.floating_text();
}
} else { } else {
var p = patchwin[cid].window.document.getElementById('new_object_textentry'); var p = patchwin[cid].window.document.getElementById('new_object_textentry');
if (p !== null) { if (p !== null) {
......
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: 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 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 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) ...@@ -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 \"%.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 specified in s_inter and in editor_new, so it should be easy to amend
if need be. if need be.
[ ] make "rtext" textarea <div> static, and turn display on/off
Crashers Crashers
-------- --------
...@@ -509,6 +509,7 @@ EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag); //5 ...@@ -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 void rtext_retext(t_rtext *x); //5
EXTERN char *rtext_gettag(t_rtext *x); //47 EXTERN char *rtext_gettag(t_rtext *x); //47
EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize); //9 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 EXTERN void rtext_getseltext(t_rtext *x, char **buf, int *bufsize); //4
/* -------------------- functions on canvases ------------------------ */ /* -------------------- functions on canvases ------------------------ */
......
...@@ -7613,6 +7613,28 @@ static void canvas_tip(t_canvas *x, t_symbol *s, int argc, t_atom *argv) ...@@ -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) void g_editor_setup(void)
{ {
/* ------------------------ events ---------------------------------- */ /* ------------------------ events ---------------------------------- */
...@@ -7634,6 +7656,8 @@ void g_editor_setup(void) ...@@ -7634,6 +7656,8 @@ void g_editor_setup(void)
A_GIMME, A_NULL); A_GIMME, A_NULL);
class_addmethod(canvas_class, (t_method)canvas_tip, gensym("echo"), class_addmethod(canvas_class, (t_method)canvas_tip, gensym("echo"),
A_GIMME, A_NULL); A_GIMME, A_NULL);
class_addmethod(canvas_class, (t_method)canvas_stringforobj,
gensym("stringforobj"), A_GIMME, A_NULL);
/* ------------------------ menu actions ---------------------------- */ /* ------------------------ menu actions ---------------------------- */
class_addmethod(canvas_class, (t_method)canvas_menuclose, class_addmethod(canvas_class, (t_method)canvas_menuclose,
gensym("menuclose"), A_DEFFLOAT, 0); gensym("menuclose"), A_DEFFLOAT, 0);
......
...@@ -106,6 +106,13 @@ void rtext_gettext(t_rtext *x, char **buf, int *bufsize) ...@@ -106,6 +106,13 @@ void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
*bufsize = x->x_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) void rtext_getseltext(t_rtext *x, char **buf, int *bufsize)
{ {
*buf = x->x_buf + x->x_selstart; *buf = x->x_buf + x->x_selstart;
...@@ -553,7 +560,7 @@ post("selected an rtext"); ...@@ -553,7 +560,7 @@ post("selected an rtext");
void rtext_activate(t_rtext *x, int state) void rtext_activate(t_rtext *x, int state)
{ {
fprintf(stderr,"rtext_activate state=%d\n", 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_glist *glist = x->x_glist;
t_canvas *canvas = glist_getcanvas(glist); t_canvas *canvas = glist_getcanvas(glist);
//if (state && x->x_active) printf("duplicate rtext_activate\n"); //if (state && x->x_active) printf("duplicate rtext_activate\n");
...@@ -578,14 +585,24 @@ void rtext_activate(t_rtext *x, int state) ...@@ -578,14 +585,24 @@ void rtext_activate(t_rtext *x, int state)
glist->gl_editor->e_textedfor = 0; glist->gl_editor->e_textedfor = 0;
x->x_active = 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); 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