Work on multiple device UI

This commit is contained in:
mmcw-dev 2019-04-16 10:01:42 -04:00
parent ed14564de7
commit b33ef36ab4
28 changed files with 975 additions and 358 deletions

View File

@ -402,7 +402,7 @@ button:focus {
#sequence {
width: 970px;
padding-bottom: 21px;
padding-left: 70px;
padding-left: 92px;
}
#sequence #camera_forward,
#sequence #camera_second_forward,
@ -460,10 +460,6 @@ button:focus {
#sequence #black_backward > div {
color: #AB1A25;
}
#sequence #camera_second_forward,
#sequence #projector_second_forward {
display: none;
}
#sequence #camera_second_forward input[type=checkbox],
#sequence #projector_second_forward input[type=checkbox] {
border: 2px solid #14d8b4;
@ -476,10 +472,6 @@ button:focus {
#sequence #projector_second_forward > div {
color: #14d8b4;
}
#sequence #camera_second_backward,
#sequence #projector_second_backward {
display: none;
}
#sequence #camera_second_backward input[type=checkbox],
#sequence #projector_second_backward input[type=checkbox] {
border: 2px solid #bf2e39;
@ -552,10 +544,10 @@ button:focus {
font-family: 'Menlo', monospace;
background-color: #272b30;
position: absolute;
top: 115px;
top: 113px;
padding-top: 2px;
padding-bottom: 15px;
width: 54px;
width: 75px;
}
#seq_labels div {
height: 43px;
@ -566,6 +558,11 @@ button:focus {
display: inline-block;
margin-right: 5px;
}
#seq_labels i.fa {
right: 3px;
position: absolute;
margin-top: 10px;
}
#loop_current {
margin-top: 21px;
margin-right: 50px;
@ -585,10 +582,15 @@ button:focus {
left: 0;
bottom: 0;
}
#buttons > div {
#buttons > div,
#buttons_2 > div {
width: 50%;
float: left;
}
#buttons .proj2,
#buttons_2 .proj2 {
float: right !important;
}
.cmd {
width: 240px;
text-align: center;
@ -789,29 +791,71 @@ button:focus {
}
#counters .cam,
#counters_2 .cam,
#counters_3 .cam,
#move_to .cam,
#move_to_2 .cam,
#counters .cam2,
#counters_2 .cam2,
#counters_3 .cam2,
#move_to .cam2,
#move_to_2 .cam2,
#counters .proj,
#counters_2 .proj,
#move_to .proj {
#counters_3 .proj,
#move_to .proj,
#move_to_2 .proj,
#counters .proj2,
#counters_2 .proj2,
#counters_3 .proj2,
#move_to .proj2,
#move_to_2 .proj2 {
width: 50%;
padding-bottom: 10px;
}
#counters .cam label,
#counters_2 .cam label,
#counters_3 .cam label,
#move_to .cam label,
#move_to_2 .cam label,
#counters .cam2 label,
#counters_2 .cam2 label,
#counters_3 .cam2 label,
#move_to .cam2 label,
#move_to_2 .cam2 label,
#counters .proj label,
#counters_2 .proj label,
#move_to .proj label {
#counters_3 .proj label,
#move_to .proj label,
#move_to_2 .proj label,
#counters .proj2 label,
#counters_2 .proj2 label,
#counters_3 .proj2 label,
#move_to .proj2 label,
#move_to_2 .proj2 label {
text-align: center;
font-size: 24px;
display: block;
}
#counters .cam input,
#counters_2 .cam input,
#counters_3 .cam input,
#move_to .cam input,
#move_to_2 .cam input,
#counters .cam2 input,
#counters_2 .cam2 input,
#counters_3 .cam2 input,
#move_to .cam2 input,
#move_to_2 .cam2 input,
#counters .proj input,
#counters_2 .proj input,
#move_to .proj input {
#counters_3 .proj input,
#move_to .proj input,
#move_to_2 .proj input,
#counters .proj2 input,
#counters_2 .proj2 input,
#counters_3 .proj2 input,
#move_to .proj2 input,
#move_to_2 .proj2 input {
background: rgba(255, 255, 255, 0.05);
color: #fff;
padding: 6px 12px;
@ -823,44 +867,143 @@ button:focus {
}
#counters .cam input.changed,
#counters_2 .cam input.changed,
#counters_3 .cam input.changed,
#move_to .cam input.changed,
#move_to_2 .cam input.changed,
#counters .cam2 input.changed,
#counters_2 .cam2 input.changed,
#counters_3 .cam2 input.changed,
#move_to .cam2 input.changed,
#move_to_2 .cam2 input.changed,
#counters .proj input.changed,
#counters_2 .proj input.changed,
#move_to .proj input.changed {
#counters_3 .proj input.changed,
#move_to .proj input.changed,
#move_to_2 .proj input.changed,
#counters .proj2 input.changed,
#counters_2 .proj2 input.changed,
#counters_3 .proj2 input.changed,
#move_to .proj2 input.changed,
#move_to_2 .proj2 input.changed {
color: #DAE035;
}
#counters .cam,
#counters_2 .cam,
#move_to .cam {
#counters_3 .cam,
#move_to .cam,
#move_to_2 .cam,
#counters .cam2,
#counters_2 .cam2,
#counters_3 .cam2,
#move_to .cam2,
#move_to_2 .cam2 {
float: left;
}
#counters .proj,
#counters_2 .proj,
#move_to .proj {
#counters_3 .proj,
#move_to .proj,
#move_to_2 .proj,
#counters .proj2,
#counters_2 .proj2,
#counters_3 .proj2,
#move_to .proj2,
#move_to_2 .proj2 {
float: right;
}
#move_to {
#counters.projectors .proj,
#counters.projectors .proj2 {
width: 25%;
}
#counters.projectors .proj label,
#counters.projectors .proj2 label {
line-height: 34px;
font-size: 18px;
}
#counters.projectors .proj input,
#counters.projectors .proj2 input {
width: 90%;
}
#counters.cameras .cam,
#counters.cameras .cam2 {
width: 25%;
}
#counters.cameras .cam label,
#counters.cameras .cam2 label {
line-height: 34px;
font-size: 18px;
}
#counters.cameras .cam input,
#counters.cameras .cam2 input {
width: 90%;
}
#move_to,
#move_to_2 {
margin-top: 20px;
}
#move_to .cam > div,
#move_to .proj > div {
#move_to_2 .cam > div,
#move_to .cam2 > div,
#move_to_2 .cam2 > div,
#move_to .proj > div,
#move_to_2 .proj > div,
#move_to .proj2 > div,
#move_to_2 .proj2 > div {
width: 294px;
margin: 0 auto;
}
#move_to .cam label,
#move_to .proj label {
#move_to_2 .cam label,
#move_to .cam2 label,
#move_to_2 .cam2 label,
#move_to .proj label,
#move_to_2 .proj label,
#move_to .proj2 label,
#move_to_2 .proj2 label {
font-size: 18px;
}
#move_to .cam input,
#move_to .proj input {
#move_to_2 .cam input,
#move_to .cam2 input,
#move_to_2 .cam2 input,
#move_to .proj input,
#move_to_2 .proj input,
#move_to .proj2 input,
#move_to_2 .proj2 input {
display: inline-block;
width: 206px;
}
#move_to .cam button,
#move_to .proj button {
#move_to_2 .cam button,
#move_to .cam2 button,
#move_to_2 .cam2 button,
#move_to .proj button,
#move_to_2 .proj button,
#move_to .proj2 button,
#move_to_2 .proj2 button {
padding: 7px 16px;
float: right;
}
#move_to > .proj2,
#move_to_2 > .proj2 {
float: right;
}
.cam2,
.proj2 {
display: none;
}
.cam2 > *,
.proj2 > * {
visibility: hidden;
}
.cam2.on,
.proj2.on {
display: block;
}
.cam2.on > *,
.proj2.on > * {
visibility: visible;
}
#overlay {
position: fixed;
top: 0;

