diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5862beb49e..cc4edf79b4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,6 +6,9 @@ include(GNUInstallDirs)
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
+set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
+configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
+
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# Extract Strings
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
@@ -60,10 +63,12 @@ install(DIRECTORY resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)
install(DIRECTORY plugins DESTINATION lib/cura)
install(FILES cura_app.py DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
if(NOT APPLE AND NOT WIN32)
- install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages)
+ install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages FILES_MATCHING PATTERN *.py)
+ install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura)
install(FILES cura.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
else()
- install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages)
+ install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages FILES_MATCHING PATTERN *.py)
+ install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/cura)
endif()
include(CPackConfig.cmake)
diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py
index c745ba168e..7fdf5b4d1d 100644
--- a/cura/BuildVolume.py
+++ b/cura/BuildVolume.py
@@ -34,10 +34,14 @@ class BuildVolume(SceneNode):
self.setCalculateBoundingBox(False)
+ self._active_profile = None
self._active_instance = None
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
self._onActiveInstanceChanged()
+ Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
+ self._onActiveProfileChanged()
+
def setWidth(self, width):
if width: self._width = width
@@ -72,7 +76,7 @@ class BuildVolume(SceneNode):
renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
if self._disallowed_area_mesh:
- renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material)
+ renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material, transparent = True)
return True
def rebuild(self):
@@ -117,18 +121,20 @@ class BuildVolume(SceneNode):
v = self._grid_mesh.getVertex(n)
self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
+ disallowed_area_height = 0.2
disallowed_area_size = 0
if self._disallowed_areas:
mb = MeshBuilder()
+ color = Color(0.0, 0.0, 0.0, 0.15)
for polygon in self._disallowed_areas:
points = polygon.getPoints()
- mb.addQuad(
- Vector(points[0, 0], 0.1, points[0, 1]),
- Vector(points[1, 0], 0.1, points[1, 1]),
- Vector(points[2, 0], 0.1, points[2, 1]),
- Vector(points[3, 0], 0.1, points[3, 1]),
- color = Color(174, 174, 174, 255)
- )
+ first = Vector(self._clamp(points[0][0], minW, maxW), disallowed_area_height, self._clamp(points[0][1], minD, maxD))
+ previous_point = Vector(self._clamp(points[0][0], minW, maxW), disallowed_area_height, self._clamp(points[0][1], minD, maxD))
+ for point in points:
+ new_point = Vector(self._clamp(point[0], minW, maxW), disallowed_area_height, self._clamp(point[1], minD, maxD))
+ mb.addFace(first, previous_point, new_point, color = color)
+ previous_point = new_point
+
# Find the largest disallowed area to exclude it from the maximum scale bounds
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
disallowed_area_size = max(size, disallowed_area_size)
@@ -141,16 +147,9 @@ class BuildVolume(SceneNode):
skirt_size = 0.0
- #profile = Application.getInstance().getMachineManager().getActiveProfile()
- #if profile:
- #if profile.getSettingValue("adhesion_type") == "skirt":
- #skirt_size = profile.getSettingValue("skirt_line_count") * profile.getSettingValue("skirt_line_width") + profile.getSettingValue("skirt_gap")
- #elif profile.getSettingValue("adhesion_type") == "brim":
- #skirt_size = profile.getSettingValue("brim_line_count") * profile.getSettingValue("skirt_line_width")
- #else:
- #skirt_size = profile.getSettingValue("skirt_line_width")
-
- #skirt_size += profile.getSettingValue("skirt_line_width")
+ profile = Application.getInstance().getMachineManager().getActiveProfile()
+ if profile:
+ skirt_size = self._getSkirtSize(profile)
scale_to_max_bounds = AxisAlignedBox(
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size),
@@ -167,12 +166,108 @@ class BuildVolume(SceneNode):
self._height = self._active_instance.getMachineSettingValue("machine_height")
self._depth = self._active_instance.getMachineSettingValue("machine_depth")
- disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
- areas = []
- if disallowed_areas:
- for area in disallowed_areas:
- areas.append(Polygon(numpy.array(area, numpy.float32)))
-
- self._disallowed_areas = areas
+ self._updateDisallowedAreas()
self.rebuild()
+
+ def _onActiveProfileChanged(self):
+ if self._active_profile:
+ self._active_profile.settingValueChanged.disconnect(self._onSettingValueChanged)
+
+ self._active_profile = Application.getInstance().getMachineManager().getActiveProfile()
+ if self._active_profile:
+ self._active_profile.settingValueChanged.connect(self._onSettingValueChanged)
+ self._updateDisallowedAreas()
+ self.rebuild()
+
+ def _onSettingValueChanged(self, setting):
+ if setting in self._skirt_settings:
+ self._updateDisallowedAreas()
+ self.rebuild()
+
+ def _updateDisallowedAreas(self):
+ if not self._active_instance or not self._active_profile:
+ return
+
+ disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
+ areas = []
+
+ skirt_size = 0.0
+ if self._active_profile:
+ skirt_size = self._getSkirtSize(self._active_profile)
+
+ if disallowed_areas:
+ for area in disallowed_areas:
+ poly = Polygon(numpy.array(area, numpy.float32))
+ poly = poly.getMinkowskiHull(Polygon(numpy.array([
+ [-skirt_size, 0],
+ [-skirt_size * 0.707, skirt_size * 0.707],
+ [0, skirt_size],
+ [skirt_size * 0.707, skirt_size * 0.707],
+ [skirt_size, 0],
+ [skirt_size * 0.707, -skirt_size * 0.707],
+ [0, -skirt_size],
+ [-skirt_size * 0.707, -skirt_size * 0.707]
+ ], numpy.float32)))
+
+ areas.append(poly)
+
+ if skirt_size > 0:
+ half_machine_width = self._active_instance.getMachineSettingValue("machine_width") / 2
+ half_machine_depth = self._active_instance.getMachineSettingValue("machine_depth") / 2
+
+ areas.append(Polygon(numpy.array([
+ [-half_machine_width, -half_machine_depth],
+ [-half_machine_width, half_machine_depth],
+ [-half_machine_width + skirt_size, half_machine_depth - skirt_size],
+ [-half_machine_width + skirt_size, -half_machine_depth + skirt_size]
+ ], numpy.float32)))
+
+ areas.append(Polygon(numpy.array([
+ [half_machine_width, half_machine_depth],
+ [half_machine_width, -half_machine_depth],
+ [half_machine_width - skirt_size, -half_machine_depth + skirt_size],
+ [half_machine_width - skirt_size, half_machine_depth - skirt_size]
+ ], numpy.float32)))
+
+ areas.append(Polygon(numpy.array([
+ [-half_machine_width, half_machine_depth],
+ [half_machine_width, half_machine_depth],
+ [half_machine_width - skirt_size, half_machine_depth - skirt_size],
+ [-half_machine_width + skirt_size, half_machine_depth - skirt_size]
+ ], numpy.float32)))
+
+ areas.append(Polygon(numpy.array([
+ [half_machine_width, -half_machine_depth],
+ [-half_machine_width, -half_machine_depth],
+ [-half_machine_width + skirt_size, -half_machine_depth + skirt_size],
+ [half_machine_width - skirt_size, -half_machine_depth + skirt_size]
+ ], numpy.float32)))
+
+ self._disallowed_areas = areas
+
+ def _getSkirtSize(self, profile):
+ skirt_size = 0.0
+
+ adhesion_type = profile.getSettingValue("adhesion_type")
+ if adhesion_type == "skirt":
+ skirt_distance = profile.getSettingValue("skirt_gap")
+ skirt_line_count = profile.getSettingValue("skirt_line_count")
+ skirt_size = skirt_distance + (skirt_line_count * profile.getSettingValue("skirt_line_width"))
+ elif adhesion_type == "brim":
+ brim_line_count = profile.getSettingValue("brim_line_count")
+ skirt_size = brim_line_count * profile.getSettingValue("skirt_line_width")
+ elif adhesion_type == "raft":
+ skirt_size = profile.getSettingValue("raft_margin")
+
+ if profile.getSettingValue("draft_shield_enabled"):
+ skirt_size += profile.getSettingValue("draft_shield_dist")
+
+ skirt_size += profile.getSettingValue("xy_offset")
+
+ return skirt_size
+
+ def _clamp(self, value, min_value, max_value):
+ return max(min(value, max_value), min_value)
+
+ _skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
diff --git a/cura/ConvexHullJob.py b/cura/ConvexHullJob.py
index 63eec87fb3..2388d1c9aa 100644
--- a/cura/ConvexHullJob.py
+++ b/cura/ConvexHullJob.py
@@ -31,6 +31,8 @@ class ConvexHullJob(Job):
self._node.callDecoration("setConvexHullJob", None)
return
+ Job.yieldThread()
+
else:
if not self._node.getMeshData():
return
diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py
index c2bf74e321..dba22ed7a4 100644
--- a/cura/CuraApplication.py
+++ b/cura/CuraApplication.py
@@ -58,6 +58,11 @@ import numpy
import copy
numpy.seterr(all="ignore")
+try:
+ from cura.CuraVersion import CuraVersion
+except ImportError:
+ CuraVersion = "master"
+
class CuraApplication(QtApplication):
class ResourceTypes:
QmlFiles = Resources.UserType + 1
@@ -69,7 +74,7 @@ class CuraApplication(QtApplication):
if not hasattr(sys, "frozen"):
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
- super().__init__(name = "cura", version = "master")
+ super().__init__(name = "cura", version = CuraVersion)
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
@@ -136,6 +141,9 @@ class CuraApplication(QtApplication):
parser.add_argument("--debug", dest="debug-mode", action="store_true", default=False, help="Enable detailed crash reports.")
def run(self):
+ if not "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION" in os.environ or os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] != "cpp":
+ Logger.log("w", "Using Python implementation of Protobuf, expect bad performance!")
+
self._i18n_catalog = i18nCatalog("cura");
i18nCatalog.setTagReplacements({
@@ -168,7 +176,7 @@ class CuraApplication(QtApplication):
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
camera = Camera("3d", root)
- camera.setPosition(Vector(0, 250, 900))
+ camera.setPosition(Vector(-80, 250, 700))
camera.setPerspective(True)
camera.lookAt(Vector(0, 0, 0))
controller.getScene().setActiveCamera("3d")
diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in
new file mode 100644
index 0000000000..bb69319ee6
--- /dev/null
+++ b/cura/CuraVersion.py.in
@@ -0,0 +1,4 @@
+# Copyright (c) 2015 Ultimaker B.V.
+# Cura is released under the terms of the AGPLv3 or higher.
+
+CuraVersion = "@CURA_VERSION@"
diff --git a/cura/LayerData.py b/cura/LayerData.py
index eb8f5553ad..1cf13a1798 100644
--- a/cura/LayerData.py
+++ b/cura/LayerData.py
@@ -63,6 +63,7 @@ class LayerData(MeshData):
offset = data.build(offset, vertices, colors, indices)
self._element_counts[layer] = data.elementCount
+ self.clear()
self.addVertices(vertices)
self.addColors(colors)
self.addIndices(indices.flatten())
@@ -200,18 +201,14 @@ class Polygon():
def build(self, offset, vertices, colors, indices):
self._begin = offset
+ self._end = self._begin + len(self._data) - 1
color = self.getColor()
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
+ color = numpy.array([color.r, color.g, color.b, color.a], numpy.float32)
- for i in range(len(self._data)):
- vertices[offset + i, :] = self._data[i, :]
- colors[offset + i, 0] = color.r
- colors[offset + i, 1] = color.g
- colors[offset + i, 2] = color.b
- colors[offset + i, 3] = color.a
-
- self._end = self._begin + len(self._data) - 1
+ vertices[self._begin:self._end + 1, :] = self._data[:, :]
+ colors[self._begin:self._end + 1, :] = color
for i in range(self._begin, self._end):
indices[i, 0] = i
diff --git a/cura_app.py b/cura_app.py
index e71fbd6515..92624be76f 100755
--- a/cura_app.py
+++ b/cura_app.py
@@ -4,6 +4,7 @@
# Cura is released under the terms of the AGPLv3 or higher.
import sys
+import os
def exceptHook(type, value, traceback):
import cura.CrashHandler
@@ -11,6 +12,13 @@ def exceptHook(type, value, traceback):
sys.excepthook = exceptHook
+try:
+ from google.protobuf.pyext import _message
+except ImportError:
+ pass
+else:
+ os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp"
+
import cura.CuraApplication
if sys.platform == "win32" and hasattr(sys, "frozen"):
diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py
index c2edab7793..033fca69aa 100644
--- a/plugins/3MFReader/ThreeMFReader.py
+++ b/plugins/3MFReader/ThreeMFReader.py
@@ -10,6 +10,7 @@ from UM.Scene.SceneNode import SceneNode
from UM.Scene.GroupDecorator import GroupDecorator
from UM.Math.Quaternion import Quaternion
+from UM.Job import Job
import os
import struct
@@ -53,6 +54,7 @@ class ThreeMFReader(MeshReader):
#for vertex in object.mesh.vertices.vertex:
for vertex in object.findall(".//3mf:vertex", self._namespaces):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
+ Job.yieldThread()
triangles = object.findall(".//3mf:triangle", self._namespaces)
@@ -64,6 +66,8 @@ class ThreeMFReader(MeshReader):
v2 = int(triangle.get("v2"))
v3 = int(triangle.get("v3"))
mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2])
+ Job.yieldThread()
+
#TODO: We currently do not check for normals and simply recalculate them.
mesh.calculateNormals()
node.setMeshData(mesh)
@@ -116,6 +120,8 @@ class ThreeMFReader(MeshReader):
#node.rotate(rotation)
result.addChild(node)
+ Job.yieldThread()
+
#If there is more then one object, group them.
try:
if len(objects) > 1:
diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py
index a751941b27..91d3b627ca 100644
--- a/plugins/CuraEngineBackend/CuraEngineBackend.py
+++ b/plugins/CuraEngineBackend/CuraEngineBackend.py
@@ -17,6 +17,7 @@ from cura.OneAtATimeIterator import OneAtATimeIterator
from . import Cura_pb2
from . import ProcessSlicedObjectListJob
from . import ProcessGCodeJob
+from . import StartSliceJob
import os
import sys
@@ -49,6 +50,7 @@ class CuraEngineBackend(Backend):
self._onActiveViewChanged()
self._stored_layer_data = None
+ Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onChanged)
self._profile = None
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
@@ -67,12 +69,8 @@ class CuraEngineBackend(Backend):
self._slicing = False
self._restart = False
-
- self._save_gcode = True
- self._save_polygons = True
- self._report_progress = True
-
self._enabled = True
+ self._always_restart = True
self._message = None
@@ -103,24 +101,12 @@ class CuraEngineBackend(Backend):
## Emitted whne the slicing process is aborted forcefully.
slicingCancelled = Signal()
- ## Perform a slice of the scene with the given set of settings.
- #
- # \param kwargs Keyword arguments.
- # Valid values are:
- # - settings: The settings to use for the slice. The default is the active machine.
- # - save_gcode: True if the generated gcode should be saved, False if not. True by default.
- # - save_polygons: True if the generated polygon data should be saved, False if not. True by default.
- # - force_restart: True if the slicing process should be forcefully restarted if it is already slicing.
- # If False, this method will do nothing when already slicing. True by default.
- # - report_progress: True if the slicing progress should be reported, False if not. Default is True.
- def slice(self, **kwargs):
+ ## Perform a slice of the scene.
+ def slice(self):
if not self._enabled:
return
if self._slicing:
- if not kwargs.get("force_restart", True):
- return
-
self._slicing = False
self._restart = True
if self._process is not None:
@@ -129,42 +115,16 @@ class CuraEngineBackend(Backend):
self._process.terminate()
except: # terminating a process that is already terminating causes an exception, silently ignore this.
pass
- self.slicingCancelled.emit()
- return
- Logger.log("d", "Preparing to send slice data to engine.")
- object_groups = []
- if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
- for node in OneAtATimeIterator(self._scene.getRoot()):
- temp_list = []
- children = node.getAllChildren()
- children.append(node)
- for child_node in children:
- if type(child_node) is SceneNode and child_node.getMeshData() and child_node.getMeshData().getVertices() is not None:
- temp_list.append(child_node)
- object_groups.append(temp_list)
- else:
- temp_list = []
- for node in DepthFirstIterator(self._scene.getRoot()):
- if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
- if not getattr(node, "_outside_buildarea", False):
- temp_list.append(node)
- if len(temp_list) == 0:
- self.processingProgress.emit(0.0)
- return
- object_groups.append(temp_list)
- #for node in DepthFirstIterator(self._scene.getRoot()):
- # if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
- # if not getattr(node, "_outside_buildarea", False):
- # objects.append(node)
- if len(object_groups) == 0:
if self._message:
self._message.hide()
self._message = None
- return #No point in slicing an empty build plate
- if kwargs.get("profile", self._profile).hasErrorValue():
+ self.slicingCancelled.emit()
+ return
+
+ if self._profile.hasErrorValue():
Logger.log('w', "Profile has error values. Aborting slicing")
if self._message:
self._message.hide()
@@ -172,62 +132,27 @@ class CuraEngineBackend(Backend):
self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
self._message.show()
return #No slicing if we have error values since those are by definition illegal values.
- # Remove existing layer data (if any)
- for node in DepthFirstIterator(self._scene.getRoot()):
- if type(node) is SceneNode and node.getMeshData():
- if node.callDecoration("getLayerData"):
- Application.getInstance().getController().getScene().getRoot().removeChild(node)
- break
- Application.getInstance().getController().getScene().gcode_list = None
+
+ self.processingProgress.emit(0.0)
+ if not self._message:
+ self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
+ self._message.show()
+ else:
+ self._message.setProgress(-1)
+
+ self._scene.gcode_list = []
self._slicing = True
- self.slicingStarted.emit()
- self._report_progress = kwargs.get("report_progress", True)
- if self._report_progress:
- self.processingProgress.emit(0.0)
- if not self._message:
- self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
- self._message.show()
- else:
- self._message.setProgress(-1)
+ job = StartSliceJob.StartSliceJob(self._profile, self._socket)
+ job.start()
+ job.finished.connect(self._onStartSliceCompleted)
- self._sendSettings(kwargs.get("profile", self._profile))
-
- self._scene.acquireLock()
-
- # Set the gcode as an empty list. This will be filled with strings by GCodeLayer messages.
- # This is done so the gcode can be fragmented in memory and does not need a continues memory space.
- # (AKA. This prevents MemoryErrors)
- self._save_gcode = kwargs.get("save_gcode", True)
- if self._save_gcode:
- setattr(self._scene, "gcode_list", [])
-
- self._save_polygons = kwargs.get("save_polygons", True)
-
- slice_message = Cura_pb2.Slice()
-
- for group in object_groups:
- group_message = slice_message.object_lists.add()
- for object in group:
- mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation())
-
- obj = group_message.objects.add()
- obj.id = id(object)
-
- verts = numpy.array(mesh_data.getVertices())
- verts[:,[1,2]] = verts[:,[2,1]]
- verts[:,1] *= -1
- obj.vertices = verts.tostring()
-
- self._handlePerObjectSettings(object, obj)
-
- # Hack to add per-object settings also to the "MeshGroup" in CuraEngine
- # We really should come up with a better solution for this.
- self._handlePerObjectSettings(group[0], group_message)
-
- self._scene.releaseLock()
- Logger.log("d", "Sending data to engine for slicing.")
- self._socket.sendMessage(slice_message)
+ def _onStartSliceCompleted(self, job):
+ if job.getError() or job.getResult() != True:
+ if self._message:
+ self._message.hide()
+ self._message = None
+ return
def _onSceneChanged(self, source):
if type(source) is not SceneNode:
@@ -257,41 +182,42 @@ class CuraEngineBackend(Backend):
self._onChanged()
def _onSlicedObjectListMessage(self, message):
- if self._save_polygons:
- if self._layer_view_active:
- job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
- job.start()
- else :
- self._stored_layer_data = message
+ if self._layer_view_active:
+ job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
+ job.start()
+ else :
+ self._stored_layer_data = message
def _onProgressMessage(self, message):
- if message.amount >= 0.99:
- self._slicing = False
-
- if self._message:
- self._message.setProgress(100)
- self._message.hide()
- self._message = None
-
if self._message:
self._message.setProgress(round(message.amount * 100))
- if self._report_progress:
- self.processingProgress.emit(message.amount)
+ self.processingProgress.emit(message.amount)
def _onGCodeLayerMessage(self, message):
- if self._save_gcode:
- job = ProcessGCodeJob.ProcessGCodeLayerJob(message)
- job.start()
+ self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
def _onGCodePrefixMessage(self, message):
- if self._save_gcode:
- self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
+ self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
def _onObjectPrintTimeMessage(self, message):
self.printDurationMessage.emit(message.time, message.material_amount)
self.processingProgress.emit(1.0)
+ self._slicing = False
+
+ if self._message:
+ self._message.setProgress(100)
+ self._message.hide()
+ self._message = None
+
+ if self._always_restart:
+ try:
+ self._process.terminate()
+ self._createSocket()
+ except: # terminating a process that is already terminating causes an exception, silently ignore this.
+ pass
+
def _createSocket(self):
super()._createSocket()
@@ -313,15 +239,6 @@ class CuraEngineBackend(Backend):
self._change_timer.start()
- def _sendSettings(self, profile):
- msg = Cura_pb2.SettingList()
- for key, value in profile.getAllSettingValues(include_machine = True).items():
- s = msg.settings.add()
- s.name = key
- s.value = str(value).encode("utf-8")
-
- self._socket.sendMessage(msg)
-
def _onBackendConnected(self):
if self._restart:
self._onChanged()
@@ -346,22 +263,6 @@ class CuraEngineBackend(Backend):
else:
self._layer_view_active = False
- def _handlePerObjectSettings(self, node, message):
- profile = node.callDecoration("getProfile")
- if profile:
- for key, value in profile.getChangedSettingValues().items():
- setting = message.settings.add()
- setting.name = key
- setting.value = str(value).encode()
-
- object_settings = node.callDecoration("getAllSettingValues")
- if not object_settings:
- return
-
- for key, value in object_settings.items():
- setting = message.settings.add()
- setting.name = key
- setting.value = str(value).encode()
def _onInstanceChanged(self):
self._slicing = False
@@ -372,4 +273,4 @@ class CuraEngineBackend(Backend):
self._process.terminate()
except: # terminating a process that is already terminating causes an exception, silently ignore this.
pass
- self.slicingCancelled.emit()
+ self.slicingCancelled.emit()
\ No newline at end of file
diff --git a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py
index 725a6562b4..0089dcb185 100644
--- a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py
+++ b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py
@@ -38,10 +38,10 @@ class ProcessSlicedObjectListJob(Job):
for node in DepthFirstIterator(self._scene.getRoot()):
if type(node) is SceneNode and node.getMeshData():
if node.callDecoration("getLayerData"):
- #if hasattr(node.getMeshData(), "layerData"):
self._scene.getRoot().removeChild(node)
else:
objectIdMap[id(node)] = node
+ Job.yieldThread()
settings = Application.getInstance().getMachineManager().getActiveProfile()
layerHeight = settings.getSettingValue("layer_height")
@@ -54,6 +54,12 @@ class ProcessSlicedObjectListJob(Job):
mesh = MeshData()
layer_data = LayerData.LayerData()
+
+ layer_count = 0
+ for object in self._message.objects:
+ layer_count += len(object.layers)
+
+ current_layer = 0
for object in self._message.objects:
try:
node = objectIdMap[object.id]
@@ -73,23 +79,34 @@ class ProcessSlicedObjectListJob(Job):
points[:,2] *= -1
- points -= numpy.array(center)
+ points -= center
layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width)
+ Job.yieldThread()
+
+ current_layer += 1
+ progress = (current_layer / layer_count) * 100
+ # TODO: Rebuild the layer data mesh once the layer has been processed.
+ # This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh.
+
+ if self._progress:
+ 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()
-
#Add layerdata decorator to scene node to indicate that the node has layerdata
decorator = LayerDataDecorator.LayerDataDecorator()
decorator.setLayerData(layer_data)
new_node.addDecorator(decorator)
-
+
new_node.setMeshData(mesh)
new_node.setParent(self._scene.getRoot())
-
+
+ if self._progress:
+ self._progress.setProgress(100)
+
view = Application.getInstance().getController().getActiveView()
if view.getPluginId() == "LayerView":
view.resetLayerData()
diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py
new file mode 100644
index 0000000000..50c3fadb0e
--- /dev/null
+++ b/plugins/CuraEngineBackend/StartSliceJob.py
@@ -0,0 +1,121 @@
+# Copyright (c) 2015 Ultimaker B.V.
+# Cura is released under the terms of the AGPLv3 or higher.
+
+import numpy
+
+from UM.Job import Job
+from UM.Application import Application
+from UM.Logger import Logger
+
+from UM.Scene.SceneNode import SceneNode
+from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
+
+from cura.OneAtATimeIterator import OneAtATimeIterator
+
+from . import Cura_pb2
+
+## Job class that handles sending the current scene data to CuraEngine
+class StartSliceJob(Job):
+ def __init__(self, profile, socket):
+ super().__init__()
+
+ self._scene = Application.getInstance().getController().getScene()
+ self._profile = profile
+ self._socket = socket
+
+ def run(self):
+ self._scene.acquireLock()
+
+ for node in DepthFirstIterator(self._scene.getRoot()):
+ if node.callDecoration("getLayerData"):
+ node.getParent().removeChild(node)
+ break
+
+ object_groups = []
+ if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
+ for node in OneAtATimeIterator(self._scene.getRoot()):
+ temp_list = []
+
+ if getattr(node, "_outside_buildarea", False):
+ continue
+
+ children = node.getAllChildren()
+ children.append(node)
+ for child_node in children:
+ if type(child_node) is SceneNode and child_node.getMeshData() and child_node.getMeshData().getVertices() is not None:
+ temp_list.append(child_node)
+
+ if temp_list:
+ object_groups.append(temp_list)
+ Job.yieldThread()
+ else:
+ temp_list = []
+ for node in DepthFirstIterator(self._scene.getRoot()):
+ if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
+ if not getattr(node, "_outside_buildarea", False):
+ temp_list.append(node)
+ Job.yieldThread()
+
+ if temp_list:
+ object_groups.append(temp_list)
+
+ self._scene.releaseLock()
+
+ if not object_groups:
+ return
+
+ self._sendSettings(self._profile)
+
+ slice_message = Cura_pb2.Slice()
+
+ for group in object_groups:
+ group_message = slice_message.object_lists.add()
+ for object in group:
+ mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation())
+
+ obj = group_message.objects.add()
+ obj.id = id(object)
+
+ verts = numpy.array(mesh_data.getVertices())
+ verts[:,[1,2]] = verts[:,[2,1]]
+ verts[:,1] *= -1
+ obj.vertices = verts.tostring()
+
+ self._handlePerObjectSettings(object, obj)
+
+ Job.yieldThread()
+
+ Logger.log("d", "Sending data to engine for slicing.")
+ self._socket.sendMessage(slice_message)
+
+ self.setResult(True)
+
+ def _sendSettings(self, profile):
+ msg = Cura_pb2.SettingList()
+ for key, value in profile.getAllSettingValues(include_machine = True).items():
+ s = msg.settings.add()
+ s.name = key
+ s.value = str(value).encode("utf-8")
+
+ self._socket.sendMessage(msg)
+
+ def _handlePerObjectSettings(self, node, message):
+ profile = node.callDecoration("getProfile")
+ if profile:
+ for key, value in profile.getAllSettingValues().items():
+ setting = message.settings.add()
+ setting.name = key
+ setting.value = str(value).encode()
+
+ Job.yieldThread()
+
+ object_settings = node.callDecoration("getAllSettingValues")
+ if not object_settings:
+ return
+
+ for key, value in object_settings.items():
+ setting = message.settings.add()
+ setting.name = key
+ setting.value = str(value).encode()
+
+ Job.yieldThread()
diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py
index 0eb6ed3066..89e4f6ff81 100644
--- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py
+++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py
@@ -52,6 +52,8 @@ class RemovableDriveOutputDevice(OutputDevice):
message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1)
message.show()
+ self.writeStarted.emit(self)
+
job._message = message
job.start()
except PermissionError as e:
diff --git a/plugins/USBPrinting/PrinterConnection.py b/plugins/USBPrinting/PrinterConnection.py
index e6e54ccbc2..341fe425b1 100644
--- a/plugins/USBPrinting/PrinterConnection.py
+++ b/plugins/USBPrinting/PrinterConnection.py
@@ -45,7 +45,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._connect_thread.daemon = True
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
- self._end_stop_thread.deamon = True
+ self._end_stop_thread.daemon = True
self._poll_endstop = -1
# Printer is connected
@@ -65,6 +65,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.daemon = True
+ self.firmwareUpdateComplete.connect(self._onFirmwareUpdateComplete)
self._heatup_wait_start_time = time.time()
@@ -197,6 +198,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
## Private fuction (threaded) that actually uploads the firmware.
def _updateFirmware(self):
+ self.setProgress(0, 100)
+
if self._is_connecting or self._is_connected:
self.close()
hex_file = intelHex.readHex(self._firmware_file_name)
@@ -207,7 +210,11 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
programmer = stk500v2.Stk500v2()
programmer.progressCallback = self.setProgress
- programmer.connect(self._serial_port)
+
+ try:
+ programmer.connect(self._serial_port)
+ except Exception:
+ pass
time.sleep(1) # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases.
@@ -336,8 +343,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._connect_thread = threading.Thread(target=self._connect)
self._connect_thread.daemon = True
+ self.setIsConnected(False)
if self._serial is not None:
- self.setIsConnected(False)
try:
self._listen_thread.join()
except:
diff --git a/plugins/USBPrinting/USBPrinterManager.py b/plugins/USBPrinting/USBPrinterManager.py
index 9d9b0b4a02..1e1cd538b3 100644
--- a/plugins/USBPrinting/USBPrinterManager.py
+++ b/plugins/USBPrinting/USBPrinterManager.py
@@ -11,6 +11,7 @@ from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Qt.ListModel import ListModel
+from UM.Message import Message
from cura.CuraApplication import CuraApplication
@@ -95,6 +96,10 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
@pyqtSlot()
def updateAllFirmware(self):
+ if not self._printer_connections:
+ Message("Cannot update firmware, there were no connected printers found.").show()
+ return
+
self.spawnFirmwareInterface("")
for printer_connection in self._printer_connections:
try:
@@ -159,6 +164,16 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
continue
self._serial_port_list = list(serial_ports)
+ connections_to_remove = []
+ for port, connection in self._printer_connections.items():
+ if port not in self._serial_port_list:
+ connection.close()
+ connections_to_remove.append(port)
+
+ for port in connections_to_remove:
+ del self._printer_connections[port]
+
+
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
def addConnection(self, serial_port):
connection = PrinterConnection.PrinterConnection(serial_port)
diff --git a/plugins/USBPrinting/avr_isp/ispBase.py b/plugins/USBPrinting/avr_isp/ispBase.py
index b5b5f8792e..fbd3bf091f 100644
--- a/plugins/USBPrinting/avr_isp/ispBase.py
+++ b/plugins/USBPrinting/avr_isp/ispBase.py
@@ -58,7 +58,7 @@ class IspBase():
raise IspError("Called undefined verifyFlash")
-class IspError(BaseException):
+class IspError(Exception):
def __init__(self, value):
self.value = value
diff --git a/resources/machines/fdmprinter.json b/resources/machines/fdmprinter.json
index a57bd61903..709811b5bb 100644
--- a/resources/machines/fdmprinter.json
+++ b/resources/machines/fdmprinter.json
@@ -140,7 +140,7 @@
"unit": "mm",
"type": "float",
"default": 0.1,
- "min_value": "0.0001",
+ "min_value": "0.001",
"min_value_warning": "0.04",
"max_value_warning": "0.32"
},
@@ -150,7 +150,7 @@
"unit": "mm",
"type": "float",
"default": 0.3,
- "min_value": "0.0001",
+ "min_value": "0.001",
"min_value_warning": "0.04",
"max_value_warning": "0.32",
"visible": false
@@ -821,7 +821,8 @@
"type": "float",
"min_value": "0.1",
"max_value_warning": "300",
- "default": 150
+ "default": 150,
+ "inherit_function": "speed_print if magic_spiralize else 150"
},
"speed_layer_0": {
"label": "Bottom Layer Speed",
diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml
index 696b37bdad..a4e81efcce 100644
--- a/resources/qml/Cura.qml
+++ b/resources/qml/Cura.qml
@@ -567,7 +567,7 @@ UM.MainWindow
addMachine.onTriggered: addMachineWizard.visible = true;
- preferences.onTriggered: { preferences.visible = true; }
+ preferences.onTriggered: { preferences.visible = true; preferences.setPage(0); }
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(3); }
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
diff --git a/resources/qml/GeneralPage.qml b/resources/qml/GeneralPage.qml
index aef53e1324..c04903b961 100644
--- a/resources/qml/GeneralPage.qml
+++ b/resources/qml/GeneralPage.qml
@@ -13,6 +13,18 @@ UM.PreferencesPage
//: General configuration page title
title: catalog.i18nc("@title:tab","General");
+ function setDefaultLanguage(languageCode)
+ {
+ //loops trough the languageList and sets the language using the languageCode
+ for(var i = 0; i < languageList.count; i++)
+ {
+ if (languageComboBox.model.get(i).code == languageCode)
+ {
+ languageComboBox.currentIndex = i
+ }
+ }
+ }
+
function reset()
{
UM.Preferences.resetPreference("general/language")
@@ -22,7 +34,8 @@ UM.PreferencesPage
pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
scaleToFitCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
- languageComboBox.currentIndex = 0
+ var defaultLanguage = UM.Preferences.getValue("general/language")
+ setDefaultLanguage(defaultLanguage)
}
GridLayout
diff --git a/resources/qml/WizardPages/AddMachine.qml b/resources/qml/WizardPages/AddMachine.qml
index 2ac479d276..a98f3ce8ef 100644
--- a/resources/qml/WizardPages/AddMachine.qml
+++ b/resources/qml/WizardPages/AddMachine.qml
@@ -7,8 +7,6 @@ import QtQuick.Window 2.1
import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM
-import Cura 1.0 as Cura
-import ".."
Item
{
@@ -18,18 +16,69 @@ Item
property variant wizard: null;
+ property bool visibility: base.wizard.visible
+ onVisibilityChanged:
+ {
+ machineName.text = getMachineName()
+ errorMessage.show = false
+ }
+
+ function editMachineName(word)
+ {
+ //Adds '#2' at the end or increases the number by 1 if the word ends with '#' and 1 or more digits
+ var regEx = /[#][\d]+$///ends with '#' and then 1 or more digit
+ var result = word.match(regEx)
+
+ if (result != null)
+ {
+ result = result[0].split('')
+
+ var numberString = ''
+ for (var i = 1; i < result.length; i++){//starting at 1, makes it ignore the '#'
+ numberString += result[i]
+ }
+ var newNumber = Number(numberString) + 1
+
+ var newWord = word.replace(/[\d]+$/, newNumber)//replaces the last digits in the string by the same number + 1
+ return newWord
+ }
+ else {
+ return word + ' #2'
+ }
+ }
+
+ function getMachineName()
+ {
+ var name = machineList.model.getItem(machineList.currentIndex).name
+
+ //if the automatically assigned name is not unique, the editMachineName function keeps editing it untill it is.
+ while (UM.MachineManager.checkInstanceExists(name) != false)
+ {
+ name = editMachineName(name)
+ }
+ return name
+ }
+
Connections
{
target: base.wizard
onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element
{
- var old_page_count = base.wizard.getPageCount()
- // Delete old pages (if any)
- for (var i = old_page_count - 1; i > 0; i--)
+ var name = machineName.text
+ if (UM.MachineManager.checkInstanceExists(name) != false)
{
- base.wizard.removePage(i)
+ errorMessage.show = true
+ }
+ else
+ {
+ var old_page_count = base.wizard.getPageCount()
+ // Delete old pages (if any)
+ for (var i = old_page_count - 1; i > 0; i--)
+ {
+ base.wizard.removePage(i)
+ }
+ saveMachine()
}
- saveMachine()
}
onBackClicked:
{
@@ -63,7 +112,8 @@ Item
{
id: machinesHolder
- anchors{
+ anchors
+ {
left: parent.left;
top: subTitle.bottom;
right: parent.right;
@@ -110,6 +160,7 @@ Item
onClicked: {
base.activeManufacturer = section;
machineList.currentIndex = machineList.model.find("manufacturer", section)
+ machineName.text = getMachineName()
}
}
@@ -128,7 +179,10 @@ Item
text: model.name
- onClicked: ListView.view.currentIndex = index;
+ onClicked: {
+ ListView.view.currentIndex = index;
+ machineName.text = getMachineName()
+ }
Label
{
@@ -169,11 +223,33 @@ Item
}
}
- Item
+
+
+ Column
{
id: machineNameHolder
- height: childrenRect.height
anchors.bottom: parent.bottom;
+ //height: insertNameLabel.lineHeight * (2 + errorMessage.lineCount)
+
+ Item
+ {
+ height: errorMessage.lineHeight
+ anchors.bottom: insertNameLabel.top
+ anchors.bottomMargin: insertNameLabel.height * errorMessage.lineCount
+ Label
+ {
+ id: errorMessage
+ property bool show: false
+ width: base.width
+ height: errorMessage.show ? errorMessage.lineHeight : 0
+ visible: errorMessage.show
+ text: catalog.i18nc("@label", "This printer name has already been used. Please choose a different printer name.");
+ wrapMode: Text.WordWrap
+ Behavior on height {NumberAnimation {duration: 75; }}
+ color: UM.Theme.colors.error
+ }
+ }
+
Label
{
id: insertNameLabel
@@ -182,8 +258,7 @@ Item
TextField
{
id: machineName;
- anchors.top: insertNameLabel.bottom
- text: machineList.model.getItem(machineList.currentIndex).name
+ text: getMachineName()
implicitWidth: UM.Theme.sizes.standard_list_input.width
}
}
@@ -218,6 +293,9 @@ Item
break;
}
}
+ if(base.wizard.lastPage == true){
+ base.wizard.visible = false
+ }
}
}
diff --git a/resources/qml/WizardPages/Bedleveling.qml b/resources/qml/WizardPages/Bedleveling.qml
index 9bb9f4f652..a6c471341c 100644
--- a/resources/qml/WizardPages/Bedleveling.qml
+++ b/resources/qml/WizardPages/Bedleveling.qml
@@ -7,6 +7,8 @@ import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import UM 1.1 as UM
+import Cura 1.0 as Cura
+import ".."
Item
{
@@ -15,11 +17,22 @@ Item
property bool three_point_leveling: true
property int platform_width: UM.MachineManager.getSettingValue("machine_width")
property int platform_height: UM.MachineManager.getSettingValue("machine_depth")
- property bool alreadyTested: base.addOriginalProgress.bedLeveling
anchors.fill: parent;
property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
Component.onCompleted: printer_connection.homeHead()
UM.I18nCatalog { id: catalog; name:"cura"}
+ property variant wizard: null;
+
+ Connections
+ {
+ target: wizardPage.wizard
+ onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element
+ {
+ if(wizardPage.wizard.lastPage == true){
+ wizardPage.wizard.visible = false
+ }
+ }
+ }
Label
{
@@ -61,7 +74,6 @@ Item
id: bedlevelingButton
anchors.top: parent.top
anchors.left: parent.left
- enabled: !alreadyTested
text: catalog.i18nc("@action:button","Move to Next Position");
onClicked:
{
@@ -79,7 +91,6 @@ Item
}
wizardPage.leveling_state++
if (wizardPage.leveling_state >= 3){
- base.addOriginalProgress.bedLeveling = true
resultText.visible = true
skipBedlevelingButton.enabled = false
bedlevelingButton.enabled = false
@@ -91,7 +102,6 @@ Item
Button
{
id: skipBedlevelingButton
- enabled: !alreadyTested
anchors.top: parent.width < wizardPage.width ? parent.top : bedlevelingButton.bottom
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
anchors.left: parent.width < wizardPage.width ? bedlevelingButton.right : parent.left
@@ -104,13 +114,13 @@ Item
Label
{
id: resultText
- visible: alreadyTested
+ visible: false
anchors.top: bedlevelingWrapper.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height
anchors.left: parent.left
width: parent.width
wrapMode: Text.WordWrap
- text: catalog.i18nc("@label", "Everythink is in order! You're done with bedeleveling.")
+ text: catalog.i18nc("@label", "Everything is in order! You're done with bedleveling.")
}
function threePointLeveling(width, height)
diff --git a/resources/qml/WizardPages/SelectUpgradedParts.qml b/resources/qml/WizardPages/SelectUpgradedParts.qml
index 4e84e61ec6..c8ccc4fe8d 100644
--- a/resources/qml/WizardPages/SelectUpgradedParts.qml
+++ b/resources/qml/WizardPages/SelectUpgradedParts.qml
@@ -17,11 +17,8 @@ Item
Component.onDestruction:
{
- base.addOriginalProgress.upgrades[0] = extruderCheckBox.checked
- base.addOriginalProgress.upgrades[1] = heatedBedCheckBox1.checked
- base.addOriginalProgress.upgrades[2] = heatedBedCheckBox2.checked
if (extruderCheckBox.checked == true){
- UM.MachineManager.setMachineSettingValue("machine_extruder_drive_upgrade", true);
+ UM.MachineManager.setMachineSettingValue("machine_extruder_drive_upgrade", true)
}
if (heatedBedCheckBox1.checked == true || heatedBedCheckBox2.checked == true){
UM.MachineManager.setMachineSettingValue("machine_heated_bed", true)
@@ -58,14 +55,14 @@ Item
{
id: extruderCheckBox
text: catalog.i18nc("@option:check","Extruder driver ugrades")
- checked: base.addOriginalProgress.upgrades[0]
+ checked: true
}
CheckBox
{
id: heatedBedCheckBox1
- text: catalog.i18nc("@option:check","Heated printer bed (standard kit)")
+ text: catalog.i18nc("@option:check","Heated printer bed")
y: extruderCheckBox.height * 1
- checked: base.addOriginalProgress.upgrades[1]
+ checked: false
onClicked: {
if (heatedBedCheckBox2.checked == true)
heatedBedCheckBox2.checked = false
@@ -76,7 +73,7 @@ Item
id: heatedBedCheckBox2
text: catalog.i18nc("@option:check","Heated printer bed (self built)")
y: extruderCheckBox.height * 2
- checked: base.addOriginalProgress.upgrades[2]
+ checked: false
onClicked: {
if (heatedBedCheckBox1.checked == true)
heatedBedCheckBox1.checked = false
diff --git a/resources/qml/WizardPages/UltimakerCheckup.qml b/resources/qml/WizardPages/UltimakerCheckup.qml
index 6ef87ef069..db538ed7d6 100644
--- a/resources/qml/WizardPages/UltimakerCheckup.qml
+++ b/resources/qml/WizardPages/UltimakerCheckup.qml
@@ -14,35 +14,40 @@ Item
property int leftRow: wizardPage.width*0.40
property int rightRow: wizardPage.width*0.60
anchors.fill: parent;
- property bool alreadyTested: base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length-1]
property bool x_min_pressed: false
property bool y_min_pressed: false
property bool z_min_pressed: false
property bool heater_works: false
property int extruder_target_temp: 0
property int bed_target_temp: 0
+ UM.I18nCatalog { id: catalog; name:"cura"}
+ property var checkupProgress: {
+ "connection": false,
+ "endstopX": wizardPage.x_min_pressed,
+ "endstopY": wizardPage.y_min_pressed,
+ "endstopZ": wizardPage.z_min_pressed,
+ "nozzleTemp": false,
+ "bedTemp": false
+ }
+
property variant printer_connection: {
if (UM.USBPrinterManager.connectedPrinterList.rowCount() != 0){
- base.addOriginalProgress.checkUp[0] = true
- checkTotalCheckUp()
+ wizardPage.checkupProgress.connection = true
return UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
}
else {
return null
}
}
- //property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
- UM.I18nCatalog { id: catalog; name:"cura"}
function checkTotalCheckUp(){
var allDone = true
- for (var i = 0; i < (base.addOriginalProgress.checkUp.length - 1); i++){
- if (base.addOriginalProgress.checkUp[i] == false){
+ for(var property in checkupProgress){
+ if (checkupProgress[property] == false){
allDone = false
}
}
if (allDone == true){
- base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length] = true
skipCheckButton.enabled = false
resultText.visible = true
}
@@ -91,7 +96,7 @@ Item
id: startCheckButton
anchors.top: parent.top
anchors.left: parent.left
- enabled: !alreadyTested
+ //enabled: !alreadyTested
text: catalog.i18nc("@action:button","Start Printer Check");
onClicked: {
checkupContent.visible = true
@@ -107,7 +112,7 @@ Item
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
anchors.left: parent.width < wizardPage.width ? startCheckButton.right : parent.left
anchors.leftMargin: parent.width < wizardPage.width ? UM.Theme.sizes.default_margin.width : 0
- enabled: !alreadyTested
+ //enabled: !alreadyTested
text: catalog.i18nc("@action:button","Skip Printer Check");
onClicked: {
base.currentPage += 1
@@ -119,7 +124,7 @@ Item
id: checkupContent
anchors.top: startStopButtons.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height
- visible: alreadyTested
+ visible: false
//////////////////////////////////////////////////////////
Label
{
@@ -156,7 +161,7 @@ Item
anchors.left: endstopXLabel.right
anchors.top: connectionLabel.bottom
wrapMode: Text.WordWrap
- text: x_min_pressed || base.addOriginalProgress.checkUp[1] ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
+ text: x_min_pressed ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
}
//////////////////////////////////////////////////////////////
Label
@@ -175,7 +180,7 @@ Item
anchors.left: endstopYLabel.right
anchors.top: endstopXLabel.bottom
wrapMode: Text.WordWrap
- text: y_min_pressed || base.addOriginalProgress.checkUp[2] ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
+ text: y_min_pressed ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
}
/////////////////////////////////////////////////////////////////////
Label
@@ -194,7 +199,7 @@ Item
anchors.left: endstopZLabel.right
anchors.top: endstopYLabel.bottom
wrapMode: Text.WordWrap
- text: z_min_pressed || base.addOriginalProgress.checkUp[3] ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
+ text: z_min_pressed ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
}
////////////////////////////////////////////////////////////
Label
@@ -233,14 +238,9 @@ Item
{
if(printer_connection != null)
{
- if (alreadyTested){
- nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
- }
- else {
- nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking")
- printer_connection.heatupNozzle(190)
- wizardPage.extruder_target_temp = 190
- }
+ nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking")
+ printer_connection.heatupNozzle(190)
+ wizardPage.extruder_target_temp = 190
}
}
}
@@ -294,14 +294,9 @@ Item
{
if(printer_connection != null)
{
- if (alreadyTested){
- bedTempStatus.text = catalog.i18nc("@info:status","Works")
- }
- else {
- bedTempStatus.text = catalog.i18nc("@info:progress","Checking")
- printer_connection.heatupBed(60)
- wizardPage.bed_target_temp = 60
- }
+ bedTempStatus.text = catalog.i18nc("@info:progress","Checking")
+ printer_connection.heatupBed(60)
+ wizardPage.bed_target_temp = 60
}
}
}
@@ -320,7 +315,7 @@ Item
Label
{
id: resultText
- visible: base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length-1]
+ visible: false
anchors.top: bedTemp.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height
anchors.left: parent.left
@@ -338,19 +333,16 @@ Item
{
if(key == "x_min")
{
- base.addOriginalProgress.checkUp[1] = true
x_min_pressed = true
checkTotalCheckUp()
}
if(key == "y_min")
{
- base.addOriginalProgress.checkUp[2] = true
y_min_pressed = true
checkTotalCheckUp()
}
if(key == "z_min")
{
- base.addOriginalProgress.checkUp[3] = true
z_min_pressed = true
checkTotalCheckUp()
}
@@ -363,7 +355,7 @@ Item
if(printer_connection != null)
{
nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
- base.addOriginalProgress.checkUp[4] = true
+ wizardPage.checkupProgress.nozzleTemp = true
checkTotalCheckUp()
printer_connection.heatupNozzle(0)
}
@@ -374,7 +366,7 @@ Item
if(printer_connection.bedTemperature > wizardPage.bed_target_temp - 5 && printer_connection.bedTemperature < wizardPage.bed_target_temp + 5)
{
bedTempStatus.text = catalog.i18nc("@info:status","Works")
- base.addOriginalProgress.checkUp[5] = true
+ wizardPage.checkupProgress.bedTemp = true
checkTotalCheckUp()
printer_connection.heatupBed(0)
}
diff --git a/resources/themes/cura/icons/check.svg b/resources/themes/cura/icons/check.svg
new file mode 100644
index 0000000000..dac3cd1618
--- /dev/null
+++ b/resources/themes/cura/icons/check.svg
@@ -0,0 +1,50 @@
+
+
+
+
\ No newline at end of file
diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json
index 8130ec9bd0..f4660e4f0f 100644
--- a/resources/themes/cura/theme.json
+++ b/resources/themes/cura/theme.json
@@ -66,6 +66,7 @@
"text_hover": [35, 35, 35, 255],
"text_pressed": [12, 169, 227, 255],
+ "error": [255, 140, 0, 255],
"sidebar_header_bar": [12, 169, 227, 255],
"button": [139, 143, 153, 255],