diff --git a/app/lib/ui/grid.js b/app/lib/ui/grid.js new file mode 100644 index 0000000..2bfb78b --- /dev/null +++ b/app/lib/ui/grid.js @@ -0,0 +1,279 @@ +/****** + Sequencer grid +*******/ +const grid = {}; +grid.swatchesElem = {}; +grid.init = function () { + 'use strict'; + grid.refresh(); + seq.stats(); + grid.events(); +}; + +/** + * Set a specific grid pad to the state stored in the sequence + * array at that step + * + * @param {integer} i Step in sequence + **/ +grid.state = function (i) { + 'use strict'; + const elem = $(`input[x=${i}]`); + const lightElem = $(`.L[x=${i}]`); + if (typeof mcopy.state.sequence.arr[i] !== 'undefined') { + elem.prop('checked', false); + $(`.${mcopy.state.sequence.arr[i]}[x=${i}]`).prop('checked', true); + if (mcopy.state.sequence.arr[i] === 'CF' || mcopy.state.sequence.arr[i] === 'CB') { + lightElem.css('background', `rgb(${mcopy.state.sequence.light[i]})`) + .addClass('a') + .prop('title', `rgb(${mcopy.state.sequence.light[i]})`); + + } else { + lightElem.css('background', 'transparent') + .removeClass('a') + .prop('title', ''); + } + } else { + lightElem.css('background', 'transparent') + .removeClass('a') + .prop('title', ''); + } +}; +/** + * Clears the UI of the grid and restores it to the + * state of the sequence. + * + **/ +grid.refresh = function () { + 'use strict'; + const cmds = ['cam_forward', 'proj_forward', 'cam_backward', 'proj_backward', 'light_set', 'numbers']; + const check = ''; + const div = '
'; + const width = 970 - 34 + ((940 / 24) * Math.abs(24 - mcopy.state.sequence.size)); + let elem; + + $('#sequence').width(`${width}px`); + for (let i = 0; i < cmds.length; i++) { + $('#' + cmds[i]).empty(); + for (let x = 0; x < mcopy.state.sequence.size; x++) { + if (i === cmds.length - 1) { + elem = div.replace('xxxx', x); + $('#' + cmds[i]).append($(elem).text(x)); + } else if (i === cmds.length - 2) { + elem = div.replace('xxxx', x); + $('#' + cmds[i]).append($(elem).addClass(mcopy.state.sequence.pads[cmds[i]])); + } else { + elem = check.replace('xxxx', x); + $('#' + cmds[i]).append($(elem).addClass(mcopy.state.sequence.pads[cmds[i]])); + } + grid.state(x); + } + } +}; +/** + * Function bound to click on grid pad elements + * + * @param {object} t This, passed from clicked element + **/ +grid.click = function (t) { + 'use strict'; + const i = parseInt($(t).attr('x')); + let c; + if ($(t).prop('checked')) { + c = $(t).attr('class').replace('.', ''); + mcopy.state.sequence.arr[i] = c; + if (c === 'CF' || c === 'CB') { + mcopy.state.sequence.light[i] = light.color.join(','); + } else { + mcopy.state.sequence.light[i] = ''; + } + } else { + mcopy.state.sequence.arr[i] = undefined; + delete mcopy.state.sequence.arr[i]; + } + grid.state(i); + seq.stats(); +}; +/** + * Clears the state of the sequence and then refreshes + * the grid and then recalculates the stats on the sequence + **/ +grid.clear = function () { + 'use strict'; + const doit = confirm('Are you sure you want to clear this sequence?'); + if (doit) { + seq.clear(); + grid.refresh(); + seq.stats(); + console.log('Sequencer cleared'); + } +}; +/** + * Function bound to the change event on the loop counter + * input element + * + * @param {object} t This, passed from changed element + */ +grid.loopChange = function (t) { + 'use strict'; + const count = parseInt(t.value); + mcopy.loop = count; + seq.stats(); +}; +/** + * Add 24 frames to the sequence in the GUI + **/ +grid.plus_24 = function () { + 'use strict'; + mcopy.state.sequence.size += 24; + grid.refresh(); + console.log(`Sequencer expanded to ${mcopy.state.sequence.size} steps`); +}; +/** + * Set the light value at a specific step and then update + * GUI grid via .state() + * + * @param {integer} x Step in sequence + * @param {array} rgb Light value in RGB + **/ +grid.setLight = function (x, rgb) { + 'use strict'; + mcopy.state.sequence.light[x] = rgb.join(','); + grid.state(x); +}; +/** + * Set light value to black (0,0,0) when double clicked + * + * @param {object} t This, passed from clicked element + **/ +grid.blackout = function (t) { + const elem = $(t); + const i = elem.attr('x'); + if (typeof mcopy.state.sequence.light[i] === 'undefined') { + return false; + } + if (mcopy.state.sequence.light[i] === '0,0,0') { + grid.setLight(i, light.color); + } else { + grid.setLight(i, [0, 0, 0]); + } +}; + +/** + * Change all lights at all camera commands to a specific + * RGB value + * + * @param {array} rgb RGB value [255. 255, 255] + */ +grid.changeAll = function (rgb) { + 'use strict'; + for (let [i, c] of mcopy.state.sequence.arr.entries()) { + if (c === 'CF' || c === 'CB') { + grid.setLight(i, rgb); + } + } +}; +/** + * Display color swatch modal for selection of light + * color value at specific step + * + * @param {integer} x Position in sequence to change value + **/ +grid.swatches = function (x) { + 'use strict'; + const current = mcopy.state.sequence.light[x]; + grid.swatchesElem = w2popup.open({ + title : 'Select Color', + body : $('#light-swatches').html(), + buttons : ' ', + onClose : () => {} + }); + $('.w2ui-msg-body .swatch').removeClass('default set'); + $(`.w2ui-msg-body .swatch[color="${current}"`).eq(0).addClass('default set'); + + $('#sequencer-cancel').on('click', grid.swatchesElem.close); + $('#sequencer-changeall').on('click', function () { + const doit = confirm('You sure you want to change all light settings?'); + const elem = $('.w2ui-msg-body .default'); + let rgb; + if (doit && elem.length > 0) { + rgb = elem.attr('color').split(','); + grid.changeAll(rgb); + grid.swatchesElem.close(); + } else if (doit && elem.length === 0) { + gui.warn('Select Color', 'Please select a color to proceed.'); + } + }); + $('#sequencer-ok').on('click', function () { + var elem = $('.w2ui-msg-body .default'), + rgb; + if (elem.length > 0) { + rgb = elem.attr('color').split(','); + grid.setLight(x, rgb); + light.color = rgb; + grid.swatchesElem.close(); + } else { + gui.warn('Select Color', 'Please select a color to proceed.'); + } + }); +}; + +/** + * Scroll the grid to a specific step + * + * @param {integer} i Step to scroll to + **/ +grid.scrollTo = function (i) { + 'use strict'; + var w = 35 + 3; //width of pad + margin + $('#seq_scroll').scrollLeft(i * w); +}; + +/** + * Bind all events to sequence. Re-evaluate this in search + * of memory leak issues with long sequences. + **/ +grid.events = function () { + 'use strict'; + $(document.body).on('click', '#sequencer input[type=checkbox]', function () { + grid.click(this); + }); + //$(document.body).on('click', '.L', function () { + //alert('click'); + //console.log('please dont happen'); + //}); + $(document.body).on('dblclick', '.L', function () { + grid.blackout(this); + }); + $(document.body).on('contextmenu', '.L', function (e) { + var x = e.target.attributes.x.value; + setTimeout(function () { + grid.swatches(x); + }, 300); + e.preventDefault(); + return false; + }); + $('#seq_scroll').on('scroll', function () { + var i = Math.ceil($('#seq_scroll').scrollLeft() / (35 + 3)); + $('#seq_scroll_state').val(gui.fmtZero(i, 6)); + }); + $('#seq_scroll_state').on('change', function () { + var i = parseInt($(this).val()); + $(this).val(gui.fmtZero(i, 6)); + grid.scrollTo(i); + }); + $(document.body).on('click', '.w2ui-msg-body .swatch', function () { + var color = $(this).attr('color'), + title = $(this).attr('title'); + if (typeof color !== 'undefined') { + color = color.split(','); + $('.w2ui-msg-body .swatch').removeClass('default set'); + $('#light-swatches .swatch').removeClass('default set'); + $(this).addClass('default set'); + $('#light-swatches .swatch[title="' + title + '"]').eq(0).addClass('default set'); + light.color = color; + } + }); +}; + +module.exports = grid; \ No newline at end of file