Compare commits

...

9 Commits

  1. 2
      README.md
  2. 458
      code/tc.preset.js
  3. 23
      docs/tc.preset.maxref.xml
  4. 1386
      help/tc.preset.maxhelp
  5. 1673
      patchers/tc.preset_demo.maxpat

2
README.md

@ -17,7 +17,7 @@ A [jsui] replacement for the [preset] object in Cycling'74 Max.
- More look customization
- Dynamically adapts to resize both in Edit and Presentation mode
- Select mode: simple click selects the slot, double click recalls it (allows for organizing presets without recalling them)
- Color mode: ability to color sstored presets with 6 customizable colors (currently colors are only assigned automatically depending on slot number)
- Color mode: various ways to colorize preset slots
## How to install
- [Download](https://github.com/Teufeuleu/tc.preset/archive/refs/heads/main.zip) this repository (and please consider donating on the [gumroad page](https://glucose47.gumroad.com/l/tc_preset) if you like this package)

458
code/tc.preset.js

@ -73,7 +73,7 @@ var auto_writeagain = 0; // When enabled, will send a "writeagain" to pattrst
var menu_number_only = 0; // Populates the umenu connected to 2nd outlet with stored preset number only, instead of number and name
var scrollable = 1; // Defines weither the object can be scrolled or not
var min_rows = 50; // Minimum number of rows to display if scrollable is enabled
var color_mode = 0; // Change the way the filled slots (stored presets) color is handeld. 0: stored_slot_color. 1: looping through color_1 to color_6
var color_mode = 0; // Change the way the filled slots (stored presets) color is handeld. 0: stored_slot_color. 1: looping through color_1 to color_6. 2: Freely assign colors 1 to 6. 3: Set any color to any preset
var select_mode = 0; // 0: single click to select and recall the slot. 1: single click to select the slot, double click to recall it.
// (WORK)
@ -105,6 +105,14 @@ var shift_hold, option_hold = 0;
var is_interpolating = 0;
var is_dragging = 0; // Drag flag
var drag_slot = -1; // Stores the slot that's being dragged
var is_writing = 0;
// Keeping track of various variables for dealing with color modes
var requested_slot = -1; // Which slot we're waiting a value for (used in get_all_preset_colors)
var color_mode_candidate = 0; // Which color mode we're aiming
var is_listening_to_subscriptionlist = 0; //Filters out received subscriptionlist messages when not updating slot color values
var is_listening_to_clientlist = 0; //Filters out received clientlist messages when not updating slot color values
var color_pattr;
var has_loaded = false;
@ -113,6 +121,42 @@ if (jsarguments.length>1) { // Depreciated, use "pattrstorage" attribute instead
}
// FUNCTIONS
function slot(left, top, right, bottom, name, lock, interp, color_index, color_custom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.name = name;
this.lock = lock;
this.interp = interp;
this.color_index = color_index;
this.color_custom = color_custom;
this.init = function() {
this.left = 0;
this.top = 0;
this.right = 0;
this.bottom = 0;
this.name = null;
this.lock = 0;
this.interp = -1;
this.init_color();
}
this.init_color = function() {
this.color_index = 0;
this.color_custom = stored_slot_color;
}
this.clear = function() {
this.name = null;
this.lock = 0;
this.interp = -1;
this.color_index = 0;
this.color_custom = stored_slot_color;
}
}
function loadbang() {
// post("loadbang\n");
has_loaded = true;
@ -125,7 +169,7 @@ function calc_rows_columns() {
half_spacing = spacing / 2;
half_slot_size = slot_size / 2;
slots[0] = [0, 0, 0, 0, "(tmp)", 0, -1]; // Slot 0 is valid, but not represented in the GUI (and never saved by pattrstorage)
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)
if (layout == 0) {
columns = Math.floor((ui_width - margin + spacing) / (slot_size + spacing));
@ -147,22 +191,19 @@ function calc_rows_columns() {
var left = margin + j * (spacing+slot_size);
var right = left + slot_size;
var cur = 1 + i * columns + j;
var prev_name = null;
var prev_lock = 0;
var prev_interp = -1;
// var prev_name = null;
// var prev_lock = 0;
// var prev_interp = -1;
var prev_state = new slot();
prev_state.init();
if (typeof slots[cur] !== 'undefined') {
prev_name = slots[cur][4];
prev_lock = slots[cur][5];
prev_interp = slots[cur][6];
prev_state = slots[cur];
// prev_name = slots[cur].name;
// prev_lock = slots[cur].lock;
// prev_interp = slots[cur].interp;
}
slots[cur] = [left, top, right, bottom, prev_name, prev_lock, prev_interp];
//0: left position
//1: top position
//2: right position
//3: bottom position
//4: name, null if nothing stored on that slot
//5: lock state
//6: is being interpolated (0 or 1)
slots[cur] = new slot(left, top, right, bottom, prev_state.name, prev_state.lock, prev_state.interp, prev_state.color_index, prev_state.color_custom);
}
}
@ -170,7 +211,8 @@ function calc_rows_columns() {
if (slots_count_display < slots_highest) {
for (var i = slots_count_display + 1; i <= slots_highest; i++) {
slots[i] = [0, 0, 0, 0, null, 0, -1];
slots[i] = new slot();
slots[i].init();
}
}
paint_base();
@ -185,21 +227,21 @@ function draw_slot(id, scale, cont) {
if(is_painting_base) {
draw_slot_bubble(slots[id][0] * scale, slots[id][1] *scale, slot_size * scale, slot_size * scale, cont);
draw_slot_bubble(slots[id].left * scale, slots[id].top *scale, slot_size * scale, slot_size * scale, cont);
} else {
draw_slot_bubble(slots[id][0] + offset, slots[id][1] + offset, slot_size * scale, slot_size * scale, cont);
draw_slot_bubble(slots[id].left + offset, slots[id].top + 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];
var bg_txt_pos_y = slots[id].top;
var bg_txt_dim_w = ui_width - (2*margin + slot_size + spacing);
var bg_txt_dim_h = slot_size;
if (slots[id][4] != null) {
if (slots[id].name != null) {
cont.set_source_rgba(stored_slot_color);
} else {
cont.set_source_rgba(empty_slot_color);
@ -252,12 +294,12 @@ draw_text_bubble.local = 1;
function format_slot_name(id) {
var text = id;
// If slot is locked, add brackets around its number
if (slots[id][5] == 1) {
if (slots[id].lock == 1) {
text = '[' + text + ']';
}
// If slot has a name, append it to the preset name
if (slots[id][4] != null) {
text += ': ' + slots[id][4];
if (slots[id].name != null) {
text += ': ' + slots[id].name;
}
text = text.toString();
return text;
@ -284,9 +326,13 @@ function paint_base() {
// All slots
for (var i = 1; i <= 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][4] != null) {
if (color_mode) {
if (slots[i].name != null) {
if (color_mode == 1) {
set_source_rgba(color_wheel_custom[i % color_wheel_size]);
} else if (color_mode == 2) {
set_source_rgba(color_wheel_custom[Math.abs(slots[i].color_index) % color_wheel_size]);
} else if (color_mode == 3) {
set_source_rgba(slots[i].color_custom);
} else {
set_source_rgba(stored_slot_color);
}
@ -329,11 +375,11 @@ function paint()
if (is_dragging == 0 && active_slot > 0 && active_slot <= slots_count_display) {
set_source_rgba(active_slot_color);
if (color_mode) {
draw_slot_bubble(slots[active_slot][0]+1.5, slots[active_slot][1]+1.5, slot_size-3, slot_size-3);
draw_slot_bubble(slots[active_slot].left+1.5, slots[active_slot].top+1.5, slot_size-3, slot_size-3);
set_line_width(3);
stroke();
} else {
draw_slot_bubble(slots[active_slot][0], slots[active_slot][1], slot_size, slot_size);
draw_slot_bubble(slots[active_slot].left, slots[active_slot].top, slot_size, slot_size);
fill();
}
}
@ -346,11 +392,11 @@ function paint()
// stroke();
set_source_rgba(active_slot_color[0], active_slot_color[1], active_slot_color[2], active_slot_color[3] * 0.5);
if (color_mode) {
draw_slot_bubble(slots[previous_active_slot][0]+1.5, slots[previous_active_slot][1]+1.5, slot_size-3, slot_size-3);
draw_slot_bubble(slots[previous_active_slot].left+1.5, slots[previous_active_slot].top+1.5, slot_size-3, slot_size-3);
set_line_width(3);
stroke();
} else {
draw_slot_bubble(slots[previous_active_slot][0], slots[previous_active_slot][1], slot_size, slot_size);
draw_slot_bubble(slots[previous_active_slot].left, slots[previous_active_slot].top, slot_size, slot_size);
fill();
}
}
@ -359,7 +405,7 @@ function paint()
if (selected_slot > 0 && selected_slot <= slots_count_display) {
set_source_rgba(active_slot_color);
set_line_width(1);
draw_slot_bubble(slots[selected_slot][0] - 0.5, slots[selected_slot][1] - 0.5, slot_size + 1, slot_size + 1);
draw_slot_bubble(slots[selected_slot].left - 0.5, slots[selected_slot].top - 0.5, slot_size + 1, slot_size + 1);
stroke();
}
@ -367,12 +413,12 @@ function paint()
if (is_dragging == 0 && display_interp && is_interpolating) {
for (var i = 1; i <= slots_count_display; i++) {
var interp = slots[i][6];
var interp = slots[i].interp;
if (interp >= 0) {
set_source_rgba(interp_slot_color);
draw_slot_bubble(slots[i][0], slots[i][1], slot_size, slot_size);
draw_slot_bubble(slots[i].left, slots[i].top, slot_size, slot_size);
stroke();
draw_slot_bubble(slots[i][0], slots[i][1] + slot_size * (1-interp), slot_size, slot_size * interp);
draw_slot_bubble(slots[i].left, slots[i].top + slot_size * (1-interp), slot_size, slot_size * interp);
fill();
}
}
@ -384,18 +430,18 @@ function paint()
if (option_hold) {
// About to delete
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);
draw_slot_bubble(slots[last_hovered].left + 1, slots[last_hovered].top + 1, slot_size-2, slot_size-2);
fill();
} else {
// About to store
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);
draw_slot_bubble(slots[last_hovered].left + 1, slots[last_hovered].top + 1, slot_size-2, slot_size-2);
fill();
}
}
// Slot border
set_source_rgba(1, 1, 1, 0.8);
draw_slot_bubble(slots[last_hovered][0], slots[last_hovered][1], slot_size, slot_size);
draw_slot_bubble(slots[last_hovered].left, slots[last_hovered].top, slot_size, slot_size);
stroke();
if (layout == 0) {
@ -407,13 +453,13 @@ function paint()
var bg_txt_dim_w = text_dim[0] > slot_size ? text_dim[0] + 4 : slot_size + 4;
var bg_txt_dim_h = text_dim[1] > slot_size ? text_dim[1] + 4 : slot_size + 4;
var bg_txt_pos_x = text_dim[0] > slot_size || is_dragging ? slots[last_hovered][0] + slot_size + 2: slots[last_hovered][0] - 2;
var bg_txt_pos_y = text_dim[1] > slot_size || is_dragging ? slots[last_hovered][1] - 2 : slots[last_hovered][1] - 2;
var bg_txt_pos_x = text_dim[0] > slot_size || is_dragging ? slots[last_hovered].left + slot_size + 2: slots[last_hovered].left - 2;
var bg_txt_pos_y = text_dim[1] > slot_size || is_dragging ? slots[last_hovered].top - 2 : slots[last_hovered].top - 2;
// If there is not enough place, text is displayed on the left
if (bg_txt_pos_x + bg_txt_dim_w > ui_width) {
bg_txt_pos_x = slots[last_hovered][0] - half_spacing - bg_txt_dim_w;
bg_txt_pos_x = slots[last_hovered].left - half_spacing - bg_txt_dim_w;
}
var txt_pos_x = text_dim[0] > slot_size ? bg_txt_pos_x + half_spacing : bg_txt_pos_x + (bg_txt_dim_w / 2) - (text_dim[0]/2);
@ -482,6 +528,7 @@ function color_wheel() {
// But that makes the code sooo ugly...
var args = arrayfromargs(arguments);
if (args.length == 0) {
// Reset to default
color_wheel_custom = [];
color_wheel_custom = color_wheel_default.slice();
color_1 = color_wheel_default[0];
@ -491,6 +538,7 @@ function color_wheel() {
color_5 = color_wheel_default[4];
color_6 = color_wheel_default[5];
} else if (args.length == 5) {
// Set color
var n = args[0];
var col = [args[1], args[2], args[3], args[4]]
if (n > 0 && n < 7) {
@ -522,6 +570,99 @@ function color_wheel() {
paint_base();
}
function setcolor() {
if (preset_color_pattr_exist()) {
var args = arrayfromargs(arguments);
var nb_args = args.length;
var slot_nb = selected_slot;
if (nb_args < 1 && nb_args > 5) {
error("color: wrong number of arguments.");
} else {
if (nb_args == 0) {
// Reset colors of selected slot to default values
slots[selected_slot].init_color();
} else if (nb_args == 1) {
// Set the color index of the currently selected slot (for when color_mode is 2)
slots[selected_slot].color_index = Math.floor(args);
} else if (nb_args == 2) {
// Set the color index to the 2nd argument for the slot number defined by the 1st argument
slot_nb = Math.floor(args[0]);
slots[slot_nb].color_index = Math.floor(args[1]);
} else if (nb_args == 4) {
// Set the custom color of the currently selected slot (for when color_mode is 3)
slots[selected_slot].color_custom = [args[0], args[1], args[2], args[3]];
} else if (nb_args == 5) {
// Set the custom color for the slot number defined by the 1st argument to the color defined by following arguments in rgba format.
slot_nb = Math.floor(args[0]);
slots[slot_nb].color_custom = [args[1], args[2], args[3], args[4]];
}
update_preset_color_pattr(slot_nb);
paint_base();
trigger_writeagain();
}
}
}
function preset_color_pattr_exist() {
var obj = this.patcher.getnamed("preset_color");
if (!obj) {
error("preset_color pattr not found.\n");
color_pattr = 0;
return false;
} else if (obj.maxclass != "pattr"){
error("preset_color named object is not a pattr object.\n");
color_pattr = 0;
return false;
} else if (obj.getattr('invisible') == 1) {
error("preset_color has been found but has invisible attribute set to 1\n");
color_pattr = 0;
return false;
} else {
color_pattr = obj;
return true;
}
}
preset_color_pattr_exist.local = 1;
function update_preset_color_pattr(s) {
var cstm = slots[s].color_custom;
to_pattrstorage("setstoredvalue", "preset_color", s, slots[s].color_index, cstm[0], cstm[1], cstm[2], cstm[3]);
}
update_preset_color_pattr.local = 1
function get_all_preset_colors() {
if (filled_slots.length) {
for (var i = 0; i < filled_slots.length; i++) {
get_preset_color(filled_slots[i]);
}
requested_slot = -1;
}
}
get_all_preset_colors.local = 1;
function get_preset_color(s) {
requested_slot = s;
to_pattrstorage("getstoredvalue", "preset_color", s);
}
get_preset_color.local = 1;
function preset_color() {
var args = arrayfromargs(arguments);
// post(pattrstorage_name, "preset_color", args, '----- args.length: ', args.length, '----- requested_slot: ', requested_slot,'\n');
if (args.length == 5) {
var col = Math.max(0, Math.floor(args[0])) % color_wheel_size;
slots[requested_slot].color_index = col;
slots[requested_slot].color_custom = [args[1], args[2], args[3], args[4]];
} else if (args.length == 4) {
slots[requested_slot].color_index = 0;
slots[requested_slot].color_custom = args;
} else if (args.length == 1) {
var col = Math.max(0, Math.floor(args)) % color_wheel_size;
slots[requested_slot].color_index = col;
slots[requested_slot].color_custom = stored_slot_color;
}
}
function anything() {
// Here just to avoid error messages in case pattrstorage sends unhandled message, like when using getstoredvalue, getsubscriptionlist, getalias, etc.
@ -530,11 +671,11 @@ function anything() {
var v = arrayfromargs(arguments)[0];
v = Math.floor(v);
if (v >= 0) {
if (slots[v][5] > 0) {
if (slots[v].lock > 0) {
error('cannot delete locked slot ' + v + '\n');
} else {
slots[v][4] = null;
slots[v][6] = -1;
slots[v].name = null;
slots[v].interp = -1;
if (active_slot == v) {
active_slot = 0;
} else if (previous_active_slot == v) {
@ -598,19 +739,21 @@ function slotlist() {
slots_highest = filled_slots[filled_slots.length - 1];
if (slots_count_display < slots_highest) {
for (var i = slots_count_display + 1; i <= slots_highest; i++) {
slots[i] = [0, 0, 0, 0, null, 0, -1];
slots[i] = new slot();
slots[i].init();
}
}
for (var i = 0; i < filled_slots.length; i++) {
to_pattrstorage("getslotname", filled_slots[i]);
}
get_all_preset_colors();
}
}
function slotname() {
var args = arrayfromargs(arguments);
if (args[0] > 0 && args[1] != "(undefined)") {
slots[args[0]][4] = args[1];
slots[args[0]].name = args[1];
}
}
@ -640,57 +783,62 @@ function recall() {
is_interpolating = 0;
set_active_slot(args[0]);
outlet(0, 'recall', args[0]);
} else {
var src_slot = args[0];
var trg_slot = args[1];
for (var i = 0; i < filled_slots.length; i++) {
slots[filled_slots[i]][6] = -1;
}
if (slots[src_slot][4] != null && slots[trg_slot][4] != null) {
if (ignore_slot_zero == 1 && src_slot == 0) {
// Set src_slot as if we were interpolating from the last recalled preset different than 0
// This way we can monitor which preset we come from even if we used preset 0 as intermediary preset
if (previous_target != active_slot) {
// If the last target preset was through interpollation or direct recall
src_slot = previous_active_slot;
} else {
src_slot = active_slot;
}
} else if (args.length == 2) {
if (typeof(args[0]) == 'number') {
var src_slot = args[0];
var trg_slot = args[1];
for (var i = 0; i < filled_slots.length; i++) {
slots[filled_slots[i]].interp = -1;
}
var interp = Math.min( 1, Math.max(0, args[2]));
if (interp == 0.0) {
slots[src_slot][6] = -1;
slots[trg_slot][6] = -1;
is_interpolating = 0;
if (previous_target != active_slot) {
previous_active_slot = active_slot;
} else if (args[0] != 0) {
previous_active_slot = args[0];
if (slots[src_slot].name != null && slots[trg_slot].name != null) {
if (ignore_slot_zero == 1 && src_slot == 0) {
// Set src_slot as if we were interpolating from the last recalled preset different than 0
// This way we can monitor which preset we come from even if we used preset 0 as intermediary preset
if (previous_target != active_slot) {
// If the last target preset was through interpollation or direct recall
src_slot = previous_active_slot;
} else {
src_slot = active_slot;
}
}
var interp = Math.min( 1, Math.max(0, args[2]));
if (interp == 0.0) {
slots[src_slot].interp = -1;
slots[trg_slot].interp = -1;
is_interpolating = 0;
if (previous_target != active_slot) {
previous_active_slot = active_slot;
} else if (args[0] != 0) {
previous_active_slot = args[0];
} else {
previous_active_slot = previous_target;
}
set_active_slot(src_slot);
} 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);
} else {
previous_active_slot = previous_target;
slots[src_slot].interp = 1 - interp;
slots[trg_slot].interp = interp;
is_interpolating = 1;
active_slot = 0;
// set_active_slot(0);
}
set_active_slot(src_slot);
} else if (interp == 1.0) {
slots[src_slot][6] = -1;
slots[trg_slot][6] = -1;
is_interpolating = 0;
previous_target = trg_slot;
set_active_slot(trg_slot);
} else {
slots[src_slot][6] = 1 - interp;
slots[trg_slot][6] = interp;
is_interpolating = 1;
active_slot = 0;
// set_active_slot(0);
outlet(0, "recall", src_slot, trg_slot, interp);
}
outlet(0, "recall", src_slot, trg_slot, interp);
}
// else {
// //typeof(args[0]) == 'string', so user just recalled a single parameter.
// }
}
@ -711,12 +859,12 @@ function recallmulti() {
for (var i = 0; i < interp_slots.length; i++) {
var nb = interp_slots[i][0];
if (slots[nb][4] != null) {
if (slots[nb].name != null) {
interp_slots[i][1] /= summed_weight;
} else {
interp_slots[i][1] = -1;
}
slots[nb][6] = interp_slots[i][1]
slots[nb].interp = interp_slots[i][1]
}
is_interpolating = 1;
@ -729,11 +877,16 @@ function recallmulti() {
function store(v) {
v = Math.floor(v);
if (v >= 0) {
if (slots[v][5] > 0) {
if (slots[v].lock > 0) {
error('cannot overwrite locked slot ' + v + '\n');
} else {
var recalc_rows_flag = scrollable && v > slots_highest;
if (color_pattr) {
//Initialize preset color to default for new preset
color_pattr.message(0);
}
to_pattrstorage("store", v);
to_pattrstorage("getslotlist");
@ -749,6 +902,7 @@ function store(v) {
outlet(0, "store", v);
if (v) {
// We writagain only if stored preset is > 0
trigger_writeagain();
}
}
@ -775,11 +929,11 @@ function lock() {
function lockedslots() {
var locked_slots = arrayfromargs(arguments);
for (var i = 1; i < slots.length; i++) {
slots[i][5] = 0;
slots[i].lock = 0;
}
if (locked_slots.length) {
for (var i = 0; i < locked_slots.length; i++) {
slots[locked_slots[i]][5] = 1;
slots[locked_slots[i]].lock = 1;
if (locked_slots[i] == selected_slot) {
select(selected_slot);
}
@ -788,14 +942,20 @@ function lockedslots() {
}
function write() {
var args = arrayfromargs(arguments);
var filename = args[0];
var state = args[1];
if (state) {
post(pattrstorage_name + ' pattrstorage: ' + filename + ' updated\n');
if (is_writing) {
is_writing = 0;
var args = arrayfromargs(arguments);
var filename = args[0];
var state = args[1];
if (state) {
post(pattrstorage_name + ' pattrstorage: ' + filename + ' updated\n');
} else {
error(pattrstorage_name + ': error while writing ' + filename + '\n');
}
} else {
error(pattrstorage_name + ': error while writing ' + filename + '\n');
error("Send your write messages directly to the pattrstorage instead.\n");
}
}
function read() {
@ -806,6 +966,37 @@ function read() {
}
}
function subscriptionlist() {
var client = arrayfromargs(arguments)[0];
if (is_listening_to_subscriptionlist) {
if (client == "preset_color") {
// [pattr preset_color] subscribed
// post("preset_color pattr object found and subscribed to bound pattrstorage. Switching to color mode", color_mode_candidate, '\n');
is_listening_to_subscriptionlist = 0;
color_mode = color_mode_candidate;
paint_base();
} else if (client == "done") {
error("A [pattr preset_color] object has been found but it isn't subscribed to your pattrstorage. Please add it to your subscribelist and try changing color mode again.\n")
is_listening_to_subscriptionlist = 0;
}
}
}
function clientlist() {
var client = arrayfromargs(arguments)[0];
if (is_listening_to_clientlist) {
if (client == "preset_color") {
// post("preset_color pattr object found and client to bound pattrstorage. Switching to color mode", color_mode_candidate, '\n');
is_listening_to_clientlist = 0;
color_mode = color_mode_candidate;
paint_base();
} else if (client == "done") {
error("A [pattr preset_color] object has been found but seems to be invisible to the pattrstorage.\n")
is_listening_to_clientlist = 0;
}
}
}
function resync() {
set_active_slot(0);
slots_clear();
@ -849,20 +1040,19 @@ function select(v) {
selected_slot = v;
set_umenu(selected_slot);
if (selected_slot != 0) {
outlet(2, "set", slots[selected_slot][4]);
outlet(2, "set", slots[selected_slot].name);
} else {
outlet(2, "set");
}
outlet(3, "set", slots[selected_slot][5]);
outlet(3, "set", slots[selected_slot].lock);
}
}
function slots_clear() {
slots[0] = [0, 0, 0, 0, "(tmp)", 0, -1];
slots[0].init();
slots[0].name = "(tmp)";
for (var i = 1; i < slots.length; i++) {
slots[i][4] = null;
slots[i][5] = 0;
slots[i][6] = -1;
slots[i].clear();
}
}
slots_clear.local = 1;
@ -870,7 +1060,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++) {
if (y > (slots[i][1] - half_spacing) && y < (slots[i][3] + half_spacing) && x > (slots[i][0] - half_spacing) && x < (slots[i][2] + half_spacing)) {
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;
}
@ -899,7 +1089,7 @@ function update_umenu() {
var nb = filled_slots[i];
var txt = null;
if (!menu_number_only) {
txt = slots[filled_slots[i]][4];
txt = slots[filled_slots[i]].name;
}
outlet(1, "append", nb, txt);
}
@ -914,12 +1104,13 @@ function set_umenu(v) {
if (menu_number_only) {
outlet(1, "setsymbol", v);
} else {
outlet(1, "setsymbol", v + ' ' + slots[v][4]);
outlet(1, "setsymbol", v + ' ' + slots[v].name);
}
}
function trigger_writeagain() {
if (auto_writeagain && !is_dragging) {
is_writing = 1;
to_pattrstorage("writeagain");
}
@ -969,7 +1160,7 @@ function onclick(x,y,but,cmd,shift,capslock,option,ctrl)
if (option) {
output = "delete";
}
} else if (slots[last_hovered][4] == null) {
} else if (slots[last_hovered].name == null) {
return;
}
if (output == "store") {
@ -1004,7 +1195,7 @@ function ondrag(x,y,but,cmd,shift,capslock,option,ctrl)
{
if (pattrstorage_name != null) {
y -= y_offset;
if (is_dragging == 0 && last_hovered > 0 && slots[last_hovered][4] !== null) {
if (is_dragging == 0 && last_hovered > 0 && slots[last_hovered].name !== null) {
// To prevent mistakes, is_dragging is set to 1 only when dragging for more than 10 pixels
var dist_from_start = Math.sqrt((x-last_x)*(x-last_x)+(y-last_y)*(y-last_y));
if (dist_from_start > 10) {
@ -1018,19 +1209,19 @@ function ondrag(x,y,but,cmd,shift,capslock,option,ctrl)
last_x = x;
last_y = y;
if (!but) {
// Wehen to button is released, the dragging ceases
// When the button is released, the dragging ceases
if (last_hovered > 0 && last_hovered != drag_slot) {
var cur_active_slot = active_slot;
var cur_prev_active_slot = previous_active_slot;
var offset = ((last_hovered <= drag_slot) && slots[last_hovered][4] != null) ? 1 : 0;
var offset_others = slots[last_hovered][4] != null ? 1 : 0;
var drag_slot_lock = slots[drag_slot][5];
var offset = ((last_hovered <= drag_slot) && slots[last_hovered].name != null) ? 1 : 0;
var offset_others = slots[last_hovered].name != null ? 1 : 0;
var drag_slot_lock = slots[drag_slot].lock;
// If the slot we wan to drag is locked, we need to temporarily unlock it.
if (drag_slot_lock) {
lock(drag_slot, 0);
}
// If new slot is empty we just move the drag preset here. If it's not, we move al next slots to the right
if (slots[last_hovered][4] !== null) {
if (slots[last_hovered].name !== null) {
to_pattrstorage("insert", last_hovered);
}
@ -1115,6 +1306,7 @@ if (ui_width == 64 && ui_height == 64) {
// Allows for dynamic resizing even in presentation mode (addressing the limitation of onresize())
var pres_rect = new MaxobjListener(this.box,"presentation_rect",get_prect);
function get_prect(prect) {
// post(this.patcher.wind.assoc.getattr("globalpatchername") == max.frontpatcher.wind.assoc.getattr("globalpatchername") ? 1 : 0, "\n")
onresize(prect.value[2], prect.value[3])
}
get_prect.local = 1;
@ -1450,12 +1642,34 @@ function getcolor_mode() {
return color_mode;
}
function setcolor_mode(v){
if (v == 1) {
color_mode = 1;
v = Math.floor(v);
v = Math.max(0, Math.min(3, v));
// For color modes 2 and 3 (select and custom),
// we need to ensure there's a [pattr preset_color] somewhere to store the preset color
if (v >= 2 ) {
if (!preset_color_pattr_exist()) {
v = 0;
color_mode = v;
paint_base();
} else {
if (pattrstorage_obj != null && pattrstorage_obj.getattr('subscribemode') == 1) {
// If the pattrstorage is in subscribe mode, we need to query its subscription list,
// ...and wait for the result to continue (see function subscribelist)
post(pattrstorage_name, "subscribe mode detected. Checking for subscribed 'preset_color' client.\n");
is_listening_to_subscriptionlist = 1;
color_mode_candidate = v;
to_pattrstorage("getsubscriptionlist");
} else {
// If not in subscribe mode
is_listening_to_clientlist = 1;
color_mode_candidate = v;
to_pattrstorage("getclientlist");
}
}
} else {
color_mode = 0;
color_mode = v;
paint_base();
}
paint_base();
}
declareattribute("color_1", "getcolor1", "setcolor1", 1);

23
docs/tc.preset.maxref.xml

@ -53,12 +53,23 @@
<description>Function depends on inlet</description>
</method> -->
<method name="color_wheel">
<digest>Set the slot colors</digest>
<digest>Define color wheel colors</digest>
<description>The message "color_wheel", followed by an integer and four float, defines one of the 6 available slot colors when color_mode is enabled.
The integer argument, between 1 and 6, defines which color in being modifier, and next the four floats define the color in the RGBA format.
The integer argument, between 1 and 6, defines which color in being modified, and next the four floats define the color in the RGBA format.
The message "color_wheel" without argument resets the six colors to their default values.
</description>
</method>
<method name="setcolor">
<digest>Set the preset colors</digest>
<description>The message "setcolor" allows to set the color of a preset as shown when in color_mode 2 (select) or 3 (custom).
With 1 or 2 integer arguments, it allows to set a preset color as seen in color mode 2. With 4 float arguments or 1 integer followed by 4 floats, it allows to set a preset color for the color mode 3.
With 1 integer argument, the currently selected preset color wheel's color is set to the argument's value.
With two integer arguments, the preset number defined by first argument is set to color wheel's color defined by the second argument.
With 4 float arguments, the currently selected preset is set to a custom color defined by the four arguments (in RGBA format).
With 1 integer followed by 4 float arguments, the preset number defined by first argument is set to a custom color defined by the four arguments (in RGBA format).
The integer argument, between 1 and 6, defines which color in being modifier, and next the four floats define the color in the RGBA format.
</description>
</method>
<method name="pattrstorage">
<digest>Link to named pattrstorage object</digest>
<description>The word 'pattrstorage' followed by the name of an existing pattrstorage links the jsui to that pattrstorage.
@ -113,7 +124,13 @@
</attribute>
<attribute name='color_mode' get='1' set='1' type='int' size='1' >
<digest>Color mode</digest>
<description>When set to 0, all preset slots have the same color (same as the preset object). When set to 1, stored preset slots are colored. See color_1 to color_6 as well as the color_wheel message.</description>
<description>When set to 0, all preset slots have the same color (same as the preset object) defined by the stored_slot_color attribute.
When set to 1, stored preset slots are colored according to one of the six colors of the color wheel, in a repeating pattern.
In mode 2, stored preset colors can be freely set to one of the six colors of the color wheel.
In mode 3, stored preset color can be set to any color in RGBA format.
To define colors of the color wheel for modes 1 and 2, see color_1 to color_6 as well as the color_wheel message.
To define preset color as in mode 2 or 3, see the setcolor message. Modes 2 and 3 require a pattr object named 'preset_color' to be at the same patcher level as the tc.preset object.
</description>
</attribute>
<attribute name='color_1' get='1' set='1' type='list' size='4' >
<digest>Slot color 1</digest>

1386
help/tc.preset.maxhelp

File diff suppressed because it is too large Load Diff

1673
patchers/tc.preset_demo.maxpat

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save