mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-10-09 14:57:53 -06:00
Merge branch 'master' of github.com:ultimaker/Cura into feature_material_editing
* 'master' of github.com:ultimaker/Cura: (110 commits) Rearrange MachineActions on Machines page Skip containers that can not be serialized Make PerObjectSettingVisiblityHandler inherit SettingVisiblityHandler and some other cleanup Use the right property for the property provider Clean up indentation Remove unused code Fix expanded settings for Per Object settings tool Use the expanded categories from Cura to expand the proper categories on startup Starting UMOCheckup before connection was established now works correctly Fixed layout Added missing decorator CURA-1385 Restored accidental delete Removed extraneous space Refactoring; Renaming firstRunWizard to machineActionsWizard Added BedLevel as supported action to UMO Refactoring (Renaming variables so they are more clear & update documentation) Remove some trailing spaces CURA-1615 GCodeProfileReader: Removing useless containername Reenable Per Object Settings tool in simple mode if the current printer has multiextrusion Fix minor codereview issues ...
This commit is contained in:
commit
f6866d703d
58 changed files with 1723 additions and 1412 deletions
|
@ -12,7 +12,7 @@ from UM.i18n import i18nCatalog
|
|||
|
||||
from UM.Math.Vector import Vector
|
||||
|
||||
from cura import LayerData
|
||||
from cura import LayerDataBuilder
|
||||
from cura import LayerDataDecorator
|
||||
|
||||
import numpy
|
||||
|
@ -63,7 +63,7 @@ class ProcessSlicedLayersJob(Job):
|
|||
return
|
||||
|
||||
mesh = MeshData()
|
||||
layer_data = LayerData.LayerData()
|
||||
layer_data = LayerDataBuilder.LayerDataBuilder()
|
||||
layer_count = len(self._layers)
|
||||
|
||||
# Find the minimum layer number
|
||||
|
@ -115,7 +115,7 @@ class ProcessSlicedLayersJob(Job):
|
|||
self._progress.setProgress(progress)
|
||||
|
||||
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
||||
layer_data.build()
|
||||
layer_mesh = layer_data.build()
|
||||
|
||||
if self._abort_requested:
|
||||
if self._progress:
|
||||
|
@ -124,7 +124,7 @@ class ProcessSlicedLayersJob(Job):
|
|||
|
||||
# Add LayerDataDecorator to scene node to indicate that the node has layer data
|
||||
decorator = LayerDataDecorator.LayerDataDecorator()
|
||||
decorator.setLayerData(layer_data)
|
||||
decorator.setLayerData(layer_mesh)
|
||||
new_node.addDecorator(decorator)
|
||||
|
||||
new_node.setMeshData(mesh)
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Application import Application #To get the machine manager to create the new profile in.
|
||||
from UM.Settings.Profile import Profile
|
||||
from UM.Settings.ProfileReader import ProfileReader
|
||||
from UM.Logger import Logger
|
||||
import os
|
||||
import re #Regular expressions for parsing escape characters in the settings.
|
||||
|
||||
from UM.Application import Application #To get the machine manager to create the new profile in.
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Logger import Logger
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
from cura.ProfileReader import ProfileReader
|
||||
|
||||
## A class that reads profile data from g-code files.
|
||||
#
|
||||
# It reads the profile data from g-code files and stores it in a new profile.
|
||||
# This class currently does not process the rest of the g-code in any way.
|
||||
class GCodeProfileReader(ProfileReader):
|
||||
## The file format version of the serialised g-code.
|
||||
## The file format version of the serialized g-code.
|
||||
#
|
||||
# It can only read settings with the same version as the version it was
|
||||
# written with. If the file format is changed in a way that breaks reverse
|
||||
# compatibility, increment this version number!
|
||||
version = 1
|
||||
|
||||
|
||||
## Dictionary that defines how characters are escaped when embedded in
|
||||
# g-code.
|
||||
#
|
||||
|
@ -51,31 +55,36 @@ class GCodeProfileReader(ProfileReader):
|
|||
# Loading all settings from the file.
|
||||
# They are all at the end, but Python has no reverse seek any more since Python3.
|
||||
# TODO: Consider moving settings to the start?
|
||||
serialised = "" # Will be filled with the serialised profile.
|
||||
serialized = "" # Will be filled with the serialized profile.
|
||||
try:
|
||||
with open(file_name) as f:
|
||||
for line in f:
|
||||
if line.startswith(prefix):
|
||||
# Remove the prefix and the newline from the line and add it to the rest.
|
||||
serialised += line[prefix_length : -1]
|
||||
serialized += line[prefix_length : -1]
|
||||
except IOError as e:
|
||||
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
|
||||
return None
|
||||
|
||||
# Un-escape the serialised profile.
|
||||
# Un-escape the serialized profile.
|
||||
pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys()))
|
||||
|
||||
# Perform the replacement with a regular expression.
|
||||
serialised = pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], serialised)
|
||||
serialized = pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], serialized)
|
||||
Logger.log("i", "Serialized the following from %s: %s" %(file_name, repr(serialized)))
|
||||
|
||||
# Apply the changes to the current profile.
|
||||
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False)
|
||||
# Create an empty profile - the id will be changed later
|
||||
profile = InstanceContainer("")
|
||||
profile.addMetaDataEntry("type", "quality")
|
||||
try:
|
||||
profile.unserialise(serialised)
|
||||
profile.setType(None) # Force type to none so it's correctly added.
|
||||
profile.setReadOnly(False)
|
||||
profile.setDirty(True)
|
||||
profile.deserialize(serialized)
|
||||
except Exception as e: # Not a valid g-code file.
|
||||
Logger.log("e", "Unable to serialise the profile: %s", str(e))
|
||||
return None
|
||||
return profile
|
||||
|
||||
#Creating a unique name using the filename of the GCode
|
||||
new_name = catalog.i18nc("@label", "Custom profile (%s)") %(os.path.splitext(os.path.basename(file_name))[0])
|
||||
profile.setName(new_name)
|
||||
profile._id = new_name
|
||||
|
||||
return profile
|
||||
|
|
|
@ -13,7 +13,7 @@ def getMetaData():
|
|||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Provides support for importing profiles from g-code files."),
|
||||
"api": 2
|
||||
"api": 3
|
||||
},
|
||||
"profile_reader": [
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@ from PyQt5.QtGui import QImage, qRed, qGreen, qBlue
|
|||
from PyQt5.QtCore import Qt
|
||||
|
||||
from UM.Mesh.MeshReader import MeshReader
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Job import Job
|
||||
|
@ -48,13 +48,9 @@ class ImageReader(MeshReader):
|
|||
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.image_color_invert)
|
||||
|
||||
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, image_color_invert):
|
||||
mesh = None # TODO: @UnusedVariable
|
||||
scene_node = None # TODO: @UnusedVariable
|
||||
|
||||
scene_node = SceneNode()
|
||||
|
||||
mesh = MeshData()
|
||||
scene_node.setMeshData(mesh)
|
||||
mesh = MeshBuilder()
|
||||
|
||||
img = QImage(file_name)
|
||||
|
||||
|
@ -76,9 +72,9 @@ class ImageReader(MeshReader):
|
|||
scale_vector = Vector(xz_size, peak_height, xz_size)
|
||||
|
||||
if width > height:
|
||||
scale_vector.setZ(scale_vector.z * aspect)
|
||||
scale_vector = scale_vector.set(z=scale_vector.z * aspect)
|
||||
elif height > width:
|
||||
scale_vector.setX(scale_vector.x / aspect)
|
||||
scale_vector = scale_vector.set(x=scale_vector.x / aspect)
|
||||
|
||||
if width > max_size or height > max_size:
|
||||
scale_factor = max_size / width
|
||||
|
@ -173,8 +169,8 @@ class ImageReader(MeshReader):
|
|||
geo_height = height_minus_one * texel_height
|
||||
|
||||
# bottom
|
||||
mesh.addFace(0, 0, 0, 0, 0, geo_height, geo_width, 0, geo_height)
|
||||
mesh.addFace(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0, 0)
|
||||
mesh.addFaceByPoints(0, 0, 0, 0, 0, geo_height, geo_width, 0, geo_height)
|
||||
mesh.addFaceByPoints(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0, 0)
|
||||
|
||||
# north and south walls
|
||||
for n in range(0, width_minus_one):
|
||||
|
@ -187,11 +183,11 @@ class ImageReader(MeshReader):
|
|||
hs0 = height_data[height_minus_one, n]
|
||||
hs1 = height_data[height_minus_one, n + 1]
|
||||
|
||||
mesh.addFace(x, 0, 0, nx, 0, 0, nx, hn1, 0)
|
||||
mesh.addFace(nx, hn1, 0, x, hn0, 0, x, 0, 0)
|
||||
mesh.addFaceByPoints(x, 0, 0, nx, 0, 0, nx, hn1, 0)
|
||||
mesh.addFaceByPoints(nx, hn1, 0, x, hn0, 0, x, 0, 0)
|
||||
|
||||
mesh.addFace(x, 0, geo_height, nx, 0, geo_height, nx, hs1, geo_height)
|
||||
mesh.addFace(nx, hs1, geo_height, x, hs0, geo_height, x, 0, geo_height)
|
||||
mesh.addFaceByPoints(x, 0, geo_height, nx, 0, geo_height, nx, hs1, geo_height)
|
||||
mesh.addFaceByPoints(nx, hs1, geo_height, x, hs0, geo_height, x, 0, geo_height)
|
||||
|
||||
# west and east walls
|
||||
for n in range(0, height_minus_one):
|
||||
|
@ -204,12 +200,14 @@ class ImageReader(MeshReader):
|
|||
he0 = height_data[n, width_minus_one]
|
||||
he1 = height_data[n + 1, width_minus_one]
|
||||
|
||||
mesh.addFace(0, 0, y, 0, 0, ny, 0, hw1, ny)
|
||||
mesh.addFace(0, hw1, ny, 0, hw0, y, 0, 0, y)
|
||||
mesh.addFaceByPoints(0, 0, y, 0, 0, ny, 0, hw1, ny)
|
||||
mesh.addFaceByPoints(0, hw1, ny, 0, hw0, y, 0, 0, y)
|
||||
|
||||
mesh.addFace(geo_width, 0, y, geo_width, 0, ny, geo_width, he1, ny)
|
||||
mesh.addFace(geo_width, he1, ny, geo_width, he0, y, geo_width, 0, y)
|
||||
mesh.addFaceByPoints(geo_width, 0, y, geo_width, 0, ny, geo_width, he1, ny)
|
||||
mesh.addFaceByPoints(geo_width, he1, ny, geo_width, he0, y, geo_width, 0, y)
|
||||
|
||||
mesh.calculateNormals(fast=True)
|
||||
|
||||
scene_node.setMeshData(mesh.build())
|
||||
|
||||
return scene_node
|
||||
|
|
|
@ -8,7 +8,7 @@ from UM.Event import Event, KeyEvent
|
|||
from UM.Signal import Signal
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Math.Color import Color
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
from UM.Job import Job
|
||||
from UM.Preferences import Preferences
|
||||
|
||||
|
@ -240,7 +240,7 @@ class _CreateTopLayersJob(Job):
|
|||
if self._cancel or not layer_data:
|
||||
return
|
||||
|
||||
layer_mesh = MeshData()
|
||||
layer_mesh = MeshBuilder()
|
||||
for i in range(self._solid_layers):
|
||||
layer_number = self._layer_number - i
|
||||
if layer_number < 0:
|
||||
|
@ -275,7 +275,7 @@ class _CreateTopLayersJob(Job):
|
|||
if not jump_mesh or jump_mesh.getVertices() is None:
|
||||
jump_mesh = None
|
||||
|
||||
self.setResult({ "layers": layer_mesh, "jumps": jump_mesh })
|
||||
self.setResult({ "layers": layer_mesh.build(), "jumps": jump_mesh })
|
||||
|
||||
def cancel(self):
|
||||
self._cancel = True
|
||||
|
|
|
@ -3,36 +3,44 @@ from UM.Application import Application
|
|||
from UM.Settings.SettingInstance import SettingInstance
|
||||
from UM.Logger import Logger
|
||||
|
||||
import UM.Settings.Models
|
||||
|
||||
from cura.SettingOverrideDecorator import SettingOverrideDecorator
|
||||
|
||||
## The per object setting visibility handler ensures that only setting defintions that have a matching instance Container
|
||||
# are returned as visible.
|
||||
class PerObjectSettingVisibilityHandler(QObject):
|
||||
class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHandler):
|
||||
def __init__(self, parent = None, *args, **kwargs):
|
||||
super().__init__(parent = parent, *args, **kwargs)
|
||||
self._selected_object_id = None
|
||||
|
||||
visibilityChanged = pyqtSignal()
|
||||
self._selected_object_id = None
|
||||
self._node = None
|
||||
self._stack = None
|
||||
|
||||
def setSelectedObjectId(self, id):
|
||||
self._selected_object_id = id
|
||||
self.visibilityChanged.emit()
|
||||
if id != self._selected_object_id:
|
||||
self._selected_object_id = id
|
||||
|
||||
self._node = Application.getInstance().getController().getScene().findObject(self._selected_object_id)
|
||||
if self._node:
|
||||
self._stack = self._node.callDecoration("getStack")
|
||||
|
||||
self.visibilityChanged.emit()
|
||||
|
||||
@pyqtProperty("quint64", fset = setSelectedObjectId)
|
||||
def selectedObjectId(self):
|
||||
pass
|
||||
return self._selected_object_id
|
||||
|
||||
def setVisible(self, visible):
|
||||
node = Application.getInstance().getController().getScene().findObject(self._selected_object_id)
|
||||
if not node:
|
||||
if not self._node:
|
||||
return
|
||||
stack = node.callDecoration("getStack")
|
||||
if not stack:
|
||||
node.addDecorator(SettingOverrideDecorator())
|
||||
stack = node.callDecoration("getStack")
|
||||
|
||||
settings = stack.getTop()
|
||||
all_instances = settings.findInstances(**{})
|
||||
if not self._stack:
|
||||
self._node.addDecorator(SettingOverrideDecorator())
|
||||
self._stack = self._node.callDecoration("getStack")
|
||||
|
||||
settings = self._stack.getTop()
|
||||
all_instances = settings.findInstances()
|
||||
visibility_changed = False # Flag to check if at the end the signal needs to be emitted
|
||||
|
||||
# Remove all instances that are not in visibility list
|
||||
|
@ -41,13 +49,12 @@ class PerObjectSettingVisibilityHandler(QObject):
|
|||
settings.removeInstance(instance.definition.key)
|
||||
visibility_changed = True
|
||||
|
||||
# Add all instances that are not added, but are in visiblity list
|
||||
# Add all instances that are not added, but are in visibility list
|
||||
for item in visible:
|
||||
if not settings.getInstance(item):
|
||||
definition_container = Application.getInstance().getGlobalContainerStack().getBottom()
|
||||
definitions = definition_container.findDefinitions(key = item)
|
||||
if definitions:
|
||||
settings.addInstance(SettingInstance(definitions[0], settings))
|
||||
definition = self._stack.getSettingDefinition(item)
|
||||
if definition:
|
||||
settings.addInstance(SettingInstance(definition, settings))
|
||||
visibility_changed = True
|
||||
else:
|
||||
Logger.log("w", "Unable to add instance (%s) to perobject visibility because we couldn't find the matching definition", item)
|
||||
|
@ -57,20 +64,16 @@ class PerObjectSettingVisibilityHandler(QObject):
|
|||
|
||||
def getVisible(self):
|
||||
visible_settings = set()
|
||||
node = Application.getInstance().getController().getScene().findObject(self._selected_object_id)
|
||||
if not node:
|
||||
if not self._node:
|
||||
return visible_settings
|
||||
|
||||
stack = node.callDecoration("getStack")
|
||||
if not stack:
|
||||
if not self._stack:
|
||||
return visible_settings
|
||||
|
||||
settings = stack.getTop()
|
||||
settings = self._stack.getTop()
|
||||
if not settings:
|
||||
return visible_settings
|
||||
|
||||
all_instances = settings.findInstances(**{})
|
||||
for instance in all_instances:
|
||||
visible_settings.add(instance.definition.key)
|
||||
visible_settings = set(map(lambda i: i.definition.key, settings.findInstances()))
|
||||
return visible_settings
|
||||
|
||||
|
|
|
@ -24,10 +24,20 @@ Item {
|
|||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
|
||||
spacing: UM.Theme.getSize("default_margin").height;
|
||||
spacing: UM.Theme.getSize("default_margin").height
|
||||
|
||||
Row
|
||||
{
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Print object with")
|
||||
anchors.verticalCenter: extruderSelector.verticalCenter
|
||||
|
||||
color: UM.Theme.getColor("setting_control_text")
|
||||
font: UM.Theme.getFont("default")
|
||||
visible: extruderSelector.visible
|
||||
}
|
||||
ComboBox
|
||||
{
|
||||
id: extruderSelector
|
||||
|
@ -40,7 +50,7 @@ Item {
|
|||
}
|
||||
visible: extruders_model.rowCount() > 1
|
||||
textRole: "name"
|
||||
width: items.width
|
||||
width: UM.Theme.getSize("setting_control").width
|
||||
height: UM.Theme.getSize("section").height
|
||||
MouseArea
|
||||
{
|
||||
|
@ -143,6 +153,8 @@ Item {
|
|||
{
|
||||
id: addedSettingsModel;
|
||||
containerId: Cura.MachineManager.activeDefinitionId
|
||||
expanded: [ "*" ]
|
||||
|
||||
visibilityHandler: Cura.PerObjectSettingVisibilityHandler
|
||||
{
|
||||
selectedObjectId: UM.ActiveTool.properties.getValue("SelectedObjectId")
|
||||
|
@ -205,9 +217,8 @@ Item {
|
|||
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
background: Item
|
||||
{
|
||||
color: control.hovered ? control.parent.style.controlHighlightColor : control.parent.style.controlColor;
|
||||
UM.RecolorImage
|
||||
{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
@ -330,6 +341,8 @@ Item {
|
|||
"settable_per_mesh": true
|
||||
}
|
||||
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
|
||||
expanded: [ "*" ]
|
||||
exclude: [ "machine_settings" ]
|
||||
}
|
||||
delegate:Loader
|
||||
{
|
||||
|
|
|
@ -16,10 +16,17 @@ class PerObjectSettingsTool(Tool):
|
|||
|
||||
self.setExposedProperties("SelectedObjectId", "ContainerID", "SelectedActiveExtruder")
|
||||
|
||||
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
|
||||
self._advanced_mode = False
|
||||
self._multi_extrusion = False
|
||||
|
||||
Selection.selectionChanged.connect(self.propertyChanged)
|
||||
|
||||
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
|
||||
self._onPreferenceChanged("cura/active_mode")
|
||||
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
||||
self._onGlobalContainerChanged()
|
||||
|
||||
def event(self, event):
|
||||
return False
|
||||
|
||||
|
@ -55,5 +62,14 @@ class PerObjectSettingsTool(Tool):
|
|||
|
||||
def _onPreferenceChanged(self, preference):
|
||||
if preference == "cura/active_mode":
|
||||
enabled = Preferences.getInstance().getValue(preference)==1
|
||||
Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, enabled)
|
||||
self._advanced_mode = Preferences.getInstance().getValue(preference) == 1
|
||||
self._updateEnabled()
|
||||
|
||||
def _onGlobalContainerChanged(self):
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
self._multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
|
||||
self._updateEnabled()
|
||||
|
||||
def _updateEnabled(self):
|
||||
Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, self._advanced_mode or self._multi_extrusion)
|
|
@ -8,6 +8,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
|||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Message import Message
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Logger import Logger
|
||||
|
||||
import collections
|
||||
import json
|
||||
|
@ -25,6 +26,8 @@ catalog = i18nCatalog("cura")
|
|||
# The data is only sent when the user in question gave permission to do so. All data is anonymous and
|
||||
# no model files are being sent (Just a SHA256 hash of the model).
|
||||
class SliceInfo(Extension):
|
||||
info_url = "https://stats.youmagine.com/curastats/slice"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
|
||||
|
@ -43,34 +46,14 @@ class SliceInfo(Extension):
|
|||
|
||||
def _onWriteStarted(self, output_device):
|
||||
if not Preferences.getInstance().getValue("info/send_slice_info"):
|
||||
Logger.log("d", "'info/send_slice_info' is turned off.")
|
||||
return # Do nothing, user does not want to send data
|
||||
settings = Application.getInstance().getMachineManager().getWorkingProfile()
|
||||
|
||||
# Load all machine definitions and put them in machine_settings dict
|
||||
#setting_file_name = Application.getInstance().getActiveMachineInstance().getMachineSettings()._json_file
|
||||
machine_settings = {}
|
||||
#with open(setting_file_name, "rt", -1, "utf-8") as f:
|
||||
# data = json.load(f, object_pairs_hook = collections.OrderedDict)
|
||||
#machine_settings[os.path.basename(setting_file_name)] = copy.deepcopy(data)
|
||||
active_machine_definition= Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition()
|
||||
data = active_machine_definition._json_data
|
||||
# Loop through inherited json files
|
||||
setting_file_name = active_machine_definition._path
|
||||
while True:
|
||||
if "inherits" in data:
|
||||
inherited_setting_file_name = os.path.dirname(setting_file_name) + "/" + data["inherits"]
|
||||
with open(inherited_setting_file_name, "rt", -1, "utf-8") as f:
|
||||
data = json.load(f, object_pairs_hook = collections.OrderedDict)
|
||||
machine_settings[os.path.basename(inherited_setting_file_name)] = copy.deepcopy(data)
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
profile_values = settings.getChangedSettings() # TODO: @UnusedVariable
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
|
||||
# Get total material used (in mm^3)
|
||||
print_information = Application.getInstance().getPrintInformation()
|
||||
material_radius = 0.5 * settings.getSettingValue("material_diameter")
|
||||
material_radius = 0.5 * global_container_stack.getProperty("material_diameter", "value")
|
||||
material_used = math.pi * material_radius * material_radius * print_information.materialAmount #Volume of material used
|
||||
|
||||
# Get model information (bounding boxes, hashes and transformation matrix)
|
||||
|
@ -99,14 +82,26 @@ class SliceInfo(Extension):
|
|||
"processor": platform.processor(),
|
||||
"machine": platform.machine(),
|
||||
"platform": platform.platform(),
|
||||
"machine_settings": json.dumps(machine_settings),
|
||||
"settings": global_container_stack.serialize(), # global_container with references on used containers
|
||||
"version": Application.getInstance().getVersion(),
|
||||
"modelhash": "None",
|
||||
"printtime": str(print_information.currentPrintTime),
|
||||
"printtime": print_information.currentPrintTime.getDisplayString(),
|
||||
"filament": material_used,
|
||||
"language": Preferences.getInstance().getValue("general/language"),
|
||||
"materials_profiles ": {}
|
||||
}
|
||||
for container in global_container_stack.getContainers():
|
||||
container_id = container.getId()
|
||||
try:
|
||||
container_serialized = container.serialize()
|
||||
except NotImplementedError:
|
||||
Logger.log("w", "Container %s could not be serialized!", container_id)
|
||||
continue
|
||||
|
||||
if container_serialized:
|
||||
submitted_data["settings_%s" %(container_id)] = container_serialized # This can be anything, eg. INI, JSON, etc.
|
||||
else:
|
||||
Logger.log("i", "No data found in %s to be serialized!", container_id)
|
||||
|
||||
# Convert data to bytes
|
||||
submitted_data = urllib.parse.urlencode(submitted_data)
|
||||
|
@ -114,8 +109,8 @@ class SliceInfo(Extension):
|
|||
|
||||
# Submit data
|
||||
try:
|
||||
f = urllib.request.urlopen("https://stats.youmagine.com/curastats/slice", data = binary_data, timeout = 1)
|
||||
f = urllib.request.urlopen(self.info_url, data = binary_data, timeout = 1)
|
||||
Logger.log("i", "Sent anonymous slice info to %s", self.info_url)
|
||||
f.close()
|
||||
except Exception as e:
|
||||
print("Exception occured", e)
|
||||
|
||||
f.close()
|
||||
Logger.logException("e", e)
|
||||
|
|
|
@ -11,7 +11,7 @@ def getMetaData():
|
|||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Submits anonymous slice info. Can be disabled through preferences."),
|
||||
"api": 2
|
||||
"api": 3
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@ from UM.View.Renderer import Renderer
|
|||
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from cura.ExtrudersModel import ExtrudersModel
|
||||
|
||||
import math
|
||||
|
||||
## Standard view for mesh models.
|
||||
## Standard view for mesh models.
|
||||
class SolidView(View):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
@ -22,6 +24,8 @@ class SolidView(View):
|
|||
self._enabled_shader = None
|
||||
self._disabled_shader = None
|
||||
|
||||
self._extruders_model = ExtrudersModel()
|
||||
|
||||
def beginRendering(self):
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
|
@ -50,15 +54,37 @@ class SolidView(View):
|
|||
# TODO: Find a better way to handle this
|
||||
#if node.getBoundingBoxMesh():
|
||||
# renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines)
|
||||
|
||||
uniforms = {}
|
||||
if self._extruders_model.rowCount() > 0:
|
||||
# Get color to render this mesh in from ExtrudersModel
|
||||
extruder_index = 0
|
||||
extruder_id = node.callDecoration("getActiveExtruder")
|
||||
if extruder_id:
|
||||
extruder_index = max(0, self._extruders_model.find("id", extruder_id))
|
||||
|
||||
extruder_color = self._extruders_model.getItem(extruder_index)["colour"]
|
||||
try:
|
||||
# Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
|
||||
# an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])
|
||||
uniforms["diffuse_color"] = [
|
||||
int(extruder_color[1:3], 16) / 255,
|
||||
int(extruder_color[3:5], 16) / 255,
|
||||
int(extruder_color[5:7], 16) / 255,
|
||||
1.0
|
||||
]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if hasattr(node, "_outside_buildarea"):
|
||||
if node._outside_buildarea:
|
||||
renderer.queueNode(node, shader = self._disabled_shader)
|
||||
else:
|
||||
renderer.queueNode(node, shader = self._enabled_shader)
|
||||
renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms)
|
||||
else:
|
||||
renderer.queueNode(node, material = self._enabled_shader)
|
||||
renderer.queueNode(node, material = self._enabled_shader, uniforms = uniforms)
|
||||
if node.callDecoration("isGroup"):
|
||||
renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines)
|
||||
renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = Renderer.RenderLines)
|
||||
|
||||
def endRendering(self):
|
||||
pass
|
||||
|
|
53
plugins/UltimakerMachineActions/BedLevelMachineAction.py
Normal file
53
plugins/UltimakerMachineActions/BedLevelMachineAction.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
from cura.MachineAction import MachineAction
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
|
||||
from UM.Application import Application
|
||||
|
||||
from cura.PrinterOutputDevice import PrinterOutputDevice
|
||||
|
||||
class BedLevelMachineAction(MachineAction):
|
||||
def __init__(self):
|
||||
super().__init__("BedLevel", "Level bed")
|
||||
self._qml_url = "BedLevelMachineAction.qml"
|
||||
self._bed_level_position = 0
|
||||
|
||||
def _execute(self):
|
||||
pass
|
||||
|
||||
def _reset(self):
|
||||
self._bed_level_position = 0
|
||||
printer_output_devices = self._getPrinterOutputDevices()
|
||||
if printer_output_devices:
|
||||
printer_output_devices[0].homeBed()
|
||||
printer_output_devices[0].moveHead(0, 0, 3)
|
||||
printer_output_devices[0].homeHead()
|
||||
|
||||
def _getPrinterOutputDevices(self):
|
||||
return [printer_output_device for printer_output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices() if isinstance(printer_output_device, PrinterOutputDevice)]
|
||||
|
||||
@pyqtSlot()
|
||||
def moveToNextLevelPosition(self):
|
||||
output_devices = self._getPrinterOutputDevices()
|
||||
if output_devices: # We found at least one output device
|
||||
output_device = output_devices[0]
|
||||
|
||||
if self._bed_level_position == 0:
|
||||
output_device.moveHead(0, 0, 3)
|
||||
output_device.homeHead()
|
||||
output_device.moveHead(0, 0, 3)
|
||||
output_device.moveHead(Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") - 10, 0, 0)
|
||||
output_device.moveHead(0, 0, -3)
|
||||
self._bed_level_position += 1
|
||||
elif self._bed_level_position == 1:
|
||||
output_device.moveHead(0, 0, 3)
|
||||
output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value" ) / 2, Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") - 10, 0)
|
||||
output_device.moveHead(0, 0, -3)
|
||||
self._bed_level_position += 1
|
||||
elif self._bed_level_position == 2:
|
||||
output_device.moveHead(0, 0, 3)
|
||||
output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") / 2 + 10, -(Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") + 10), 0)
|
||||
output_device.moveHead(0, 0, -3)
|
||||
self._bed_level_position += 1
|
||||
elif self._bed_level_position >= 3:
|
||||
self.setFinished()
|
85
plugins/UltimakerMachineActions/BedLevelMachineAction.qml
Normal file
85
plugins/UltimakerMachineActions/BedLevelMachineAction.qml
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 2016 Ultimaker B.V.
|
||||
// Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
import UM 1.2 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
|
||||
Cura.MachineAction
|
||||
{
|
||||
anchors.fill: parent;
|
||||
Item
|
||||
{
|
||||
id: bedLevelMachineAction
|
||||
anchors.fill: parent;
|
||||
|
||||
UM.I18nCatalog { id: catalog; name: "cura"; }
|
||||
|
||||
Label
|
||||
{
|
||||
id: pageTitle
|
||||
width: parent.width
|
||||
text: catalog.i18nc("@title", "Bed Leveling")
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: 18;
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: pageDescription
|
||||
anchors.top: pageTitle.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "To make sure your prints will come out great, you can now adjust your buildplate. When you click 'Move to Next Position' the nozzle will move to the different positions that can be adjusted.")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: bedlevelingText
|
||||
anchors.top: pageDescription.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "For every position; insert a piece of paper under the nozzle and adjust the print bed height. The print bed height is right when the paper is slightly gripped by the tip of the nozzle.")
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: bedlevelingWrapper
|
||||
anchors.top: bedlevelingText.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: skipBedlevelingButton.height
|
||||
width: bedlevelingButton.width + skipBedlevelingButton.width + UM.Theme.getSize("default_margin").height < bedLevelMachineAction.width ? bedlevelingButton.width + skipBedlevelingButton.width + UM.Theme.getSize("default_margin").height : bedLevelMachineAction.width
|
||||
Button
|
||||
{
|
||||
id: bedlevelingButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
text: catalog.i18nc("@action:button","Move to Next Position");
|
||||
onClicked:
|
||||
{
|
||||
manager.moveToNextLevelPosition()
|
||||
}
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: skipBedlevelingButton
|
||||
anchors.top: parent.width < bedLevelMachineAction.width ? parent.top : bedlevelingButton.bottom
|
||||
anchors.topMargin: parent.width < bedLevelMachineAction.width ? 0 : UM.Theme.getSize("default_margin").height/2
|
||||
anchors.left: parent.width < bedLevelMachineAction.width ? bedlevelingButton.right : parent.left
|
||||
anchors.leftMargin: parent.width < bedLevelMachineAction.width ? UM.Theme.getSize("default_margin").width : 0
|
||||
text: catalog.i18nc("@action:button","Skip bed leveling");
|
||||
onClicked:
|
||||
{
|
||||
manager.setFinished()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
160
plugins/UltimakerMachineActions/UMOCheckupMachineAction.py
Normal file
160
plugins/UltimakerMachineActions/UMOCheckupMachineAction.py
Normal file
|
@ -0,0 +1,160 @@
|
|||
from cura.MachineAction import MachineAction
|
||||
from cura.PrinterOutputDevice import PrinterOutputDevice
|
||||
from UM.Application import Application
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty
|
||||
|
||||
class UMOCheckupMachineAction(MachineAction):
|
||||
def __init__(self):
|
||||
super().__init__("UMOCheckup", "Checkup")
|
||||
self._qml_url = "UMOCheckupMachineAction.qml"
|
||||
self._hotend_target_temp = 180
|
||||
self._bed_target_temp = 60
|
||||
self._output_device = None
|
||||
self._bed_test_completed = False
|
||||
self._hotend_test_completed = False
|
||||
|
||||
# Endstop tests
|
||||
self._x_min_endstop_test_completed = False
|
||||
self._y_min_endstop_test_completed = False
|
||||
self._z_min_endstop_test_completed = False
|
||||
|
||||
self._check_started = False
|
||||
|
||||
Application.getInstance().getOutputDeviceManager().outputDevicesChanged.connect(self._onOutputDevicesChanged)
|
||||
|
||||
|
||||
onBedTestCompleted = pyqtSignal()
|
||||
onHotendTestCompleted = pyqtSignal()
|
||||
|
||||
onXMinEndstopTestCompleted = pyqtSignal()
|
||||
onYMinEndstopTestCompleted = pyqtSignal()
|
||||
onZMinEndstopTestCompleted = pyqtSignal()
|
||||
|
||||
bedTemperatureChanged = pyqtSignal()
|
||||
hotendTemperatureChanged = pyqtSignal()
|
||||
|
||||
def _onOutputDevicesChanged(self):
|
||||
# Check if this action was started, but no output device was found the first time.
|
||||
# If so, re-try now that an output device has been added/removed.
|
||||
if self._output_device is None and self._check_started:
|
||||
self.startCheck()
|
||||
|
||||
|
||||
def _getPrinterOutputDevices(self):
|
||||
return [printer_output_device for printer_output_device in
|
||||
Application.getInstance().getOutputDeviceManager().getOutputDevices() if
|
||||
isinstance(printer_output_device, PrinterOutputDevice)]
|
||||
|
||||
def _reset(self):
|
||||
if self._output_device:
|
||||
self._output_device.bedTemperatureChanged.disconnect(self.bedTemperatureChanged)
|
||||
self._output_device.hotendTemperaturesChanged.disconnect(self.hotendTemperatureChanged)
|
||||
self._output_device.bedTemperatureChanged.disconnect(self._onBedTemperatureChanged)
|
||||
self._output_device.hotendTemperaturesChanged.disconnect(self._onHotendTemperatureChanged)
|
||||
self._output_device.endstopStateChanged.disconnect(self._onEndstopStateChanged)
|
||||
try:
|
||||
self._output_device.stopPollEndstop()
|
||||
except AttributeError: # Connection is probably not a USB connection. Something went pretty wrong if this happens.
|
||||
pass
|
||||
self._output_device = None
|
||||
|
||||
self._check_started = False
|
||||
|
||||
# Ensure everything is reset (and right signals are emitted again)
|
||||
self._bed_test_completed = False
|
||||
self.onBedTestCompleted.emit()
|
||||
self._hotend_test_completed = False
|
||||
self.onHotendTestCompleted.emit()
|
||||
|
||||
self._x_min_endstop_test_completed = False
|
||||
self.onXMinEndstopTestCompleted.emit()
|
||||
self._y_min_endstop_test_completed = False
|
||||
self.onYMinEndstopTestCompleted.emit()
|
||||
self._z_min_endstop_test_completed = False
|
||||
self.onZMinEndstopTestCompleted.emit()
|
||||
|
||||
@pyqtProperty(bool, notify = onBedTestCompleted)
|
||||
def bedTestCompleted(self):
|
||||
return self._bed_test_completed
|
||||
|
||||
@pyqtProperty(bool, notify = onHotendTestCompleted)
|
||||
def hotendTestCompleted(self):
|
||||
return self._hotend_test_completed
|
||||
|
||||
@pyqtProperty(bool, notify = onXMinEndstopTestCompleted)
|
||||
def xMinEndstopTestCompleted(self):
|
||||
return self._x_min_endstop_test_completed
|
||||
|
||||
@pyqtProperty(bool, notify=onYMinEndstopTestCompleted)
|
||||
def yMinEndstopTestCompleted(self):
|
||||
return self._y_min_endstop_test_completed
|
||||
|
||||
@pyqtProperty(bool, notify=onZMinEndstopTestCompleted)
|
||||
def zMinEndstopTestCompleted(self):
|
||||
return self._z_min_endstop_test_completed
|
||||
|
||||
@pyqtProperty(float, notify = bedTemperatureChanged)
|
||||
def bedTemperature(self):
|
||||
if not self._output_device:
|
||||
return 0
|
||||
return self._output_device.bedTemperature
|
||||
|
||||
@pyqtProperty(float, notify=hotendTemperatureChanged)
|
||||
def hotendTemperature(self):
|
||||
if not self._output_device:
|
||||
return 0
|
||||
return self._output_device.hotendTemperatures[0]
|
||||
|
||||
def _onHotendTemperatureChanged(self):
|
||||
if not self._output_device:
|
||||
return
|
||||
if not self._hotend_test_completed:
|
||||
if self._output_device.hotendTemperatures[0] + 10 > self._hotend_target_temp and self._output_device.hotendTemperatures[0] - 10 < self._hotend_target_temp:
|
||||
self._hotend_test_completed = True
|
||||
self.onHotendTestCompleted.emit()
|
||||
|
||||
def _onBedTemperatureChanged(self):
|
||||
if not self._output_device:
|
||||
return
|
||||
if not self._bed_test_completed:
|
||||
if self._output_device.bedTemperature + 5 > self._bed_target_temp and self._output_device.bedTemperature - 5 < self._bed_target_temp:
|
||||
self._bed_test_completed = True
|
||||
self.onBedTestCompleted.emit()
|
||||
|
||||
def _onEndstopStateChanged(self, switch_type, state):
|
||||
if state:
|
||||
if switch_type == "x_min":
|
||||
self._x_min_endstop_test_completed = True
|
||||
self.onXMinEndstopTestCompleted.emit()
|
||||
elif switch_type == "y_min":
|
||||
self._y_min_endstop_test_completed = True
|
||||
self.onYMinEndstopTestCompleted.emit()
|
||||
elif switch_type == "z_min":
|
||||
self._z_min_endstop_test_completed = True
|
||||
self.onZMinEndstopTestCompleted.emit()
|
||||
|
||||
@pyqtSlot()
|
||||
def startCheck(self):
|
||||
self._check_started = True
|
||||
output_devices = self._getPrinterOutputDevices()
|
||||
if output_devices:
|
||||
self._output_device = output_devices[0]
|
||||
try:
|
||||
self._output_device.startPollEndstop()
|
||||
self._output_device.bedTemperatureChanged.connect(self.bedTemperatureChanged)
|
||||
self._output_device.hotendTemperaturesChanged.connect(self.hotendTemperatureChanged)
|
||||
self._output_device.bedTemperatureChanged.connect(self._onBedTemperatureChanged)
|
||||
self._output_device.hotendTemperaturesChanged.connect(self._onHotendTemperatureChanged)
|
||||
self._output_device.endstopStateChanged.connect(self._onEndstopStateChanged)
|
||||
except AttributeError: # Connection is probably not a USB connection. Something went pretty wrong if this happens.
|
||||
pass
|
||||
|
||||
@pyqtSlot()
|
||||
def heatupHotend(self):
|
||||
if self._output_device is not None:
|
||||
self._output_device.setTargetHotendTemperature(0, self._hotend_target_temp)
|
||||
|
||||
@pyqtSlot()
|
||||
def heatupBed(self):
|
||||
if self._output_device is not None:
|
||||
self._output_device.setTargetBedTemperature(self._bed_target_temp)
|
271
plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml
Normal file
271
plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml
Normal file
|
@ -0,0 +1,271 @@
|
|||
import UM 1.2 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
Cura.MachineAction
|
||||
{
|
||||
anchors.fill: parent;
|
||||
Item
|
||||
{
|
||||
id: checkupMachineAction
|
||||
anchors.fill: parent;
|
||||
property int leftRow: checkupMachineAction.width * 0.40
|
||||
property int rightRow: checkupMachineAction.width * 0.60
|
||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||
Label
|
||||
{
|
||||
id: pageTitle
|
||||
width: parent.width
|
||||
text: catalog.i18nc("@title", "Check Printer")
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: 18;
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: pageDescription
|
||||
anchors.top: pageTitle.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","It's a good idea to do a few sanity checks on your Ultimaker. You can skip this step if you know your machine is functional");
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: startStopButtons
|
||||
anchors.top: pageDescription.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: childrenRect.height
|
||||
width: startCheckButton.width + skipCheckButton.width + UM.Theme.getSize("default_margin").height < checkupMachineAction.width ? startCheckButton.width + skipCheckButton.width + UM.Theme.getSize("default_margin").height : checkupMachineAction.width
|
||||
Button
|
||||
{
|
||||
id: startCheckButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
text: catalog.i18nc("@action:button","Start Printer Check");
|
||||
onClicked:
|
||||
{
|
||||
checkupContent.visible = true
|
||||
startCheckButton.enabled = false
|
||||
manager.startCheck()
|
||||
}
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: skipCheckButton
|
||||
anchors.top: parent.width < checkupMachineAction.width ? parent.top : startCheckButton.bottom
|
||||
anchors.topMargin: parent.width < checkupMachineAction.width ? 0 : UM.Theme.getSize("default_margin").height/2
|
||||
anchors.left: parent.width < checkupMachineAction.width ? startCheckButton.right : parent.left
|
||||
anchors.leftMargin: parent.width < checkupMachineAction.width ? UM.Theme.getSize("default_margin").width : 0
|
||||
text: catalog.i18nc("@action:button", "Skip Printer Check");
|
||||
onClicked: manager.setFinished()
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: checkupContent
|
||||
anchors.top: startStopButtons.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
visible: false
|
||||
width: parent.width
|
||||
height: 250
|
||||
//////////////////////////////////////////////////////////
|
||||
Label
|
||||
{
|
||||
id: connectionLabel
|
||||
width: checkupMachineAction.leftRow
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","Connection: ")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: connectionStatus
|
||||
width: checkupMachineAction.rightRow
|
||||
anchors.left: connectionLabel.right
|
||||
anchors.top: parent.top
|
||||
wrapMode: Text.WordWrap
|
||||
text: Cura.USBPrinterManager.connectedPrinterList.rowCount() > 0 || base.addOriginalProgress.checkUp[0] ? catalog.i18nc("@info:status","Done"):catalog.i18nc("@info:status","Incomplete")
|
||||
}
|
||||
//////////////////////////////////////////////////////////
|
||||
Label
|
||||
{
|
||||
id: endstopXLabel
|
||||
width: checkupMachineAction.leftRow
|
||||
anchors.left: parent.left
|
||||
anchors.top: connectionLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","Min endstop X: ")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: endstopXStatus
|
||||
width: checkupMachineAction.rightRow
|
||||
anchors.left: endstopXLabel.right
|
||||
anchors.top: connectionLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: manager.xMinEndstopTestCompleted ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
||||
}
|
||||
//////////////////////////////////////////////////////////////
|
||||
Label
|
||||
{
|
||||
id: endstopYLabel
|
||||
width: checkupMachineAction.leftRow
|
||||
anchors.left: parent.left
|
||||
anchors.top: endstopXLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","Min endstop Y: ")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: endstopYStatus
|
||||
width: checkupMachineAction.rightRow
|
||||
anchors.left: endstopYLabel.right
|
||||
anchors.top: endstopXLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: manager.yMinEndstopTestCompleted ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
Label
|
||||
{
|
||||
id: endstopZLabel
|
||||
width: checkupMachineAction.leftRow
|
||||
anchors.left: parent.left
|
||||
anchors.top: endstopYLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","Min endstop Z: ")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: endstopZStatus
|
||||
width: checkupMachineAction.rightRow
|
||||
anchors.left: endstopZLabel.right
|
||||
anchors.top: endstopYLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: manager.zMinEndstopTestCompleted ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
Label
|
||||
{
|
||||
id: nozzleTempLabel
|
||||
width: checkupMachineAction.leftRow
|
||||
anchors.left: parent.left
|
||||
anchors.top: endstopZLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","Nozzle temperature check: ")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: nozzleTempStatus
|
||||
width: checkupMachineAction.rightRow * 0.4
|
||||
anchors.top: nozzleTempLabel.top
|
||||
anchors.left: nozzleTempLabel.right
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@info:status","Not checked")
|
||||
}
|
||||
Item
|
||||
{
|
||||
id: nozzleTempButton
|
||||
width: checkupMachineAction.rightRow * 0.3
|
||||
height: nozzleTemp.height
|
||||
anchors.top: nozzleTempLabel.top
|
||||
anchors.left: bedTempStatus.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width/2
|
||||
Button
|
||||
{
|
||||
height: nozzleTemp.height - 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: catalog.i18nc("@action:button","Start Heating")
|
||||
onClicked:
|
||||
{
|
||||
manager.heatupHotend()
|
||||
nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking")
|
||||
}
|
||||
}
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: nozzleTemp
|
||||
anchors.top: nozzleTempLabel.top
|
||||
anchors.left: nozzleTempButton.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
width: checkupMachineAction.rightRow * 0.2
|
||||
wrapMode: Text.WordWrap
|
||||
text: manager.hotendTemperature + "°C"
|
||||
font.bold: true
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Label
|
||||
{
|
||||
id: bedTempLabel
|
||||
width: checkupMachineAction.leftRow
|
||||
anchors.left: parent.left
|
||||
anchors.top: nozzleTempLabel.bottom
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label","bed temperature check:")
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: bedTempStatus
|
||||
width: checkupMachineAction.rightRow * 0.4
|
||||
anchors.top: bedTempLabel.top
|
||||
anchors.left: bedTempLabel.right
|
||||
wrapMode: Text.WordWrap
|
||||
text: manager.bedTestCompleted ? catalog.i18nc("@info:status","Not checked"): catalog.i18nc("@info:status","Checked")
|
||||
}
|
||||
Item
|
||||
{
|
||||
id: bedTempButton
|
||||
width: checkupMachineAction.rightRow * 0.3
|
||||
height: bedTemp.height
|
||||
anchors.top: bedTempLabel.top
|
||||
anchors.left: bedTempStatus.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width/2
|
||||
Button
|
||||
{
|
||||
height: bedTemp.height - 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: catalog.i18nc("@action:button","Start Heating")
|
||||
onClicked:
|
||||
{
|
||||
manager.heatupBed()
|
||||
}
|
||||
}
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: bedTemp
|
||||
width: checkupMachineAction.rightRow * 0.2
|
||||
anchors.top: bedTempLabel.top
|
||||
anchors.left: bedTempButton.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
wrapMode: Text.WordWrap
|
||||
text: manager.bedTemperature + "°C"
|
||||
font.bold: true
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: resultText
|
||||
visible: false
|
||||
anchors.top: bedTemp.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "Everything is in order! You're done with your CheckUp.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
from cura.MachineAction import MachineAction
|
||||
|
||||
class UpgradeFirmwareMachineAction(MachineAction):
|
||||
def __init__(self):
|
||||
super().__init__("UpgradeFirmware", "Upgrade Firmware")
|
||||
self._qml_url = "UpgradeFirmwareMachineAction.qml"
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 2016 Ultimaker B.V.
|
||||
// Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
import UM 1.2 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
|
||||
Cura.MachineAction
|
||||
{
|
||||
anchors.fill: parent;
|
||||
Item
|
||||
{
|
||||
id: upgradeFirmwareMachineAction
|
||||
anchors.fill: parent;
|
||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||
|
||||
Label
|
||||
{
|
||||
id: pageTitle
|
||||
width: parent.width
|
||||
text: catalog.i18nc("@title", "Upgrade Firmware")
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: 18
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: pageDescription
|
||||
anchors.top: pageTitle.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "Firmware is the piece of software running directly on your 3D printer. This firmware controls the step motors, regulates the temperature and ultimately makes your printer work.")
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: upgradeText1
|
||||
anchors.top: pageDescription.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "The firmware shipping with new Ultimakers works, but upgrades have been made to make better prints, and make calibration easier.");
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: upgradeText2
|
||||
anchors.top: upgradeText1.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "Cura requires these new features and thus your firmware will most likely need to be upgraded. You can do so now.");
|
||||
}
|
||||
Item
|
||||
{
|
||||
anchors.top: upgradeText2.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: upgradeButton.width + skipUpgradeButton.width + UM.Theme.getSize("default_margin").height < upgradeFirmwareMachineAction.width ? upgradeButton.width + skipUpgradeButton.width + UM.Theme.getSize("default_margin").height : upgradeFirmwareMachineAction.width
|
||||
Button
|
||||
{
|
||||
id: upgradeButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
text: catalog.i18nc("@action:button","Upgrade to Marlin Firmware");
|
||||
onClicked: Cura.USBPrinterManager.updateAllFirmware()
|
||||
}
|
||||
Button
|
||||
{
|
||||
id: skipUpgradeButton
|
||||
anchors.top: parent.width < upgradeFirmwareMachineAction.width ? parent.top : upgradeButton.bottom
|
||||
anchors.topMargin: parent.width < upgradeFirmwareMachineAction.width ? 0 : UM.Theme.getSize("default_margin").height / 2
|
||||
anchors.left: parent.width < upgradeFirmwareMachineAction.width ? upgradeButton.right : parent.left
|
||||
anchors.leftMargin: parent.width < upgradeFirmwareMachineAction.width ? UM.Theme.getSize("default_margin").width : 0
|
||||
text: catalog.i18nc("@action:button", "Skip Upgrade");
|
||||
onClicked: manager.setFinished()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
plugins/UltimakerMachineActions/__init__.py
Normal file
23
plugins/UltimakerMachineActions/__init__.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import BedLevelMachineAction
|
||||
from . import UpgradeFirmwareMachineAction
|
||||
from . import UMOCheckupMachineAction
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": catalog.i18nc("@label", "Ultimaker machine actions"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc)"),
|
||||
"api": 3
|
||||
}
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return { "machine_action": [BedLevelMachineAction.BedLevelMachineAction(), UpgradeFirmwareMachineAction.UpgradeFirmwareMachineAction(), UMOCheckupMachineAction.UMOCheckupMachineAction()]}
|
Loading…
Add table
Add a link
Reference in a new issue