View File

@ -20,32 +20,45 @@
<label>CAMERA</label>
<input type="number" id="seq_cam_count" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
</div>
<div class="cam2">
<label>CAMERA</label>
<input type="number" id="seq_cam_count_2" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
</div>
<div class="proj2">
<label>PROJECTOR 2</label>
<input type="number" id="seq_proj_count_2" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
</div>
<div class="proj">
<label>PROJECTOR</label>
<input type="number" id="seq_proj_count" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
</div>
</div>
<div id="seq_scroll">
<div id="sequence">
<div id="camera_forward" class="row" y="0"></div>
<div id="camera_second_forward" class="row" y="2"></div>
<div id="camera_second_forward" class="row cam2" y="2"></div>
<div id="projector_forward" class="row" y="1"></div>
<div id="projector_second_forward" class="row" y="3"></div>
<div id="projector_second_forward" class="row proj2" y="3"></div>
<div id="camera_backward" class="row spacer" y="0"></div>
<div id="camera_second_backward" class="row" y="2"></div>
<div id="camera_second_backward" class="row cam2" y="2"></div>
<div id="projector_backward" class="row" y="1"></div>
<div id="projector_second_backward" class="row" y="3"></div>
<div id="projector_second_backward" class="row proj2" y="3"></div>
<div id="light_set" class="row spacer"></div>
<div id="numbers" class="row"></div>
</div>
<div id="seq_labels">
<div><span>CAM </span><i class="fa fa-plus"></i></div>
<div><span>PRO </span><i class="fa fa-plus"></i></div>
<div class="cam2"><span>CAM2 </span><i class="fa fa-plus"></i></div>
<div><span>PROJ </span><i class="fa fa-plus"></i></div>
<div class="proj2"><span>PROJ2 </span><i class="fa fa-plus"></i></div>
<div class="spacer"><span>CAM </span><i class="fa fa-minus"></i></div>
<div><span>PRO </span><i class="fa fa-minus"></i></div>
<div class="cam2"><span>CAM2 </span><i class="fa fa-minus"></i></div>
<div><span>PROJ </span><i class="fa fa-minus"></i></div>
<div class="proj2"><span>PROJ2 </span><i class="fa fa-minus"></i></div>
<div class="spacer"><span>LIGHT</span></div>
</div>
@ -89,7 +102,7 @@
</footer>
</div>
<div id="controls" class="screen">
<div id="counters_2">
<div id="counters_2" class="clearfix">
<div class="cam">
<label>CAMERA</label>
<input type="number" id="seq_cam_count_2" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
@ -99,7 +112,7 @@
<input type="number" id="seq_proj_count_2" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
</div>
</div>
<div id="move_to">
<div id="move_to" class="clearfix">
<div class="cam">
<!--<label>MOVE TO</label>-->
<div>
@ -163,6 +176,80 @@
</div>
</div>
</div>
<div id="counters_3" class="clearfix">
<div class="cam2">
<label>CAMERA 2</label>
<input type="number" id="seq_cam_count_3" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
</div>
<div class="proj2">
<label>PROJECTOR 2</label>
<input type="number" id="seq_proj_count_3" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
</div>
</div>
<div id="move_to_2" class="clearfix">
<div class="cam2">
<!--<label>MOVE TO</label>-->
<div>
<input type="number" id="move_cam_to_2" class="count" value="00000" onchange="gui.counterFormat(this, this.value);" />
<button id="move_cam_to_go_2" onclick="return cmd.camera_to();">GO TO</button>
</div>
</div>
<div class="proj proj2">
<!--<label>MOVE TO</label>-->
<div>
<input type="number" id="move_proj_to_2" class="count" value="00000" onchange="gui.counterFormat(this, this.value);"/>
<button id="move_proj_to_go_2" onclick="return cmd.projector_to();">GO TO</button>
</div>
</div>
</div>
<div id="buttons_2" class="clearfix">
<div class="cam2">
<div>
<button id="cmd_cam_forward" onclick="cmd.camera_second_forward(light.color);" class="cmd fwd">
<i class="fa fa-video-camera"></i>
CAMERA 2 +1
<i class="fa fa-step-forward"></i>
</button>
</div>
<div>
<button id="cmd_cam_backward" onclick="cmd.camera_backward(light.color);" class="cmd bwd">
<i class="fa fa-video-camera"></i>
CAMERA 2 -1
<i class="fa fa-step-backward"></i>
</button>
</div>
<div>
<button id="cmd_black_forward" onclick="cmd.black_forward();" class="cmd fwd">
<i class="fa fa-times-circle"></i>
BLANK +1
<i class="fa fa-step-forward"></i>
</button>
</div>
<div>
<button id="cmd_black_backward" onclick="cmd.black_backward();" class="cmd bwd">
<i class="fa fa-times-circle"></i>
BLANK -1
<i class="fa fa-step-backward"></i>
</button>
</div>
</div>
<div class="proj2">
<div>
<button id="cmd_proj_forward" onclick="cmd.projector_forward();" class="cmd fwd">
<i class="fa fa-film"></i>
PROJECTOR 2 +1
<i class="fa fa-step-forward"></i>
</button>
</div>
<div>
<button id="cmd_proj_backward" onclick="cmd.projector_backward();" class="cmd bwd">
<i class="fa fa-film"></i>
PROJECTOR 2 -1
<i class="fa fa-step-backward"></i>
</button>
</div>
</div>
</div>
</div>
<div id="light" class="screen">
<div id="colors-tabs"></div>

