diff --git a/package.json b/package.json
index f528e3b..a52767a 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
},
"dependencies": {
"bytes": "^2.4.0",
- "cncserver": "2.6.1",
+ "cncserver": "2.6.6",
"d3plus": "^1.9.3",
"fs-finder": "^1.8.1",
"fs-plus": "^2.8.1",
diff --git a/resources/_i18n/robopaint.en-US.json b/resources/_i18n/robopaint.en-US.json
index 53521a5..4460a76 100644
--- a/resources/_i18n/robopaint.en-US.json
+++ b/resources/_i18n/robopaint.en-US.json
@@ -86,6 +86,26 @@
"autofill": "Filling path __id__...",
"autostroke": "Stroking path __id__...",
"autocomplete": "Automatic Paint Complete!",
+ "manual": {
+ "status": "Waiting for manual change...",
+ "notice": "Please insert the __color__ __type__ to continue",
+ "info": "Motors unlocked for calibration, use the toggle button find the correct draw height, ensure the pen is put back in park position, then click continue to resume drawing.",
+ "resume": "Now drawing with __color__",
+ "options": {
+ "cancel": {
+ "title": "Cancel Print [Escape]",
+ "info": "Cancel the current print job, close the mode and return to the home screen."
+ },
+ "continue": {
+ "title": "Continue with __color__ [Enter]",
+ "info": "Once you've finished changing to the correct drawing implement, click to continue drawing."
+ },
+ "toggle": {
+ "title": "Toggle height [Space]",
+ "info": "Toggle the raising/lowering of the pen to calibrate its height."
+ }
+ }
+ },
"spool": {
"stroke": "Tracing stroke path __id__...",
"fill": "Tracing fill path __id__...",
diff --git a/resources/colorsets/_i18n/colorsets.en-US.json b/resources/colorsets/_i18n/colorsets.en-US.json
index 56e4352..78925bf 100644
--- a/resources/colorsets/_i18n/colorsets.en-US.json
+++ b/resources/colorsets/_i18n/colorsets.en-US.json
@@ -5,14 +5,14 @@
"release": "0.9.2",
"basetype": "colorset"
},
-
+
"media":{
"watercolor": "Watercolor",
- "pen": "Pen",
+ "pen": "Pen/Pencil",
"engraver": "Diamond Engraver",
"wax": "Electro-Kistka"
},
-
+
"colors": {
"beige": "Beige",
"black": "Black",
diff --git a/resources/colorsets/generic/_i18n/generic.en-US.json b/resources/colorsets/generic/_i18n/generic.en-US.json
index ff205c6..db4668f 100644
--- a/resources/colorsets/generic/_i18n/generic.en-US.json
+++ b/resources/colorsets/generic/_i18n/generic.en-US.json
@@ -9,5 +9,15 @@
"manufacturer": "Generic",
"name": "Standard",
"description": "Set of primary colors in standard order. Use for stock Crayola, store brand or movable primary color pans."
+ },
+ "generic-pen-single": {
+ "manufacturer": "Generic",
+ "name": "Single pen/pencil",
+ "description": "Single color, use when only one implement needed."
+ },
+ "generic-pen-multi": {
+ "manufacturer": "Generic",
+ "name": "Multi pen/pencil",
+ "description": "Standard set of primary color pens/pencils."
}
}
diff --git a/resources/colorsets/generic/generic.json b/resources/colorsets/generic/generic.json
index cdc402f..565f93a 100644
--- a/resources/colorsets/generic/generic.json
+++ b/resources/colorsets/generic/generic.json
@@ -1,19 +1,50 @@
-[{
- "media": "watercolor",
- "machineName": "generic",
- "weight": -10,
- "styles" : {
- "src" : "standard.css",
- "baseClass": "generic-standard"
- },
- "colors": [
- {"black":"#000000"},
- {"red":"#FF0000"},
- {"orange":"#FFA500"},
- {"yellow":"#FFFF00"},
- {"green":"#008000"},
- {"blue":"#0000FF"},
- {"purple":"#800080"},
- {"brown":"#8B4513"}
- ]
-}]
+[{
+ "media": "watercolor",
+ "machineName": "generic",
+ "weight": -10,
+ "styles" : {
+ "src" : "standard.css",
+ "baseClass": "generic-standard"
+ },
+ "colors": [
+ {"black":"#000000"},
+ {"red":"#FF0000"},
+ {"orange":"#FFA500"},
+ {"yellow":"#FFFF00"},
+ {"green":"#008000"},
+ {"blue":"#0000FF"},
+ {"purple":"#800080"},
+ {"brown":"#8B4513"}
+ ]
+},
+{
+ "media": "pen",
+ "machineName": "generic-pen-single",
+ "weight": 20,
+ "styles" : {
+ "src" : "standard.css",
+ "baseClass": "generic-standard"
+ },
+ "colors": [
+ {"black":"#000000"}
+ ]
+},
+{
+ "media": "pen",
+ "machineName": "generic-pen-multi",
+ "weight": 21,
+ "styles" : {
+ "src" : "standard.css",
+ "baseClass": "generic-standard"
+ },
+ "colors": [
+ {"black":"#000000"},
+ {"red":"#FF0000"},
+ {"orange":"#FFA500"},
+ {"yellow":"#FFFF00"},
+ {"green":"#008000"},
+ {"blue":"#0000FF"},
+ {"purple":"#800080"},
+ {"brown":"#8B4513"}
+ ]
+}]
diff --git a/resources/colorsets/generic/standard.css b/resources/colorsets/generic/standard.css
index bd5f943..c7933d6 100644
--- a/resources/colorsets/generic/standard.css
+++ b/resources/colorsets/generic/standard.css
@@ -1,32 +1,32 @@
-.generic-standard #color0 {
- background-color: black; /* Black */
-}
-
-.generic-standard #color1 {
- background-color: red; /* Red */
-}
-
-.generic-standard #color2 {
- background-color: orange; /* Orange */
-}
-
-#colors.generic-standard #color3 {
- background-color: yellow; /* Yellow */
- color: black;
-}
-
-.generic-standard #color4 {
- background-color: green; /* Green */
-}
-
-.generic-standard #color5 {
- background-color: blue; /* Blue */
-}
-
-.generic-standard #color6 {
- background-color: purple; /* Violet */
-}
-
-.generic-standard #color7 {
- background-color: SaddleBrown; /* Brown */
-}
\ No newline at end of file
+.generic-standard #color0 {
+ background-color: black; /* Black */
+}
+
+.generic-standard #color1 {
+ background-color: red; /* Red */
+}
+
+.generic-standard #color2 {
+ background-color: orange; /* Orange */
+}
+
+#colors.generic-standard #color3 {
+ background-color: yellow; /* Yellow */
+ color: black;
+}
+
+.generic-standard #color4 {
+ background-color: green; /* Green */
+}
+
+.generic-standard #color5 {
+ background-color: blue; /* Blue */
+}
+
+.generic-standard #color6 {
+ background-color: purple; /* Violet */
+}
+
+.generic-standard #color7 {
+ background-color: SaddleBrown; /* Brown */
+}
diff --git a/resources/main.html b/resources/main.html
index 9d5cdf0..df5f8ff 100644
--- a/resources/main.html
+++ b/resources/main.html
@@ -42,11 +42,11 @@
...
-
+
⌛
status.question
-
+
status.button.continue
status.button.retry
external.title
@@ -64,6 +64,16 @@
external.address
+
+ libs.manual.notice
+
+
+
+
+
+
+
+
diff --git a/resources/main.js b/resources/main.js
index 70e7367..17e2fa0 100644
--- a/resources/main.js
+++ b/resources/main.js
@@ -3,6 +3,7 @@
* central cncserver object to control low-level non-restful APIs, and general
* "top-level" UI initialization for settings.
*/
+/* globals window, document, $*/
// Must use require syntax for including these libs because of node duality.
window.$ = window.jQuery = require('jquery');
@@ -73,7 +74,7 @@ try {
rpRequire('mediasets') // Colors and other media specific details.
} catch(e) {
$(function(){
- $('body.home h1').attr('class', 'error').text('Error During Pre-Initialization:')
+ $('#connection').attr('class', 'error').text('Error During Pre-Initialization:')
.append($('
').addClass('message').html("" + e.message + "\n\n" + e.stack + " "));
console.error(e.stack);
});
@@ -117,15 +118,15 @@ function startInitialization() {
initHistoryload();
// Prep the connection status overlay
- $stat = $('body.home h1');
- $options = $('.options', $stat);
+ $stat = $('#connection');
+ $options = $('.options:first', $stat);
// Actually try to init the connection and handle the various callbacks
startSerial();
bindMainControls(); // Bind all the controls for the main interface
} catch(e) {
- $('body.home h1').attr('class', 'error').text('Error During Initialization:')
+ $('#connection').attr('class', 'error').text('Error During Initialization:')
.append($('').addClass('message').html("" + e.message + "\n\n" + e.stack + " "));
console.error(e.stack);
}
@@ -234,8 +235,7 @@ function destroySubwindow(callback) {
*/
function bindMainControls() {
// Bind the continue/simulation mode button functionality
- $('button.continue', $options).click(function(e){
- $stat.fadeOut('slow');
+ $('#connection button.continue').click(function(e){
cncserver.continueSimulation();
cncserver.serialReadyInit();
@@ -251,18 +251,18 @@ function bindMainControls() {
initializing = false;
}
- setModal(false);
+ setModal(false, '#connection');
});
// Bind the reconnect button functionality
- $('button.reconnect').click(function(e){
+ $('#connection button.reconnect').click(function() {
// Reconnect! Resets status and tries to start again
$options.hide();
startSerial();
});
// Bind the external server connection button functionality
- $('button.external').click(function(e){
+ $('#connection button.external').click(function() {
if ($('div.external').is(':visible')){
$('div.external').slideUp('slow');
} else {
@@ -271,7 +271,7 @@ function bindMainControls() {
});
robopaint.statedata.external = false;
- $('button#external-go').click(function(e){
+ $('#connection button#external-go').click(function() {
var $stat = $('#external-status');
$stat.text(robopaint.t('external.status.connect'));
@@ -295,6 +295,37 @@ function bindMainControls() {
});
});
+ // Bind visible buttons to keystrokes ========================================
+ $(document).keydown(function(e) {
+ $('button[data-bind-keycode="' + e.keyCode + '"]:visible:not(:focus)').click();
+ });
+
+ // Bind buttons for manual swap ==============================================
+ $('#manualswap button').click(function() {
+ var $this = $(this);
+ if ($this.is('.toggle')) {
+ $this.toggleClass('pen-down');
+ if ($this.is('.pen-down')) {
+ cncserver.cmd.run('down', true);
+ } else {
+ cncserver.cmd.run('up', true);
+ }
+ return;
+ }
+
+ // Switch between the other two button options that close the window.
+ if ($this.is('.cancel')) {
+ // Cancel the print... then go home.
+ cncserver.fullCancel();
+ robopaint.switchMode('home');
+ } else if ($this.is('.continue')) {
+ // Run resume immediately.
+ cncserver.cmd.run('resume', true);
+ }
+ // Hide the window.
+ setModal(false, '#manualswap');
+ });
+
window.onbeforeunload = onClose; // Catch close event
// Bind links for toolbar ===========================
@@ -509,8 +540,7 @@ function startSerial(){
},
connect: function() {
setMessage('status.success', 'success');
- $stat.fadeOut('slow');
- setModal(false);
+ setModal(false, '#connection');
// If caught on startup...
if (initializing) {
@@ -526,14 +556,13 @@ function startSerial(){
initSocketIO();
},
disconnect: function() {
- setModal(true);
- $stat.show();
+ setModal(true, '#connection');
setMessage('status.disconnect', 'error');
$options.slideDown();
}
});
} catch(e) {
- $('body.home h1').attr('class', 'error').text('Error During Serial Start:')
+ $('#connection').attr('class', 'error').text('Error During Serial Start:')
.append($('').addClass('message').html("" + e.message + "\n\n" + e.stack + " "));
console.log(e.stack);
}
@@ -602,8 +631,12 @@ function initToolTips() {
target: $this, // my target,
viewport: $(window)
},
+ hide: {
+ event: 'click mouseleave'
+ },
events: {
render: function(event, api) {
+ if (!$this.data('i18n')) return;
// Extract the title translation ID
var transIDs = $this.data('i18n').split(';');
var titleTransID = transIDs[0].split(']')[1];
@@ -815,8 +848,8 @@ function getColorsets() {
$('#colorset').append(
$('')
.attr('value', setIndex)
- .text(c.type + ' - ' + c.name)
- .prop('selected', setIndex == robopaint.settings.colorset)
+ .text(c.media + ' - ' + c.type + ' - ' + c.name)
+ .prop('selected', setIndex === robopaint.settings.colorset)
.prop('disabled', !c.enabled) // Disable unavailable options
);
});
@@ -1049,12 +1082,15 @@ function setMessage(transKey, mode, append){
*
* @param {Boolean} toggle
* True for modal overlay on, false for off.
+ * @param {string} selectors
+ * Selectors to add to the fadeIn/Out.
*/
-function setModal(toggle){
+function setModal(toggle, selectors){
+ selectors = selectors ? [selectors, '#modalmask'] : ['#modalmask'];
if (toggle) {
- $('#modalmask').fadeIn('slow');
+ $(selectors.join(', ')).fadeIn('slow');
} else {
- $('#modalmask').fadeOut('slow');
+ $(selectors.join(', ')).fadeOut('fast');
}
isModal = toggle;
diff --git a/resources/rp_modules/cncserver.commander.js b/resources/rp_modules/cncserver.commander.js
index cb77c0f..704139c 100644
--- a/resources/rp_modules/cncserver.commander.js
+++ b/resources/rp_modules/cncserver.commander.js
@@ -6,6 +6,7 @@
* Only applies to specific API functions that require waiting for the bot to
* finish, handles all API callbacks internally.
*/
+/* globals window, $ */
var robopaint = window.robopaint;
var _ = window._;
@@ -15,8 +16,6 @@ var cncserver = robopaint.cncserver;
// That commands sent very quickly get sent out in the correct order.
var sendBuffer = cncserver.sendBuffer = [];
var running = false;
-var lastPoint = {};
-
// Command iterator (sends the next command to be timed/queued by CNCserver)
function sendNext() {
@@ -81,13 +80,17 @@ function sendNext() {
case "media":
cncserver.wcb.setMedia(cmd[1], sendNext, true);
break;
+
case "tool":
api.tools.change(cmd[1], sendNext, {ignoreTimeout: '1'});
break;
+
case "up":
setHeight = 0;
+ /* falls through */
case "down":
if (setHeight === null) setHeight = 1;
+ /* falls through */
case "height":
if (setHeight === null) setHeight = cmd[1]; // Specific height
var options = {};
@@ -102,6 +105,7 @@ function sendNext() {
api.pen.height(setHeight, sendNext, options);
}
break;
+
case "power":
var setPower = cmd[1]; // Power from 0 to 1
if (!robopaint.statedata.external) {
@@ -110,6 +114,7 @@ function sendNext() {
api.pen.power(setPower, sendNext);
}
break;
+
case "status":
// Third argument: skipBuffer
if (cmd[2] === true) { // Skipping buffer means just show it!
@@ -119,6 +124,7 @@ function sendNext() {
api.buffer.message(cmd[1], sendNext);
}
break;
+
case "progress":
// Shortcut for streaming progress updates from modes. Use sparingly.
var p = {val: cmd[1]};
@@ -126,24 +132,29 @@ function sendNext() {
cncserver.progress(p);
sendNext();
break;
+
case "callbackname":
api.buffer.callbackname(cmd[1], sendNext);
break;
+
case "pause":
api.buffer.pause(function(){
cncserver.pushToMode('fullyPaused');
sendNext();
});
break;
+
case "resume":
api.buffer.resume(function(){
cncserver.pushToMode('fullyResumed');
sendNext();
});
break;
+
case "clear":
api.buffer.clear(sendNext);
break;
+
case "localclear":
sendBuffer = cncserver.sendBuffer = [];
@@ -154,18 +165,25 @@ function sendNext() {
}
sendNext();
break;
+
case "resetdistance":
api.pen.resetCounter(sendNext);
break;
+
case "zero":
api.pen.zero(sendNext);
break;
+
case "unlock":
- api.motors.unlock(sendNext);
+ options = {};
+ if (cmd[1] === true) options.skipBuffer = true;
+ api.motors.unlock(sendNext, options);
break;
+
case "wash":
cncserver.wcb.fullWash(sendNext, cmd[1], true);
break;
+
case "park":
options = {ignoreTimeout: '1'};
@@ -174,6 +192,7 @@ function sendNext() {
api.pen.park(sendNext, options);
break;
+
default:
console.debug('Queue shortcut not found:' + cmd);
sendNext();
@@ -190,7 +209,7 @@ cncserver.cmd = {
// Reverse the order of items added to the wrong end of the buffer
if (reverse) arguments[0].reverse();
- $.each(arguments[0], function(i, args){
+ $.each(arguments[0], function(i, args) {
if (!reverse) {
sendBuffer.unshift(args);
} else {
diff --git a/resources/rp_modules/cncserver.manager.js b/resources/rp_modules/cncserver.manager.js
index c62de10..2e4858c 100644
--- a/resources/rp_modules/cncserver.manager.js
+++ b/resources/rp_modules/cncserver.manager.js
@@ -2,10 +2,7 @@
* @file Manage clientside state, messages, progress bar and status, and all
* cncserver specific communication from modes to the one instance of the API.
*/
-var $ = window.$;
-var _ = window._;
-var robopaint = window.robopaint;
-var cncserver = robopaint.cncserver;
+/* globals $, _, robopaint, cncserver, i18n, setModal */
var modeWindow = {};
cncserver.state = {
@@ -28,7 +25,7 @@ cncserver.state = {
// When the subwindow has been (re)created.
$(robopaint).on('subwindowReady', function(){
- modeWindow = window.$subwindow[0]; // Set to actual webview
+ modeWindow = $subwindow[0]; // Set to actual webview
// Bind for client messages
modeWindow.addEventListener('ipc-message', function(event){
@@ -82,6 +79,7 @@ $(robopaint).on('socketIOComplete', function(){
}
robopaint.socket.on('message update', messageUpdateEvent);
robopaint.socket.on('callback update', callbackEvent);
+ robopaint.socket.on('manualswap trigger', manualSwapTrigger);
});
// CNCServer Buffer Change events (for pause, update, or resume)
@@ -139,6 +137,39 @@ function bufferUpdateEvent(b){
}
}
+/**
+ * Tool manual swap event trigger. When a queued tool change to a manual tool
+ * is reached, the queue will be paused and this will get called. We need to
+ * tell the use to get ready and actually do the manual swap. When done, we just
+ * resume the queue.
+ *
+ * @param {object} data
+ * Currently only supports one property: index, containing the originally sent
+ * tool index (color) to be used to tell the user what they should change to.
+ */
+function manualSwapTrigger(data) {
+ // Alert user.
+ var shell = require('electron').shell;
+ shell.beep();
+
+ // Unlock immediately.
+ cncserver.cmd.run('unlock', true);
+
+ // Translate window text based on given implement.
+ var set = robopaint.media.currentSet;
+ var name = set.colors[data.index].name;
+ var type = set.media.toLowerCase();
+ $('#manualswap b').text(
+ i18n.t('libs.manual.notice', {color: name.toLowerCase(), type: type})
+ );
+ $('#manualswap button.continue').text(
+ i18n.t('libs.manual.options.continue.title', {color: name})
+ );
+
+ // Show window and overlay.
+ setModal(true, '#manualswap');
+}
+
// Pen update event callback
function penUpdateEvent(actualPen){
actualPen.absCoord = cncserver.utils.getStepstoAbsCoord(actualPen);
@@ -178,36 +209,7 @@ $(robopaint).on('settingsUpdate', function(){
// Handle CNCServer requests from mode windows.
function handleClientCmd(type, data) {
switch(type) {
- case 'pauseTillEmpty':
- if (data === true) { // Starting
- if (!cncserver.state.pausingTillEmpty) {
- cncserver.state.pausingTillEmpty = true;
- cncserver.api.buffer.pause();
- }
- } else { // Finishing (initialize check)
- if (cncserver.state.pausingTillEmpty) {
- var max = cncserver.sendBuffer.length;
- var last = max;
- var val = 0;
- cncserver.status(robopaint.t('status.pausetillempty'));
- cncserver.progress({max: max, val: val});
- cncserver.state.pausingTillEmpty = true;
- var poll = setInterval(function () {
- if (cncserver.sendBuffer.length === 0) { // Sendbuffer is empty! Resume.
- cncserver.api.buffer.resume(function(){
- clearInterval(poll);
- cncserver.state.pausingTillEmpty = false;
- });
- } else {
- val+= last - cncserver.sendBuffer.length;
- last = cncserver.sendBuffer.length;
- cncserver.status(robopaint.t('status.pausetillempty') + ' ' + val + '/' + max);
- cncserver.progress({val: val, max: max});
- }
- }, 200);
- }
- }
- break;
+
default:
console.log('CNC clientcmd', args);
}
@@ -271,5 +273,20 @@ cncserver.progress = function(p) {
popoutStatus();
};
+/**
+ * Fully cancel anything that's going on.
+ */
+cncserver.fullCancel = function() {
+ cncserver.cmd.run([
+ 'clear',
+ 'resume',
+ 'park',
+ ['progress', 0, 1],
+ 'localclear'
+ // As a nice reminder, localclear MUST be last, otherwise the commands
+ // after it will be cleared before being sent :P
+ ], true); // As this is a forceful cancel, shove to the front of the queue
+};
+
// TODO: Provide something for the parent script?
module.exports = {};
diff --git a/resources/rp_modules/cncserver.wcb.js b/resources/rp_modules/cncserver.wcb.js
index 5da14eb..01b320c 100644
--- a/resources/rp_modules/cncserver.wcb.js
+++ b/resources/rp_modules/cncserver.wcb.js
@@ -2,6 +2,7 @@
* @file Holds all Robopaint watercolorbot specific configuration and utility
* functions.
*/
+/* globals window, mainWindow */
var robopaint = window.robopaint;
var cncserver = robopaint.cncserver;
@@ -15,7 +16,9 @@ cncserver.wcb = {
case 2: // Dissallow water
cncserver.status(
robopaint.t('libs.ignorewash', {mode:
- robopaint.t('settings.output.penmode.opt' + robopaint.settings.penmode)
+ robopaint.t(
+ 'settings.output.penmode.opt' + robopaint.settings.penmode
+ )
})
);
if (callback) callback(true);
@@ -50,7 +53,7 @@ cncserver.wcb = {
// Get the name of paint/water/media on the brush
getMediaName: function(toolName) {
- if (typeof toolName != 'string') toolName = cncserver.state.media;
+ if (typeof toolName !== 'string') toolName = cncserver.state.media;
if (toolName === "") return '';
// TODO: There probably has to be a better way to do this.
@@ -59,17 +62,25 @@ cncserver.wcb = {
if (toolName.indexOf('water') !== -1) {
return robopaint.t('common.water');
} else {
- return robopaint.media.currentSet.colors[toolName.substr(-1)].name;
+ if (robopaint.media.currentSet.colors[toolName.substr(-1)]) {
+ return robopaint.media.currentSet.colors[toolName.substr(-1)].name;
+ } else {
+ console.error(
+ 'Mode requested tool index [' +
+ toolName.substr(-1) + '] not available. Defaulting to 0.'
+ );
+ return robopaint.media.currentSet.colors[0].name;
+ }
}
},
// Wrapper for toolchange to manage pen mode logic
setMedia: function(toolName, callback, fromSendBuffer){
var name = cncserver.wcb.getMediaName(toolName).toLowerCase();
- var mode = parseInt(robopaint.settings.penmode);
+ var mode = parseInt(robopaint.settings.penmode, 10);
// Water change
- if (name == "water") {
+ if (name === "water") {
switch(mode) {
case 3: // Dissallow all
case 2: // Dissallow water
@@ -81,7 +92,7 @@ cncserver.wcb = {
if (callback) callback(true);
return;
}
- } else { // Color Change
+ } else if (toolName.indexOf('color') !== -1) { // Color Change
switch(mode) {
case 3: // Dissallow all
case 1: // Dissallow paint
@@ -96,21 +107,27 @@ cncserver.wcb = {
}
// If we've gotten this far, we can make the change!
-
// Save the targeted media (separate from media state)
cncserver.state.mediaTarget = toolName;
- // Visually show the selection
- var idName = toolName.indexOf('dip') !== -1 ? toolName.slice(0, -3) : toolName;
- $('nav#tools a.selected').removeClass('selected');
- $('nav#tools #' + idName).addClass('selected');
+ if (toolName.indexOf('manualswap') !== -1) { // Manual Change
+ // Spool into the buffer pen specific statuses and manualswap start.
+ cncserver.cmd.run([
+ ['status', robopaint.t('libs.manual.status', {color: name})],
+ 'resetdistance',
+ ['tool', toolName], // Buffer will pause on this, till resume.
+ ['status', robopaint.t('libs.manual.resume', {color: name})]
+ ], fromSendBuffer);
+ } else {
+ // Spool into the buffer brush specific statuses and tool change.
+ cncserver.cmd.run([
+ ['status', robopaint.t('libs.inking', {media: name})],
+ 'resetdistance',
+ ['tool', toolName],
+ ['status', robopaint.t('libs.inked', {media: name})]
+ ], fromSendBuffer);
+ }
- cncserver.cmd.run([
- ['status', robopaint.t('libs.inking', {media: name})],
- 'resetdistance',
- ['tool', toolName],
- ['status', robopaint.t('libs.inked', {media: name})]
- ], fromSendBuffer);
if (callback) callback();
},
@@ -122,9 +139,11 @@ cncserver.wcb = {
// Reset the counter for every mode on getMorePaint
robopaint.cncserver.api.pen.resetCounter();
+ var penmode = parseInt(robopaint.settings.penmode, 10);
+ var refillaction = parseInt(robopaint.settings.refillaction, 10);
// Change what happens here depending on penmode
- switch(parseInt(robopaint.settings.penmode)) {
+ switch(penmode) {
case 1: // Dissallow paint
// TODO: Does this output the wrong target name if disallowed?
cncserver.cmd.run([
@@ -158,7 +177,7 @@ cncserver.wcb = {
if (callback) callback(true);
break;
default:
- if (parseInt(robopaint.settings.refillaction) == 0) {
+ if (refillaction === 0) {
cncserver.cmd.run([
['status', robopaint.t('libs.reinking', {media: name})],
'resetdistance',
@@ -169,7 +188,7 @@ cncserver.wcb = {
['status', robopaint.t('libs.reinked', {media: name})],
'down'
], true); // Add to the start (not the end) of the local buffer
- } else if (parseInt(robopaint.settings.refillaction) == 1) {
+ } else if (parseInt(robopaint.settings.refillaction, 10) === 1) {
cncserver.cmd.run([
['status', robopaint.t('libs.reinking', {media: name})],
'resetdistance',
@@ -180,7 +199,7 @@ cncserver.wcb = {
['status', robopaint.t('libs.reinked', {media: name})],
'down'
], true); // Add to the start (not the end) of the local buffer
- } else if (parseInt(robopaint.settings.refillaction) == 2) {
+ } else if (refillaction === 2) {
cncserver.cmd.run([
['status', robopaint.t('libs.reinking', {media: name})],
'resetdistance',
@@ -197,14 +216,4 @@ cncserver.wcb = {
if (callback) callback();
}
},
-
- // Retrieve a fill path depending on config
- getFillPath: function(options){
- var ft = options.filltype;
- if (ft == 'tsp') {
- return $('#fill-spiral');
- } else {
- return $('#fill-' + ft);
- }
- }
};
diff --git a/resources/rp_modules/paper.auto.fill.js b/resources/rp_modules/paper.auto.fill.js
index dc448ad..2ad6d83 100644
--- a/resources/rp_modules/paper.auto.fill.js
+++ b/resources/rp_modules/paper.auto.fill.js
@@ -331,10 +331,8 @@ module.exports = function(paper) {
return false;
}
- // Ignore white paths (color id 8)
- // TODO: This should probably be handled depending on num of colors in the
- // media (you can have more pens than 8), paper color might not be white.
- if (fillPath.data.color === 'color8') {
+ // Ignore white/skip paths.
+ if (fillPath.data.color === false) {
fillPath.remove();
return true;
}
diff --git a/resources/rp_modules/paper.auto.stroke.js b/resources/rp_modules/paper.auto.stroke.js
index 7464e70..0f3c676 100644
--- a/resources/rp_modules/paper.auto.stroke.js
+++ b/resources/rp_modules/paper.auto.stroke.js
@@ -198,7 +198,7 @@ module.exports = function(paper) {
// color (only when they have a fillable color);
if (!path.closed && settings.closeFilledPaths) {
if (hasColor(path.fillColor)) {
- if (snapColorID(path.fillColor, path.opacity) !== 'color8') {
+ if (snapColorID(path.fillColor, path.opacity) !== false) {
path.closed = true;
}
}
@@ -288,11 +288,8 @@ module.exports = function(paper) {
return true;
}
- // Ignore white paths (color id 8)
- // TODO: This should probably be handled depending on number of colors in the
- // media (you can have more pens than 8), paper color might not be white.
- if (cPath.data.color === 'color8') {
- console.log('REMOVE WHITE STROKE:', cPath);
+ // Ignore white/skip paths
+ if (cPath.data.color === false) {
cPath.remove(); return true;
}
diff --git a/resources/rp_modules/paper.hersheytext.js b/resources/rp_modules/paper.hersheytext.js
index 1253131..b4ca829 100644
--- a/resources/rp_modules/paper.hersheytext.js
+++ b/resources/rp_modules/paper.hersheytext.js
@@ -1,6 +1,7 @@
/*
* @file exports a function for rendering Hersheytext onto a PaperScope Layer.
*/
+/* globals _, window */
var hershey = window.hershey ? window.hershey : require('hersheytext');
@@ -16,7 +17,7 @@ module.exports = function(paper) {
paper.renderText = function(text, options) {
// Mesh in option defaults
- options = $.extend({
+ options = _.extend({
spaceWidth: 15,
strokeWidth: 2,
strokeColor: 'black',
@@ -35,14 +36,14 @@ module.exports = function(paper) {
var t = hershey.renderTextArray(text, options);
var caretPos = new Point(0, 50);
- chars.remove()
+ chars.remove();
chars = new Group(); // Hold output lines groups
var lines = [new Group()]; // Hold chars in lines
var cLine = 0;
_.each(t, function(char, index){
if (char.type === "space" || char.type === "newline") {
- caretPos.x+= options.spaceWidth
+ caretPos.x+= options.spaceWidth;
// Allow line wrap on space
if (caretPos.x > options.wrapWidth || char.type === "newline") {
@@ -91,7 +92,9 @@ module.exports = function(paper) {
});
chars.addChildren(lines);
- chars.position = view.center.add(new Point(options.hCenter, options.vCenter));
+ chars.position = view.center.add(
+ new Point(options.hCenter, options.vCenter)
+ );
chars.scale(options.scale);
// Align the lines
@@ -108,5 +111,5 @@ module.exports = function(paper) {
// Rotation!
chars.rotate(options.rotation);
- }
+ };
};
diff --git a/resources/rp_modules/paper.utils.js b/resources/rp_modules/paper.utils.js
index dd7b256..4391597 100644
--- a/resources/rp_modules/paper.utils.js
+++ b/resources/rp_modules/paper.utils.js
@@ -1,16 +1,14 @@
/**
* @file Robopaint->Mode->Paper.JS include module. Contains useful paper.js
- * paper.js not tied to mode specific use that will be attached to the passed
- * paper object under paper.utils
+ * utilities not tied to mode specific use that will be attached to the passed
+ * paper object under paper.utils.
*/
-/* globals _ */
+/* globals $, _, robopaint, mode, i18n */
module.exports = function(paper) {
// Emulate PaperScript "Globals" as needed
var Point = paper.Point;
- var Path = paper.Path;
var Layer = paper.Layer;
- var view = paper.view;
var project = paper.project;
paper.utils = {
@@ -29,10 +27,17 @@ module.exports = function(paper) {
setupLayers: function() {
if (!paper.canvas) paper.canvas = {};
- paper.canvas.mainLayer = project.getActiveLayer(); // SVG is imported to here
- paper.canvas.tempLayer = new Layer(); // Temporary working layer
- paper.canvas.actionLayer = new Layer(); // Actual movement paths & preview
- paper.canvas.overlayLayer = new Layer(); // Overlay elements, like the pen position.
+ // SVG is imported to here
+ paper.canvas.mainLayer = project.getActiveLayer();
+
+ // Temporary working layer
+ paper.canvas.tempLayer = new Layer();
+
+ // Actual movement paths & preview
+ paper.canvas.actionLayer = new Layer();
+
+ // Overlay elements, like the pen position.
+ paper.canvas.overlayLayer = new Layer();
},
// Check if a fill/stroke color is "real".
@@ -233,15 +238,15 @@ module.exports = function(paper) {
// 3. Has fill, no stroke (Strokeless Filled shape)
// 4. No fill, No stroke (Invisible path!)
if (hasStroke && hasFill) {
- return 1
+ return 1;
}
if (hasStroke && !hasFill) {
- return 2
+ return 2;
}
if (!hasStroke && hasFill) {
- return 3
+ return 3;
}
if (!hasStroke && !hasFill) {
@@ -271,12 +276,21 @@ module.exports = function(paper) {
}
},
- // Snap the given color to the nearest tool ID
- // TODO: When refactoring media sets, pull tool names from definition.
+ // Snap the given color to the nearest tool ID name.
snapColorID: function (color, opacity) {
+ var penmode = parseInt(robopaint.settings.penmode, 10);
+
+ // Is the color/opacity transparent?
if ((typeof opacity !== 'undefined' && opacity < 1) ||
(color.alpha < 1 && color.alpha > 0)) {
- return 'water2';
+
+ // If the penmode supports water, output that.
+ if (penmode === 0 || penmode === 1) {
+ return 'water2';
+ } else {
+ // If it doesn't, match to white/skip.
+ return false;
+ }
}
// If the color has alpha at this point, we need to reset that to 1 as the
@@ -286,16 +300,28 @@ module.exports = function(paper) {
color.alpha = 1;
}
- var closestColorID = robopaint.utils.closestColor(color.toCSS(), robopaint.media.currentSet.colors);
+ var closestColorID = robopaint.utils.closestColor(
+ color.toCSS(), robopaint.media.currentSet.colors
+ );
+
+ // If the closest color is outside the range, skip it.
+ if (closestColorID === -1) {
+ return false;
+ }
// Skip white paint if selected and setting is enabled.
if (robopaint.media.currentSet.colors[closestColorID].key === 'white') {
if (robopaint.settings.skipwhite) {
- // Change ID to "skipped" id 8
- closestColorID = 8;
+ return false;
}
}
- return "color" + closestColorID;
+
+ // If pen/pencil mode, return a special ID with a color index in it.
+ if (penmode === 3) {
+ return "manualswap|" + closestColorID;
+ } else {
+ return "color" + closestColorID;
+ }
},
// Get the actual color of the nearest color to the one given.
@@ -309,6 +335,11 @@ module.exports = function(paper) {
snapID = paper.utils.snapColorID(color, opacity);
}
+ // If the closest color is a skip, just use white.
+ if (snapID === false) {
+ return new paper.Color(robopaint.media.white.color.HEX);
+ }
+
var outColor;
// Switch between water and regular colors
if (snapID.indexOf('water') !== -1) {
@@ -317,7 +348,9 @@ module.exports = function(paper) {
outColor = new paper.Color('#256d7b');
outColor.alpha = 0.3;
} else {
- outColor = new paper.Color(robopaint.media.currentSet.colors[snapID.substr(-1)].color.HEX);
+ outColor = new paper.Color(
+ robopaint.media.currentSet.colors[snapID.substr(-1)].color.HEX
+ );
}
return outColor;
@@ -348,7 +381,7 @@ module.exports = function(paper) {
},
- // Find the closest point to a given source point from an array of point groups.
+ // Find the closest point to a given point from an array of point groups.
closestPointInGroup: function (srcPoint, pathGroup) {
var closestID = 0;
var closestPointIndex = 0;
@@ -362,27 +395,31 @@ module.exports = function(paper) {
closestID = index;
closestPointIndex = pointIndex;
}
- })
+ });
});
- return {id: closestID, closestPointIndex: closestPointIndex, dist: closest};
+ return {
+ id: closestID,
+ closestPointIndex: closestPointIndex,
+ dist: closest
+ };
},
- // Order a layers children by top left travel path from tip to tail, reversing
- // path order where needed, grouped by data.color. Only works with paths,
- // not groups or compound paths as it needs everything on an even playing
- // field to be reordered.
+ // Order a layers children by top left travel path from tip to tail,
+ // reversing path order where needed, grouped by data.color. Only works
+ // with paths, not groups or compound paths as it needs everything on an
+ // even playing field to be reordered.
travelSortLayer: function(layer) {
var a = layer;
if (a.children.count <= 1) return; // This doesn't need to be run
// 1. Move through all paths, group into colors
- // 2. Move through each group, convert list of paths into sets of first and
- // last segment points, ensure groups are sorted by luminosity.
- // 3. Find the point closest to the top left corner. If it's an end, reverse
- // the path associated, make the first point the next one to check, remove
- // the points from the group.
+ // 2. Move through each group, convert list of paths into sets of first
+ // and last segment points, ensure groups are sorted by luminosity.
+ // 3. Find the point closest to the top left corner. If it's an end,
+ // reverse the path associated, make the first point the next one to
+ // check, remove the points from the group.
// 4. Rinse and repeat!
// Prep the colorGroups
@@ -390,7 +427,7 @@ module.exports = function(paper) {
var colorGroups = {};
_.each(sortedColors, function(tool) {
colorGroups[tool] = [];
- })
+ });
// Put each path in the sorted colorGroups, with its first and last point
_.each(a.children, function(path){
@@ -416,7 +453,7 @@ module.exports = function(paper) {
});
// Move through each color group, then each point set for distance
- var drawIndex = 0; // Track the path index to insert paths into on the layer
+ var drawIndex = 0; // Track the path index to insert paths to on the layer
_.each(colorGroups, function(group){
var lastPoint = new Point(0, 0); // Last point, start at the corner
var lastPath = null; // The last path worked on for joining 0 dist paths
@@ -436,7 +473,6 @@ module.exports = function(paper) {
lastPoint = group[c.id].points[0];
}
-
// If the distance between the lastPoint and the next closest point is
// 0, and our lastPoint is on a path, we can make this more efficient
// by joining the two paths.
@@ -483,6 +519,13 @@ module.exports = function(paper) {
// Actually handle a fully setup action layer to be streamed into the buffer
// in the path and segment order they're meant to be streamed.
autoPaint: function(layer) {
+ // Run through and delete any paths without color/tool information.
+ _.each(_.extend([], layer.children), function(path){
+ if (path.data.color === false) {
+ path.remove();
+ }
+ });
+
if (robopaint.settings.optimizepath) {
paper.utils.travelSortLayer(layer);
}
@@ -497,12 +540,6 @@ module.exports = function(paper) {
// * data.type: either "fill" or "stroke"
var runColor;
- if (robopaint.settings.prefillbuffer) {
- // Wait for all these commands to stream in before starting to actually
- // run them. This ensures a smooth start.
- robopaint.pauseTillEmpty(true);
- }
-
// Add a callback for begin so we know when things have kicked off, which
// can definitely be later than expected if prefillbuffer is enabled.
run('callbackname', 'autoPaintBegin');
@@ -514,7 +551,7 @@ module.exports = function(paper) {
run(['wash', ['media', runColor]]);
}
- var typeKey = 'stroke'
+ var typeKey = 'stroke';
if (path.data.type === "fill") {
typeKey = 'fill';
}
@@ -522,7 +559,7 @@ module.exports = function(paper) {
// If it doesn't have a name, default to an empty string.
if (typeof path.data.name === 'undefined') path.data.name = '';
- run('status', i18n.t('libs.auto' + typeKey, {id: path.data.name}))
+ run('status', i18n.t('libs.auto' + typeKey, {id: path.data.name}));
paper.utils.runPath(path);
});
@@ -530,18 +567,10 @@ module.exports = function(paper) {
run([
'wash',
'park',
- 'up', // Ensure the last command sent is clean, see evil-mad/robopaint#250
+ 'up', // Ensure last command sent is clean, see evil-mad/robopaint#250
['status', i18n.t('libs.autocomplete')],
['callbackname', 'autoPaintComplete']
]);
-
-
- if (robopaint.settings.prefillbuffer) {
- // This tells pause Till Empty that we're ready to start checking for
- // local buffer depletion. We can't check sooner as we haven't finished
- // sending all the data yet!
- robopaint.pauseTillEmpty(false);
- }
}
- }
+ };
};
diff --git a/resources/rp_modules/robopaint.mediasets.js b/resources/rp_modules/robopaint.mediasets.js
index 2680015..0aa9fe7 100644
--- a/resources/rp_modules/robopaint.mediasets.js
+++ b/resources/rp_modules/robopaint.mediasets.js
@@ -2,6 +2,7 @@
* @file Holds all Robopaint media / color set related loading, parsing, etc
* functionality.
*/
+/* globals _, window */
var robopaint = window.robopaint;
var fs = require('fs-plus');
@@ -24,77 +25,79 @@ robopaint.media = {
this.sets = {};
+ // Save a universal white for color comparisons.
+ robopaint.media.white = robopaint.media.getColorsetColor(
+ '#FFFFFF', 'white'
+ );
+
// Move through each colorset JSON definition file...
- for(var i in sets) {
- var set = sets[i];
+ _.each(sets, function(set) {
var setDir = colorsetDir + set + '/';
-
+ var fileSets = {};
try {
- var fileSets = require(setDir + set + '.json');
+ fileSets = require(setDir + set + '.json');
} catch(e) {
// Silently fail on bad parse!
- continue;
+ return;
}
// Move through all colorsets in file
- for(var s in fileSets) {
- var c = fileSets[s];
- var machineName = c.machineName;
+ _.each(fileSets, function(fileSet, fileSetKey) {
+ var machineName = fileSet.machineName;
+ var colorsOut = [];
try {
- // Add pure white to the end of the color set for auto-color
- c.colors.push({'white': '#FFFFFF'});
-
// Process Colors to avoid re-processing later
- var colorsOut = [];
- for (var i in c.colors){
- var color = c.colors[i];
+ _.each(fileSet.colors, function(color){
var name = Object.keys(color)[0];
- var h = c.colors[i][name];
- var r = robopaint.utils.colorStringToArray(h);
- colorsOut.push({
- name: robopaint.t("colorsets.colors." + name),
- key: name,
- color: {
- HEX: h,
- RGB: r,
- HSL: robopaint.utils.rgbToHSL(r),
- YUV: robopaint.utils.rgbToYUV(r)
- }
-
- });
- }
+ colorsOut.push(robopaint.media.getColorsetColor(color[name], name));
+ });
} catch(e) {
- console.error("Parse error on colorset: " + s, e);
- continue;
+ console.error("Parse error on colorset: " + fileSetKey, e);
+ return;
}
+
// Use the machine name and set name of the colorset to create translate
// strings.
var name = "colorsets." + set + "." + machineName + ".name";
var maker = "colorsets." + set + "." + machineName + ".manufacturer";
var desc = "colorsets." + set + "." + machineName + ".description";
- var media = "colorsets.media." + c.media;
+ var media = "colorsets.media." + fileSet.media;
- robopaint.media.sets[c.styles.baseClass] = {
+ robopaint.media.sets[machineName] = {
name: robopaint.t(name),
type: robopaint.t(maker),
- weight: parseInt(c.weight),
+ weight: parseInt(fileSet.weight),
description: robopaint.t(desc),
media: robopaint.t(media),
- enabled: robopaint.currentBot.allowedMedia[c.media],
- baseClass: c.styles.baseClass,
+ enabled: robopaint.currentBot.allowedMedia[fileSet.media],
+ baseClass: fileSet.styles.baseClass,
colors: colorsOut,
- styleSrc: setDir + c.styles.src
+ styleSrc: setDir + fileSet.styles.src
};
- }
- }
+ });
+ });
this.setOrder = Object.keys(robopaint.media.sets).sort(function(a, b) {
- return (robopaint.media.sets[a].weight - robopaint.media.sets[b].weight)
+ return (robopaint.media.sets[a].weight - robopaint.media.sets[b].weight);
});
},
+ // Get the colorset color object for a HEX color and machine name.
+ getColorsetColor: function(colorHex, name) {
+ var colorRGB = robopaint.utils.colorStringToArray(colorHex);
+ return {
+ name: robopaint.t("colorsets.colors." + name),
+ key: name,
+ color: {
+ HEX: colorHex,
+ RGB: colorRGB,
+ HSL: robopaint.utils.rgbToHSL(colorRGB),
+ YUV: robopaint.utils.rgbToYUV(colorRGB),
+ }
+ };
+ },
// Add a stylesheet for the given media set to the page
// TODO: fully document
@@ -109,6 +112,11 @@ robopaint.media = {
// Always return the current media set, as defined in robopaint.settings
get currentSet() {
if (!this.sets) this.load();
+
+ // If the saved set doesn't exist anymore, default to generic.
+ if (!this.sets[robopaint.settings.colorset]) {
+ robopaint.settings.colorset = 'generic';
+ }
return this.sets[robopaint.settings.colorset];
},
@@ -117,14 +125,14 @@ robopaint.media = {
var colorsort = [];
// Use JS internal sort by slapping a zero padded value into an array
- $.each(robopaint.media.currentSet.colors, function(index, color){
- if (index != 8) { // Ignore white
- colorsort.push(robopaint.utils.pad(color.color.YUV[0], 3) + '|' + 'color' + index);
- }
+ _.each(robopaint.media.currentSet.colors, function(color, index){
+ colorsort.push(
+ robopaint.utils.pad(color.color.YUV[0], 3) + '|' + 'color' + index
+ );
});
colorsort.sort().reverse();
- // Now extract the luminostiy from the array, and leave a clean list of colors
+ // Now extract the luminostiy from the array, and leave a clean color list.
for(var i in colorsort){
colorsort[i] = colorsort[i].split('|')[1];
}
@@ -136,4 +144,4 @@ robopaint.media = {
return colorsort;
},
-}
+};
diff --git a/resources/rp_modules/robopaint.utils.js b/resources/rp_modules/robopaint.utils.js
index b867d65..1c56e6d 100644
--- a/resources/rp_modules/robopaint.utils.js
+++ b/resources/rp_modules/robopaint.utils.js
@@ -2,6 +2,7 @@
* @file Holds all Utility helper functions, must not be linked to anything
* cncserver specific as every function should be atomic (at least to this file)
*/
+/* globals robopaint, _, $ */
var utils = {
/**
@@ -18,15 +19,14 @@ var utils = {
rgbToHSL: function (color){
if (!color) return false;
- var r = color[0];
- var g = color[1];
- var b = color[2];
+ var r = color[0] / 255;
+ var g = color[1] / 255;
+ var b = color[2] / 255;
- r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
- if(max == min){
+ if (max === min){
h = s = 0; // achromatic
}else{
var d = max - min;
@@ -121,7 +121,7 @@ var utils = {
*/
colorStringToArray: function(string) {
// Quick sanity check
- if (typeof string != 'string') {
+ if (typeof string !== 'string') {
return null;
}
@@ -131,7 +131,7 @@ var utils = {
$.each(color, function(i, c){
color[i] = Number(c);
- })
+ });
return color;
} else if(string.indexOf('#') !== -1) {
@@ -161,17 +161,22 @@ var utils = {
* @param {Array/String} source
* triplet array [r,g,b] or jQuery RGB string like "rgb(0,0,0)"
* @param {Array} colors
- * Array of triplet arrays defining up to 7 colors, like [[r,g,b], [r,g,b], ...]
+ * Array of colorset objects defining colors.
* @return {Number}
- * The index in the colors array that best matches the incoming color
+ * The index in the colors array that best matches the incoming color, -1
+ * if white/background color is best match.
*/
closestColor: function(source, colors){
- if (typeof source == 'string'){
+ // Clone colors so we can compare with a "white" color in it.
+ colors = _.extend([], colors);
+ colors.push(robopaint.media.white);
+
+ if (typeof source === 'string'){
source = utils.colorStringToArray(source);
}
// Assume false (white) if null
- if (source == null || isNaN(source[0])){
+ if (source === null || isNaN(source[0])){
source = utils.colorStringToArray('#FFFFFF');
}
@@ -181,7 +186,7 @@ var utils = {
var lowestIndex = 0;
var lowestValue = 1000; // High value start is replaced immediately below
var distance = 0;
- for (var i=0; i < colors.length; i++){
+ for (var i = 0; i < colors.length; i++){
var c = colors[i].color.YUV;
// Color distance finder
@@ -197,6 +202,12 @@ var utils = {
lowestIndex = i;
}
}
+
+ // If we picked the last color (our added white), force value to be -1.
+ if (lowestIndex === colors.length - 1) {
+ lowestIndex = -1;
+ }
+
return lowestIndex;
},
@@ -211,7 +222,7 @@ var utils = {
* The zero padded string
*/
pad: function(str, max) {
- if (typeof str == "number") str = String(str);
+ if (typeof str === "number") str = String(str);
return str.length < max ? utils.pad("0" + str, max) : str;
},
@@ -238,7 +249,7 @@ var utils = {
height: $path.transformMatrix.d * bbox.height
// TODO: Add X & Y?
};
- }
+ };
if ($path[0].getTotalLength) {
$path.maxLength = $path[0].getTotalLength(); // Shortcut!
}
@@ -248,7 +259,7 @@ var utils = {
* Get the distance between two points... Dude, it's Geometric!!
*
* @param {Object/Array} p1
- * The first point in array or simple object format like [0,0] or {x: 0, y:0}
+ * The first point in array/object format like [0,0] or {x: 0, y:0}
* @param {Object/Array} p1
* The second point in the same format
* @return {Number}
@@ -260,8 +271,8 @@ var utils = {
p2 = [p2.x, p2.y];
}
- var xdiff = Math.abs(p1[0]-p2[0]);
- var ydiff = Math.abs(p1[1]-p2[1]);
+ var xdiff = Math.abs(p1[0] - p2[0]);
+ var ydiff = Math.abs(p1[1] - p2[1]);
return Math.sqrt(xdiff*xdiff + ydiff*ydiff);
},
@@ -277,8 +288,12 @@ var utils = {
if (!path.pathSegList) return false;
for (var i = 0; i < path.pathSegList.numberOfItems; i++) {
- var letter = path.pathSegList.getItem(i).pathSegTypeAsLetter.toUpperCase();
- if (letter != 'M' && letter != 'L') {
+ var letter = path
+ .pathSegList
+ .getItem(i)
+ .pathSegTypeAsLetter
+ .toUpperCase();
+ if (letter !== 'M' && letter !== 'L') {
// Non-linear path segment! We're done here...
return false;
}
@@ -324,6 +339,7 @@ var utils = {
$(recolorTypes, context).each(function(){
var i = 0;
var setColor = "";
+ var newColor = {};
if ($(this).css('fill') !== "none") {
if (!recover) {
@@ -331,14 +347,21 @@ var utils = {
setColor = $(this).css('fill');
$(this).data('oldColor', setColor);
i = utils.closestColor(setColor, colors);
- setColor = 'rgb(' + colors[i].color.RGB.join(',') + ')';
+
+ if (i === -1) {
+ newColor = robopaint.media.white;
+ } else {
+ newColor = colors[i];
+ }
+
+ setColor = 'rgb(' + newColor.color.RGB.join(',') + ')';
} else {
// Recover the old color
setColor = $(this).data('oldColor');
}
// Set the new color!
- $(this).css('fill', setColor)
+ $(this).css('fill', setColor);
}
if ($(this).css('stroke') !== "none") {
@@ -347,6 +370,13 @@ var utils = {
setColor = $(this).css('stroke');
$(this).data('oldStrokeColor', setColor);
i = utils.closestColor(setColor, colors);
+
+ if (i === -1) {
+ newColor = robopaint.media.white;
+ } else {
+ newColor = colors[i];
+ }
+
setColor = 'rgb(' + colors[i].color.RGB.join(',') + ')';
} else {
// Recover the old color
@@ -354,7 +384,7 @@ var utils = {
}
// Set the new color!
- $(this).css('stroke', setColor)
+ $(this).css('stroke', setColor);
}
});
},
@@ -371,13 +401,13 @@ var utils = {
if (isLocal) {
return "localhost";
} else {
- var os=require('os');
- var ifaces=os.networkInterfaces();
+ var os = require('os');
+ var ifaces = os.networkInterfaces();
var out = [];
for (var dev in ifaces) {
ifaces[dev].forEach(function(details){
- if (details.family=='IPv4') {
+ if (details.family === 'IPv4') {
out.push(details.address);
}
});
@@ -452,7 +482,7 @@ var utils = {
extraKey = "";
}
- if (t == 'watercolorbot') {
+ if (t === 'watercolorbot') {
return 'cncserver-' + extraKey + 'settings';
} else {
return t + '-' + extraKey + 'settings';
diff --git a/resources/scripts/cncserver.client.paths.js b/resources/scripts/cncserver.client.paths.js
deleted file mode 100644
index 887a55f..0000000
--- a/resources/scripts/cncserver.client.paths.js
+++ /dev/null
@@ -1,851 +0,0 @@
-/**
- * @file Holds all CNC Server path management and tracing functions
- */
-
-define(function(){return function($, robopaint, cncserver){
-cncserver.paths = {
- // Find out what DOM object is directly below the point given
- // Will NOT work if point is outside visible screen range!
-
- // TODO: maybe this can be replaced by polygonal collision detection? :P
- // Wait, no, on second thought this is a terrible idea. We should just
- // boolean difference all the paths into each other!
- // https://github.com/Delapouite/JsClipper
- getPointPathCollide: function(point) {
-
- // Add 48 to each side for 96dpi 1/2in offset
- var x = ((point.x+48) * cncserver.canvas.scale) + cncserver.canvas.offset.left;
- var y = ((point.y+48) * cncserver.canvas.scale) + cncserver.canvas.offset.top;
-
- // Debug for positioning canvas offset (damn tricky without this)
- if (cncserver.config.canvasDebug) {
- var ctx = $('canvas#debug')[0].getContext("2d");
- ctx.strokeStyle = "rgba(255, 0, 0, 0.8)";
- ctx.lineWidth = 2;
- ctx.lineTo(x, y);
- ctx.stroke();
- }
-
- return document.elementFromPoint(x, y);
- },
-
- // Convert all document svg elements capable into paths!
- // Adapted from svgcanvas in svg-edit main
- changeToPaths: function(context) {
- $('*:not(path,svg,g,title,metadata)', context).each(function(){
- var elem = this;
- var $elem = $(this);
-
- // Pass over attributes to new path element
-
- if (!elem.ownerSVGElement) {
- // Delete non-supported SVG elements
- elem.parentNode.removeChild(elem);
- return;
- }
-
- var svgNS = elem.ownerSVGElement.namespaceURI;
- var path = document.createElementNS(svgNS, 'path');
-
- $(path).attr({
- fill: $elem.attr('fill') == 'rgba(0, 0, 0, 0)' ? 'none' : $elem.attr('fill'),
- stroke: $elem.attr('stroke') == 'rgba(0, 0, 0, 0)' ? 'none' : $elem.attr('stroke'),
- 'stroke-width': parseInt($elem.attr('stroke-width')) == 0 ? 10 : parseInt($elem.attr('stroke-width')),
- id: $elem.attr('id')
- })[0];
-
- if ($elem.attr('transform')){
- $(path).attr('transform', $elem.attr('transform'));
- }
-
- var d = '';
-
- var joinSegs = function(segs) {
- $.each(segs, function(j, seg) {
- var l = seg[0], pts = seg[1];
- d += l;
- for(var i=0; i < pts.length; i+=2) {
- d += (pts[i] +','+pts[i+1]) + ' ';
- }
- });
- }
-
- // Possibly the cubed root of 6, but 1.81 works best
- var num = 1.81;
-
- switch (elem.tagName) {
- case 'ellipse':
- case 'circle':
- var cx = $elem.attr('cx');
- var cy = $elem.attr('cy');
- var rx = $elem.attr('rx');
- var ry = $elem.attr('ry');
-
- if(elem.tagName == 'circle') {
- rx = ry = $elem.attr('r');
- }
-
- joinSegs([
- ['M',[(cx-rx),(cy)]],
- ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]],
- ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]],
- ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]],
- ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]],
- ['Z',[]]
- ]);
- break;
- case 'line':
- d = "M"+$(elem).attr('x1')+","+$(elem).attr('y1')+"L"+$(elem).attr('x2')+","+$(elem).attr('y2');
- break;
- case 'polyline':
- case 'polygon':
- d = "M" + $elem.attr('points');
- break;
- case 'rect':
- var rx = $elem.attr('rx');
- var ry = $elem.attr('ry');
- var b = elem.getBBox();
- var x = b.x, y = b.y, w = b.width, h = b.height;
- num = 4-num; // Why? Because!
-
- if(!rx && !ry) {
- // Regular rect
- joinSegs([
- ['M',[x, y]],
- ['L',[x+w, y]],
- ['L',[x+w, y+h]],
- ['L',[x, y+h]],
- ['L',[x, y]],
- ['Z',[]]
- ]);
- } else {
- joinSegs([
- ['M',[x, y+ry]],
- ['C',[x,y+ry/num, x+rx/num,y, x+rx,y]],
- ['L',[x+w-rx, y]],
- ['C',[x+w-rx/num,y, x+w,y+ry/num, x+w,y+ry]],
- ['L',[x+w, y+h-ry]],
- ['C',[x+w, y+h-ry/num, x+w-rx/num,y+h, x+w-rx,y+h]],
- ['L',[x+rx, y+h]],
- ['C',[x+rx/num, y+h, x,y+h-ry/num, x,y+h-ry]],
- ['L',[x, y+ry]],
- ['Z',[]]
- ]);
- }
- break;
- default:
- // Delete non-supported SVG elements
- elem.parentNode.removeChild(elem);
- return;
- }
-
- if(d) {
- path.setAttribute('d',d);
- }
-
- // Replace the current element with the converted one
- elem.parentNode.replaceChild(path, elem);
- });
- },
-
- /**
- * Helper function to run the outline of a linear path into the buffer.
- * Takes over path running when occlusions aren't an issue and the path
- * only contains M and L type segments.
- *
- * @param {SVGpath object} path
- * DOM object for the path
- * @returns {boolean}
- * True on success, false on failure
- */
- _runLinearOutline: function(path) {
- if (!robopaint.utils.pathIsLinear(path)) return false;
- var run = cncserver.cmd.run;
- var lastPoint = {x: 0, y: 0};
-
- if (!path.transformMatrix) {
- path.transformMatrix = path.getTransformToElement(path.ownerSVGElement);
- path.transPoint = function(point){ // Handy helper function for gPAL
- var svgPoint = this.ownerSVGElement.createSVGPoint();
- svgPoint.x = point.x; svgPoint.y = point.y;
- svgPoint = svgPoint.matrixTransform(this.transformMatrix);
- return {x: svgPoint.x + 48, y: svgPoint.y + 48};
- };
- }
-
- // Move through each segment
- for (var i = 0; i < path.pathSegList.numberOfItems; i++) {
- var seg = path.pathSegList.getItem(i);
- var letter = seg.pathSegTypeAsLetter;
-
- var point = {x: seg.x, y: seg.y};
-
- if (letter == 'm' || letter == 'l') { // Relative point offset (convert to ABS)
- point.x = lastPoint.x + point.x;
- point.y = lastPoint.y + point.y;
- letter = letter.toUpperCase(); // We're all friends now :)
- }
-
- lastPoint.x = point.x; lastPoint.y = point.y;
-
- point = path.transPoint(point);
-
- // TODO: Add overshoot at end movements
- // Code can probably be copied from runOutline below using lastPoint, etc
- if (letter == 'M') { // Move to pos
- run('up');
- run('move', {x: point.x, y: point.y});
- run('down');
-
- } else if (letter == 'L' || letter == 'l') { // Draw Line
- run('move', {x: point.x, y: point.y});
- }
-
- }
-
- return true;
- },
-
- /**
- * Run a the outline of a given path into the buffer
- *
- * @param {object} $path
- * The jQuery object for the path to be filled
- * @param {function} callback
- * Callback function for when the run completes
- * @param {object} options
- * The JSON set of options
- * * strokeovershoot: amount to move the brush when about to lift
- *
- */
- runOutline: function($path, callback, options) {
- var run = cncserver.cmd.run;
-
- // Default options object to a copy of the full global settings object
- if (typeof options === 'undefined') options = jQuery.extend({}, robopaint.settings);
-
- // Hide sim window
- $('#sim').hide();
-
- // Start with brush up
- run('up');
-
- // If we don't care about occlusions, and it's linear, run it the "easy" way!
- if (cncserver.config.checkVisibility === false && robopaint.utils.pathIsLinear($path[0])) {
- if (cncserver.paths._runLinearOutline($path[0])) {
- run('up');
- console.info($path[0].id + ' linear path outline run done!');
- if (callback) callback();
- return;
- }
- }
-
- // We can think of the very first brush down as waiting till we should paint
- cncserver.state.process.waiting = true;
-
- var distance = 0;
- var lastPoint = {};
- var p = {};
- var drawAngle = 0;
- var lastPathSeg = -1; // Assume change on first subpath
- var overshootMultiplier = 4.5;
- var cPathSeg = 0;
- var subPathCount = 0;
-
- runNextPoint();
-
- function runNextPoint() {
- lastPoint = {x:p.x, y:p.y}; // Store the last run point
-
- if (distance <= $path.maxLength) {
-
- p = $path.getPoint(distance); // Get a new point
- drawAngle = Math.atan2(p.x - lastPoint.x, lastPoint.y - p.y);
- cPathSeg = $path[0].getPathSegAtLength(distance); // Store the current seg ID
-
- // Increment distance, only after the first check
- // allows for starting at distance 0
- distance+= parseInt(options.strokeprecision);
-
- // If the path is still visible here
- // Assume as always visible if we're not actually checking
- var isVisible = true;
- if (cncserver.config.checkVisibility) {
- var pathAtPoint = cncserver.paths.getPointPathCollide(p);
- if (pathAtPoint != $path[0]) {
- isVisible = false;
- }
- }
- if (isVisible){
-
- if (cPathSeg !== lastPathSeg) {
- // If our last segment jumped, check if it's a move to path
- if (cPathSeg > lastPathSeg+1) {
- // Move through all segments from previous, to last
- for(var checkSeg = cPathSeg-1; checkSeg > lastPathSeg; checkSeg--) {
- var seg = $path[0].pathSegList.getItem(checkSeg);
- if (seg.pathSegTypeAsLetter.toLowerCase() === "m") {
- subPathCount++;
- if (options.refillmode == 0) {
- run([
- ['status', robopaint.t("libs.sub", {num: subPathCount})],
- 'up',
- ['move', p],
- 'down'
- ]);
- } else if (options.refillmode == 1) {
- run([
- ['status', robopaint.t("libs.subrefill", {num: subPathCount})],
- 'up',
- ['getpaintfull', p],
- ['move', p],
- 'down'
- ]);
- }
- break;
- }
- }
- } else {
- // Next sequential path segment, move to point
- run('move', p);
- }
-
- lastPathSeg = cPathSeg;
- } else {
- // Same path segment, move to point
- run('move', p);
- }
-
- // If we were waiting, move to point then pen goes down
- if (cncserver.state.process.waiting) {
- run([
- ['move', p],
- 'down'
- ]);
- cncserver.state.process.waiting = false;
- }
- } else { // Path is invisible, lift the brush if we're not already waiting
- if (!cncserver.state.process.waiting) {
- // Figure out how much change since last point, move more before lifting
- if (lastPoint.x && options.strokeovershoot) {
- // Overshoot to make up for brush flexibility
- run('move', {
- x: p.x + (options.strokeovershoot * Math.sin(drawAngle) * overshootMultiplier),
- y: p.y - (options.strokeovershoot * Math.cos(drawAngle) * overshootMultiplier)
- });
- }
-
- run('up');
- cncserver.state.process.waiting = true;
- }
- }
- setTimeout(runNextPoint, 0);
- } else { // Done
- // Overshoot to make up for brush flexibility
- if (options.strokeovershoot) {
- run('move', {
- x: p.x + (options.strokeovershoot * Math.sin(drawAngle) * overshootMultiplier),
- y: p.y - (options.strokeovershoot * Math.cos(drawAngle) * overshootMultiplier)
- });
- }
-
-
- run('up');
- console.info($path[0].id + ' path outline run done!');
- if (callback) callback();
- }
- }
- },
-
- /**
- * "Private" function, run a full path fill for a given path into the buffer
- *
- * @param {object} $path
- * The jQuery object for the path to be filled
- * @param {object} options
- * The JSON set of options:
- * * filltype: The type of the fill, must resolve to an existing path ID
- * * fillangle: The angle of the line. 0, 45 or 90
- * * fillprecision: The number of steps between each path position check
- * * fillspacing: the amount of space between the lines
- * @param {function} callback
- * Callback function for when the runFill completes
- *
- */
- _runPathFill: function($path, options, callback) {
- var run = cncserver.cmd.run;
- var pathRect = $path[0].getBBox();
- var $fill = cncserver.wcb.getFillPath(options);
- var fillType = $fill.attr('id').split('-')[1];
-
- var center = {
- x: pathRect.x + (pathRect.width / 2) + 48,
- y: pathRect.y + (pathRect.height / 2) + 48
- }
-
- // Center the fill path
- $fill.attr('transform', 'translate(' + center.x + ',' + center.y + ')');
-
- $fill.transformMatrix = $fill[0].getTransformToElement($fill[0].ownerSVGElement);
- $fill.getPoint = function(distance){ // Handy helper function for gPAL
- var p = this[0].getPointAtLength(distance).matrixTransform(this.transformMatrix);
- return {x: p.x-48, y: p.y-48};
- };
-
- var pathPos = 0;
- var p = {};
- var max = $fill[0].getTotalLength();
- runNextFill();
-
- function runNextFill() {
- pathPos+= parseInt(options.fillprecision);
- p = $fill.getPoint(pathPos);
-
- // Short circuit for full path trace completion
- if (fillType == 'spiral') {
- // Spiral is outside top left, and therefore can never return
- if (p.x < pathRect.x && p.y < pathRect.y ) pathPos = max;
-
- // Outside bottom right, and therefore can never return
- if (p.x > pathRect.x + pathRect.width && p.y > pathRect.y + pathRect.height) pathPos = max;
- }
-
- if (pathPos < max) {
- // If the path is still visible here
- var isVisible = false;
-
- // Is the point within the bounding box of the path to be filled?
- if ((p.x >= pathRect.x && p.y >= pathRect.y) &&
- (p.x < pathRect.x + pathRect.width && p.y < pathRect.y + pathRect.height)) {
- isVisible = true;
- }
-
- // Only if we've passed previous checks should we run the expensive
- // getPointPathCollide function
- if (isVisible){
- isVisible = cncserver.paths.getPointPathCollide(p) == $path[0]
- }
-
- if (isVisible){
- // Move to point!
- run('move', p);
- lastPoint = {x:p.x, y:p.y};
-
- // If we were waiting, pen goes down
- if (cncserver.state.process.waiting) {
- run('down');
- cncserver.state.process.waiting = false;
- }
- } else { // Path is invisible, lift the brush if we're not already waiting
- if (!cncserver.state.process.waiting) {
- run('move', $fill.getPoint(pathPos+5));
- run('up');
- cncserver.state.process.waiting = true;
- }
- }
- window.parent.process.nextTick(runNextFill);
- } else { // Done
- if (callback) callback();
- }
- }
- },
-
- /**
- * "Private" function, run a full line fill for a given path into the buffer
- *
- * @param {object} $path
- * The jQuery object for the path to be filled
- * @param {object} options
- * The JSON set of options, required set listed:
- * * filltype: The type of the fill, must resolve to an existing path ID
- * * fillprecision: The amount of space between each path position check
- * * fillangle: The angle of the line. 0, 45 or 90
- * * fillspacing: the amount of space between the lines
- * @param {function} callback
- * Callback function for when the runFill completes
- *
- */
- _runLineFill: function($path, options, callback) {
- var run = cncserver.cmd.run;
- var pathRect = $path[0].getBBox();
- var $fill = cncserver.wcb.getFillPath(options);
- var fillType = $fill.attr('id').split('-')[2];
- var isLinear = (fillType == 'straight');
-
- $fill.transformMatrix = $fill[0].getTransformToElement($fill[0].ownerSVGElement);
- $fill.getPoint = function(distance){ // Handy helper function for gPAL
- var p = this[0].getPointAtLength(distance).matrixTransform(this.transformMatrix);
- return {x: p.x-48, y: p.y-48};
- };
-
- // Sanity check incoming angle to match supported angles
- if (options.fillangle != 0 && options.fillangle !=90) {
- options.fillangle = options.fillangle == 45 ? -45 : 0;
- }
-
- options.fillprecision = parseInt(options.fillprecision);
-
- var linePos = 0;
- var lineIteration = 0;
- var lastPointChecked = {};
- var p = {};
- var max = $fill[0].getTotalLength();
- var goRight = true;
- var gapConnectThreshold = options.fillprecision * 5;
- var done = false;
- var leftOffset = -48;
- var topOffset = 48;
- var bottomLimit = 48;
- var fillOffsetPadding = options.fillprecision;
- var fillCount = 0;
-
- // Offset calculation for non-flat angles
- // TODO: Support angles other than 45
- if (options.fillangle == -45) {
- var rads = (Math.abs(options.fillangle)/2) * Math.PI / 180
- topOffset = (pathRect.height / 2) + 48;
- leftOffset = (Math.tan(rads) * (pathRect.height * 1.2))-48;
-
- bottomLimit = Math.tan(rads) * (pathRect.width * 1.2) + 48;
- }
-
- // Start fill position at path top left (less fill offset padding)
- $fill.attr('transform', 'translate(' + (pathRect.x - fillOffsetPadding - leftOffset) +
- ',' + (pathRect.y - fillOffsetPadding + topOffset) + ') rotate(' + options.fillangle + ')');
-
- runNextFill();
-
- function runNextFill() {
- linePos+= options.fillprecision;
-
- var shortcut = false;
-
- // Shortcut ending a given line check based on position (45deg) ==========
- if (options.fillangle == -45 && false) {
- // Line has run away up beyond the path
- if (goRight && p.y < pathRect.y - fillOffsetPadding) {
- shortcut = true;
- console.log('line #' + lineIteration + ' up shortcut!');
- }
- }
-
- // Shortcut ending a given line check based on position (vertical) =======
- if (options.fillangle == 90) {
- // Line has run away down beyond the BBox
- if (goRight && p.y > pathRect.y + pathRect.height) {
- shortcut = true;
- }
-
- // Line is too far right
- if (p.x > pathRect.x + pathRect.width) {
- shortcut = true;
- }
-
- }
-
- // Shortcut ending a given line check based on position (horizontal) =====
- if (options.fillangle == 0) {
- // Line has run away down beyond the BBox
- if (goRight && p.x > pathRect.x + pathRect.width) {
- shortcut = true;
- }
-
- // Line is beyond the bottom
- if (p.y > pathRect.y + pathRect.height) {
- shortcut = true;
- }
- }
-
-
- // If we've used up this line, move on to the next one!
- if (linePos > max || shortcut) {
- lineIteration++; // Next line! Move it to the new position
-
- var lineSpaceAmt = options.fillspacing * lineIteration;
-
- // Move down
- var lineSpace = {
- x: 0,
- y: lineSpaceAmt
- }
-
- // TODO: Support angles other than 45 & 90
- if (options.fillangle == -45) {
- // Move down and right
- lineSpace = {
- x: (options.fillspacing/2) * lineIteration,
- y: (options.fillspacing/2) * lineIteration
- }
- } else if (options.fillangle == 90) {
- // Move right
- lineSpace = {
- x: lineSpaceAmt,
- y: 0
- }
- }
-
- var fillOrigin = {
- x: pathRect.x + lineSpace.x - fillOffsetPadding - leftOffset,
- y: pathRect.y + lineSpace.y - fillOffsetPadding + topOffset
- };
-
- if (fillOrigin.y > pathRect.y + pathRect.height + bottomLimit + 24 ||
- fillOrigin.x > pathRect.x + pathRect.width - leftOffset + 24 ) {
- done = true;
- } else {
- // Set new position of fill line, and reset counter
- $fill.attr('transform', 'translate(' + fillOrigin.x + ',' + fillOrigin.y + ') rotate(' + options.fillangle + ')');
- $fill.transformMatrix = $fill[0].getTransformToElement($fill[0].ownerSVGElement);
-
- linePos = 0;
- goRight = !goRight;
- }
- }
-
- // Still work to do? Lets go!
- if (!done) {
-
- // Reverse direction? Simply invert the value!
- var lineGet = goRight ? linePos : max-linePos;
-
- // Go and get the x,y for the position on the line
- p = $fill.getPoint(lineGet);
-
-
- // If the path is still visible here, assume it's not for now
- var isVisible = false;
-
- // Is the point within the bounding box of the path to be filled?
- if ((p.x >= pathRect.x && p.y >= pathRect.y) &&
- (p.x < pathRect.x + pathRect.width && p.y < pathRect.y + pathRect.height)) {
- isVisible = true;
- }
-
- // Only if we've passed previous checks should we run the expensive
- // getPointPathCollide function
- if (isVisible){
- isVisible = cncserver.paths.getPointPathCollide(p) == $path[0]
- }
-
- if (isVisible){ // Path is visible at this position!
-
- // If we were waiting...
- if (cncserver.state.process.waiting) {
- cncserver.state.process.waiting = false;
-
- // Find out how far away we are now...
- var diff = robopaint.utils.getDistance(lastPointChecked, p);
-
- // If we're too far away, lift the pen, then move to the position, then come down
- if (diff > gapConnectThreshold || isNaN(diff)) {
- run('up');
- run('move', p);
- run('down');
- } else { // If we're close enough, just move to the new point
- run('move', p);
- }
-
- } else { // Still visible, just keep moving
- // Only log the in-between moves if it's non-linear
- if (!isLinear) {
- run('move', p);
- }
- }
-
- } else { // Path is invisible, lift the brush if we're not already waiting
- if (!cncserver.state.process.waiting) {
- run('move', p);
- cncserver.state.process.waiting = true;
-
- // Save the point that we looked at to check later.
- lastPointChecked = {x:p.x, y:p.y};
- }
- }
- window.parent.process.nextTick(runNextFill);
- } else { // DONE!
- // Reset position of fill line (avoids odd prefill lines)
- $fill.attr('transform', 'translate(0,0)');
- if (callback) callback();
- }
- }
- },
-
- /**
- * "Private" function, run a full TSP fill for a given path into the buffer
- *
- * @param {object} $path
- * The jQuery object for the path to be filled
- * @param {object} options
- * The JSON set of options
- * * tsprunnertype: Type of TSP to run, OPT (fast) or ACO (slow)
- * * fillprecision: sets the spacing between the dots to connect
- * @param {function} callback
- * Callback function for when the runFill completes
- *
- */
- _runTSPFill: function($path, options, callback) {
- var run = cncserver.cmd.run;
- var pathRect = $path[0].getBBox();
- var $fill = cncserver.wcb.getFillPath({filltype: 'tsp'});
-
- var points = []; // Final points to run TSP on
-
- var center = {
- x: pathRect.x + (pathRect.width / 2) + 48,
- y: pathRect.y + (pathRect.height / 2) + 48
- }
-
- // Center the fill path
- $fill.attr('transform', 'translate(' + center.x + ',' + center.y + ')');
-
- $fill.transformMatrix = $fill[0].getTransformToElement($fill[0].ownerSVGElement);
- $fill.getPoint = function(distance){ // Handy helper function for gPAL
- var p = this[0].getPointAtLength(distance).matrixTransform(this.transformMatrix);
- // Add 48 to each side for 96dpi 1/2in offset
- return {x: p.x-48, y: p.y-48};
- };
-
- var fillCount = 0;
- var p = {};
- var max = $fill[0].getTotalLength();
- runNextFill();
-
- // Fill up the slow point path finder points
- function runNextFill() {
- fillCount+= parseInt(options.fillprecision);
- p = $fill.getPoint(fillCount);
-
- // Spiral is outside top left, and therefore can never return
- if (p.x < pathRect.x && p.y < pathRect.y ) fillCount = max;
-
- // Spiral is outside bottom right, and therefore can never return
- if (p.x > pathRect.x + pathRect.width && p.y > pathRect.y + pathRect.height) fillCount = max;
-
- if (fillCount < max) {
- // If the path is still visible here
- if (cncserver.paths.getPointPathCollide(p) == $path[0]){
- // Save the point!
- points.push([p.x, p.y]);
- }
- window.parent.process.nextTick(runNextFill);
- } else { // Points are filled! Run the solver
- runTSPSolver();
- }
- }
-
- function runTSPSolver() {
- var numPoints = points.length-1;
- var _distances = null;
- var allDistances = new Array(numPoints);
-
- console.info('Finding distances between ' + numPoints + '...');
-
- // Calculate distances between all points(!!)
- for(var i=0; i= iterations) {
- clearInterval(repeatInterval);
-
- // Push complex route into real run sequence!
- for (var i in runner.route) {
- var p = points[runner.route[i]];
- run('move', {x: p[0], y: p[1]});
- if (i == 0) run('down');
- }
-
- if (callback) callback();
- }
- }, 1);
- }
- },
-
- /**
- * Wrapper to run fill for a given path
- *
- * @param {object} $path
- * The jQuery object for the path to be filled
- * @param {function} callback
- * Callback function for when the run completes
- * @param {object} options
- * The JSON set of options, if unset, defaults to copy of global settings
- *
- */
- runFill: function($path, callback, options) {
-
- // Default options object to a copy of the full global settings object
- if (typeof options == 'undefined') options = jQuery.extend({}, robopaint.settings);
-
- // runFill common stuff for code reuse ==================================
- $('#sim').hide(); // Hide sim window
- console.info($path[0].id + ' ' + options.filltype + ' path fill run started...');
- cncserver.cmd.run('up'); // Start with brush up
- cncserver.state.process.waiting = true;
-
-
- switch (options.filltype){
- case 'tsp':
- cncserver.paths._runTSPFill($path, options, runFillCallback);
- break;
- case 'spiral':
- cncserver.paths._runPathFill($path, options, runFillCallback);
- break;
- default: // Line based fill!
- cncserver.paths._runLineFill($path, options, runFillCallback);
- }
-
- // Common callback to handle more code reuse
- function runFillCallback() {
- cncserver.cmd.run('up');
- console.info($path[0].id + ' ' + options.filltype + ' path fill run done!');
- callback();
- }
-
- }
-};
-}});
diff --git a/resources/scripts/main.settings.js b/resources/scripts/main.settings.js
index 72f8e81..6d9f266 100644
--- a/resources/scripts/main.settings.js
+++ b/resources/scripts/main.settings.js
@@ -1,8 +1,13 @@
/*
* @file Holds all RoboPaint GLOBAL settings specific configuration, binding and
* handler code. If a new setting wants to show up in the application, in needs
- * to have its markup added in main.settings.inc.html. This may all eventually move
- * to a more centralized singluar configuration file ... but not yet. ;)
+ * to have its markup added in main.settings.inc.html. This may all eventually
+ * move to a more centralized singluar configuration file ... but not yet. ;)
+ */
+
+// TODO: Limit the number of random globals going on here. :P
+/* globals window, _, cncserver, robopaint, localStorage, $, initializing,
+setModal, rpRequire, paper, homeVis, mainWindow, appMode, $subwindow, isModal,
*/
/**
@@ -81,11 +86,11 @@ function loadSettings() {
// Allow machine specific overrides of initial default settings
settingsDefaultAlter(robopaint.settings);
- // Are there existing settings from a previous run? Mesh them into the defaults
+ // Are there existing settings from a previous run? Mesh into the defaults.
if (localStorage[robopaint.utils.settingsStorageKey()]) {
var s = robopaint.utils.getSettings();
for (var key in robopaint.settings) {
- if (typeof s[key] != 'undefined' && s[key] !== null) {
+ if (typeof s[key] !== 'undefined' && s[key] !== null) {
robopaint.settings[key] = s[key];
}
}
@@ -103,7 +108,7 @@ function loadSettings() {
}
break;
default:
- if ($input.attr('type') == 'checkbox') {
+ if ($input.attr('type') === 'checkbox') {
$input.prop('checked', robopaint.settings[key]);
} else {
$input.val(robopaint.settings[key]);
@@ -162,7 +167,7 @@ $(robopaint).on('settingsComplete', function(){
addSettingsRangeValues(); // Add in the range value displays
// Clear last used image
- if (robopaint.settings.openlast == 0) delete localStorage["svgedit-default"];
+ if (robopaint.settings.openlast === 0) delete localStorage["svgedit-default"];
});
/**
@@ -241,11 +246,12 @@ function bindSettingsControls() {
var $input = $(this);
var pushKey = [];
var pushVal = '';
+ var name = '';
// Do this first as switch case can't use indexOf
// Update available modes
if (this.id.indexOf('modeenable') !== -1) {
- var name = this.id.replace('modeenable', '');
+ name = this.id.replace('modeenable', '');
var enabled = $input.is(':checked');
robopaint.settings.enabledmodes[name] = enabled;
$('#bar-' + name).toggleClass('hidden', !enabled);
@@ -270,19 +276,22 @@ function bindSettingsControls() {
case 'servoup':
case 'servopaint':
case 'servowash':
- var name = this.id.substr(5);
+ name = this.id.substr(5);
// Shim to translate robopaint name to cncserver name
- if (name == "paint") name = 'draw';
+ if (name === "paint") name = 'draw';
// Save settings
- cncserver.conf.bot.set('servo:presets:' + name, parseFloat($input.val()/10));
+ cncserver.conf.bot.set(
+ 'servo:presets:' + name, parseFloat($input.val()/10)
+ );
// On input with nothing in the buffer allow active change of the bot.
// On "change" of sliders, the user has finished sliding, we can reset
// the height back to UP. Allows changing while paused.
var state = robopaint.cncserver.state;
- if (!initializing && (state.bufferList.length === 0 || state.process.paused)) {
+ if (!initializing &&
+ (state.bufferList.length === 0 || state.process.paused)) {
if (e.type === 'change') {
cncserver.setHeight('up', null, state.process.paused);
} else {
@@ -336,30 +345,32 @@ function bindSettingsControls() {
pushVal = parseInt($input.val());
break;
case 'penmode':
+ var v = parseInt($input.val(), 10);
+
// No paint?
- toggleDisableSetting(
+ /*toggleDisableSetting(
'#showcolortext, #colorset',
- ($input.val() == 2 || $input.val() == 0),
+ (v === 2 || v === 0),
robopaint.t('settings.output.penmode.warningPaint')
- );
+ );*/
// No nothing!
toggleDisableSetting(
'#maxpaintdistance, #refillmode, #refillaction, #maxpaint',
- $input.val() != 3,
+ v !== 3,
robopaint.t('settings.output.penmode.warningAll')
);
robopaint.settings[this.id] = $input.val();
break;
case 'bottype': // Bot type change! Not a real setting
- localStorage["currentBot"] = JSON.stringify({
+ localStorage.currentBot = JSON.stringify({
type: $input.val(),
name: $('#bottype option:selected').text()
});
return;
default: // Nothing special to set, just change the settings object value
- if ($input.attr('type') == 'checkbox') {
+ if ($input.attr('type') === 'checkbox') {
robopaint.settings[this.id] = $input.is(':checked');
} else {
robopaint.settings[this.id] = $input.val();
@@ -367,26 +378,26 @@ function bindSettingsControls() {
}
// Enable only for debug windows (users can close them by hand).
- if (this.id == 'rpdebug' && $input.is(':checked')) {
+ if (this.id === 'rpdebug' && $input.is(':checked')) {
mainWindow.openDevTools();
if (appMode !== 'home') $subwindow[0].openDevTools();
}
// Update paint sets when changes made that would effect them
- if (this.id == 'colorset' || this.id == 'showcolortext') {
+ if (this.id === 'colorset' || this.id === 'showcolortext') {
updateColorSetSettings();
cncserver.pushToMode('updateMediaSet');
}
// Update visibility of paintsets on penmode change
- if (this.id == 'penmode') {
+ if (this.id === 'penmode') {
cncserver.pushToMode('updatePenMode');
}
// If there's a key to override for CNC server, set it
if (pushKey.length) {
robopaint.settings[this.id] = pushVal;
- if (pushKey[0] == 'b') { // Bot!
+ if (pushKey[0] === 'b') { // Bot!
cncserver.conf.bot.set(pushKey[1], pushVal);
} else { // Global conf
cncserver.conf.global.set(pushKey[1], pushVal);
@@ -400,21 +411,21 @@ function bindSettingsControls() {
});
// Done Button
- $('#settings-done').click(function(e) {
+ $('#settings-done').click(function() {
setSettingsWindow(false);
});
// Keyboard shortcut for exiting settings
$(window).keydown(function (e){
if (isModal && $('#settings').is(':visible')) {
- if (e.keyCode == 27) {
+ if (e.keyCode === 27) {
$('#settings-done').click();
}
}
});
// Reset button
- $('#settings-reset').click(function(e) {
+ $('#settings-reset').click(function() {
if (confirm(robopaint.t('settings.buttons.reset.confirm'))) {
// Disable any non-core modes
$('.advanced-modes input').prop('checked', false).change();
@@ -518,7 +529,9 @@ function addSettingsRangeValues() {
// Display as Centimeters (2.24076923 mm per step!)
num = Math.round((num / 224.076923) * 10) / 10;
num = robopaint.t('common.metric.cm', {count: num}) + ' / ' +
- robopaint.t('common.imperial.in', {count: (Math.round((num / 2.54) * 10) / 10)});
+ robopaint.t('common.imperial.in', {
+ count: (Math.round((num / 2.54) * 10) / 10)
+ });
dosep = false;
break;
case 'servoup':
@@ -551,7 +564,7 @@ function addSettingsRangeValues() {
}
// Format translated text with
- if (['servotime', 'latencyoffset'].indexOf(this.id) != -1) {
+ if (['servotime', 'latencyoffset'].indexOf(this.id) !== -1) {
post = '';
num = robopaint.t('common.time.ms', {count: num});
}
@@ -562,7 +575,7 @@ function addSettingsRangeValues() {
}).change();
$r.addClass('processed').after($l);
- })
+ });
}
/**
@@ -578,17 +591,16 @@ function updateColorSetSettings() {
// Add Sortable color names/colors
$colors.empty();
- for (var i in set.colors) {
- if (i == set.colors.length-1) break; // Ignore the last value
+ _.each(set.colors, function(color) {
$('')
.append(
$('')
.addClass('color')
- .css('background-color', set.colors[i].color['HEX'])
+ .css('background-color', color.color.HEX)
.text(' '),
- $('').text(set.colors[i].name)
+ $('').text(color.name)
).appendTo($colors);
- }
+ });
// Add metadata
var meta = 'type name description media'.split(' ');
diff --git a/resources/styles/main.css b/resources/styles/main.css
index 7b15bf2..da362a7 100644
--- a/resources/styles/main.css
+++ b/resources/styles/main.css
@@ -39,6 +39,14 @@ button.normal:focus {
outline: none;
}
+button.normal.cancel {
+ background: linear-gradient(to bottom, #696969, #BB5A5A);
+}
+
+button.normal.cancel:hover {
+ background: linear-gradient(to bottom, #961A1A, #FF0000);
+}
+
img.logo {
margin-left: -100px;
height: 37px;
@@ -516,29 +524,45 @@ body.home #bar span.right {
padding-left: 0.5em;
}
-/* Semi-modal alert status message */
+/* Semi-modal alert status messages */
body.home h1 {
- padding: 11px;
+ box-sizing: border-box;
+ padding: 1em;
position: absolute;
top: 50%;
width: 100%;
+ line-height: 0.8em;
min-height: 46px;
transform: translate(0, -50%);
text-align: center;
- background-color: #fff;
+ background: linear-gradient(to bottom, #b4e391 0%,#61c419 50%,#b4e391 100%);
z-index: 13;
}
+body.home h1 div.options {
+ margin-top: 0.5em;
+}
+
+body.home h1 aside {
+ font-size: 0.65em;
+ font-weight: 500;
+ margin-top: 0.6em;
+ line-height: 1em;
+}
+
body.home h1.error {
background-color: red;
+ background: linear-gradient(to bottom, #ff7f8c 0%,#f60227 44%,#de0021 100%);
}
body.home h1.warning {
background-color: orange;
+ background: linear-gradient(to bottom, #f0b7a1 0%,#bf6e4e 100%);
}
body.home h1.loading {
background-color: #b1c9d6;
+ background: linear-gradient(to bottom, #7abcff 0%,#b7d6f6 44%,#86b6e7 100%);
}
body.home h1 span.message {
diff --git a/resources/styles/modes.css b/resources/styles/modes.css
index b3661aa..38ef281 100644
--- a/resources/styles/modes.css
+++ b/resources/styles/modes.css
@@ -56,6 +56,13 @@ button.normal:disabled, button.normal:disabled:hover {
-webkit-animation: none;
}
+button.normal.cancel {
+ background: linear-gradient(to bottom, #696969, #BB5A5A);
+}
+
+button.normal.cancel:hover {
+ background: linear-gradient(to bottom, #961A1A, #FF0000);
+}
/* Animation Keyframes */
@-webkit-keyframes hover-pulse {