From f8416fec043381c8f3e783dc547eb1587fc1237d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Clet?= Date: Fri, 14 Jun 2024 20:26:34 +0200 Subject: [PATCH] initial commit --- .DS_Store | Bin 0 -> 6148 bytes tc.preset.js | 1118 +++++++++++++++++++++++++++++++++ tc.preset_demo.maxpat | 1382 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2500 insertions(+) create mode 100644 .DS_Store create mode 100644 tc.preset.js create mode 100755 tc.preset_demo.maxpat diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..315eb4aac2cb3581749781650405f294316cf4ca GIT binary patch literal 6148 zcmeH~JqiLr422W55Nx)zoW=uqgF*BJUO;rqg)PK>j_%733$E58@&d`5$tEoO6+06V z(Zi$Pi*zEghMUUH!ps!=rHnF2-`{V;bsUGOVv#GWfp;={J{5970wh2JBtQZr@G}JL z+=i_;p^PLz0wgdIu>V7Wo7U78>c0*I9|52%q}{OgSpr%t0j;Sm6d9OCD>Pcw#}LbV zJG5k7O>LpkE}FxK=9|@~7??)8Xu$@i)rElsNMJ@_8T-!8{}cSv{6A~qmIO%P&j{%1 zcs?HRQF*q$eV*knnYDF;L%kf~ - https://tflcl.xyz. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +autowatch = 0; +// When developping, autowatch = 1 isn't enough. You also need to manually call the loadbang function, and then re-binding the pattrstorage. +// A "loadbang, pattrstorage test" message does the trick. + +inlets = 1 +setinletassist(0, "Connect to the linked pattrstorage"); + +outlets = 4; +setoutletassist(0, "Outputs last triggered action"); +setoutletassist(1, "Connect to umenu to list stored presets"); +setoutletassist(2, "Connect to textedit to edit preset name"); +setoutletassist(3, "Connect to toggle to show active presets lock state") + +mgraphics.init(); +mgraphics.relative_coords = 0; +mgraphics.autofill = 0; + +// LOOK +var slot_size = 20; +var slot_round = 0; + +var margin = 4; +var spacing = 4; + +var font_size = 14; +var font_name = "Arial"; + +var background_color = [0.2, 0.2, 0.2, 1]; +var empty_slot_color = [0.349, 0.349, 0.349, 1]; +var active_slot_color = [0.808, 0.898, 0.910, 1]; +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]; + +// FEEL +var layout = 1; +var display_interp = 1; // Enable/disable the UI feedback when interpolating between presets +var ignore_slot_zero = 1; // Makes previous_active_slot and interpolation display to ignore slot 0. Can be usefull when using slot 0 as a temporary step for interpolation. +var auto_writeagain = 0; // When enabled, will send a "writeagain" to pattrstorage any time a preset is stored/deleted/moved/renamed/(un)locked +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 is scrollable is enabled + +// (WORK) +var pattrstorage_name, pattrstorage_obj = null; + +var columns, rows = 0; +var slots = []; +var slots_highest = 0; // Highest filled preset slot number +var slots_count_display = 0; +var filled_slots = []; + +var active_slot = 0; +var previous_active_slot = 0; +var previous_target = 0; + +var ui_width = box.rect[2] - box.rect[0]; +var ui_height = box.rect[3] - box.rect[1]; +var bg_width, bg_height = 0; + +var mg = new MGraphics(ui_width, ui_height); +var base_drawing; + +var half_slot_size, half_margin, half_spacing; +var last_x, last_y, last_hovered = -1; +var y_offset = 0; // handle scrolling +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 + +if (jsarguments.length>1) { + pattrstorage_name = jsarguments[1]; +} + +function loadbang() { + outlet(2, "set"); + find_pattrstorage(pattrstorage_name); + calc_rows_columns(); +} + +// loadbang(); + +function calc_rows_columns() { + half_margin = margin / 2; + 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) + + if (layout == 0) { + columns = Math.floor((ui_width - margin + spacing) / (slot_size + spacing)); + rows = Math.floor((ui_height - margin + spacing) / (slot_size + spacing)); + slots_count_display = columns * rows; + } else { + columns = 1; + rows = Math.floor((ui_height - margin + spacing) / (slot_size + spacing)); + if (scrollable) { + rows = Math.max(rows, Math.max(min_rows, slots_highest)); + } + slots_count_display = columns * rows; + } + + for (var i = 0; i < rows; i++) { + var top = margin + i * (spacing+slot_size); + var bottom = top + slot_size; + for (var j = 0; j < columns; j++) { + 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; + if (typeof slots[cur] !== 'undefined') { + prev_name = slots[cur][4]; + prev_lock = slots[cur][5]; + prev_interp = slots[cur][6]; + } + 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) + } + + } + + + 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]; + } + } + // outlet(0, "init"); + paint_base(); +} +calc_rows_columns.local = 1; + +function draw_slot(id, scale, cont) { + scale = typeof cont !== 'undefined' ? scale : 1; // Sets scale to 1 by default if not passed as argument + 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 ; + + // set_source_rgba(text_color); + // move_to(nb_pos_x, nb_pos_y); + // show_text(nb); + + // 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(bg_txt_pos_x, bg_txt_pos_y, bg_txt_dim_w, bg_txt_dim_h, 4, 4); + cont.fill(); + + + // slot name + if (1) { + + // if (slots[id][4] != null) { + 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()); + } + + } + +} +draw_slot.local = 1; + +function draw_slot_bubble (x, y, w, h, cont) { + cont = typeof cont !== 'undefined' ? cont : mgraphics; + + // I assume rectange is faster to draw than rectangle_rounded. Btw rectangle_rounded is wacky when showing interpolation. Maybe *interp on the first slot_round could solve this? + if (slot_round) { + cont.rectangle_rounded(x, y, w, h, slot_round, slot_round); + } else { + cont.rectangle(x, y, w, h); + } +} +draw_slot_bubble.local = 1; + +function paint_base() { + // We draw all slots (empty and stored ones) so we don't have to for every redraw + + // 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); + with(mg) { + set_source_rgba(background_color); + rectangle(0, 0, bg_width, bg_height); + fill(); + + select_font_face(font_name); + set_font_size(font_size); + + // All slots + 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(); + } + + // 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(); + + + // } + // } + } + update_umenu(); + base_drawing = new Image(mg); + mgraphics.redraw(); +} +paint_base.local = 1; + +function paint() +{ + // post("redraw\n"); + with (mgraphics) { + translate(0, y_offset); + // Draw the base, which includes empty and filled slots + image_surface_draw(base_drawing); + + set_line_width(1); + + // Active slot + if (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) { + 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) { + + for (var i = 1; i <= slots_count_display; i++) { + var interp = slots[i][6]; + if (interp >= 0) { + set_source_rgba(interp_slot_color); + draw_slot_bubble(slots[i][0], slots[i][1], slot_size, slot_size); + stroke(); + draw_slot_bubble(slots[i][0], slots[i][1] + slot_size * (1-interp), slot_size, slot_size * interp); + fill(); + } + } + } + + // Hovered slot + if (last_hovered > -1) { + if (shift_hold) { + 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); + 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); + 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); + stroke(); + + 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_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. + + var bg_txt_pos_x = text_dim[0] > slot_size || is_dragging ? slots[last_hovered][0] + slot_size + half_spacing : slots[last_hovered][0] - half_spacing; + var bg_txt_pos_y = text_dim[1] > slot_size || is_dragging ? slots[last_hovered][1] + (slot_size - text_dim[1]) / 2 - half_spacing : slots[last_hovered][1] - half_spacing; + var bg_txt_dim_w = text_dim[0] > slot_size ? text_dim[0] + spacing : slot_size + spacing; + var bg_txt_dim_h = text_dim[1] > slot_size ? text_dim[1] + spacing : slot_size + spacing; + + // 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; + } + + 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); + var txt_pos_y = bg_txt_pos_y + (bg_txt_dim_h - spacing + text_dim[1]) / 2 ; + + // Bubble background + set_source_rgba(text_bg_color); + rectangle_rounded(bg_txt_pos_x, bg_txt_pos_y, bg_txt_dim_w, bg_txt_dim_h, 4, 4); + fill(); + + // Buble text + set_source_rgba(text_color); + move_to(txt_pos_x, txt_pos_y); + show_text(text.toString()); + } + + } + + // Drag slot + if (is_dragging) { + translate(last_x, last_y ); + rotate(0.15); + scale(1.1, 1.1); + // scale(3, 3); + + // 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); + fill(); + } + draw_slot_bubble( 2-slot_size/2, 2-slot_size/2, slot_size, slot_size); + fill(); + set_source_rgba(stored_slot_color); + draw_slot_bubble( -slot_size/2, -slot_size/2, slot_size, slot_size); + fill(); + } + + } +} +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. + if (messagename == "delete") { + var v = arrayfromargs(arguments)[0]; + v = Math.floor(v); + if (v >= 0) { + if (slots[v][5] > 0) { + error('cannot delete locked slot ' + v + '\n'); + } else { + slots[v][4] = null; + slots[v][6] = -1; + if (active_slot == v) { + active_slot = 0; + } + + // to_pattrstorage("getslotname", v); + to_pattrstorage("delete", v); + to_pattrstorage("getslotlist"); + paint_base(); + set_active_slot(active_slot); + outlet(0, "delete", v); + trigger_writeagain(); + } + } + } +} + +function bang() +{ + to_pattrstorage("recall", active_slot); +} + +function msg_int(v) { + to_pattrstorage("recall", v); +} + +function msg_float(v) +{ + var s = Math.floor(v); + var i = v % 1; + to_pattrstorage("recall", s, s+1, i); +} + +function pattrstorage(v){ + find_pattrstorage(v); + paint_base(); +} + +function slotlist() { + filled_slots = arrayfromargs(arguments); + if (filled_slots.length) { + + // If the highest numbered preset is above the maximum number of displayed presets, we need to extend slots[] + 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]; + } + } + for (var i = 0; i < filled_slots.length; i++) { + to_pattrstorage("getslotname", filled_slots[i]); + } + } + // paint_base(); +} + +function slotname() { + var args = arrayfromargs(arguments); + if (args[0] > 0 && args[1] != "(undefined)") { + + slots[args[0]][4] = args[1]; + + } + +} + +function setslotname() { + // Because [pattrstorage] doesn't output anything when renaming presets with "slotname", we use a custom "setslotname" instead, that will rename the active preset + if (active_slot > 0) { + var sname = arrayfromargs(arguments).join(' '); + slotname(active_slot, sname); + to_pattrstorage("slotname", active_slot, sname); + update_umenu(); + set_active_slot(active_slot); + trigger_writeagain(); + if (layout == 1) { + paint_base(); + } + } +} + +function text() { + setslotname(arrayfromargs(arguments).join(' ')); +} + +function recall() { + var args = arrayfromargs(arguments); + if (args.length == 1) { + previous_active_slot = active_slot; + 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; + } + } + 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]; + } else { + previous_active_slot = previous_target; + } + + 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); + } + + } + + mgraphics.redraw(); +} + +function recallmulti() { + var args = arrayfromargs(arguments); + var interp_slots = []; + var summed_weight = 0; + + for (var i = 0; i < args.length; i++) { + var weight = args[i] % 1.; + if (weight == 0) weight = 1; + summed_weight += weight; + interp_slots.push([Math.floor(args[i]), weight]); + } + + for (var i = 0; i < interp_slots.length; i++) { + var nb = interp_slots[i][0]; + if (slots[nb][4] != null) { + interp_slots[i][1] /= summed_weight; + } else { + interp_slots[i][1] = -1; + } + slots[nb][6] = interp_slots[i][1] + } + + is_interpolating = 1; + mgraphics.redraw(); + + outlet(0, "recallmulti", args); + +} + +function store(v) { + v = Math.floor(v); + if (v >= 0) { + if (slots[v][5] > 0) { + error('cannot overwrite locked slot ' + v + '\n'); + } else { + var recalc_rows_flag = scrollable && v > slots_highest; + + to_pattrstorage("store", v); + to_pattrstorage("getslotlist"); + + if (recalc_rows_flag) { + calc_rows_columns(); + } else { + paint_base(); + } + + if (!(ignore_slot_zero && v == 0)) { + set_active_slot(v); + } + + outlet(0, "store", v); + if (v != 0) { + trigger_writeagain(); + } + } + } +} + +function setlock(v) { + lock(active_slot, v); +} + +function lock() { + var args = arrayfromargs(arguments); + if (args.length == 2) { + to_pattrstorage("lock", args[0], args[1]); + to_pattrstorage("getlockedslots"); + outlet(0, "lock", args[0], args[1]); + trigger_writeagain(); + if (layout == 1) { + paint_base(); + } + } +} + +function lockedslots() { + var locked_slots = arrayfromargs(arguments); + for (var i = 1; i < slots.length; i++) { + slots[i][5] = 0; + } + if (locked_slots.length) { + for (var i = 0; i < locked_slots.length; i++) { + slots[locked_slots[i]][5] = 1; + } + } +} + +function write() { + 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'); + } +} + +function read() { + var args = arrayfromargs(arguments); + var state = args[1]; + if (state) { + pattrstorage(pattrstorage_name); + } +} + +function find_pattrstorage(name) { + active_slot = 0; + pattrstorage_obj = this.patcher.getnamed(name); + if (pattrstorage_obj !== null) { + pattrstorage_name = name; + // slots_clear(); + to_pattrstorage("getslotlist"); + to_pattrstorage("getlockedslots"); + } else { + pattrstorage_name = null; + slots_clear(); + // error("Pattrstorage", name, "doesn't exist.\n"); + } +} +find_pattrstorage.local = 1; + +function to_pattrstorage() { + if (pattrstorage_obj !== null) { + pattrstorage_obj.message(arrayfromargs(arguments)); + } +} + +function slots_clear() { + slots[0] = [0, 0, 0, 0, "(tmp)", 0, -1]; + for (var i = 1; i < slots.length; i++) { + slots[i][4] = null; + slots[i][5] = 0; + slots[i][6] = -1; + } +} +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)) { + return i; + } + + } + return -1; +} +get_slot_index.local = 1; + +function set_active_slot(int) { + if (int < 0) { + active_slot = 0; + } else { + active_slot = int; + } + outlet(0, "previous", previous_active_slot); + if (menu_number_only) { + outlet(1, "setsymbol", active_slot); + } else { + outlet(1, "setsymbol", active_slot + ' ' + slots[active_slot][4]); + } + if (active_slot != 0) { + outlet(2, "set", slots[active_slot][4]); + } else { + outlet(2, "set"); + } + outlet(3, "set", slots[active_slot][5]); +} +set_active_slot.local = 1; + +function update_umenu() { + if (pattrstorage_obj !== null) { + outlet(1, "clear"); + + for (var i=0; i < filled_slots.length; i++) { + var txt = filled_slots[i].toString(); + if (!menu_number_only) { + txt += ' ' + slots[filled_slots[i]][4]; + } + outlet(1, "append", txt); + } + } +} +update_umenu.local = 1; + +function trigger_writeagain() { + if (auto_writeagain && !is_dragging) { + to_pattrstorage("writeagain"); + + } +} +trigger_writeagain.local = 1; + +// MOUSE EVENTS +function onidle(x,y,but,cmd,shift,capslock,option,ctrl) +{ + if (last_x != x || last_y != y - y_offset|| shift_hold != shift || option_hold != option) { + last_x = x; + last_y = y - y_offset; + shift_hold = shift; + option_hold = option; + var cur = get_slot_index(x, y - y_offset); + if (cur != last_hovered) { + last_hovered = cur; + mgraphics.redraw(); + } + } +} +onidle.local = 1; + +function onidleout() +{ + last_hovered = -1; + mgraphics.redraw(); +} +onidleout.local = 1; + +function onclick(x,y,but,cmd,shift,capslock,option,ctrl) +{ + if (last_hovered > -1 && pattrstorage_name != null) { + var output = "recall"; + if (shift) { + output = "store"; + if (option) { + output = "delete"; + } + } else if (slots[last_hovered][4] == null) { + return; + } + if (output == "store") { + store(last_hovered); + } else { + to_pattrstorage(output, last_hovered); + } + } + + last_x = x; + last_y = y - y_offset; +} +onclick.local = 1; + + +function ondrag(x,y,but,cmd,shift,capslock,option,ctrl) +{ + y -= y_offset; + if (is_dragging == 0 && last_hovered > 0 && slots[last_hovered][4] !== null) { + var dist_from_start = Math.sqrt((x-last_x)*(x-last_x)+(y-last_y)*(y-last_y)); + if (dist_from_start > 10) { + is_dragging = 1; + drag_slot = last_hovered; + } + + } else if (is_dragging == 1) { + last_hovered = get_slot_index(x, y); + last_x = x; + last_y = y; + if (!but) { + // Wehen to button is released, the dragging ceases + if (last_hovered > 0 && last_hovered != drag_slot) { + var cur_active_slot = active_slot; + var offset = ((last_hovered <= drag_slot) && slots[last_hovered][4] != null) ? 1 : 0; + var drag_slot_lock = slots[drag_slot][5]; + // 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) { + to_pattrstorage("insert", last_hovered); + } + + to_pattrstorage("copy", drag_slot + offset, last_hovered); + to_pattrstorage("delete", drag_slot + offset); + + slots_clear(); + to_pattrstorage("getslotlist"); + + to_pattrstorage("getlockedslots"); + if (cur_active_slot == drag_slot) { + active_slot = last_hovered; + } + // If the dragged slot was locked, relock it. + if (drag_slot_lock) { + lock(last_hovered, 1); + } + + paint_base(); + outlet(0, "drag", drag_slot, last_hovered, offset); + set_active_slot(last_hovered); + is_dragging = 0; + trigger_writeagain(); + + } else { + is_dragging = 0; + mgraphics.redraw(); + } + + } else { + mgraphics.redraw(); + } + } +} +ondrag.local = 1; + +function onwheel(x, y, wheel_inc_x, wheel_inc_y, cmd, shift, caps, opt, ctrl) +{ + if (scrollable) { + y_offset += wheel_inc_y * 100.0; + y_offset = Math.min(y_offset, 0); + y_offset = Math.max(y_offset, -1 * (bg_height - ui_height)); + mgraphics.redraw(); + } +} +onwheel.local = 1; + +function onresize(w,h) +{ + ui_width = w; + ui_height = h; + calc_rows_columns(); + // loadbang(); + to_pattrstorage("getslotlist"); + paint_base(); +} +onresize.local = 1; + +// function ondblclick(x,y,but,cmd,shift,capslock,option,ctrl) +// { +// last_x = x; +// last_y = y; +// } +// ondblclick.local = 1; + +// ATTRIBUTES DECLARATION +declareattribute("bubblesize", "getslotsize", "setslotsize", 1); +function getslotsize() { + return slot_size; +} +function setslotsize(v){ + slot_size = Math.max(2, v); + calc_rows_columns(); +} + +declareattribute("slot_round", "getslotround", "setslotround", 1); +function getslotround() { + return slot_round; +} +function setslotround(v){ + slot_round = Math.max(0, Math.min(slot_size, v)); + calc_rows_columns(); +} + +declareattribute("margin", "getmargin", "setmargin", 1); +function getmargin() { + return margin; +} +function setmargin(v){ + margin = Math.max(0, v); + calc_rows_columns(); +} + +declareattribute("spacing", "getspacing", "setspacing", 1); +function getspacing() { + return spacing; +} +function setspacing(v){ + spacing = Math.max(1, v); + calc_rows_columns(); +} + +declareattribute("bgcolor", "getbgcolor", "setbgcolor", 1); +function getbgcolor() { + return background_color; +} +function setbgcolor(){ + background_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + paint_base(); +} + +declareattribute("empty_slot_color", "getemptycolor", "setemptycolor", 1); +function getemptycolor() { + return empty_slot_color; +} +function setemptycolor(){ + empty_slot_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + paint_base(); +} + +declareattribute("active_slot_color", "getactiveslotcolor", "setactiveslotcolor", 1); +function getactiveslotcolor() { + return active_slot_color; +} +function setactiveslotcolor(){ + active_slot_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + mgraphics.redraw(); +} + +declareattribute("stored_slot_color", "getstoredslotcolor", "setstoredslotcolor", 1); +function getstoredslotcolor() { + return stored_slot_color; +} +function setstoredslotcolor(){ + stored_slot_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + paint_base(); +} + +declareattribute("interp_slot_color", "getinterpslotcolor", "setinterpslotcolor", 1); +function getinterpslotcolor() { + return interp_slot_color; +} +function setinterpslotcolor(){ + interp_slot_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + mgraphics.redraw(); +} + +declareattribute("text_bg_color", "gettextbgcolor", "settextbgcolor", 1); +function gettextbgcolor() { + return text_bg_color; +} +function settextbgcolor(){ + text_bg_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + mgraphics.redraw(); +} + +declareattribute("text_color", "gettextcolor", "settextcolor", 1); +function gettextcolor() { + return text_color; +} +function settextcolor(){ + text_color = [arguments[0], arguments[1], arguments[2], arguments[3]]; + mgraphics.redraw(); +} + +declareattribute("fontsize", "getfontsize", "setfontsize", 1); +function getfontsize() { + return font_size; +} +function setfontsize(v){ + font_size = Math.max(2, v); + mgraphics.redraw(); +} + +declareattribute("fontname", "getfontname", "setfontname", 1); +function getfontname() { + return font_name; +} +function setfontname(v){ + var fontlist = mgraphics.getfontlist(); + if (fontlist.indexOf(v) > -1) { + font_name = v.toString(); + mgraphics.redraw(); + } else { + error("Font not found.\n"); + } +} + +declareattribute("autowriteagain", "getautowriteagain", "setautowriteagain", 1); +function getautowriteagain() { + return auto_writeagain; +} +function setautowriteagain(v){ + if (v == 0) { + auto_writeagain = 0; + } else { + auto_writeagain = 1; + } +} + +declareattribute("ignoreslotzero", "getignoreslotzero", "setignoreslotzero", 1); +function getignoreslotzero() { + return ignore_slot_zero; +} +function setignoreslotzero(v){ + if (v == 0) { + ignore_slot_zero = 0; + } else { + ignore_slot_zero = 1; + } +} + +declareattribute("displayinterp", "getdisplayinterp", "setdisplayinterp", 1); +function getdisplayinterp() { + return display_interp; +} +function setdisplayinterp(v){ + if (v == 0) { + display_interp = 0; + } else { + display_interp = 1; + } +} + +declareattribute("layout", "getlayout", "setlayout", 1); +function getlayout() { + return layout; +} +function setlayout(v){ + if (v == 0) { + layout = 0; + } else { + layout = 1; + } + y_offset = 0; + calc_rows_columns(); +} + +declareattribute("scrollable", "getscrollable", "setscrollable", 1); +function getscrollable() { + return scrollable; +} +function setscrollable(v){ + if (v == 0) { + scrollable = 0; + } else { + scrollable = 1; + } + y_offset = 0; + calc_rows_columns(); +} + +declareattribute("min_rows", "getmin_rows", "setmin_rows", 1); +function getmin_rows() { + return min_rows; +} +function setmin_rows(v){ + if (v > 0) { + min_rows = v; + } + if (scrollable) { + calc_rows_columns(); + } +} diff --git a/tc.preset_demo.maxpat b/tc.preset_demo.maxpat new file mode 100755 index 0000000..4f0714b --- /dev/null +++ b/tc.preset_demo.maxpat @@ -0,0 +1,1382 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 2, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 134.0, 100.0, 715.0, 848.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-65", + "linecount" : 6, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 850.0, 546.0, 150.0, 87.0 ], + "text" : "Minimum number of slots to display when scrollable is enabled. If a preset is stored in a slot higher than that value, then it is ignored." + } + + } +, { + "box" : { + "id" : "obj-62", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 573.0, 537.5, 150.0, 47.0 ], + "text" : "Enable to scroll through your presets! (Only work in list mode currently)" + } + + } +, { + "box" : { + "id" : "obj-60", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 768.0, 550.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-57", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 768.0, 583.0, 77.0, 22.0 ], + "text" : "min_rows $1" + } + + } +, { + "box" : { + "id" : "obj-39", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 360.5, 546.0, 150.0, 33.0 ], + "text" : "Choose to display presets as a grid (0) or a list (1)!" + } + + } +, { + "box" : { + "id" : "obj-33", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 545.0, 549.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-35", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 545.0, 583.0, 76.0, 22.0 ], + "text" : "scrollable $1" + } + + } +, { + "box" : { + "id" : "obj-29", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 333.5, 550.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-15", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 333.5, 583.0, 57.0, 22.0 ], + "text" : "layout $1" + } + + } +, { + "box" : { + "id" : "obj-50", + "linecount" : 5, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 858.0, 316.0, 185.0, 74.0 ], + "text" : "Makes displayed previous active slot and interpolation status to ignore slot 0. Can be usefull when using slot 0 as a temporary step for interpolation." + } + + } +, { + "box" : { + "id" : "obj-43", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 601.0, 261.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-37", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 858.0, 261.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-34", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 2, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 107.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-8", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 159.166666666666686, 223.0, 45.0, 22.0 ], + "text" : "store 0" + } + + } +, { + "box" : { + "id" : "obj-5", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "bang", "int", "bang" ], + "patching_rect" : [ 52.5, 170.0, 125.666666666666686, 22.0 ], + "text" : "t b i b" + } + + } +, { + "box" : { + "id" : "obj-4", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 52.5, 213.0, 29.5, 22.0 ], + "text" : "i" + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 196.0, 100.0, 90.0, 22.0 ], + "text" : "loadmess 1000" + } + + } +, { + "box" : { + "id" : "obj-31", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "float" ], + "patching_rect" : [ 52.5, 308.0, 29.5, 22.0 ], + "text" : "t b f" + } + + } +, { + "box" : { + "id" : "obj-29", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "patching_rect" : [ 52.5, 281.0, 41.0, 22.0 ], + "text" : "line 0." + } + + } +, { + "box" : { + "id" : "obj-25", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 52.5, 250.0, 52.0, 22.0 ], + "text" : "0., 1. $1" + } + + } +, { + "box" : { + "id" : "obj-14", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 52.5, 336.0, 99.0, 22.0 ], + "text" : "pack recall 0 0 0." + } + + } +, { + "box" : { + "id" : "obj-9", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 52.5, 126.0, 55.0, 22.0 ], + "text" : "zl.slice 1" + } + + } +, { + "box" : { + "id" : "obj-6", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 52.5, 100.0, 71.0, 22.0 ], + "text" : "fromsymbol" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-32", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 52.5, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-33", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 52.5, 418.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-4", 1 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-33", 0 ], + "source" : [ "obj-14", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-29", 0 ], + "source" : [ "obj-25", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-31", 0 ], + "source" : [ "obj-29", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 3 ], + "source" : [ "obj-31", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-31", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-6", 0 ], + "source" : [ "obj-32", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-25", 0 ], + "source" : [ "obj-4", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 2 ], + "source" : [ "obj-5", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "source" : [ "obj-5", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-8", 0 ], + "source" : [ "obj-5", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-9", 0 ], + "source" : [ "obj-6", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-33", 0 ], + "source" : [ "obj-8", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-5", 0 ], + "source" : [ "obj-9", 0 ] + } + + } + ] + } +, + "patching_rect" : [ 231.0, 833.0, 125.0, 22.0 ], + "saved_object_attributes" : { + "description" : "", + "digest" : "", + "globalpatchername" : "", + "tags" : "" + } +, + "text" : "p trigger_interpolation" + } + + } +, { + "box" : { + "id" : "obj-28", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 16.0, 457.0, 150.0, 33.0 ], + "text" : "Usefull when making changes to the js file" + } + + } +, { + "box" : { + "id" : "obj-17", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 15.0, 496.0, 151.0, 22.0 ], + "text" : "loadbang, pattrstorage test" + } + + } +, { + "box" : { + "id" : "obj-30", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 527.0, 665.0, 65.0, 20.0 ], + "text" : "For testing" + } + + } +, { + "box" : { + "id" : "obj-23", + "linecount" : 7, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 446.0, 37.5, 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." + } + + } +, { + "box" : { + "id" : "obj-13", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 72.0, 916.0, 321.0, 20.0 ], + "text" : "Here's a regular [preset] just to check everything goes fine." + } + + } +, { + "box" : { + "id" : "obj-45", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 601.0, 448.0, 99.0, 22.0 ], + "text" : "display_interp $1" + } + + } +, { + "box" : { + "id" : "obj-19", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 601.0, 413.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-26", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 507.0, 414.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-18", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 507.0, 448.0, 81.0, 22.0 ], + "text" : "slot_round $1" + } + + } +, { + "box" : { + "id" : "obj-90", + "linecount" : 4, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 601.0, 316.0, 241.0, 60.0 ], + "text" : "When enabled, sends writeagain to pattrstrage when a preset has been stored/renamed/deleted/moved/(un)locked, keeping the json file always up to date" + } + + } +, { + "box" : { + "id" : "obj-88", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 464.0, 316.0, 129.0, 20.0 ], + "text" : "Lock/unlock active slot" + } + + } +, { + "box" : { + "id" : "obj-87", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 464.0, 296.0, 63.0, 22.0 ], + "text" : "setlock $1" + } + + } +, { + "box" : { + "id" : "obj-85", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 464.0, 260.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-82", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 350.0, 316.0, 104.0, 20.0 ], + "text" : "Lock/unlock slot 2" + } + + } +, { + "box" : { + "id" : "obj-79", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 169.0, 68.5, 29.5, 22.0 ], + "text" : "t l l" + } + + } +, { + "box" : { + "id" : "obj-78", + "linecount" : 5, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 690.0, 448.0, 219.0, 74.0 ], + "text" : "...and: bgcolor, empty_slot_color, stored_slot_color, interp_slot_color, active_slot_color, fontname, fontsize, text_bg_color, text_color\n(see the jsui attributes in the inspector)" + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-55", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 270.0, 414.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-47", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 270.0, 448.0, 83.0, 22.0 ], + "text" : "bubblesize $1" + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-41", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 433.0, 414.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-21", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 433.0, 448.0, 62.0, 22.0 ], + "text" : "margin $1" + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-24", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 363.0, 414.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-20", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 362.0, 448.0, 67.0, 22.0 ], + "text" : "spacing $1" + } + + } +, { + "box" : { + "id" : "obj-36", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 169.0, 37.5, 133.0, 22.0 ], + "text" : "recallmulti 1.5 2.1 3 5.2" + } + + } +, { + "box" : { + "id" : "obj-66", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 72.0, 829.0, 135.0, 22.0 ], + "text" : "print jsui_out @popup 1" + } + + } +, { + "box" : { + "id" : "obj-63", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 341.5, 37.5, 73.0, 22.0 ], + "text" : "pattrstorage" + } + + } +, { + "box" : { + "id" : "obj-59", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 428.0, 805.0, 93.0, 22.0 ], + "text" : "prepend setlock" + } + + } +, { + "box" : { + "id" : "obj-56", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 428.0, 774.0, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 119.0, 62.5, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-48", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 350.0, 256.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-44", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 350.0, 292.0, 57.0, 22.0 ], + "text" : "lock 2 $1" + } + + } +, { + "box" : { + "id" : "obj-27", + "keymode" : 1, + "maxclass" : "textedit", + "nosymquotes" : 1, + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "", "int", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 309.0, 774.0, 100.0, 50.0 ], + "presentation" : 1, + "presentation_rect" : [ 146.0, 63.5, 119.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-8", + "items" : "0 (tmp)", + "maxclass" : "umenu", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "int", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 191.0, 788.0, 100.0, 22.0 ], + "presentation" : 1, + "presentation_rect" : [ 1.0, 63.5, 116.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-22", + "linecount" : 6, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 285.0, 165.0, 507.0, 87.0 ], + "text" : "Pattrstorage messages that doesn't trigger output and need to be sent to the jsui instead:\n- store (send to jsui only)\n- recallmulti (send to pattrstorage first for timing accuracy, then to jsui)\n- slotname (send \"setslotname\" or \"text\" to jsui instead, will rename active slot)\n- lock (or setlock to lock/unlock of the active slot)\n- some other. I've not tested them all. " + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-16", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 72.0, 37.5, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-11", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 72.0, 68.5, 74.0, 22.0 ], + "text" : "recall 1 4 $1" + } + + } +, { + "box" : { + "id" : "obj-5", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 285.0, 292.0, 45.0, 22.0 ], + "text" : "store 5" + } + + } +, { + "box" : { + "bubblesize" : 30, + "id" : "obj-4", + "maxclass" : "preset", + "numinlets" : 1, + "numoutlets" : 5, + "outlettype" : [ "preset", "int", "preset", "int", "" ], + "patching_rect" : [ 72.0, 941.0, 248.0, 87.0 ], + "pattrstorage" : "test" + } + + } +, { + "box" : { + "id" : "obj-12", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 341.5, 65.5, 95.0, 22.0 ], + "text" : "pattrstorage test" + } + + } +, { + "box" : { + "border" : 0, + "embedstate" : [ [ "fontsize", 14 ], [ "displayinterp", 1 ], [ "fontname", "Arial" ], [ "stored_slot_color", 0.502, 0.502, 0.502, 1 ], [ "scrollable", 1 ], [ "layout", 1 ], [ "interp_slot_color", 1, 1, 1, 0.8 ], [ "bubblesize", 20 ], [ "spacing", 4 ], [ "min_rows", 10 ], [ "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", 7 ], [ "slot_round", 0 ], [ "active_slot_color", 0.808, 0.898, 0.91, 1 ] ], + "filename" : "preset.better.js", + "id" : "obj-10", + "jsarguments" : [ "test" ], + "maxclass" : "jsui", + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "", "", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 72.0, 637.0, 375.0, 132.0 ], + "presentation" : 1, + "presentation_rect" : [ 1.0, 103.0, 269.0, 77.0 ] + } + + } +, { + "box" : { + "id" : "obj-7", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 285.0, 262.0, 45.0, 22.0 ], + "text" : "store 4" + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "", "" ], + "patching_rect" : [ 459.0, 664.0, 52.0, 22.0 ], + "restore" : [ -0.857142857142857, -0.228571428571429, 0.314285714285714, 0.314285714285714, -0.171428571428571, -0.714285714285714, -0.942857142857143, 0.142857142857143, 0.485714285714286, 0.314285714285714, -0.057142857142857, -0.457142857142857, -0.771428571428571, -0.971428571428571, -1.0, -0.8 ], + "saved_object_attributes" : { + "parameter_enable" : 0, + "parameter_mappable" : 0 + } +, + "text" : "pattr oui", + "varname" : "oui" + } + + } +, { + "box" : { + "id" : "obj-2", + "maxclass" : "multislider", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 475.0, 691.0, 209.0, 70.0 ], + "size" : 16, + "varname" : "multislider" + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 72.0, 108.5, 176.0, 22.0 ], + "saved_object_attributes" : { + "client_rect" : [ 100, 100, 519, 600 ], + "parameter_enable" : 0, + "parameter_mappable" : 0, + "storage_rect" : [ 966, 212, 1566, 512 ] + } +, + "text" : "pattrstorage test @savemode 0", + "varname" : "test" + } + + } +, { + "box" : { + "attr" : "autowriteagain", + "id" : "obj-40", + "maxclass" : "attrui", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "parameter_enable" : 0, + "patching_rect" : [ 601.0, 292.0, 122.0, 22.0 ] + } + + } +, { + "box" : { + "attr" : "ignoreslotzero", + "id" : "obj-46", + "maxclass" : "attrui", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "parameter_enable" : 0, + "patching_rect" : [ 858.0, 292.0, 121.0, 22.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-27", 0 ], + "source" : [ "obj-10", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-56", 0 ], + "source" : [ "obj-10", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-66", 0 ], + "source" : [ "obj-10", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-8", 0 ], + "source" : [ "obj-10", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "source" : [ "obj-11", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-12", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-15", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-11", 0 ], + "source" : [ "obj-16", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-17", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-18", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-45", 0 ], + "source" : [ "obj-19", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-20", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-21", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-20", 0 ], + "source" : [ "obj-24", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-18", 0 ], + "source" : [ "obj-26", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-27", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-15", 0 ], + "source" : [ "obj-29", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-3", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-35", 0 ], + "source" : [ "obj-33", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "midpoints" : [ 240.5, 865.0, 57.0, 865.0, 57.0, 102.0, 81.5, 102.0 ], + "source" : [ "obj-34", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-35", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-79", 0 ], + "source" : [ "obj-36", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-46", 0 ], + "source" : [ "obj-37", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-40", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-21", 0 ], + "source" : [ "obj-41", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-43", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-44", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-45", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-46", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-47", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-44", 0 ], + "source" : [ "obj-48", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-5", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-47", 0 ], + "source" : [ "obj-55", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-59", 0 ], + "source" : [ "obj-56", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-57", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-59", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-57", 0 ], + "source" : [ "obj-60", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-63", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-7", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "source" : [ "obj-79", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-79", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-34", 0 ], + "source" : [ "obj-8", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-87", 0 ], + "source" : [ "obj-85", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-10", 0 ], + "source" : [ "obj-87", 0 ] + } + + } + ], + "dependency_cache" : [ { + "name" : "preset.better.js", + "bootpath" : "~/Documents/_MAX/pattrstorage_helper", + "patcherrelativepath" : ".", + "type" : "TEXT", + "implicit" : 1 + } + ], + "autosave" : 0 + } + +}