|
|
|
|
@@ -56,6 +56,7 @@ var stored_slot_color = [0.502, 0.502, 0.502, 1];
|
|
|
|
|
var interp_slot_color = [1.0, 1.0, 1.0, 0.8];
|
|
|
|
|
var text_bg_color = [1,1,1, 0.5];
|
|
|
|
|
var text_color = [0.129, 0.129, 0.129, 1];
|
|
|
|
|
var edited_color = [1, 0.49, 0.263, 1];
|
|
|
|
|
|
|
|
|
|
var color_1 = [0.743, 0.41, 0.501, 1]; // Color set for the filled slots. I don't like how this is declared. More info in color_wheel() declaration
|
|
|
|
|
var color_2 = [0.679, 0.405, 0.669,1];
|
|
|
|
|
@@ -82,6 +83,8 @@ var unique_names = false; // When enabled, force names to be unique when renam
|
|
|
|
|
var use_uid = 0; // Generating UID for each presets when enabled. Requires a [pattr preset_metadata]
|
|
|
|
|
var recall_passthrough = true; // By default (true), clicking a slot sends a recall message directly to [pattrstorage], and the jsui left outlet outputs a recall message once the recall is done. When disabled, clicking a slot will send a recall message straight from the jsui left outlet, so it's up to the user to forward the message to pattrstorage. It can be usefull for triggering interpolations with custom logic.
|
|
|
|
|
var ui_rename = false; // Use the attached textedit, if any, to edit slot names directly in the JSUI frame when clicking a slot while holding the control key. When disabled, the textedit remains untouched but gets focused when clicking a slot while holding the control key.
|
|
|
|
|
var poll_edited = 1; // If >0, check if current preset is edited every X seconds defined by the variable value.
|
|
|
|
|
var nbslot_edit = true; // If nbslot_edit and scrollable are enabled, the last two visible slots are replaced by buttons to add or remove lines of slot.
|
|
|
|
|
|
|
|
|
|
// (WORK)
|
|
|
|
|
var pattrstorage_name, pattrstorage_obj = null;
|
|
|
|
|
@@ -90,10 +93,12 @@ var columns, rows = 0;
|
|
|
|
|
var slots = []; // Stores on screen box, name, lock and interpolation state for all slots
|
|
|
|
|
var slots_highest = 0; // Highest filled preset slot number
|
|
|
|
|
var slots_count_display = 0; // Number of slots to be displayed
|
|
|
|
|
var true_slots_count_display = 0; // Number of slots to be displayed, including 2 extra slots for nbslot_edit buttons used as buttons instead of preset slots
|
|
|
|
|
var filled_slots = []; // List of stored slots
|
|
|
|
|
var filled_slots_dict = new Dict();
|
|
|
|
|
|
|
|
|
|
var active_slot = 0; //Last recalled slot
|
|
|
|
|
var active_slot_edited = false; //Active slot edited state flag. See run_edited_poll_task()
|
|
|
|
|
var previous_active_slot = 0; //Previously recalled slot
|
|
|
|
|
var previous_target = 0; //Here to deal with ongoing interpolations
|
|
|
|
|
var selected_slot = 0; //Last selected slot. Relevant especially when select_mode = 1. Otherwise it is the same as active_slot
|
|
|
|
|
@@ -112,6 +117,7 @@ var is_painting_base = 0;
|
|
|
|
|
|
|
|
|
|
var half_slot_size, half_margin, half_spacing;
|
|
|
|
|
var last_x, last_y, last_hovered = -1;
|
|
|
|
|
var last_hovered_is_preset_slot = false;
|
|
|
|
|
var y_offset = 0; // handle scrolling
|
|
|
|
|
var drag_scroll = 0; // handle scrolling when dragging outside of boundaries
|
|
|
|
|
var shift_hold, option_hold = 0;
|
|
|
|
|
@@ -133,6 +139,8 @@ var textedit_obj = null;
|
|
|
|
|
var textedit_initstate = {};
|
|
|
|
|
var is_typing_name = false;
|
|
|
|
|
|
|
|
|
|
var poll_edited_task = new Task(do_poll_edited, this);
|
|
|
|
|
|
|
|
|
|
var has_loaded = false;
|
|
|
|
|
|
|
|
|
|
if (jsarguments.length>1) { // Depreciated, use "pattrstorage" attribute instead of jsarguments.
|
|
|
|
|
@@ -195,20 +203,36 @@ function calc_rows_columns() {
|
|
|
|
|
|
|
|
|
|
slots[0] = new slot(0, 0, 0, 0, "(tmp)", 0, -1, 0, stored_slot_color); // Slot 0 is valid, but not represented in the GUI (and never saved by pattrstorage)
|
|
|
|
|
|
|
|
|
|
var minus_slots_carry = 0;
|
|
|
|
|
if (layout == 0) {
|
|
|
|
|
columns = Math.floor((ui_width - margin + spacing) / (slot_size + spacing));
|
|
|
|
|
rows = Math.floor((ui_height - margin + spacing) / (slot_size + spacing));
|
|
|
|
|
if (scrollable) {
|
|
|
|
|
rows = Math.max(rows, Math.max(min_rows, Math.ceil(slots_highest/columns)));
|
|
|
|
|
min_rows = Math.max(rows, min_rows);
|
|
|
|
|
if (nbslot_edit) {
|
|
|
|
|
rows += columns >= 2 ? 1 : 2;
|
|
|
|
|
if (columns > 2) {
|
|
|
|
|
minus_slots_carry = columns - 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
columns = 1;
|
|
|
|
|
rows = Math.floor((ui_height - margin + spacing) / (slot_size + spacing));
|
|
|
|
|
min_rows = Math.max(rows, min_rows);
|
|
|
|
|
if (scrollable) {
|
|
|
|
|
rows = Math.max(rows, Math.max(min_rows, slots_highest));
|
|
|
|
|
if (nbslot_edit) {
|
|
|
|
|
rows += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
slots_count_display = columns * rows;
|
|
|
|
|
if (scrollable && nbslot_edit) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
true_slots_count_display = columns * rows - minus_slots_carry;
|
|
|
|
|
slots_count_display = scrollable && nbslot_edit ? true_slots_count_display - 2 : true_slots_count_display;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < rows; i++) {
|
|
|
|
|
var top = margin + i * (spacing+slot_size);
|
|
|
|
|
@@ -267,16 +291,39 @@ function draw_slot(id, scale, cont) {
|
|
|
|
|
|
|
|
|
|
// slot name
|
|
|
|
|
cont.set_font_size(font_size*scale);
|
|
|
|
|
var text = format_slot_name(id);
|
|
|
|
|
var text;
|
|
|
|
|
if (scrollable && nbslot_edit && (id > (true_slots_count_display - 2))) {
|
|
|
|
|
if (id == true_slots_count_display - 1) {
|
|
|
|
|
text = "remove slot";
|
|
|
|
|
} else {
|
|
|
|
|
text = "add slot";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
text = format_slot_name(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
} 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (scrollable && nbslot_edit) {
|
|
|
|
|
cont.set_line_width(Math.floor(slot_size * 0.3));
|
|
|
|
|
if (id > true_slots_count_display - 2) {
|
|
|
|
|
cont.set_source_rgba(stored_slot_color);
|
|
|
|
|
cont.move_to((slots[id].left + slot_size * 0.1) * scale, (slots[id].top + half_slot_size) * scale);
|
|
|
|
|
cont.rel_line_to(slot_size * 0.8 * scale, 0);
|
|
|
|
|
cont.stroke();
|
|
|
|
|
}
|
|
|
|
|
if (id > true_slots_count_display - 1) {
|
|
|
|
|
cont.move_to((slots[id].left + half_slot_size) * scale, (slots[id].top + slot_size * 0.1) * scale);
|
|
|
|
|
cont.rel_line_to(0, slot_size * 0.8 * scale);
|
|
|
|
|
cont.stroke();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
draw_slot.local = 1;
|
|
|
|
|
|
|
|
|
|
@@ -288,7 +335,7 @@ function draw_slot_bubble(x, y, w, h, cont) {
|
|
|
|
|
cont.rectangle_rounded(x, y, w, h, slot_round_ratio * w, slot_round_ratio * h);
|
|
|
|
|
} else {
|
|
|
|
|
cont.rectangle(x, y, w, h);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
draw_slot_bubble.local = 1;
|
|
|
|
|
|
|
|
|
|
@@ -342,7 +389,7 @@ function paint_base() {
|
|
|
|
|
set_font_size(font_size);
|
|
|
|
|
|
|
|
|
|
// All slots
|
|
|
|
|
for (var i = 1; i <= slots_count_display; i++) {
|
|
|
|
|
for (var i = 1; i <= true_slots_count_display; i++) {
|
|
|
|
|
if (i != drag_slot) { //We mask the slot that is currently dragged as it is drawn at the mouse position already
|
|
|
|
|
if (slots[i].name != null) {
|
|
|
|
|
if (color_mode == 1) {
|
|
|
|
|
@@ -416,7 +463,7 @@ function paint()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Hide dragged slot
|
|
|
|
|
if (is_dragging) {
|
|
|
|
|
if (is_dragging) {
|
|
|
|
|
set_source_rgba(empty_slot_color);
|
|
|
|
|
draw_slot_bubble(slots[drag_slot].left, slots[drag_slot].top, slot_size, slot_size);
|
|
|
|
|
fill();
|
|
|
|
|
@@ -445,6 +492,14 @@ function paint()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Edited dot
|
|
|
|
|
if (active_slot_edited && active_slot > 0 && selected_slot <= slots_count_display) {
|
|
|
|
|
post("draw edited dot\n");
|
|
|
|
|
set_source_rgba(edited_color);
|
|
|
|
|
ellipse(slots[active_slot].left + 1, slots[active_slot].top + 1, slot_size/3, slot_size/3);
|
|
|
|
|
fill();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hovered slot
|
|
|
|
|
if (last_hovered > -1) {
|
|
|
|
|
if (shift_hold) {
|
|
|
|
|
@@ -468,7 +523,16 @@ function paint()
|
|
|
|
|
|
|
|
|
|
if (layout == 0) {
|
|
|
|
|
//Text (slot number and name)
|
|
|
|
|
var text = format_slot_name(last_hovered);
|
|
|
|
|
var text = null;
|
|
|
|
|
if (scrollable && nbslot_edit && (last_hovered > (true_slots_count_display - 2))) {
|
|
|
|
|
if (last_hovered == true_slots_count_display - 1) {
|
|
|
|
|
text = "remove slot row";
|
|
|
|
|
} else {
|
|
|
|
|
text = "add slot row";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
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.
|
|
|
|
|
@@ -913,20 +977,26 @@ function recall() {
|
|
|
|
|
} else {
|
|
|
|
|
previous_active_slot = previous_target;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_active_slot(src_slot);
|
|
|
|
|
active_slot_edited = 0;
|
|
|
|
|
run_edited_poll_task();
|
|
|
|
|
} else if (interp == 1.0) {
|
|
|
|
|
slots[src_slot].interp = -1;
|
|
|
|
|
slots[trg_slot].interp = -1;
|
|
|
|
|
is_interpolating = 0;
|
|
|
|
|
previous_target = trg_slot;
|
|
|
|
|
set_active_slot(trg_slot);
|
|
|
|
|
|
|
|
|
|
active_slot_edited = 0;
|
|
|
|
|
run_edited_poll_task();
|
|
|
|
|
} else {
|
|
|
|
|
slots[src_slot].interp = 1 - interp;
|
|
|
|
|
slots[trg_slot].interp = interp;
|
|
|
|
|
is_interpolating = 1;
|
|
|
|
|
active_slot = 0;
|
|
|
|
|
// if (src_slot != trg_slot) {
|
|
|
|
|
// active_slot_edited = 1;
|
|
|
|
|
// cancel_edited_poll_task();
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
if (recall_passthrough) {
|
|
|
|
|
outlet(0, "recall", src_slot, trg_slot, interp);
|
|
|
|
|
@@ -968,6 +1038,8 @@ function recallmulti() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_interpolating = 1;
|
|
|
|
|
active_slot_edited = 0;
|
|
|
|
|
run_edited_poll_task();
|
|
|
|
|
mgraphics.redraw();
|
|
|
|
|
|
|
|
|
|
outlet(0, "recallmulti", args);
|
|
|
|
|
@@ -1006,6 +1078,9 @@ function store(v) {
|
|
|
|
|
to_pattrstorage("store", v);
|
|
|
|
|
to_pattrstorage("getslotlist");
|
|
|
|
|
|
|
|
|
|
active_slot_edited = 0;
|
|
|
|
|
run_edited_poll_task();
|
|
|
|
|
|
|
|
|
|
if (recalc_rows_flag) {
|
|
|
|
|
calc_rows_columns();
|
|
|
|
|
} else {
|
|
|
|
|
@@ -1186,7 +1261,7 @@ slots_clear.local = 1;
|
|
|
|
|
|
|
|
|
|
function get_slot_index(x, y) {
|
|
|
|
|
// Returns which slot is hovered by the mouse
|
|
|
|
|
for (var i = 1; i <= slots_count_display; i++) {
|
|
|
|
|
for (var i = 1; i <= true_slots_count_display; i++) {
|
|
|
|
|
if (layout === 0) {
|
|
|
|
|
if (y > (slots[i].top - half_spacing) && y < (slots[i].bottom + half_spacing) && x > (slots[i].left - half_spacing) && x < (slots[i].right + half_spacing)) {
|
|
|
|
|
return i;
|
|
|
|
|
@@ -1389,6 +1464,7 @@ function onidle(x,y,but,cmd,shift,capslock,option,ctrl)
|
|
|
|
|
option_hold = option;
|
|
|
|
|
redraw_flag = true;
|
|
|
|
|
}
|
|
|
|
|
last_hovered_is_preset_slot = scrollable && nbslot_edit && last_hovered > (true_slots_count_display - 2) ? false : true;
|
|
|
|
|
if (redraw_flag) {
|
|
|
|
|
mgraphics.redraw();
|
|
|
|
|
}
|
|
|
|
|
@@ -1409,6 +1485,19 @@ onidleout.local = 1;
|
|
|
|
|
|
|
|
|
|
function onclick(x,y,but,cmd,shift,capslock,option,ctrl)
|
|
|
|
|
{
|
|
|
|
|
if (scrollable && nbslot_edit) {
|
|
|
|
|
if (last_hovered == true_slots_count_display - 1) {
|
|
|
|
|
setmin_rows(min_rows-1);
|
|
|
|
|
y_offset = -1 * (bg_height - ui_height);
|
|
|
|
|
mgraphics.redraw();
|
|
|
|
|
return
|
|
|
|
|
} else if (last_hovered == true_slots_count_display) {
|
|
|
|
|
setmin_rows(min_rows+1);
|
|
|
|
|
y_offset = -1 * (bg_height - ui_height);
|
|
|
|
|
mgraphics.redraw();
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (is_typing_name) {
|
|
|
|
|
restore_textedit();
|
|
|
|
|
}
|
|
|
|
|
@@ -1485,9 +1574,13 @@ function ondrag(x,y,but,cmd,shift,capslock,option,ctrl)
|
|
|
|
|
|
|
|
|
|
} else if (is_dragging == 1) {
|
|
|
|
|
last_hovered = get_slot_index(x, y);
|
|
|
|
|
last_hovered_is_preset_slot = scrollable && nbslot_edit && last_hovered > (true_slots_count_display - 2) ? false : true;
|
|
|
|
|
if (!last_hovered_is_preset_slot) {
|
|
|
|
|
last_hovered = 0;
|
|
|
|
|
}
|
|
|
|
|
if (!but) {
|
|
|
|
|
// When the button is released, the dragging ceases
|
|
|
|
|
if (last_hovered > 0 && last_hovered != drag_slot) {
|
|
|
|
|
if (last_hovered > 0 && last_hovered != drag_slot && last_hovered_is_preset_slot) {
|
|
|
|
|
var cur_active_slot = active_slot;
|
|
|
|
|
var cur_prev_active_slot = previous_active_slot;
|
|
|
|
|
var offset = ((last_hovered <= drag_slot) && slots[last_hovered].name != null) ? 1 : 0;
|
|
|
|
|
@@ -1614,6 +1707,10 @@ function get_prect(prect) {
|
|
|
|
|
}
|
|
|
|
|
get_prect.local = 1;
|
|
|
|
|
|
|
|
|
|
function notifydeleted(){
|
|
|
|
|
poll_edited_task.freepeer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ATTRIBUTES DECLARATION
|
|
|
|
|
// If loaded in JSUI, only the first 4 arguments passed in declareattribute() will be used (no attribute styling). V8UI will also use the latest object argument.
|
|
|
|
|
declareattribute("pattrstorage", "getpattrstorage","setpattrstorage", 1, {type: "symbol", label: "Pattrstorage"});
|
|
|
|
|
@@ -2114,6 +2211,72 @@ function setui_rename(v){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
declareattribute("poll_edited", "getpoll_edited", "setpoll_edited", 1, {type: "float", min: 0, label: "Poll Edited State"});
|
|
|
|
|
function getpoll_edited() {
|
|
|
|
|
return poll_edited;
|
|
|
|
|
}
|
|
|
|
|
function setpoll_edited(v){
|
|
|
|
|
poll_edited = v == 0 ? 0 : Math.max(0.1, Math.abs(v));
|
|
|
|
|
if (poll_edited > 0) {
|
|
|
|
|
run_edited_poll_task();
|
|
|
|
|
} else {
|
|
|
|
|
cancel_edited_poll_task();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function run_edited_poll_task() {
|
|
|
|
|
if (poll_edited_task.valid && !poll_edited_task.running && poll_edited > 0 && active_slot > 0) {
|
|
|
|
|
poll_edited_task.interval = poll_edited * 1000;
|
|
|
|
|
post("run task!\n");
|
|
|
|
|
poll_edited_task.repeat();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
run_edited_poll_task.local = 1;
|
|
|
|
|
|
|
|
|
|
function cancel_edited_poll_task() {
|
|
|
|
|
poll_edited_task.cancel();
|
|
|
|
|
}
|
|
|
|
|
cancel_edited_poll_task.local = 1;
|
|
|
|
|
|
|
|
|
|
function do_poll_edited() {
|
|
|
|
|
if (pattrstorage_obj != null) {
|
|
|
|
|
to_pattrstorage("getedited");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
do_poll_edited.local = 1;
|
|
|
|
|
|
|
|
|
|
declareattribute("edited_color", "getedited_color", "setedited_color", 1, {style: "rgba", label: "Edited Dot Color", category: "Appearance"});
|
|
|
|
|
function getedited_color() {
|
|
|
|
|
return edited_color;
|
|
|
|
|
}
|
|
|
|
|
function setedited_color(){
|
|
|
|
|
if (arguments.length == 4) {
|
|
|
|
|
edited_color = [arguments[0], arguments[1], arguments[2], arguments[3]];
|
|
|
|
|
} else if (arguments.length == 0) {
|
|
|
|
|
edited_color = [1, 0.49, 0.263, 1];
|
|
|
|
|
} else {
|
|
|
|
|
error('edited_color: wrong number of arguments\n');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function edited(v) {
|
|
|
|
|
active_slot_edited = v;
|
|
|
|
|
if (v == 1) {
|
|
|
|
|
cancel_edited_poll_task();
|
|
|
|
|
mgraphics.redraw();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
declareattribute("nbslot_edit", "getnbslot_edit", "setnbslot_edit", 1, {style: "onoff", label: "Rename In UI"});
|
|
|
|
|
function getnbslot_edit() {
|
|
|
|
|
return nbslot_edit;
|
|
|
|
|
}
|
|
|
|
|
function setnbslot_edit(v){
|
|
|
|
|
nbslot_edit = v > 0;
|
|
|
|
|
y_offset = 0;
|
|
|
|
|
calc_rows_columns();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UTILITY
|
|
|
|
|
function post_keys(obj) {
|
|
|
|
|
post('Keys of obj: ', obj, '\n');
|
|
|
|
|
|