Compare commits

...

2 Commits

Author SHA1 Message Date
TFLCL 58b1724be8 blurry text fix 3 months ago
TFLCL a4ce6ba861 format_slot_name 3 months ago
  1. 2
      README.md
  2. 171
      tc.preset.js
  3. 64
      tc.preset_demo.maxpat

2
README.md

@ -29,6 +29,8 @@ A [jsui] replacement for the [preset] object in Cycling'74 Max.
- `store`: send to [jsui] only
- The js program send a lot of message to the [pattrstorage] (patch cord not required), which makes it output a lot of messages required for the [jsui] to stay in sync. Using one of the above messages incorrectly, or sending `getslotlist`, `getslotnamelist`, or any message that will impact the presets, it might cause the [pattrstorage] to get out of sync. In case something like that happens, you can send the `resync` message to the [jsui].
## Known bugs
- Some interactions should be ignored when no pattrstorage is linked
## Desired features (for someday)
- No need for a patch cord (programmatically create a [send]/[receive] pair?)

171
tc.preset.js

@ -82,6 +82,7 @@ var bg_width, bg_height = 0;
var mg = new MGraphics(ui_width, ui_height);
var base_drawing;
var is_painting_base = 0;
var half_slot_size, half_margin, half_spacing;
var last_x, last_y, last_hovered = -1;
@ -166,22 +167,17 @@ function draw_slot(id, scale, cont) {
cont = typeof cont !== 'undefined' ? cont : mgraphics; // Sets drawing context to mgraphics by default if not passed as argument
var offset = slot_size * (1 - scale);
draw_slot_bubble(slots[id][0] + offset, slots[id][1] + offset, slot_size * scale, slot_size * scale, cont);
cont.fill();
if (layout == 1) {
// // Slot number
// var nb = i.toString();
// var nb_dim = text_measure(nb);
// var nb_pos_x = slots[i][0] + (slot_size - nb_dim[0]) / 2;
// var nb_pos_y = slots[i][1] + (slot_size - spacing + nb_dim[1]) / 2 ;
if(is_painting_base) {
draw_slot_bubble(slots[id][0] * scale, slots[id][1] *scale, slot_size * scale, slot_size * scale, cont);
// set_source_rgba(text_color);
// move_to(nb_pos_x, nb_pos_y);
// show_text(nb);
} else {
draw_slot_bubble(slots[id][0] + offset, slots[id][1] + offset, slot_size * scale, slot_size * scale, cont);
}
cont.fill();
if (layout == 1) {
// slot text background
var bg_txt_pos_x = margin + slot_size + spacing;
var bg_txt_pos_y = slots[id][1];
@ -193,44 +189,17 @@ function draw_slot(id, scale, cont) {
} else {
cont.set_source_rgba(empty_slot_color);
}
// cont.rectangle_rounded(bg_txt_pos_x, bg_txt_pos_y, bg_txt_dim_w, bg_txt_dim_h, 4, 4);
// slot name
var text = id;
// If slot is locked, add brackets around its number
if (slots[id][5] == 1) {
text = '[' + text + ']';
}
// If slot has a name, append it to the preset name
if (slots[id][4] != null) {
text += ': ' + slots[id][4];
}
cont.set_font_size(font_size*scale);
var text = format_slot_name(id);
draw_text_bubble(bg_txt_pos_x, bg_txt_pos_y, bg_txt_dim_w, bg_txt_dim_h, text, cont);
// cont.fill();
if (is_painting_base) {
draw_text_bubble(bg_txt_pos_x * scale, bg_txt_pos_y * scale, bg_txt_dim_w * scale, bg_txt_dim_h * scale, text, cont);
// // slot name
// var text = id;
// // If slot is locked, add brackets around its number
// if (slots[id][5] == 1) {
// text = '[' + text + ']';
// }
// // If slot has a name, append it to the preset name
// if (slots[id][4] != null) {
// text += ': ' + slots[id][4];
// }
// text = text.toString();
// var text_dim = cont.text_measure(text);
// var txt_pos_x = margin + slot_size + 2 * spacing;
// var txt_pos_y = bg_txt_pos_y + (bg_txt_dim_h - spacing + text_dim[1]) / 2 ;
// cont.set_source_rgba(text_color);
// cont.move_to(txt_pos_x, txt_pos_y);
// cont.show_text(text.toString());
} else {
draw_text_bubble(bg_txt_pos_x + offset, bg_txt_pos_y + offset, bg_txt_dim_w * scale, bg_txt_dim_h * scale, text, cont);
}
}
}
@ -251,40 +220,45 @@ draw_slot_bubble.local = 1;
function draw_text_bubble(x, y, w, h, text, cont) {
cont = typeof cont !== 'undefined' ? cont : mgraphics;
// slot text background
// var bg_txt_pos_x = margin + slot_size + spacing;
// var bg_txt_pos_y = slots[id][1];
// var bg_txt_dim_w = ui_width - (2*margin + slot_size + spacing);
// var bg_txt_dim_h = slot_size;
// if (slots[id][4] != null) {
// cont.set_source_rgba(stored_slot_color);
// } else {
// cont.set_source_rgba(empty_slot_color);
// }
cont.rectangle_rounded(x, y, w, h, 4, 4);
cont.fill();
text = text.toString();
var text_dim = cont.text_measure(text);
var txt_pos_x = margin + slot_size + 2 * spacing;
var txt_pos_y = y + (h - spacing + text_dim[1]) / 2 ;
var txt_pos_x = x + spacing;
var txt_pos_y = y + (text_dim[1] + h)/2 - text_dim[1]*0.18;
cont.set_source_rgba(text_color);
cont.move_to(txt_pos_x, txt_pos_y);
cont.show_text(text.toString());
}
function format_slot_name(id) {
var text = id;
// If slot is locked, add brackets around its number
if (slots[id][5] == 1) {
text = '[' + text + ']';
}
// If slot has a name, append it to the preset name
if (slots[id][4] != null) {
text += ': ' + slots[id][4];
}
text = text.toString();
return text;
}
format_slot_name.local = 1;
function paint_base() {
// We draw all slots (empty and stored ones) so we don't have to for every redraw
is_painting_base = 1;
// Background
bg_width = layout == 0 ? columns * (slot_size + spacing) - spacing + 2 * margin : ui_width;
bg_height = rows * (slot_size + spacing) - spacing + 2 * margin;
mg = new MGraphics(ui_width, bg_height);
mg = new MGraphics(ui_width*2, bg_height*2);
with(mg) {
set_source_rgba(background_color);
rectangle(0, 0, bg_width, bg_height);
rectangle(0, 0, bg_width*2, bg_height*2);
fill();
select_font_face(font_name);
@ -298,36 +272,11 @@ function paint_base() {
} else {
set_source_rgba(empty_slot_color);
}
draw_slot(i, 1, mg);
// fill();
draw_slot(i, 2, mg);
}
}
// if (layout == 0) {
// for (var i = 1; i <= slots_count_display; i++) {
// if (slots[i][4] != null) {
// set_source_rgba(stored_slot_color);
// } else {
// set_source_rgba(empty_slot_color);
// }
// draw_slot_bubble(i, 1, mg);
// fill();
// }
// } else {
// for (var i = 1; i <= slots_count_display; i++) {
// if (slots[i][4] != null) {
// set_source_rgba(stored_slot_color);
// } else {
// set_source_rgba(empty_slot_color);
// }
// draw_slot(i, 1, mg);
// // fill();
// }
// }
}
is_painting_base = 0;
update_umenu();
base_drawing = new Image(mg);
mgraphics.redraw();
@ -338,28 +287,34 @@ function paint()
{
// post("redraw\n");
with (mgraphics) {
select_font_face(font_name);
set_font_size(font_size);
translate(0, y_offset);
// Draw the base, which includes empty and filled slots
// It is first rendered at twice the size in order to make texts look nice and cripsy on hidpi discplays
// So we need to scale it down here
scale(0.5, 0.5);
image_surface_draw(base_drawing);
scale(2, 2);
set_line_width(1);
// Active slot
if (active_slot > 0 && active_slot <= slots_count_display && is_dragging == 0) {
if (is_dragging == 0 && active_slot > 0 && active_slot <= slots_count_display) {
set_source_rgba(active_slot_color);
draw_slot_bubble(slots[active_slot][0], slots[active_slot][1], slot_size, slot_size);
fill();
}
// Previous active slot
if (previous_active_slot > 0 && previous_active_slot <= slots_count_display) {
if (is_dragging == 0 && previous_active_slot > 0 && previous_active_slot <= slots_count_display) {
set_source_rgba(active_slot_color);
draw_slot_bubble(slots[previous_active_slot][0], slots[previous_active_slot][1], slot_size, slot_size);
stroke();
}
// Interpolated slots
if (display_interp && is_interpolating) {
if (is_dragging == 0 && display_interp && is_interpolating) {
for (var i = 1; i <= slots_count_display; i++) {
var interp = slots[i][6];
@ -378,13 +333,11 @@ function paint()
if (shift_hold) {
if (option_hold) {
// About to delete
post("about to delete\n");
set_source_rgba(empty_slot_color[0], empty_slot_color[1], empty_slot_color[2], 0.8);
draw_slot_bubble(slots[last_hovered][0] + 1, slots[last_hovered][1] + 1, slot_size-2, slot_size-2);
fill();
} else {
// About to store
post("about to stàre\n");
set_source_rgba(active_slot_color[0], active_slot_color[1], active_slot_color[2], 0.7);
draw_slot_bubble(slots[last_hovered][0] + 1, slots[last_hovered][1] + 1, slot_size-2, slot_size-2);
fill();
@ -397,17 +350,7 @@ function paint()
if (layout == 0) {
//Text (slot number and name)
var text = last_hovered;
if (slots[last_hovered][5] == 1) {
text = '[' + text + ']';
}
if (slots[last_hovered][4] != null) {
text += ': ' + slots[last_hovered][4];
}
text = text.toString();
select_font_face(font_name);
set_font_size(font_size);
var text = format_slot_name(last_hovered);
var text_dim = text_measure(text);
// If the text is too big or a slot is being dragged, display the text on top of the next slot.
// Otherwise, it gets displayed on the hovered slot.
@ -444,9 +387,8 @@ function paint()
translate(last_x, last_y );
rotate(0.15);
scale(1.1, 1.1);
// scale(3, 3);
// Shadow
// Slot shadow
set_source_rgba(0, 0, 0, 0.15);
for (var i = 0; i<4; i++) {
draw_slot_bubble( i*0.4 + 1-slot_size/2, i*0.4 + 1-slot_size/2, slot_size + i*0.8, slot_size+i*0.8);
@ -454,6 +396,8 @@ function paint()
}
draw_slot_bubble( 2-slot_size/2, 2-slot_size/2, slot_size, slot_size);
fill();
//Flying slot
set_source_rgba(active_slot_color);
draw_slot_bubble( -slot_size/2, -slot_size/2, slot_size, slot_size);
fill();
@ -465,15 +409,7 @@ function paint()
draw_slot_bubble( -slot_size/2, -slot_size/2, slot_size, slot_size);
fill();
// slot name
var text = drag_slot;
// If slot is locked, add brackets around its number
if (slots[drag_slot][5] == 1) {
text = '[' + text + ']';
}
// If slot has a name, append it to the preset name
if (slots[drag_slot][4] != null) {
text += ': ' + slots[drag_slot][4];
}
var text = format_slot_name(drag_slot);
var bg_txt_pos_x = slot_size/2+ spacing;
var bg_txt_pos_y = -slot_size/2;
var bg_txt_dim_w = ui_width - (2*margin + slot_size + spacing);
@ -492,7 +428,7 @@ paint.local = 1;
function anything() {
// Here just to avoid error messages in case pattrstorage sends unhandled message, like when using getstoredvalue, getsubscriptionlist, getalias, etc.
// Handle the "delete" messages here because it is a reserevd word in js and cannot be used as a function name.
// Handle the "delete" messages here because we can't declare a "function delete" (it is a reserved word in js and cannot be used as a function name.
if (messagename == "delete") {
var v = arrayfromargs(arguments)[0];
v = Math.floor(v);
@ -765,7 +701,8 @@ function find_pattrstorage(name) {
pattrstorage_obj = this.patcher.getnamed(name);
if (pattrstorage_obj !== null) {
pattrstorage_name = name;
// slots_clear();
slots_clear();
// this.patcher.hiddenconnect(pattrstorage_obj, 0, this.box, 0);
to_pattrstorage("getslotlist");
to_pattrstorage("getlockedslots");
} else {

64
tc.preset_demo.maxpat

@ -10,7 +10,7 @@
}
,
"classnamespace" : "box",
"rect" : [ 134.0, 100.0, 715.0, 848.0 ],
"rect" : [ 34.0, 100.0, 688.0, 848.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
@ -39,6 +39,18 @@
"subpatcher_template" : "",
"assistshowspatchername" : 0,
"boxes" : [ {
"box" : {
"id" : "obj-9",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 465.0, 630.0, 127.0, 22.0 ],
"text" : "fontname \"Arial Black\""
}
}
, {
"box" : {
"id" : "obj-65",
"linecount" : 6,
@ -475,7 +487,7 @@
]
}
,
"patching_rect" : [ 231.0, 833.0, 125.0, 22.0 ],
"patching_rect" : [ 227.0, 845.0, 125.0, 22.0 ],
"saved_object_attributes" : {
"description" : "",
"digest" : "",
@ -494,7 +506,7 @@
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 16.0, 457.0, 150.0, 33.0 ],
"patching_rect" : [ 30.0, 523.5, 150.0, 33.0 ],
"text" : "Usefull when making changes to the js file"
}
@ -506,7 +518,7 @@
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 15.0, 496.0, 151.0, 22.0 ],
"patching_rect" : [ 29.0, 562.5, 151.0, 22.0 ],
"text" : "loadbang, pattrstorage test"
}
@ -529,7 +541,7 @@
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 446.0, 37.5, 505.0, 100.0 ],
"patching_rect" : [ 120.0, 27.0, 505.0, 100.0 ],
"text" : "In order to use that custom jsui, you need to:\n1. bind the jsui to a named pattrstorage, either by setting the pattrstorage name as the jsui jsarguments attribute, or by sending a message to the jsui starting by \"pattrstorage\" followed by the pattrstorage name (prefered). You can re-send this message manually at any time to re-sync the jsui with the pattstorage (in case you send some messages to the pattrstorage that doesn't trigger an output). An empty \"pattrstorage\" message to the jsui will unbind it.\n2. Connect the pattrstorage outlet to the jsui inlet."
}
@ -659,7 +671,7 @@
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "" ],
"patching_rect" : [ 169.0, 68.5, 29.5, 22.0 ],
"patching_rect" : [ 169.0, 374.0, 29.5, 22.0 ],
"text" : "t l l"
}
@ -758,7 +770,7 @@
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 169.0, 37.5, 133.0, 22.0 ],
"patching_rect" : [ 169.0, 343.0, 133.0, 22.0 ],
"text" : "recallmulti 1.5 2.1 3 5.2"
}
@ -769,7 +781,7 @@
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 72.0, 829.0, 135.0, 22.0 ],
"patching_rect" : [ 72.0, 845.0, 135.0, 22.0 ],
"text" : "print jsui_out @popup 1"
}
@ -781,7 +793,7 @@
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 341.5, 37.5, 73.0, 22.0 ],
"patching_rect" : [ 16.0, 38.0, 73.0, 22.0 ],
"text" : "pattrstorage"
}
@ -793,7 +805,7 @@
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 428.0, 805.0, 93.0, 22.0 ],
"patching_rect" : [ 417.0, 803.0, 93.0, 22.0 ],
"text" : "prepend setlock"
}
@ -806,7 +818,7 @@
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 428.0, 774.0, 24.0, 24.0 ],
"patching_rect" : [ 417.0, 772.0, 24.0, 24.0 ],
"presentation" : 1,
"presentation_rect" : [ 119.0, 62.5, 24.0, 24.0 ]
}
@ -846,22 +858,23 @@
"numoutlets" : 4,
"outlettype" : [ "", "int", "", "" ],
"parameter_enable" : 0,
"patching_rect" : [ 309.0, 774.0, 100.0, 50.0 ],
"patching_rect" : [ 302.0, 772.0, 100.0, 50.0 ],
"presentation" : 1,
"presentation_rect" : [ 146.0, 63.5, 119.0, 22.0 ]
"presentation_rect" : [ 146.0, 63.5, 119.0, 22.0 ],
"text" : "<(unnamed)>"
}
}
, {
"box" : {
"id" : "obj-8",
"items" : "<empty>",
"items" : [ "1 <(unnamed)>", ",", "2 <(unnamed)>" ],
"maxclass" : "umenu",
"numinlets" : 1,
"numoutlets" : 3,
"outlettype" : [ "int", "", "" ],
"parameter_enable" : 0,
"patching_rect" : [ 191.0, 788.0, 100.0, 22.0 ],
"patching_rect" : [ 187.0, 800.0, 100.0, 22.0 ],
"presentation" : 1,
"presentation_rect" : [ 1.0, 63.5, 116.0, 22.0 ]
}
@ -888,7 +901,7 @@
"numoutlets" : 2,
"outlettype" : [ "", "bang" ],
"parameter_enable" : 0,
"patching_rect" : [ 72.0, 37.5, 50.0, 22.0 ]
"patching_rect" : [ 72.0, 343.0, 50.0, 22.0 ]
}
}
@ -899,7 +912,7 @@
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 72.0, 68.5, 74.0, 22.0 ],
"patching_rect" : [ 72.0, 374.0, 74.0, 22.0 ],
"text" : "recall 1 4 $1"
}
@ -936,7 +949,7 @@
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 341.5, 65.5, 95.0, 22.0 ],
"patching_rect" : [ 16.0, 66.0, 95.0, 22.0 ],
"text" : "pattrstorage test"
}
@ -944,7 +957,7 @@
, {
"box" : {
"border" : 0,
"embedstate" : [ [ "fontsize", 14 ], [ "displayinterp", 1 ], [ "fontname", "Arial" ], [ "stored_slot_color", 0.502, 0.502, 0.502, 1 ], [ "scrollable", 1 ], [ "layout", 0 ], [ "interp_slot_color", 1, 1, 1, 0.8 ], [ "bubblesize", 20 ], [ "spacing", 4 ], [ "min_rows", 50 ], [ "text_bg_color", 1, 1, 1, 0.5 ], [ "autowriteagain", 0 ], [ "empty_slot_color", 0.349, 0.349, 0.349, 1 ], [ "bgcolor", 0.2, 0.2, 0.2, 1 ], [ "text_color", 0.129, 0.129, 0.129, 1 ], [ "ignoreslotzero", 1 ], [ "margin", 4 ], [ "slot_round", 0 ], [ "active_slot_color", 0.808, 0.898, 0.91, 1 ] ],
"embedstate" : [ [ "text_bg_color", 1, 1, 1, 0.5 ], [ "autowriteagain", 0 ], [ "layout", 1 ], [ "empty_slot_color", 0.349, 0.349, 0.349, 1 ], [ "spacing", 4 ], [ "text_color", 0.129, 0.129, 0.129, 1 ], [ "ignoreslotzero", 1 ], [ "min_rows", 50 ], [ "active_slot_color", 0.808, 0.898, 0.91, 1 ], [ "bubblesize", 20 ], [ "displayinterp", 1 ], [ "stored_slot_color", 0.502, 0.502, 0.502, 1 ], [ "scrollable", 1 ], [ "margin", 4 ], [ "fontsize", 14 ], [ "interp_slot_color", 1, 1, 1, 0.8 ], [ "slot_round", 0 ], [ "bgcolor", 0.2, 0.2, 0.2, 1 ], [ "fontname", "Arial" ] ],
"filename" : "tc.preset.js",
"id" : "obj-10",
"jsarguments" : [ "test" ],
@ -953,7 +966,7 @@
"numoutlets" : 4,
"outlettype" : [ "", "", "", "" ],
"parameter_enable" : 0,
"patching_rect" : [ 72.0, 637.0, 375.0, 132.0 ],
"patching_rect" : [ 72.0, 637.0, 364.0, 124.0 ],
"presentation" : 1,
"presentation_rect" : [ 1.0, 103.0, 269.0, 77.0 ]
}
@ -1011,7 +1024,7 @@
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 72.0, 108.5, 176.0, 22.0 ],
"patching_rect" : [ 72.0, 414.0, 176.0, 22.0 ],
"saved_object_attributes" : {
"client_rect" : [ 100, 100, 519, 600 ],
"parameter_enable" : 0,
@ -1194,7 +1207,7 @@
, {
"patchline" : {
"destination" : [ "obj-1", 0 ],
"midpoints" : [ 240.5, 865.0, 57.0, 865.0, 57.0, 102.0, 81.5, 102.0 ],
"midpoints" : [ 236.5, 884.0, 57.0, 884.0, 57.0, 405.0, 81.5, 405.0 ],
"source" : [ "obj-34", 0 ]
}
@ -1366,6 +1379,13 @@
"source" : [ "obj-87", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-10", 0 ],
"source" : [ "obj-9", 0 ]
}
}
],
"dependency_cache" : [ {

Loading…
Cancel
Save