WIP: Printer profiles & management now functional, but integration with connection dialog still broken

The API documentation is also still missing.
This commit is contained in:
Gina Häußge 2014-11-29 20:55:30 +01:00
parent 985b0970f1
commit 93a852e6ea
6 changed files with 369 additions and 78 deletions

View file

@ -652,7 +652,7 @@ class Printer():
def getCurrentConnection(self):
if self._comm is None:
return "Closed", None, None
return "Closed", None, None, None
port, baudrate = self._comm.getConnection()
printer_profile = self._printerProfileManager.get_current_or_default()

View file

@ -1,20 +1,26 @@
function AppearanceViewModel(settingsViewModel) {
var self = this;
self.name = settingsViewModel.appearance_name;
self.color = settingsViewModel.appearance_color;
self.settings = settingsViewModel;
self.brand = ko.computed(function() {
if (self.name())
return gettext("OctoPrint") + ": " + self.name();
if (self.settings.printerProfiles.currentProfileData().name())
return gettext("OctoPrint") + ": " + self.settings.printerProfiles.currentProfileData().name();
else
return gettext("OctoPrint");
});
self.title = ko.computed(function() {
if (self.name())
return self.name() + " [" + gettext("OctoPrint") + "]";
if (self.settings.printerProfiles.currentProfileData().name())
return self.settings.printerProfiles.currentProfileData().name() + " [" + gettext("OctoPrint") + "]";
else
return gettext("OctoPrint");
});
self.color = ko.computed(function() {
if (self.settings.printerProfiles.currentProfileData().color())
return self.settings.printerProfiles.currentProfileData().color();
else
return "default";
});
}

View file