View File

@ -72,9 +72,13 @@
#counters,
#counters_2,
#move_to{
#counters_3,
#move_to,
#move_to_2{
.cam,
.proj{
.cam2,
.proj,
.proj2{
width: 50%;
padding-bottom: 10px;
label{
@ -96,18 +100,52 @@
}
}
}
.cam{
.cam,
.cam2{
float: left;
}
.proj{
.proj,
.proj2{
float: right;
}
}
#move_to{
#counters{
&.projectors{
.proj,
.proj2{
width: 25%;
label{
line-height: 34px;
font-size: 18px;
}
input{
width: 90%;
}
}
}
&.cameras{
.cam,
.cam2{
width: 25%;
label{
line-height: 34px;
font-size: 18px;
}
input{
width: 90%;
}
}
}
}
#move_to,
#move_to_2{
margin-top: 20px;
.cam,
.proj{
.cam2,
.proj,
.proj2{
> div {
width: 294px;
margin: 0 auto;
@ -124,6 +162,24 @@
float: right;
}
}
> .proj2{
float: right;
}
}
.cam2,
.proj2{
display : none;
> * {
visibility: hidden;
}
&.on {
display: block;
> * {
visibility: visible;
}
}
}
#overlay{

View File

@ -1,8 +1,12 @@
#buttons{
#buttons,
#buttons_2{
> div{
width: 50%;
float: left;
}
.proj2 {
float: right !important;
}
}
.cmd{

View File

@ -67,7 +67,7 @@
#sequence{
width: 970px;
padding-bottom: 21px;
padding-left: 70px;
padding-left: 92px;
#camera_forward,
#camera_second_forward,
#projector_forward,
@ -103,7 +103,6 @@
#camera_second_forward,
#projector_second_forward {
display: none;
input[type=checkbox]{
border: 2px solid @FORWARD + @SECOND;
&:checked{
@ -117,7 +116,6 @@
}
#camera_second_backward,
#projector_second_backward{
display: none;
input[type=checkbox]{
border: 2px solid @BACKWARD + @SECOND;
&:checked{
@ -191,10 +189,10 @@
.monospace();
background-color: #272b30;
position: absolute;
top: 115px;
top: 113px;
padding-top: 2px;
padding-bottom: 15px;
width: 54px;
width: 75px;
div{
height: 43px;
line-height: 35px;
@ -204,6 +202,11 @@
display: inline-block;
margin-right: 5px;
}
i.fa{
right: 3px;
position: absolute;
margin-top: 10px;
}
}
#loop_current{

View File

@ -61,6 +61,9 @@ class Arduino {
else if ((port.comName + '').toLowerCase().indexOf('usbmodem') !== -1) {
matches.push(port.comName);
}
else if ((port.comName + '').toLowerCase().indexOf('ttyusb') !== -1) {
matches.push(port.comName);
}
});
if (matches.length === 0) {
return reject('No USB devices found');

File diff suppressed because one or more lines are too long

View File

@ -222,8 +222,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);
@ -260,8 +260,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);
@ -293,8 +293,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);

