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:
parent
985b0970f1
commit
93a852e6ea
6 changed files with 369 additions and 78 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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> | <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">×</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">
|
||||
|
|
|
|||
Loading…
Reference in a new issue