@ -114,7 +114,8 @@ function ConnectionViewModel(loginStateViewModel, settingsViewModel) {
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(data),
success: function(response) {
self.settings.requestData()
self.settings.requestData();
self.settings.printerProfiles.requestData();
}
});
} else {

View file

@ -95,27 +95,46 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
self.reader_hideEmptyLayers.subscribe(self.synchronizeOptions);
// subscribe to relevant printer settings...
self.settings.printer_extruderOffsets.subscribe(function() {
if (!self.enabled) return;
if (!self.settings.printer_extruderOffsets()) return;
GCODE.ui.updateOptions({
reader: {
toolOffsets: self.settings.printer_extruderOffsets()
}
});
});
self.settings.printer_bedDimensions.subscribe(function() {
self.settings.printerProfiles.currentProfileData.subscribe(function() {
if (!self.enabled) return;
var bedDimensions = self.settings.printer_bedDimensions();
if (!bedDimensions || (!bedDimensions.hasOwnProperty("x") && !bedDimensions.hasOwnProperty("y") && !bedDimensions.hasOwnProperty("r"))) return;
var currentProfileData = self.settings.printerProfiles.currentProfileData();
if (!currentProfileData) return;
GCODE.ui.updateOptions({
renderer: {
bed: bedDimensions
if (currentProfileData.extruder() && currentProfileData.extruder().extruderOffsets()) {
GCODE.ui.updateOptions({
reader: {
toolOffsets: self.settings.printer_extruderOffsets()
}
});
};
if (currentProfileData.volume() && currentProfileData.volume().width() && currentProfileData.volume().depth()) {
GCODE.ui.updateOptions({
renderer: {
bed: bedDimensions
}
});
};
if (currentProfileData.axes()) {
var invertX = false, invertY = false;
if (currentProfileData.axes().x()) {
invertX = currentProfileData.axes().x().inverted();
}
});
if (currentProfileData.axes().y()) {
invertY = currentProfileData.axes().y().inverted();
}
GCODE.ui.updateOptions({
renderer: {
invertAxes: {
x: invertX,
y: invertY
}
}
});
}
});
self.settings.printer_invertAxes.subscribe(function() {
if (!self.enabled) return;

View file

@ -1,6 +1,34 @@
function PrinterProfilesViewModel() {
var self = this;
self._cleanProfile = function() {
return {
id: "",
name: "",
model: "",
color: "default",
volume: {
formFactor: "rectangular",
width: 200,
depth: 200,
height: 200
},
heatedBed: false,
axes: {
x: {speed: 6000, inverted: false},
y: {speed: 6000, inverted: false},
z: {speed: 200, inverted: false},
e: {speed: 300, inverted: false}
},
extruder: {
count: 1,
offsets: [
[0,0]
]
}
}
};
self.profiles = new ItemListHelper(
"printerProfiles",
{
@ -20,14 +48,19 @@ function PrinterProfilesViewModel() {
self.defaultProfile = ko.observable();
self.currentProfile = ko.observable();
self.currentProfileData = ko.observable(ko.mapping.fromJS(self._cleanProfile()));
self.editorNew = ko.observable(false);
self.editorName = ko.observable();
self.editorColor = ko.observable();
self.editorIdentifier = ko.observable();
self.editorModel = ko.observable();
self.editorWidth = ko.observable();
self.editorDepth = ko.observable();
self.editorHeight = ko.observable();
self.editorFormFactor = ko.observable();
self.editorVolumeWidth = ko.observable();
self.editorVolumeDepth = ko.observable();
self.editorVolumeHeight = ko.observable();
self.editorVolumeFormFactor = ko.observable();
self.editorHeatedBed = ko.observable();
@ -42,6 +75,46 @@ function PrinterProfilesViewModel() {
self.editorAxisXInverted = ko.observable(false);
self.editorAxisYInverted = ko.observable(false);
self.editorAxisZInverted = ko.observable(false);
self.editorAxisEInverted = ko.observable(false);
self.availableColors = ko.observable([
{key: "default", name: gettext("default")},
{key: "red", name: gettext("red")},
{key: "orange", name: gettext("orange")},
{key: "yellow", name: gettext("yellow")},
{key: "green", name: gettext("green")},
{key: "blue", name: gettext("blue")},
{key: "black", name: gettext("black")}
]);
self.koEditorExtruderOffsets = ko.computed(function() {
var extruderOffsets = self.editorExtruderOffsets();
var numExtruders = self.editorExtruders();
if (!numExtruders) {
numExtruders = 1;
}
if (numExtruders > extruderOffsets.length) {
for (var i = extruderOffsets.length; i < numExtruders; i++) {
extruderOffsets[i] = {
x: ko.observable(0),
y: ko.observable(0)
}
}
self.editorExtruderOffsets(extruderOffsets);
}
return extruderOffsets.slice(0, numExtruders);
});
self.makeDefault = function(data) {
var profile = {
id: data.id,
default: true
};
self.updateProfile(profile);
};
self.requestData = function() {
$.ajax({
@ -56,60 +129,39 @@ function PrinterProfilesViewModel() {
var items = [];
var defaultProfile = undefined;
var currentProfile = undefined;
var currentProfileData = undefined;
_.each(data.profiles, function(entry) {
if (entry.default) {
defaultProfile = entry.id;
}
if (entry.current) {
currentProfile = entry.id;
currentProfileData = ko.mapping.fromJS(entry, self.currentProfileData);
}
items.push({
id: ko.observable(entry.id),
name: ko.observable(entry.name),
model: ko.observable(entry.model),
volume: {
width: ko.observable(entry.volume.width),
depth: ko.observable(entry.volume.depth),
height: ko.observable(entry.volume.height),
formFactor: ko.observable(entry.volume.formFactor)
},
heatedBed: ko.observable(entry.heatedBed),
axes: {
x: {
speed: ko.observable(entry.axes.x.speed),
inverted: ko.observable(entry.axes.x.inverted)
},
y: {
speed: ko.observable(entry.axes.y.speed),
inverted: ko.observable(entry.axes.y.inverted)
},
z: {
speed: ko.observable(entry.axes.z.speed),
inverted: ko.observable(entry.axes.z.inverted)
},
e: {
speed: ko.observable(entry.axes.e.speed),
inverted: ko.observable(entry.axes.e.inverted)
}
},
isdefault: ko.observable(entry.default),
iscurrent: ko.observable(entry.current),
resource: ko.observable(entry.resource)
});
entry["isdefault"] = ko.observable(entry.default);
entry["iscurrent"] = ko.observable(entry.current);
items.push(entry);
});
self.profiles.updateItems(items);
self.defaultProfile(defaultProfile);
self.currentProfile(currentProfile);
self.currentProfileData(currentProfileData);
};
self.addProfile = function() {
self.addProfile = function(callback) {
var profile = self._editorData();
$.ajax({
url: API_BASEURL + "printerProfiles/" + profile.id,
type: "PUT",
url: API_BASEURL + "printerProfiles",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({profile: profile})
data: JSON.stringify({profile: profile}),
success: function() {
if (callback !== undefined) {
callback();
}
self.requestData();
}
});
};
@ -117,11 +169,12 @@ function PrinterProfilesViewModel() {
$.ajax({
url: data.resource,
type: "DELETE",
dataType: "json"
dataType: "json",
success: self.requestData
})
};
self.updateProfile = function(identifier, profile) {
self.updateProfile = function(profile, callback) {
if (profile == undefined) {
profile = self._editorData();
}
@ -131,20 +184,89 @@ function PrinterProfilesViewModel() {
type: "PATCH",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({profile: profile})
data: JSON.stringify({profile: profile}),
success: function() {
if (callback !== undefined) {
callback();
}
self.requestData();
}
});
};
self.showEditProfileDialog = function(data) {
var add = false;
if (data == undefined) {
data = self._cleanProfile();
add = true;
}
self.editorIdentifier(data.id);
self.editorName(data.name);
self.editorColor(data.color);
self.editorModel(data.model);
self.editorVolumeWidth(data.volume.width);
self.editorVolumeDepth(data.volume.depth);
self.editorVolumeHeight(data.volume.height);
self.editorVolumeFormFactor(data.volume.formFactor);
self.editorHeatedBed(data.volume.heatedBed);
self.editorExtruders(data.extruder.count);
var offsets = [];
_.each(data.extruder.offsets, function(offset) {
offsets.push({
x: ko.observable(offset[0]),
y: ko.observable(offset[1])
});
});
self.editorExtruderOffsets(offsets);
self.editorAxisXSpeed(data.axes.x.speed);
self.editorAxisXInverted(data.axes.x.inverted);
self.editorAxisYSpeed(data.axes.y.speed);
self.editorAxisYInverted(data.axes.y.inverted);
self.editorAxisZSpeed(data.axes.z.speed);
self.editorAxisZInverted(data.axes.z.inverted);
self.editorAxisESpeed(data.axes.e.speed);
self.editorAxisEInverted(data.axes.e.inverted);
var editDialog = $("#settings_printerProfiles_editDialog");
var confirmButton = $("button.btn-confirm", editDialog);
var dialogTitle = $("h3.modal-title", editDialog);
dialogTitle.text(add ? gettext("Add Printer Profile") : _.sprintf(gettext("Edit Printer Profile \"%(name)s\""), {name: data.name}));
confirmButton.unbind("click");
confirmButton.bind("click", function() {
self.confirmEditProfile(add);
});
editDialog.modal("show");
};
self.confirmEditProfile = function(add) {
var callback = function() {
$("#settings_printerProfiles_editDialog").modal("hide");
};
if (add) {
self.addProfile(callback);
} else {
self.updateProfile(undefined, callback);
}
};
self._editorData = function() {
var profile = {
id: self.editorIdentifier(),
name: self.editorName(),
color: self.editorColor(),
id: self.editorIdentifier(),
model: self.editorModel(),
volume: {
width: self.editorWidth(),
depth: self.editorDepth(),
height: self.editorHeight(),
type: self.editorFormFactor()
width: self.editorVolumeWidth(),
depth: self.editorVolumeDepth(),
height: self.editorVolumeHeight(),
type: self.editorVolumeFormFactor()
},
heatedBed: self.editorHeatedBed(),
extruder: {
@ -182,7 +304,6 @@ function PrinterProfilesViewModel() {
return profile;
};
self.onStartup = function() {
self.requestData();
};
self.onSettingsShown = self.requestData;
self.onStartup = self.requestData;
}

View file

@ -122,7 +122,7 @@
<tbody data-bind="foreach: printerProfiles.profiles.paginatedItems">
<tr data-bind="attr: {title: name}">
<td class="settings_printerProfiles_profiles_name"><span class="icon-star" data-bind="invisible: !isdefault()"></span> <span data-bind="text: name"></span></td>
<td class="settings_printerProfiles_profiles_model" data-bind="model"></td>
<td class="settings_printerProfiles_profiles_model" data-bind="text: model"></td>
<td class="settings_printerProfiles_profiles_action">
<a href="#" class="icon-pencil" title="{{ _('Edit Profile') }}" data-bind="click: function() { $root.printerProfiles.showEditProfileDialog($data); }"></a>&nbsp;|&nbsp;<a href="#" class="icon-trash" title="{{ _('Delete Profile') }}" data-bind="click: function() { $root.printerProfiles.removeProfile($data); }"></a>
</td>
@ -130,6 +130,150 @@
</tbody>
</table>
<button class="btn pull-right" data-bind="click: function() { $root.printerProfiles.showEditProfileDialog(); }">{{ _('Add Profile...') }}</button>
<div id="settings_printerProfiles_editDialog" class="modal hide fade">
<div class="modal-header">
<a href="#" class="close" data-dismiss="modal" aria-hidden="true">&times;</a>
<h3 class="modal-title"></h3>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label">{{ _('Name') }}</label>
<div class="controls">
<input type="text" class="disabled" data-bind="value: printerProfiles.editorIdentifier">
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Name') }}</label>
<div class="controls">
<input type="text" data-bind="value: printerProfiles.editorName">
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Model') }}</label>
<div class="controls">
<input type="text" data-bind="value: printerProfiles.editorModel">
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Color') }}</label>
<div class="controls">
<select data-bind="value: printerProfiles.editorColor, options: printerProfiles.availableColors, optionsText: 'name', optionsValue: 'key'">
</select>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Form Factor') }}</label>
<div class="controls">
<label class="radio"><input type="radio" name="printerProfileFormFactorGroup" value="rectangular" data-bind="checked: printerProfiles.editorVolumeFormFactor"> {{ _('Rectangular') }}</label>
</div>
<div class="controls">
<label class="radio"><input type="radio" name="printerProfileFormFactorGroup" value="circular" data-bind="checked: printerProfiles.editorVolumeFormFactor"> {{ _('Circular') }}</label>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Volume') }}</label>
<div class="controls form-inline">
<label>{{ _('X') }}</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: printerProfiles.editorVolumeWidth">
<span class="add-on">mm</span>
</div>
</div>
<div class="controls form-inline">
<label>{{ _('Y') }}</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: printerProfiles.editorVolumeDepth">
<span class="add-on">mm</span>
</div>
</div>
<div class="controls form-inline">
<label>{{ _('Z') }}</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: printerProfiles.editorVolumeHeight">
<span class="add-on">mm</span>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Heated Bed') }}</label>
<div class="controls">
<input type="checkbox" data-bind="checked: printerProfiles.editorHeatedBed">
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Axis') }}</label>
<div class="controls form-inline">
<label>{{ _('X') }}</label>
<div class="input-append">
<input type="number" class="input-mini text-right" data-bind="value: printerProfiles.editorAxisXSpeed">
<span class="add-on">mm/min</span>
</div>
<label class="checkbox">
<input type="checkbox" data-bind="checked: printerProfiles.editorAxisXInverted"> {{ _('Invert control') }}
</label>
</div>
<div class="controls form-inline">
<label>{{ _('Y') }}</label>
<div class="input-append">
<input type="number" class="input-mini text-right" data-bind="value: printerProfiles.editorAxisYSpeed">
<span class="add-on">mm/min</span>
</div>
<label class="checkbox">
<input type="checkbox" data-bind="checked: printerProfiles.editorAxisYInverted"> {{ _('Invert control') }}
</label>
</div>
<div class="controls form-inline">
<label>{{ _('Z') }}</label>
<div class="input-append">
<input type="number" class="input-mini text-right" data-bind="value: printerProfiles.editorAxisZSpeed">
<span class="add-on">mm/min</span>
</div>
<label class="checkbox">
<input type="checkbox" data-bind="checked: printerProfiles.editorAxisYInverted"> {{ _('Invert control') }}
</label>
</div>
<div class="controls form-inline">
<label>{{ _('E') }}</label>
<div class="input-append">
<input type="number" class="input-mini text-right" data-bind="value: printerProfiles.editorAxisESpeed">
<span class="add-on">mm/min</span>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Number of Extruders') }}</label>
<div class="controls">
<input type="number" class="input-mini text-right" min="1" max="5" data-bind="value: printerProfiles.editorExtruders">
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Extruder Offsets') }}</label>
<!-- ko foreach: printerProfiles.koEditorExtruderOffsets -->
<div class="controls form-inline">
<label>X:</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: x">
<span class="add-on">mm</span>
</div>
<label>Y:</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: y">
<span class="add-on">mm</span>
</div>
</div>
<!-- /ko -->
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">{{ _('Abort') }}</button>
<button class="btn btn-primary btn-confirm">{{ _('Confirm') }}</button>
</div>
</div>
</div>
<div class="tab-pane" id="settings_printerParameters">