File diff suppressed because one or more lines are too long

View File

@ -95,10 +95,16 @@ cam.second.dir = true;
cam.second.enable = function () {
cam.second.enabled = true;
//ui actions
$('.cam2').addClass('on');
$('#counters').addClass('cameras');
}
cam.second.disable = function () {
cam.second.enabled = false;
//ui actions
$('.cam2').removeClass('on');
$('#counters').removeClass('cameras');
}
module.exports = cam;

View File

@ -99,9 +99,11 @@ devices.ready = function (event, arg) {
if (arg.projector_second) {
//add second row of projector pads to grid
proj.second.enable();
}
if (arg.camera_second) {
//add second row of camera pads to grid
cam.second.enable();
}
return event.returnValue = true;
};

View File

@ -1,266 +1,263 @@
'use strict';
let grid;
/******
Sequencer grid
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} x Step in sequence
**/
grid.state = function (x) {
'use strict';
const elem = $(`input[x=${x}]`);
const lightElem = $(`.L[x=${x}]`);
const step = seq.grid[x];
if (typeof step !== 'undefined') {
elem.prop('checked', false);
$(`.${step.cmd}[x=${x}]`).prop('checked', true);
if (step.cmd === 'CF' || step.cmd === 'CB') {
lightElem.css('background', `rgb(${step.light})`)
.addClass('a')
.prop('title', `rgb(${seq.light})`);
} 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 = [
'camera_forward',
'camera_second_forward',
'projector_forward',
'projector_second_forward',
'camera_backward',
'camera_second_backward',
'projector_backward',
'projector_second_backward',
'light_set',
'numbers'
];
const width = 970 - 34 + ((940 / 24) * Math.abs(24 - seq.size));
let elem;
let cmd;
$('#sequence').width(`${width}px`);
for (let i = 0; i < cmds.length; i++) {
cmd = `#${cmds[i]}`;
$(cmd).empty();
for (let x = 0; x < seq.size; x++) {
if (cmds[i] === 'numbers') {
elem = `<div x="${x}">${x}</div>`
$(cmd).append($(elem));
} else if (cmds[i] === 'light_set') {
elem = `<div x="${x}" class="L"></div>`
$(cmd).append($(elem));
} else {
elem = `<input type="checkbox" x="${x}" />`;
$(cmd).append($(elem).addClass(cfg.cmd[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 x = parseInt($(t).attr('x'));
let c;
if ($(t).prop('checked')) {
c = $(t).attr('class').replace('.', '');
seq.set(x, c);
} else {
seq.grid[i] = undefined;
delete seq.grid[i];
seq.unset(x);
}
grid.state(x);
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();
log.info('Sequencer cleared');
}
};
/**
* Add 24 frames to the sequence in the GUI
**/
grid.plus_24 = function () {
'use strict';
seq.size += 24;
grid.refresh();
log.info(`Sequencer expanded to ${seq.size} steps`);
};
/**
* 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 x = elem.attr('x');
if (typeof seq.grid[x].light === 'undefined') {
return false;
}
if (seq.grid[x].light === '0,0,0') {
seq.setLight(i, light.color);
} else {
seq.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';
let c;
for (let step of seq.grid) {
c = step.cmd;
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 = seq.grid[x].light;
grid.swatchesElem = w2popup.open({
title : 'Select Color',
body : $('#light-swatches').html(),
buttons : '<button id="sequencer-ok" class="btn btn-default">Ok</button> <button id="sequencer-changeall" class="btn btn-warning">Change All</button> <button id="sequencer-cancel" class="btn btn-default">Cancel</button>',
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');
//log.warn('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;
}
});
};
class Grid {
constructor() {
this.swatchesElem = {};
}
init() {
this.refresh();
seq.stats();
this.events();
}
/**
* Set a specific grid pad to the state stored in the sequence
* array at that step
*
* @param {integer} x Step in sequence
**/
state(x) {
const elem = $(`input[x=${x}]`);
const lightElem = $(`.L[x=${x}]`);
const step = seq.grid[x];
if (typeof step !== 'undefined') {
elem.prop('checked', false);
$(`.${step.cmd}[x=${x}]`).prop('checked', true);
if (step.cmd === 'CF' || step.cmd === 'CB') {
lightElem.css('background', `rgb(${step.light})`)
.addClass('a')
.prop('title', `rgb(${seq.light})`);
}
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.
*
**/
refresh() {
const cmds = [
'camera_forward',
'camera_second_forward',
'projector_forward',
'projector_second_forward',
'camera_backward',
'camera_second_backward',
'projector_backward',
'projector_second_backward',
'light_set',
'numbers'
];
const width = 970 - 34 + ((940 / 24) * Math.abs(24 - seq.size));
let elem;
let cmd;
$('#sequence').width(`${width}px`);
for (let i = 0; i < cmds.length; i++) {
cmd = `#${cmds[i]}`;
$(cmd).empty();
for (let x = 0; x < seq.size; x++) {
if (cmds[i] === 'numbers') {
elem = `<div x="${x}">${x}</div>`;
$(cmd).append($(elem));
}
else if (cmds[i] === 'light_set') {
elem = `<div x="${x}" class="L"></div>`;
$(cmd).append($(elem));
}
else {
elem = `<input type="checkbox" x="${x}" />`;
$(cmd).append($(elem).addClass(cfg.cmd[cmds[i]]));
}
this.state(x);
}
}
}
/**
* Function bound to click on grid pad elements
*
* @param {object} t This, passed from clicked element
**/
click(t) {
const x = parseInt($(t).attr('x'));
let c;
if ($(t).prop('checked')) {
c = $(t).attr('class').replace('.', '');
seq.set(x, c);
}
else {
seq.grid[x] = undefined;
delete seq.grid[x];
seq.unset(x);
}
this.state(x);
seq.stats();
}
/**
* Clears the state of the sequence and then refreshes
* the grid and then recalculates the stats on the sequence
**/
clear() {
const doit = confirm('Are you sure you want to clear this sequence?');
if (doit) {
seq.clear();
this.refresh();
seq.stats();
log.info('Sequencer cleared');
}
}
/**
* Add 24 frames to the sequence in the GUI
**/
plus_24() {
seq.size += 24;
this.refresh();
log.info(`Sequencer expanded to ${seq.size} steps`);
}
/**
* Set light value to black (0,0,0) when double clicked
*
* @param {object} t This, passed from clicked element
**/
blackout(t) {
const elem = $(t);
const x = parseInt(elem.attr('x'));
if (typeof seq.grid[x].light === 'undefined') {
return false;
}
console.log(x);
if (seq.grid[x].light === '0,0,0') {
seq.setLight(x, light.color);
}
else {
seq.setLight(x, [0, 0, 0]);
}
}
/**
* Change all lights at all camera commands to a specific
* RGB value
*
* @param {array} rgb RGB value [255. 255, 255]
*/
changeAll(rgb) {
let c;
for (let step of seq.grid) {
c = step.cmd;
if (c === 'CF' || c === 'CB') {
seq.setLight(step.x, rgb);
}
}
}
/**
* Display color swatch modal for selection of light
* color value at specific step
*
* @param {integer} x Position in sequence to change value
**/
swatches(x) {
const current = seq.grid[x].light;
this.swatchesElem = w2popup.open({
title: 'Select Color',
body: $('#light-swatches').html(),
buttons: '<button id="sequencer-ok" class="btn btn-default">Ok</button> <button id="sequencer-changeall" class="btn btn-warning">Change All</button> <button id="sequencer-cancel" class="btn btn-default">Cancel</button>',
onClose: () => { }
});
$('.w2ui-msg-body .swatch').removeClass('default set');
$(`.w2ui-msg-body .swatch[color="${current}"`).eq(0).addClass('default set');
$('#sequencer-cancel').on('click', this.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(',');
seq.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} x Step to scroll to
**/
scrollTo(x) {
const w = 35 + 3; //width of pad + margin
$('#seq_scroll').scrollLeft(x * w);
}
/**
* Bind all events to sequence. Re-evaluate this in search
* of memory leak issues with long sequences.
**/
events() {
$(document.body).on('click', '#sequencer input[type=checkbox]', function () {
grid.click(this);
});
//$(document.body).on('click', '.L', function () {
//alert('click');
//log.warn('please dont happen');
//});
$(document.body).on('dblclick', '.L', function () {
grid.blackout(this);
});
$(document.body).on('contextmenu', '.L', function (e) {
const x = e.target.attributes.x.value;
setTimeout(function () {
grid.swatches(x);
}, 300);
e.preventDefault();
return false;
});
$('#seq_scroll').on('scroll', function () {
let x = Math.ceil($('#seq_scroll').scrollLeft() / (35 + 3));
$('#seq_scroll_state').val(gui.fmtZero(x, 6));
});
$('#seq_scroll_state').on('change', function () {
let x = parseInt($(this).val() + '');
$(this).val(gui.fmtZero(x, 6));
grid.scrollTo(x);
});
$(document.body).on('click', '.w2ui-msg-body .swatch', function () {
const colorStr = $(this).attr('color');
const title = $(this).attr('title');
let color;
if (typeof color !== 'undefined') {
color = colorStr.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;
}
});
}
;
}
grid = new Grid();
module.exports = grid;

View File

@ -96,10 +96,16 @@ proj.second.pos = 0;
proj.second.enable = function () {
proj.second.enabled = true;
//ui actions
$('.proj2').addClass('on');
$('#counters').addClass('projectors');
}
proj.second.disable = function () {
proj.second.disabled = true;
//ui actions
$('.proj2').removeClass('on');
$('#counters').removeClass('projectors');
}
module.exports = proj;

View File

@ -69,21 +69,6 @@ var createWindow = function () {
})
}
/*const seq = {};
seq.init = function () {
seq.listen();
}
seq.listen = function () {
ipcMain.on('seq', async (evt, arg) => {
if (arg.action === 'stop' && proj.digital) {
display.close()
} else if (arg.action === 'start' && proj.digital) {
display.open()
}
})
}*/
var init = async function () {
log = await require('log')({})
@ -105,7 +90,7 @@ var init = async function () {
arduino = require('arduino')(cfg, ee)
mscript = require('mscript')
dev = require('devices')(arduino, settings, mainWindow, cam)
dev = require('devices')(arduino, settings, mainWindow)
//why is delay happening still?
await delay(2000)
@ -132,9 +117,6 @@ var init = async function () {
cmd = require('cmd')(cfg, proj, cam, light, cam2, proj2)
seq = require('sequencer')(cfg, cmd, mainWindow.webContents)
await delay(5000)
await cmd.projectors_forward();
}
app.on('ready', init)

21
app/package-lock.json generated
View File

@ -98,6 +98,15 @@
"@types/node": "*"
}
},
"@types/jquery": {
"version": "3.3.29",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.29.tgz",
"integrity": "sha512-FhJvBninYD36v3k6c+bVk1DSZwh7B5Dpb/Pyk3HKVsiohn0nhbefZZ+3JXbWQhFyt0MxSl2jRDdGQPHeOHFXrQ==",
"dev": true,
"requires": {
"@types/sizzle": "*"
}
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@ -108,6 +117,12 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.3.tgz",
"integrity": "sha512-2lhc7S28vo8FwR3Jv3Ifyd77AxEsx+Nl9ajWiac6/eWuvZ84zPK4RE05pfqcn3acIzlZDpQj5F1rIKQZX3ptLQ=="
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
"dev": true
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -6526,6 +6541,12 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typescript": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz",
"integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==",
"dev": true
},
"uglify-js": {
"version": "2.8.29",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",

View File

@ -5,7 +5,9 @@
"main": "main.js",
"scripts": {
"start": "./node_modules/.bin/electron main.js",
"dev": "./node_modules/.bin/gulp && ./node_modules/.bin/electron main.js -d",
"dev": "npm run compile && npm run gulp && ./node_modules/.bin/electron main.js -d",
"gulp": "./node_modules/.bin/gulp",
"compile": "sh ./scripts/compile.sh",
"install": "./node_modules/.bin/electron-rebuild",
"test": "./node_modules/.bin/mocha test"
},
@ -26,6 +28,7 @@
},
"homepage": "https://github.com/sixteenmillimeter/mcopy#readme",
"devDependencies": {
"@types/jquery": "^3.3.29",
"chai": "^4.2.0",
"electron": "^4.1.3",
"electron-installer-common": "^0.6.2",
@ -36,7 +39,8 @@
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
"gulp-less": "^4.0.1",
"mocha": "^6.1.3"
"mocha": "^6.1.3",
"typescript": "^3.4.3"
},
"dependencies": {
"arduino": "file:lib/arduino",

3
app/scripts/compile.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
./node_modules/.bin/tsc ./src/lib/ui/grid.ts --outFile ./lib/ui/grid.js --noImplicitAny --lib ES2017 --lib ES2016 --lib dom -t ES2016

292
app/src/lib/ui/grid.ts Normal file
View File

@ -0,0 +1,292 @@
'use strict'
/// <reference path ="jquery.d.ts"/>
declare var gui : any;
declare var seq : any;
declare var light : any;
declare var cfg : any;
declare var log : any;
declare var w2popup : any;
interface Step {
cmd : string;
light: string;
x : number;
}
let grid : Grid;
/******
Sequencer grid
*******/
class Grid {
private swatchesElem : any = {};
constructor () {
}
public init () {
this.refresh();
seq.stats();
this.events();
}
/**
* Set a specific grid pad to the state stored in the sequence
* array at that step
*
* @param {integer} x Step in sequence
**/
public state (x : number) {
const elem : any = $(`input[x=${x}]`);
const lightElem : any = $(`.L[x=${x}]`);
const step : Step = seq.grid[x];
if (typeof step !== 'undefined') {
elem.prop('checked', false);
$(`.${step.cmd}[x=${x}]`).prop('checked', true);
if (step.cmd === 'CF' || step.cmd === 'CB') {
lightElem.css('background', `rgb(${step.light})`)
.addClass('a')
.prop('title', `rgb(${seq.light})`);
} 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.
*
**/
public refresh () {
const cmds : string[] = [
'camera_forward',
'camera_second_forward',
'projector_forward',
'projector_second_forward',
'camera_backward',
'camera_second_backward',
'projector_backward',
'projector_second_backward',
'light_set',
'numbers'
];
const width : number = 970 - 34 + ((940 / 24) * Math.abs(24 - seq.size));
let elem : any;
let cmd : string;
$('#sequence').width(`${width}px`);
for (let i : number = 0; i < cmds.length; i++) {
cmd = `#${cmds[i]}`;
$(cmd).empty();
for (let x = 0; x < seq.size; x++) {
if (cmds[i] === 'numbers') {
elem = `<div x="${x}">${x}</div>`
$(cmd).append($(elem));
} else if (cmds[i] === 'light_set') {
elem = `<div x="${x}" class="L"></div>`
$(cmd).append($(elem));
} else {
elem = `<input type="checkbox" x="${x}" />`;
$(cmd).append($(elem).addClass(cfg.cmd[cmds[i]]));
}
this.state(x);
}
}
}
/**
* Function bound to click on grid pad elements
*
* @param {object} t This, passed from clicked element
**/
public click (t : any) {
const x : number = parseInt($(t).attr('x'));
let c : string;
let checked : boolean = $(t).prop('checked');
//if input was not checked, but now is
//event occurs after user action
if (checked) {
c = $(t).attr('class').replace('.', '');
seq.set(x, c);
} else {
seq.grid[x] = undefined;
delete seq.grid[x];
seq.unset(x);
}
this.state(x);
seq.stats();
}
/**
* Clears the state of the sequence and then refreshes
* the grid and then recalculates the stats on the sequence
**/
public clear () {
const doit = confirm('Are you sure you want to clear this sequence?');
if (doit) {
seq.clear();
this.refresh();
seq.stats();
log.info('Sequencer cleared');
}
}
/**
* Add 24 frames to the sequence in the GUI
**/
plus_24 () {
seq.size += 24;
this.refresh();
log.info(`Sequencer expanded to ${seq.size} steps`);
}
/**
* Set light value to black (0,0,0) when double clicked
*
* @param {object} t This, passed from clicked element
**/
public blackout (t : any) {
const elem : any = $(t);
const x : number = parseInt(elem.attr('x'));
if (typeof seq.grid[x].light === 'undefined') {
return false;
}
console.log(x)
if (seq.grid[x].light === '0,0,0') {
seq.setLight(x, light.color);
} else {
seq.setLight(x, [0, 0, 0]);
}
}
/**
* Change all lights at all camera commands to a specific
* RGB value
*
* @param {array} rgb RGB value [255. 255, 255]
*/
public changeAll (rgb : string[]) {
let c : string;
for (let step of seq.grid) {
c = step.cmd;
if (c === 'CF' || c === 'CB') {
seq.setLight(step.x, rgb);
}
}
}
/**
* Display color swatch modal for selection of light
* color value at specific step
*
* @param {integer} x Position in sequence to change value
**/
public swatches (x : number) {
const current : any = seq.grid[x].light;
this.swatchesElem = w2popup.open({
title : 'Select Color',
body : $('#light-swatches').html(),
buttons : '<button id="sequencer-ok" class="btn btn-default">Ok</button> <button id="sequencer-changeall" class="btn btn-warning">Change All</button> <button id="sequencer-cancel" class="btn btn-default">Cancel</button>',
onClose : () => {}
});
$('.w2ui-msg-body .swatch').removeClass('default set');
$(`.w2ui-msg-body .swatch[color="${current}"`).eq(0).addClass('default set');
$('#sequencer-cancel').on('click', this.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 : string[];
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(',');
seq.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} x Step to scroll to
**/
public scrollTo (x : number) {
const w : number = 35 + 3; //width of pad + margin
$('#seq_scroll').scrollLeft(x * w);
}
/**
* Bind all events to sequence. Re-evaluate this in search
* of memory leak issues with long sequences.
**/
public events () {
$(document.body).on('click', '#sequencer input[type=checkbox]', function () {
grid.click(this);
});
//$(document.body).on('click', '.L', function () {
//alert('click');
//log.warn('please dont happen');
//});
$(document.body).on('dblclick', '.L', function () {
grid.blackout(this);
});
$(document.body).on('contextmenu', '.L', function (e) {
const x : number = e.target.attributes.x.value;
setTimeout(function () {
grid.swatches(x);
}, 300);
e.preventDefault();
return false;
});
$('#seq_scroll').on('scroll', function () {
let x : number = Math.ceil($('#seq_scroll').scrollLeft() / (35 + 3));
$('#seq_scroll_state').val(gui.fmtZero(x, 6));
});
$('#seq_scroll_state').on('change', function () {
let x : number = parseInt($(this).val() + '');
$(this).val(gui.fmtZero(x, 6));
grid.scrollTo(x);
});
$(document.body).on('click', '.w2ui-msg-body .swatch', function () {
const colorStr = $(this).attr('color');
const title = $(this).attr('title');
let color : string[];
if (typeof color !== 'undefined') {
color = colorStr.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;
}
});
};
}
grid = new Grid();
module.exports = grid

View File

@ -61,6 +61,9 @@ class Arduino {
else if ((port.comName + '').toLowerCase().indexOf('usbmodem') !== -1) {
matches.push(port.comName);
}
else if ((port.comName + '').toLowerCase().indexOf('ttyusb') !== -1) {
matches.push(port.comName);
}
});
if (matches.length === 0) {
return reject('No USB devices found');

File diff suppressed because one or more lines are too long

View File

@ -222,8 +222,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);
@ -260,8 +260,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);
@ -293,8 +293,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);

File diff suppressed because one or more lines are too long

View File

@ -61,6 +61,9 @@ class Arduino {
else if ((port.comName + '').toLowerCase().indexOf('usbmodem') !== -1) {
matches.push(port.comName);
}
else if ((port.comName + '').toLowerCase().indexOf('ttyusb') !== -1) {
matches.push(port.comName);
}
});
if (matches.length === 0) {
return reject('No USB devices found');

File diff suppressed because one or more lines are too long

View File

@ -222,8 +222,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);
@ -260,8 +260,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);
@ -293,8 +293,8 @@ class Commands {
}
else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
await delay(this.cfg.arduino.serialDelay);

File diff suppressed because one or more lines are too long

View File

@ -67,6 +67,8 @@ class Arduino {
matches.push(port.comName)
} else if ((port.comName + '').toLowerCase().indexOf('usbmodem') !== -1) {
matches.push(port.comName)
} else if ((port.comName + '').toLowerCase().indexOf('ttyusb') !== -1) {
matches.push(port.comName)
}
})
if (matches.length === 0) {

View File

@ -230,8 +230,8 @@ class Commands {
ms = await this.cam.both();
} else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
@ -268,8 +268,8 @@ class Commands {
ms = await this.cam.both();
} else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}
@ -302,8 +302,8 @@ class Commands {
ms = await this.cam.both();
} else {
this.cam.move();
this.cam.move();
both = [await this.cam.move, await this.proj2.move];
this.cam2.move();
both = [await this.cam.move, await this.cam2.move];
ms = Math.max(...both);
}