WIP: Improved temperature controls
This commit is contained in:
parent
dad956b5c9
commit
fc53febb87
6 changed files with 308 additions and 62 deletions
File diff suppressed because one or more lines are too long
|
|
@ -6,7 +6,7 @@ $(function() {
|
|||
self.settingsViewModel = parameters[1];
|
||||
|
||||
self._createToolEntry = function() {
|
||||
return {
|
||||
var entry = {
|
||||
name: ko.observable(),
|
||||
key: ko.observable(),
|
||||
actual: ko.observable(0),
|
||||
|
|
@ -14,11 +14,55 @@ $(function() {
|
|||
offset: ko.observable(0),
|
||||
newTarget: ko.observable(),
|
||||
newOffset: ko.observable()
|
||||
}
|
||||
};
|
||||
|
||||
entry.newTargetValid = ko.pureComputed(function() {
|
||||
var value = entry.newTarget();
|
||||
|
||||
try {
|
||||
value = parseInt(value);
|
||||
} catch (exc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (value >= 0 && value <= 999);
|
||||
});
|
||||
|
||||
entry.newOffsetValid = ko.pureComputed(function() {
|
||||
var value = entry.newOffset();
|
||||
|
||||
try {
|
||||
value = parseInt(value);
|
||||
} catch (exc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (-50 <= value <= 50);
|
||||
});
|
||||
|
||||
return entry;
|
||||
};
|
||||
|
||||
self.changingOffset = {
|
||||
offset: ko.observable(0),
|
||||
newOffset: ko.observable(0),
|
||||
name: ko.observable(""),
|
||||
item: undefined,
|
||||
|
||||
title: ko.pureComputed(function() {
|
||||
return _.sprintf(gettext("Changing Offset of %(name)s"), {name: self.changingOffset.name()});
|
||||
}),
|
||||
description: ko.pureComputed(function() {
|
||||
return _.sprintf(gettext("Use the form below to specify a new offset to apply to all temperature commands sent from printed files for \"%(name)s\""),
|
||||
{name: self.changingOffset.name()});
|
||||
})
|
||||
};
|
||||
self.changeOffsetDialog = undefined;
|
||||
|
||||
self.tools = ko.observableArray([]);
|
||||
|
||||
self.hasBed = ko.observable(true);
|
||||
|
||||
self.bedTemp = self._createToolEntry();
|
||||
self.bedTemp["name"](gettext("Bed"));
|
||||
self.bedTemp["key"]("bed");
|
||||
|
|
@ -324,66 +368,147 @@ $(function() {
|
|||
return maxTemp;
|
||||
};
|
||||
|
||||
self.incrementTarget = function(item) {
|
||||
var value = item.newTarget();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) value = item.target();
|
||||
try {
|
||||
value = parseInt(value);
|
||||
if (value > 999) return;
|
||||
item.newTarget(value + 1);
|
||||
} catch (ex) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
self.decrementTarget = function(item) {
|
||||
var value = item.newTarget();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) value = item.target();
|
||||
try {
|
||||
value = parseInt(value);
|
||||
if (value <= 0) return;
|
||||
item.newTarget(value - 1);
|
||||
} catch (ex) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
self.setTarget = function(item) {
|
||||
var value = item.newTarget();
|
||||
if (!value) return;
|
||||
|
||||
var onSuccess = function() {
|
||||
item.newTarget("");
|
||||
};
|
||||
|
||||
if (item.key() == "bed") {
|
||||
self._setBedTemperature(value)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolTemperature(item.key(), value)
|
||||
.done(onSuccess);
|
||||
}
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) return OctoPrintClient.createRejectedDeferred();
|
||||
return self.setTargetToValue(item, value);
|
||||
};
|
||||
|
||||
self.setTargetFromProfile = function(item, profile) {
|
||||
if (!profile) return;
|
||||
if (!profile) return OctoPrintClient.createRejectedDeferred();
|
||||
return self.setTargetToValue(item, (item.key() == "bed" ? profile.bed : profile.extruder));
|
||||
};
|
||||
|
||||
self.setTargetToZero = function(item) {
|
||||
return self.setTargetToValue(item, 0);
|
||||
};
|
||||
|
||||
self.setTargetToValue = function(item, value) {
|
||||
try {
|
||||
value = parseInt(value);
|
||||
} catch (ex) {
|
||||
return OctoPrintClient.createRejectedDeferred();
|
||||
}
|
||||
|
||||
if (value < 0 || value > 999) return OctoPrintClient.createRejectedDeferred();
|
||||
|
||||
var onSuccess = function() {
|
||||
item.target(value);
|
||||
item.newTarget("");
|
||||
};
|
||||
|
||||
if (item.key() == "bed") {
|
||||
self._setBedTemperature(profile.bed)
|
||||
return self._setBedTemperature(value)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolTemperature(item.key(), profile.extruder)
|
||||
return self._setToolTemperature(item.key(), value)
|
||||
.done(onSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
self.setTargetToZero = function(item) {
|
||||
var onSuccess = function() {
|
||||
item.newTarget("");
|
||||
};
|
||||
self.changeOffset = function(item) {
|
||||
// copy values
|
||||
self.changingOffset.item = item;
|
||||
self.changingOffset.name(item.name());
|
||||
self.changingOffset.offset(item.offset());
|
||||
self.changingOffset.newOffset(item.offset());
|
||||
|
||||
if (item.key() == "bed") {
|
||||
self._setBedTemperature(0)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolTemperature(item.key(), 0)
|
||||
.done(onSuccess);
|
||||
self.changeOffsetDialog.modal("show");
|
||||
};
|
||||
|
||||
self.incrementChangeOffset = function() {
|
||||
var value = self.changingOffset.newOffset();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) value = self.changingOffset.offset();
|
||||
try {
|
||||
value = parseInt(value);
|
||||
if (value >= 50) return;
|
||||
self.changingOffset.newOffset(value + 1);
|
||||
} catch (ex) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
self.decrementChangeOffset = function() {
|
||||
var value = self.changingOffset.newOffset();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) value = self.changingOffset.offset();
|
||||
try {
|
||||
value = parseInt(value);
|
||||
if (value <= -50) return;
|
||||
self.changingOffset.newOffset(value - 1);
|
||||
} catch (ex) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
self.confirmChangeOffset = function() {
|
||||
var item = self.changingOffset.item;
|
||||
item.newOffset(self.changingOffset.newOffset());
|
||||
|
||||
self.setOffset(item)
|
||||
.done(function() {
|
||||
self.changeOffsetDialog.modal("hide");
|
||||
|
||||
// reset
|
||||
self.changingOffset.offset(0);
|
||||
self.changingOffset.newOffset(0);
|
||||
self.changingOffset.name("");
|
||||
self.changingOffset.item = undefined;
|
||||
})
|
||||
};
|
||||
|
||||
self.setOffset = function(item) {
|
||||
var value = item.newOffset();
|
||||
if (!value) return;
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) return OctoPrintClient.createRejectedDeferred();
|
||||
return self.setOffsetToValue(item, value);
|
||||
};
|
||||
|
||||
self.setOffsetToZero = function(item) {
|
||||
return self.setOffsetToValue(item, 0);
|
||||
};
|
||||
|
||||
self.setOffsetToValue = function(item, value) {
|
||||
try {
|
||||
value = parseInt(value);
|
||||
} catch (ex) {
|
||||
return OctoPrintClient.createRejectedDeferred();
|
||||
}
|
||||
|
||||
if (value < -50 || value > 50) return OctoPrintClient.createRejectedDeferred();
|
||||
|
||||
var onSuccess = function() {
|
||||
item.offset(value);
|
||||
item.newOffset("");
|
||||
};
|
||||
|
||||
if (item.key() == "bed") {
|
||||
self._setBedOffset(value)
|
||||
return self._setBedOffset(value)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolOffset(item.key(), value)
|
||||
return self._setToolOffset(item.key(), value)
|
||||
.done(onSuccess);
|
||||
}
|
||||
};
|
||||
|
|
@ -411,13 +536,28 @@ $(function() {
|
|||
self.handleEnter = function(event, type, item) {
|
||||
if (event.keyCode == 13) {
|
||||
if (type == "target") {
|
||||
self.setTarget(item);
|
||||
self.setTarget(item)
|
||||
.done(function() {
|
||||
event.target.blur();
|
||||
});
|
||||
} else if (type == "offset") {
|
||||
self.setOffset(item);
|
||||
self.confirmChangeOffset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.handleFocus = function(event, type, item) {
|
||||
if (type == "target") {
|
||||
var value = item.newTarget();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) {
|
||||
item.newTarget(item.target());
|
||||
}
|
||||
event.target.select();
|
||||
} else if (type == "offset") {
|
||||
event.target.select();
|
||||
}
|
||||
};
|
||||
|
||||
self.onAfterTabChange = function(current, previous) {
|
||||
if (current != "#temp") {
|
||||
return;
|
||||
|
|
@ -425,6 +565,10 @@ $(function() {
|
|||
self.updatePlot();
|
||||
};
|
||||
|
||||
self.onStartup = function() {
|
||||
self.changeOffsetDialog = $("#change_offset_dialog");
|
||||
};
|
||||
|
||||
self.onStartupComplete = function() {
|
||||
self._printerProfileUpdated();
|
||||
};
|
||||
|
|
@ -434,6 +578,6 @@ $(function() {
|
|||
OCTOPRINT_VIEWMODELS.push([
|
||||
TemperatureViewModel,
|
||||
["loginStateViewModel", "settingsViewModel"],
|
||||
"#temp"
|
||||
["#temp", "#change_offset_dialog"]
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -401,6 +401,40 @@ table {
|
|||
.actioncol;
|
||||
}
|
||||
|
||||
// Temperature panel
|
||||
&.temperature_tool,
|
||||
&.temperature_actual,
|
||||
&.temperature_target,
|
||||
&.temperature_offset {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
&.temperature_tool {
|
||||
width: 18%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&.temperature_actual {
|
||||
width: 12%;
|
||||
}
|
||||
|
||||
&.temperature_target {
|
||||
width: 40%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&.temperature_offset {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -417,10 +451,6 @@ table {
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
.tempInput {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
#temp_newTemp, #temp_newBedTemp, #speed_innerWall, #speed_outerWall, #speed_fill, #speed_support,
|
||||
#webcam_timelapse_interval, #webcam_timelapse_postRoll, #webcam_timelapse_fps, #webcam_timelapse_retractionZHop {
|
||||
text-align: right;
|
||||
|
|
@ -1236,6 +1266,27 @@ _::-webkit-full-page-media, _:future, :root .full-sized-box {
|
|||
width: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group:first-child {
|
||||
.btn:first-child {
|
||||
-webkit-border-radius: 4px 0 0 4px;
|
||||
-moz-border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
.btn:first-child {
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-input-dec,
|
||||
.btn-input-enc {
|
||||
//font-size: 80%;
|
||||
}
|
||||
|
||||
.control-group.error .input-prepend .fileinput-button,
|
||||
|
|
@ -1247,6 +1298,15 @@ input[type=number] {
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
input[type="number"].input-nospin::-webkit-outer-spin-button,
|
||||
input[type="number"].input-nospin::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
input[type="number"].input-nospin {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
// Progress bars with text
|
||||
//
|
||||
// .progress-text-front will also need to have the full width of the enclosing
|
||||
|
|
|
|||
33
src/octoprint/templates/dialogs/temperature.jinja2
Normal file
33
src/octoprint/templates/dialogs/temperature.jinja2
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<div id="change_offset_dialog" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<a href="javascript:void(0)" class="close" data-dismiss="modal" aria-hidden="true">×</a>
|
||||
<h3 data-bind="text: changingOffset.title"></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p data-bind="text: changingOffset.description"></p>
|
||||
<form class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Current Offset') }}</label>
|
||||
<div class="controls">
|
||||
<span data-bind="html: changingOffset.offset() + ' °C'"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('New Offset') }}</label>
|
||||
<div class="controls">
|
||||
<div class="input-prepend input-append">
|
||||
<button class="btn btn-input-dec" data-bind="click: $root.decrementChangeOffset" title="{{ _('-1') }}"><i class="fa fa-minus"></i></button>
|
||||
<input type="number" min="-50" max="50" class="input-mini input-nospin" style="width: 30px" data-bind="value: changingOffset.newOffset, event: { focus: function(d, e) {$root.handleFocus(e, 'target', changingOffset.item);}, keyup: function(d, e) {$root.handleEnter(e, 'offset', changingOffset.item);} }">
|
||||
<span class="add-on">°C</span>
|
||||
<button class="btn btn-input-inc" data-bind="click: $root.incrementChangeOffset" title="{{ _('+1') }}"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
<span class="help-block">{{ _('Hint: Hitting <kbd>Enter</kbd> in the input field will also submit the form') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="javascript:void(0)" class="btn" data-dismiss="modal" aria-hidden="true">{{ _('Cancel') }}</a>
|
||||
<a href="javascript:void(0)" class="btn btn-primary" data-bind="click: confirmChangeOffset">{{ _('Submit') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -131,6 +131,7 @@
|
|||
{% include 'dialogs/wizard.jinja2' %}
|
||||
{% include 'dialogs/about.jinja2' %}
|
||||
{% include 'dialogs/files.jinja2' %}
|
||||
{% include 'dialogs/temperature.jinja2' %}
|
||||
<!-- End of dialogs -->
|
||||
|
||||
<!-- Overlays -->
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
<table class="table table-bordered table-hover" style="table-layout: fixed; width: 100%; margin-top: 20px">
|
||||
<tr>
|
||||
<th style="width: 18%"></th>
|
||||
<th style="width: 12%; text-align: right">{{ _('Actual') }}</th>
|
||||
<th style="width: 35%">{{ _('Target') }}</th>
|
||||
<th style="width: 35%">{{ _('Offset') }}</th>
|
||||
<th class="temperature_tool"></th>
|
||||
<th class="temperature_actual" title="{{ _('Current actual temperature as reported by your printer') }}">{{ _('Actual') }}</th>
|
||||
<th class="temperature_target" title="{{ _('Current target temperature as reported by your printer') }}">{{ _('Target') }}</th>
|
||||
<th class="temperature_offset" title="{{ _('Offset to apply to temperature commands sent from files') }}">{{ _('Offset') }}</th>
|
||||
</tr>
|
||||
<!-- ko foreach: tools -->
|
||||
<tr data-bind="template: { name: 'temprow-template' }"></tr>
|
||||
|
|
@ -19,37 +19,45 @@
|
|||
</table>
|
||||
|
||||
<script type="text/html" id="temprow-template">
|
||||
<th style="vertical-align: middle" data-bind="text: name"></th>
|
||||
<td style="text-align: right; vertical-align: middle" data-bind="html: formatTemperature(actual())"></td>
|
||||
<td style="vertical-align: middle; overflow: visible">
|
||||
<div class="input-append">
|
||||
<input type="number" class="input-mini text-right tempInput" data-bind="attr: {placeholder: cleanTemperature(target()) }, value: newTarget, enable: $root.isOperational() && $root.loginState.isUser(), event: { keyup: function(d, e) {$root.handleEnter(e, 'target', $data);} }">
|
||||
<span class="add-on">°C</span>
|
||||
<th class="temperature_tool" data-bind="text: name"></th>
|
||||
<td class="temperature_actual" data-bind="html: formatTemperature(actual())"></td>
|
||||
<td class="temperature_target">
|
||||
<form class="form-inline" style="margin:0">
|
||||
<div class="input-prepend input-append">
|
||||
<button class="btn btn-input-dec" data-bind="click: $root.decrementTarget, enable: $root.isOperational() && $root.loginState.isUser()" title="{{ _('-1') }}"><i class="fa fa-minus"></i></button>
|
||||
<input type="number" min="0" max="999" class="input-mini input-nospin" style="width: 30px" data-bind="attr: {placeholder: cleanTemperature(target())}, value: newTarget, valueUpdate: 'input', enable: $root.isOperational() && $root.loginState.isUser(), event: { focus: function(d, e) {$root.handleFocus(e, 'target', $data);}, keyup: function(d, e) {$root.handleEnter(e, 'target', $data);} }">
|
||||
<span class="add-on">°C</span>
|
||||
<button class="btn btn-input-inc" data-bind="click: $root.incrementTarget, enable: $root.isOperational() && $root.loginState.isUser()" title="{{ _('+1') }}"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="submit" data-bind="click: $parent.setTarget, enable: $root.isOperational() && $root.loginState.isUser()" class="btn">{{ _('Set') }}</button>
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown" data-bind="enable: $root.isOperational() && $root.loginState.isUser()">
|
||||
<button data-bind="click: $root.setTarget, enable: $root.isOperational() && $root.loginState.isUser() && $data.newTargetValid()" class="btn btn-primary" title="{{ _('Set') }}"><i class="fa fa-check"></i></button>
|
||||
<button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" data-bind="enable: $root.isOperational() && $root.loginState.isUser()">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#" data-bind="click: $root.setTargetToZero">{{ _('Off') }}</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<!-- ko foreach: $root.temperature_profiles -->
|
||||
<li>
|
||||
<a href="#" data-bind="click: function() {$root.setTargetFromProfile($parent, $data);}, text: 'Set ' + name + ' (' + ($parent.key() == 'bed' ? bed : extruder) + '°C)'"></a>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href="#" data-bind="click: $root.setTargetToZero">{{ _('Off') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
<td style="vertical-align: middle">
|
||||
<div class="input-append">
|
||||
<input type="number" min="-50" max="50" class="input-mini text-right tempInput" data-bind="attr: {placeholder: offset}, value: newOffset, enable: $root.isOperational() && $root.loginState.isUser(), event: { keyup: function(d, e) {$root.handleEnter(e, 'offset', $data);} }">
|
||||
<span class="add-on">°C</span>
|
||||
<button type="submit" data-bind="click: $root.setOffset, enable: $root.isOperational() && $root.loginState.isUser()" class="btn">{{ _('Set') }}</button>
|
||||
</div>
|
||||
<td class="temperature_offset">
|
||||
<form class="form-inline" style="margin:0">
|
||||
<div class="input-append">
|
||||
<span class="input-mini uneditable-input text-right" style="width: 30px" data-bind="text: offset"></span>
|
||||
<span class="add-on">°C</span>
|
||||
<button class="btn" title="{{ _('Change Offset') }}" data-bind="click: $root.changeOffset, enable: $root.isOperational() && $root.loginState.isUser()"><i class="fa fa-pencil"></i></button>
|
||||
<button class="btn" title="{{ _('Delete Offset') }}" data-bind="click: $root.setOffsetToZero, enable: $root.isOperational() && $root.loginState.isUser()"><i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</script>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue