This commit is contained in:
Tim Kuipers 2015-11-13 15:28:27 +01:00
commit 8ca6b87e17
26 changed files with 663 additions and 286 deletions

View File

@ -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(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 "") if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# Extract Strings # Extract Strings
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura) 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(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) 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) 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) install(FILES cura.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
else() 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() endif()
include(CPackConfig.cmake) include(CPackConfig.cmake)

View File

@ -34,10 +34,14 @@ class BuildVolume(SceneNode):
self.setCalculateBoundingBox(False) self.setCalculateBoundingBox(False)
self._active_profile = None
self._active_instance = None self._active_instance = None
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged) Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
self._onActiveInstanceChanged() self._onActiveInstanceChanged()
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
self._onActiveProfileChanged()
def setWidth(self, width): def setWidth(self, width):
if width: self._width = 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, material = self._material, mode = Renderer.RenderLines)
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True) renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
if self._disallowed_area_mesh: 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 return True
def rebuild(self): def rebuild(self):
@ -117,18 +121,20 @@ class BuildVolume(SceneNode):
v = self._grid_mesh.getVertex(n) v = self._grid_mesh.getVertex(n)
self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
disallowed_area_height = 0.2
disallowed_area_size = 0 disallowed_area_size = 0
if self._disallowed_areas: if self._disallowed_areas:
mb = MeshBuilder() mb = MeshBuilder()
color = Color(0.0, 0.0, 0.0, 0.15)
for polygon in self._disallowed_areas: for polygon in self._disallowed_areas:
points = polygon.getPoints() points = polygon.getPoints()
mb.addQuad( first = Vector(self._clamp(points[0][0], minW, maxW), disallowed_area_height, self._clamp(points[0][1], minD, maxD))
Vector(points[0, 0], 0.1, points[0, 1]), previous_point = Vector(self._clamp(points[0][0], minW, maxW), disallowed_area_height, self._clamp(points[0][1], minD, maxD))
Vector(points[1, 0], 0.1, points[1, 1]), for point in points:
Vector(points[2, 0], 0.1, points[2, 1]), new_point = Vector(self._clamp(point[0], minW, maxW), disallowed_area_height, self._clamp(point[1], minD, maxD))
Vector(points[3, 0], 0.1, points[3, 1]), mb.addFace(first, previous_point, new_point, color = color)
color = Color(174, 174, 174, 255) previous_point = new_point
)
# Find the largest disallowed area to exclude it from the maximum scale bounds # Find the largest disallowed area to exclude it from the maximum scale bounds
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1])) size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
disallowed_area_size = max(size, disallowed_area_size) disallowed_area_size = max(size, disallowed_area_size)
@ -141,16 +147,9 @@ class BuildVolume(SceneNode):
skirt_size = 0.0 skirt_size = 0.0
#profile = Application.getInstance().getMachineManager().getActiveProfile() profile = Application.getInstance().getMachineManager().getActiveProfile()
#if profile: if profile:
#if profile.getSettingValue("adhesion_type") == "skirt": skirt_size = self._getSkirtSize(profile)
#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")
scale_to_max_bounds = AxisAlignedBox( scale_to_max_bounds = AxisAlignedBox(
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size), 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._height = self._active_instance.getMachineSettingValue("machine_height")
self._depth = self._active_instance.getMachineSettingValue("machine_depth") self._depth = self._active_instance.getMachineSettingValue("machine_depth")
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") disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
areas = [] areas = []
skirt_size = 0.0
if self._active_profile:
skirt_size = self._getSkirtSize(self._active_profile)
if disallowed_areas: if disallowed_areas:
for area in disallowed_areas: for area in disallowed_areas:
areas.append(Polygon(numpy.array(area, numpy.float32))) 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 self._disallowed_areas = areas
self.rebuild() 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"]

View File

@ -31,6 +31,8 @@ class ConvexHullJob(Job):
self._node.callDecoration("setConvexHullJob", None) self._node.callDecoration("setConvexHullJob", None)
return return
Job.yieldThread()
else: else:
if not self._node.getMeshData(): if not self._node.getMeshData():
return return

View File

@ -58,6 +58,11 @@ import numpy
import copy import copy
numpy.seterr(all="ignore") numpy.seterr(all="ignore")
try:
from cura.CuraVersion import CuraVersion
except ImportError:
CuraVersion = "master"
class CuraApplication(QtApplication): class CuraApplication(QtApplication):
class ResourceTypes: class ResourceTypes:
QmlFiles = Resources.UserType + 1 QmlFiles = Resources.UserType + 1
@ -69,7 +74,7 @@ class CuraApplication(QtApplication):
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) 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"))) 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.") parser.add_argument("--debug", dest="debug-mode", action="store_true", default=False, help="Enable detailed crash reports.")
def run(self): 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"); self._i18n_catalog = i18nCatalog("cura");
i18nCatalog.setTagReplacements({ i18nCatalog.setTagReplacements({
@ -168,7 +176,7 @@ class CuraApplication(QtApplication):
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
camera = Camera("3d", root) camera = Camera("3d", root)
camera.setPosition(Vector(0, 250, 900)) camera.setPosition(Vector(-80, 250, 700))
camera.setPerspective(True) camera.setPerspective(True)
camera.lookAt(Vector(0, 0, 0)) camera.lookAt(Vector(0, 0, 0))
controller.getScene().setActiveCamera("3d") controller.getScene().setActiveCamera("3d")

4
cura/CuraVersion.py.in Normal file
View File

@ -0,0 +1,4 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
CuraVersion = "@CURA_VERSION@"

View File

@ -63,6 +63,7 @@ class LayerData(MeshData):
offset = data.build(offset, vertices, colors, indices) offset = data.build(offset, vertices, colors, indices)
self._element_counts[layer] = data.elementCount self._element_counts[layer] = data.elementCount
self.clear()
self.addVertices(vertices) self.addVertices(vertices)
self.addColors(colors) self.addColors(colors)
self.addIndices(indices.flatten()) self.addIndices(indices.flatten())
@ -200,18 +201,14 @@ class Polygon():
def build(self, offset, vertices, colors, indices): def build(self, offset, vertices, colors, indices):
self._begin = offset self._begin = offset
self._end = self._begin + len(self._data) - 1
color = self.getColor() color = self.getColor()
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a) 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[self._begin:self._end + 1, :] = self._data[:, :]
vertices[offset + i, :] = self._data[i, :] colors[self._begin:self._end + 1, :] = color
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
for i in range(self._begin, self._end): for i in range(self._begin, self._end):
indices[i, 0] = i indices[i, 0] = i

View File

@ -4,6 +4,7 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
import sys import sys
import os
def exceptHook(type, value, traceback): def exceptHook(type, value, traceback):
import cura.CrashHandler import cura.CrashHandler
@ -11,6 +12,13 @@ def exceptHook(type, value, traceback):
sys.excepthook = exceptHook sys.excepthook = exceptHook
try:
from google.protobuf.pyext import _message
except ImportError:
pass
else:
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp"
import cura.CuraApplication import cura.CuraApplication
if sys.platform == "win32" and hasattr(sys, "frozen"): if sys.platform == "win32" and hasattr(sys, "frozen"):

View File

@ -10,6 +10,7 @@ from UM.Scene.SceneNode import SceneNode
from UM.Scene.GroupDecorator import GroupDecorator from UM.Scene.GroupDecorator import GroupDecorator
from UM.Math.Quaternion import Quaternion from UM.Math.Quaternion import Quaternion
from UM.Job import Job
import os import os
import struct import struct
@ -53,6 +54,7 @@ class ThreeMFReader(MeshReader):
#for vertex in object.mesh.vertices.vertex: #for vertex in object.mesh.vertices.vertex:
for vertex in object.findall(".//3mf:vertex", self._namespaces): for vertex in object.findall(".//3mf:vertex", self._namespaces):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")]) vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
Job.yieldThread()
triangles = object.findall(".//3mf:triangle", self._namespaces) triangles = object.findall(".//3mf:triangle", self._namespaces)
@ -64,6 +66,8 @@ class ThreeMFReader(MeshReader):
v2 = int(triangle.get("v2")) v2 = int(triangle.get("v2"))
v3 = int(triangle.get("v3")) 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]) 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. #TODO: We currently do not check for normals and simply recalculate them.
mesh.calculateNormals() mesh.calculateNormals()
node.setMeshData(mesh) node.setMeshData(mesh)
@ -116,6 +120,8 @@ class ThreeMFReader(MeshReader):
#node.rotate(rotation) #node.rotate(rotation)
result.addChild(node) result.addChild(node)
Job.yieldThread()
#If there is more then one object, group them. #If there is more then one object, group them.
try: try:
if len(objects) > 1: if len(objects) > 1:

View File

@ -17,6 +17,7 @@ from cura.OneAtATimeIterator import OneAtATimeIterator
from . import Cura_pb2 from . import Cura_pb2
from . import ProcessSlicedObjectListJob from . import ProcessSlicedObjectListJob
from . import ProcessGCodeJob from . import ProcessGCodeJob
from . import StartSliceJob
import os import os
import sys import sys
@ -49,6 +50,7 @@ class CuraEngineBackend(Backend):
self._onActiveViewChanged() self._onActiveViewChanged()
self._stored_layer_data = None self._stored_layer_data = None
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onChanged)
self._profile = None self._profile = None
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged) Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
@ -67,12 +69,8 @@ class CuraEngineBackend(Backend):
self._slicing = False self._slicing = False
self._restart = False self._restart = False
self._save_gcode = True
self._save_polygons = True
self._report_progress = True
self._enabled = True self._enabled = True
self._always_restart = True
self._message = None self._message = None
@ -103,24 +101,12 @@ class CuraEngineBackend(Backend):
## Emitted whne the slicing process is aborted forcefully. ## Emitted whne the slicing process is aborted forcefully.
slicingCancelled = Signal() slicingCancelled = Signal()
## Perform a slice of the scene with the given set of settings. ## Perform a slice of the scene.
# def slice(self):
# \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):
if not self._enabled: if not self._enabled:
return return
if self._slicing: if self._slicing:
if not kwargs.get("force_restart", True):
return
self._slicing = False self._slicing = False
self._restart = True self._restart = True
if self._process is not None: if self._process is not None:
@ -129,42 +115,16 @@ class CuraEngineBackend(Backend):
self._process.terminate() self._process.terminate()
except: # terminating a process that is already terminating causes an exception, silently ignore this. except: # terminating a process that is already terminating causes an exception, silently ignore this.
pass 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: if self._message:
self._message.hide() self._message.hide()
self._message = None 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") Logger.log('w', "Profile has error values. Aborting slicing")
if self._message: if self._message:
self._message.hide() self._message.hide()
@ -172,18 +132,7 @@ class CuraEngineBackend(Backend):
self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors.")) self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
self._message.show() self._message.show()
return #No slicing if we have error values since those are by definition illegal values. 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._slicing = True
self.slicingStarted.emit()
self._report_progress = kwargs.get("report_progress", True)
if self._report_progress:
self.processingProgress.emit(0.0) self.processingProgress.emit(0.0)
if not self._message: if not self._message:
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1) self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
@ -191,43 +140,19 @@ class CuraEngineBackend(Backend):
else: else:
self._message.setProgress(-1) self._message.setProgress(-1)
self._sendSettings(kwargs.get("profile", self._profile)) self._scene.gcode_list = []
self._slicing = True
self._scene.acquireLock() job = StartSliceJob.StartSliceJob(self._profile, self._socket)
job.start()
job.finished.connect(self._onStartSliceCompleted)
# Set the gcode as an empty list. This will be filled with strings by GCodeLayer messages. def _onStartSliceCompleted(self, job):
# This is done so the gcode can be fragmented in memory and does not need a continues memory space. if job.getError() or job.getResult() != True:
# (AKA. This prevents MemoryErrors) if self._message:
self._save_gcode = kwargs.get("save_gcode", True) self._message.hide()
if self._save_gcode: self._message = None
setattr(self._scene, "gcode_list", []) return
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 _onSceneChanged(self, source): def _onSceneChanged(self, source):
if type(source) is not SceneNode: if type(source) is not SceneNode:
@ -257,7 +182,6 @@ class CuraEngineBackend(Backend):
self._onChanged() self._onChanged()
def _onSlicedObjectListMessage(self, message): def _onSlicedObjectListMessage(self, message):
if self._save_polygons:
if self._layer_view_active: if self._layer_view_active:
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message) job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
job.start() job.start()
@ -265,7 +189,21 @@ class CuraEngineBackend(Backend):
self._stored_layer_data = message self._stored_layer_data = message
def _onProgressMessage(self, message): def _onProgressMessage(self, message):
if message.amount >= 0.99: if self._message:
self._message.setProgress(round(message.amount * 100))
self.processingProgress.emit(message.amount)
def _onGCodeLayerMessage(self, message):
self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
def _onGCodePrefixMessage(self, message):
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 self._slicing = False
if self._message: if self._message:
@ -273,24 +211,12 @@ class CuraEngineBackend(Backend):
self._message.hide() self._message.hide()
self._message = None self._message = None
if self._message: if self._always_restart:
self._message.setProgress(round(message.amount * 100)) try:
self._process.terminate()
if self._report_progress: self._createSocket()
self.processingProgress.emit(message.amount) except: # terminating a process that is already terminating causes an exception, silently ignore this.
pass
def _onGCodeLayerMessage(self, message):
if self._save_gcode:
job = ProcessGCodeJob.ProcessGCodeLayerJob(message)
job.start()
def _onGCodePrefixMessage(self, message):
if self._save_gcode:
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)
def _createSocket(self): def _createSocket(self):
super()._createSocket() super()._createSocket()
@ -313,15 +239,6 @@ class CuraEngineBackend(Backend):
self._change_timer.start() 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): def _onBackendConnected(self):
if self._restart: if self._restart:
self._onChanged() self._onChanged()
@ -346,22 +263,6 @@ class CuraEngineBackend(Backend):
else: else:
self._layer_view_active = False 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): def _onInstanceChanged(self):
self._slicing = False self._slicing = False

View File

@ -38,10 +38,10 @@ class ProcessSlicedObjectListJob(Job):
for node in DepthFirstIterator(self._scene.getRoot()): for node in DepthFirstIterator(self._scene.getRoot()):
if type(node) is SceneNode and node.getMeshData(): if type(node) is SceneNode and node.getMeshData():
if node.callDecoration("getLayerData"): if node.callDecoration("getLayerData"):
#if hasattr(node.getMeshData(), "layerData"):
self._scene.getRoot().removeChild(node) self._scene.getRoot().removeChild(node)
else: else:
objectIdMap[id(node)] = node objectIdMap[id(node)] = node
Job.yieldThread()
settings = Application.getInstance().getMachineManager().getActiveProfile() settings = Application.getInstance().getMachineManager().getActiveProfile()
layerHeight = settings.getSettingValue("layer_height") layerHeight = settings.getSettingValue("layer_height")
@ -54,6 +54,12 @@ class ProcessSlicedObjectListJob(Job):
mesh = MeshData() mesh = MeshData()
layer_data = LayerData.LayerData() 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: for object in self._message.objects:
try: try:
node = objectIdMap[object.id] node = objectIdMap[object.id]
@ -73,15 +79,23 @@ class ProcessSlicedObjectListJob(Job):
points[:,2] *= -1 points[:,2] *= -1
points -= numpy.array(center) points -= center
layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width) 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 # We are done processing all the layers we got from the engine, now create a mesh out of the data
layer_data.build() layer_data.build()
#Add layerdata decorator to scene node to indicate that the node has layerdata #Add layerdata decorator to scene node to indicate that the node has layerdata
decorator = LayerDataDecorator.LayerDataDecorator() decorator = LayerDataDecorator.LayerDataDecorator()
decorator.setLayerData(layer_data) decorator.setLayerData(layer_data)
@ -90,6 +104,9 @@ class ProcessSlicedObjectListJob(Job):
new_node.setMeshData(mesh) new_node.setMeshData(mesh)
new_node.setParent(self._scene.getRoot()) new_node.setParent(self._scene.getRoot())
if self._progress:
self._progress.setProgress(100)
view = Application.getInstance().getController().getActiveView() view = Application.getInstance().getController().getActiveView()
if view.getPluginId() == "LayerView": if view.getPluginId() == "LayerView":
view.resetLayerData() view.resetLayerData()

View File

@ -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()

View File

@ -41,6 +41,33 @@ Item {
anchors.fill: parent; anchors.fill: parent;
} }
Button {
id: closeButton;
width: UM.Theme.sizes.message_close.width;
height: UM.Theme.sizes.message_close.height;
anchors {
right: parent.right;
rightMargin: UM.Theme.sizes.default_margin.width / 2;
top: parent.top;
topMargin: UM.Theme.sizes.default_margin.width / 2;
}
UM.RecolorImage {
anchors.fill: parent;
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.colors.message_dismiss
source: UM.Theme.icons.cross2;
}
onClicked: settingsPanel.opacity = 0
style: ButtonStyle {
background: Rectangle {
color: UM.Theme.colors.message_background
}
}
}
Column { Column {
id: items id: items
anchors.top: parent.top; anchors.top: parent.top;
@ -58,7 +85,6 @@ Item {
name: catalog.i18nc("@label", "Profile") name: catalog.i18nc("@label", "Profile")
type: "enum" type: "enum"
perObjectSetting: true
style: UM.Theme.styles.setting_item; style: UM.Theme.styles.setting_item;
@ -88,8 +114,6 @@ Item {
description: model.description; description: model.description;
unit: model.unit; unit: model.unit;
valid: model.valid; valid: model.valid;
perObjectSetting: true
dismissable: true
options: model.options options: model.options
style: UM.Theme.styles.setting_item; style: UM.Theme.styles.setting_item;
@ -98,18 +122,36 @@ Item {
settings.model.setSettingValue(model.key, value) settings.model.setSettingValue(model.key, value)
} }
// Button { Button
// anchors.left: parent.right; {
// text: "x"; anchors.left: parent.horizontalCenter;
// anchors.leftMargin: UM.Theme.sizes.default_margin.width;
// width: UM.Theme.sizes.setting.height;
// height: UM.Theme.sizes.setting.height; width: UM.Theme.sizes.setting.height;
// height: UM.Theme.sizes.setting.height;
// opacity: parent.hovered || hovered ? 1 : 0;
// onClicked: UM.ActiveTool.properties.Model.removeSettingOverride(UM.ActiveTool.properties.Model.getItem(base.currentIndex).id, model.key) opacity: parent.hovered || hovered ? 1 : 0;
// onClicked: UM.ActiveTool.properties.Model.removeSettingOverride(UM.ActiveTool.properties.Model.getItem(base.currentIndex).id, model.key)
// style: ButtonStyle { }
// } style: ButtonStyle
{
background: Rectangle
{
color: control.hovered ? control.parent.style.controlHighlightColor : control.parent.style.controlColor;
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width/2
height: parent.height/2
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.colors.setting_control_revert
source: UM.Theme.icons.cross1
}
}
}
}
} }
} }
@ -172,6 +214,8 @@ Item {
checkable: true; checkable: true;
onClicked: { onClicked: {
if(settingsPanel.opacity < 0.5) //Per-object panel is not currently displayed.
{
base.currentIndex = index; base.currentIndex = index;
settingsPanel.anchors.left = right; settingsPanel.anchors.left = right;
@ -179,6 +223,11 @@ Item {
settingsPanel.opacity = 1; settingsPanel.opacity = 1;
} }
else //Per-object panel is already displayed. Deactivate it (same behaviour as the close button).
{
settingsPanel.opacity = 0;
}
}
style: ButtonStyle style: ButtonStyle
{ {

View File

@ -44,9 +44,7 @@ class SettingOverrideModel(ListModel):
if not self._decorator: if not self._decorator:
return return
self._ignore_setting_change = key
self._decorator.setSettingValue(key, value) self._decorator.setSettingValue(key, value)
self._ignore_setting_change = None
def _onDecoratorsChanged(self, node): def _onDecoratorsChanged(self, node):
if not self._node.getDecorator(SettingOverrideDecorator): if not self._node.getDecorator(SettingOverrideDecorator):
@ -97,6 +95,6 @@ class SettingOverrideModel(ListModel):
def _onSettingValueChanged(self, setting): def _onSettingValueChanged(self, setting):
index = self.find("key", setting.getKey()) index = self.find("key", setting.getKey())
value = self._decorator.getSettingValue(setting.getKey()) value = self._decorator.getSettingValue(setting.getKey())
if index != -1 and self._ignore_setting_change != setting.getKey(): if index != -1:
self.setProperty(index, "value", str(value)) self.setProperty(index, "value", str(value))
self.setProperty(index, "valid", setting.validate(value)) self.setProperty(index, "valid", setting.validate(value))

View File

@ -52,6 +52,8 @@ class RemovableDriveOutputDevice(OutputDevice):
message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1) message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
message.show() message.show()
self.writeStarted.emit(self)
job._message = message job._message = message
job.start() job.start()
except PermissionError as e: except PermissionError as e:

View File

@ -45,7 +45,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._connect_thread.daemon = True self._connect_thread.daemon = True
self._end_stop_thread = threading.Thread(target = self._pollEndStop) 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 self._poll_endstop = -1
# Printer is connected # 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 = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.daemon = True self._update_firmware_thread.daemon = True
self.firmwareUpdateComplete.connect(self._onFirmwareUpdateComplete)
self._heatup_wait_start_time = time.time() self._heatup_wait_start_time = time.time()
@ -197,6 +198,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
## Private fuction (threaded) that actually uploads the firmware. ## Private fuction (threaded) that actually uploads the firmware.
def _updateFirmware(self): def _updateFirmware(self):
self.setProgress(0, 100)
if self._is_connecting or self._is_connected: if self._is_connecting or self._is_connected:
self.close() self.close()
hex_file = intelHex.readHex(self._firmware_file_name) hex_file = intelHex.readHex(self._firmware_file_name)
@ -207,7 +210,11 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
programmer = stk500v2.Stk500v2() programmer = stk500v2.Stk500v2()
programmer.progressCallback = self.setProgress programmer.progressCallback = self.setProgress
try:
programmer.connect(self._serial_port) 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. 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 = threading.Thread(target=self._connect)
self._connect_thread.daemon = True self._connect_thread.daemon = True
if self._serial is not None:
self.setIsConnected(False) self.setIsConnected(False)
if self._serial is not None:
try: try:
self._listen_thread.join() self._listen_thread.join()
except: except:

View File

@ -11,6 +11,7 @@ from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Message import Message
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
@ -95,6 +96,10 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
@pyqtSlot() @pyqtSlot()
def updateAllFirmware(self): def updateAllFirmware(self):
if not self._printer_connections:
Message("Cannot update firmware, there were no connected printers found.").show()
return
self.spawnFirmwareInterface("") self.spawnFirmwareInterface("")
for printer_connection in self._printer_connections: for printer_connection in self._printer_connections:
try: try:
@ -159,6 +164,16 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
continue continue
self._serial_port_list = list(serial_ports) 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. ## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
def addConnection(self, serial_port): def addConnection(self, serial_port):
connection = PrinterConnection.PrinterConnection(serial_port) connection = PrinterConnection.PrinterConnection(serial_port)

View File

@ -58,7 +58,7 @@ class IspBase():
raise IspError("Called undefined verifyFlash") raise IspError("Called undefined verifyFlash")
class IspError(BaseException): class IspError(Exception):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value

View File

@ -140,7 +140,7 @@
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default": 0.1, "default": 0.1,
"min_value": "0.0001", "min_value": "0.001",
"min_value_warning": "0.04", "min_value_warning": "0.04",
"max_value_warning": "0.32" "max_value_warning": "0.32"
}, },
@ -150,7 +150,7 @@
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default": 0.3, "default": 0.3,
"min_value": "0.0001", "min_value": "0.001",
"min_value_warning": "0.04", "min_value_warning": "0.04",
"max_value_warning": "0.32", "max_value_warning": "0.32",
"visible": false "visible": false
@ -825,7 +825,8 @@
"type": "float", "type": "float",
"min_value": "0.1", "min_value": "0.1",
"max_value_warning": "300", "max_value_warning": "300",
"default": 150 "default": 150,
"inherit_function": "speed_print if magic_spiralize else 150"
}, },
"speed_layer_0": { "speed_layer_0": {
"label": "Bottom Layer Speed", "label": "Bottom Layer Speed",

View File

@ -567,7 +567,7 @@ UM.MainWindow
addMachine.onTriggered: addMachineWizard.visible = true; 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); } configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(3); }
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); } manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }

View File

@ -13,6 +13,18 @@ UM.PreferencesPage
//: General configuration page title //: General configuration page title
title: catalog.i18nc("@title:tab","General"); 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() function reset()
{ {
UM.Preferences.resetPreference("general/language") UM.Preferences.resetPreference("general/language")
@ -22,7 +34,8 @@ UM.PreferencesPage
pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free")) pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info")) sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
scaleToFitCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_to_fit")) scaleToFitCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
languageComboBox.currentIndex = 0 var defaultLanguage = UM.Preferences.getValue("general/language")
setDefaultLanguage(defaultLanguage)
} }
GridLayout GridLayout

View File

@ -7,8 +7,6 @@ import QtQuick.Window 2.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM import UM 1.1 as UM
import Cura 1.0 as Cura
import ".."
Item Item
{ {
@ -18,10 +16,60 @@ Item
property variant wizard: null; 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 Connections
{ {
target: base.wizard target: base.wizard
onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element
{
var name = machineName.text
if (UM.MachineManager.checkInstanceExists(name) != false)
{
errorMessage.show = true
}
else
{ {
var old_page_count = base.wizard.getPageCount() var old_page_count = base.wizard.getPageCount()
// Delete old pages (if any) // Delete old pages (if any)
@ -31,6 +79,7 @@ Item
} }
saveMachine() saveMachine()
} }
}
onBackClicked: onBackClicked:
{ {
var old_page_count = base.wizard.getPageCount() var old_page_count = base.wizard.getPageCount()
@ -63,7 +112,8 @@ Item
{ {
id: machinesHolder id: machinesHolder
anchors{ anchors
{
left: parent.left; left: parent.left;
top: subTitle.bottom; top: subTitle.bottom;
right: parent.right; right: parent.right;
@ -110,6 +160,7 @@ Item
onClicked: { onClicked: {
base.activeManufacturer = section; base.activeManufacturer = section;
machineList.currentIndex = machineList.model.find("manufacturer", section) machineList.currentIndex = machineList.model.find("manufacturer", section)
machineName.text = getMachineName()
} }
} }
@ -128,7 +179,10 @@ Item
text: model.name text: model.name
onClicked: ListView.view.currentIndex = index; onClicked: {
ListView.view.currentIndex = index;
machineName.text = getMachineName()
}
Label Label
{ {
@ -169,11 +223,33 @@ Item
} }
} }
Item
Column
{ {
id: machineNameHolder id: machineNameHolder
height: childrenRect.height
anchors.bottom: parent.bottom; 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 Label
{ {
id: insertNameLabel id: insertNameLabel
@ -182,8 +258,7 @@ Item
TextField TextField
{ {
id: machineName; id: machineName;
anchors.top: insertNameLabel.bottom text: getMachineName()
text: machineList.model.getItem(machineList.currentIndex).name
implicitWidth: UM.Theme.sizes.standard_list_input.width implicitWidth: UM.Theme.sizes.standard_list_input.width
} }
} }
@ -218,6 +293,9 @@ Item
break; break;
} }
} }
if(base.wizard.lastPage == true){
base.wizard.visible = false
}
} }
} }

View File

@ -7,6 +7,8 @@ import QtQuick.Layouts 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import UM 1.1 as UM import UM 1.1 as UM
import Cura 1.0 as Cura
import ".."
Item Item
{ {
@ -15,11 +17,22 @@ Item
property bool three_point_leveling: true property bool three_point_leveling: true
property int platform_width: UM.MachineManager.getSettingValue("machine_width") property int platform_width: UM.MachineManager.getSettingValue("machine_width")
property int platform_height: UM.MachineManager.getSettingValue("machine_depth") property int platform_height: UM.MachineManager.getSettingValue("machine_depth")
property bool alreadyTested: base.addOriginalProgress.bedLeveling
anchors.fill: parent; anchors.fill: parent;
property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
Component.onCompleted: printer_connection.homeHead() Component.onCompleted: printer_connection.homeHead()
UM.I18nCatalog { id: catalog; name:"cura"} 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 Label
{ {
@ -61,7 +74,6 @@ Item
id: bedlevelingButton id: bedlevelingButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
enabled: !alreadyTested
text: catalog.i18nc("@action:button","Move to Next Position"); text: catalog.i18nc("@action:button","Move to Next Position");
onClicked: onClicked:
{ {
@ -79,7 +91,6 @@ Item
} }
wizardPage.leveling_state++ wizardPage.leveling_state++
if (wizardPage.leveling_state >= 3){ if (wizardPage.leveling_state >= 3){
base.addOriginalProgress.bedLeveling = true
resultText.visible = true resultText.visible = true
skipBedlevelingButton.enabled = false skipBedlevelingButton.enabled = false
bedlevelingButton.enabled = false bedlevelingButton.enabled = false
@ -91,7 +102,6 @@ Item
Button Button
{ {
id: skipBedlevelingButton id: skipBedlevelingButton
enabled: !alreadyTested
anchors.top: parent.width < wizardPage.width ? parent.top : bedlevelingButton.bottom 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.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
anchors.left: parent.width < wizardPage.width ? bedlevelingButton.right : parent.left anchors.left: parent.width < wizardPage.width ? bedlevelingButton.right : parent.left
@ -104,13 +114,13 @@ Item
Label Label
{ {
id: resultText id: resultText
visible: alreadyTested visible: false
anchors.top: bedlevelingWrapper.bottom anchors.top: bedlevelingWrapper.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height anchors.topMargin: UM.Theme.sizes.default_margin.height
anchors.left: parent.left anchors.left: parent.left
width: parent.width width: parent.width
wrapMode: Text.WordWrap 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) function threePointLeveling(width, height)

View File

@ -17,11 +17,8 @@ Item
Component.onDestruction: Component.onDestruction:
{ {
base.addOriginalProgress.upgrades[0] = extruderCheckBox.checked
base.addOriginalProgress.upgrades[1] = heatedBedCheckBox1.checked
base.addOriginalProgress.upgrades[2] = heatedBedCheckBox2.checked
if (extruderCheckBox.checked == true){ 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){ if (heatedBedCheckBox1.checked == true || heatedBedCheckBox2.checked == true){
UM.MachineManager.setMachineSettingValue("machine_heated_bed", true) UM.MachineManager.setMachineSettingValue("machine_heated_bed", true)
@ -58,14 +55,14 @@ Item
{ {
id: extruderCheckBox id: extruderCheckBox
text: catalog.i18nc("@option:check","Extruder driver ugrades") text: catalog.i18nc("@option:check","Extruder driver ugrades")
checked: base.addOriginalProgress.upgrades[0] checked: true
} }
CheckBox CheckBox
{ {
id: heatedBedCheckBox1 id: heatedBedCheckBox1
text: catalog.i18nc("@option:check","Heated printer bed (standard kit)") text: catalog.i18nc("@option:check","Heated printer bed")
y: extruderCheckBox.height * 1 y: extruderCheckBox.height * 1
checked: base.addOriginalProgress.upgrades[1] checked: false
onClicked: { onClicked: {
if (heatedBedCheckBox2.checked == true) if (heatedBedCheckBox2.checked == true)
heatedBedCheckBox2.checked = false heatedBedCheckBox2.checked = false
@ -76,7 +73,7 @@ Item
id: heatedBedCheckBox2 id: heatedBedCheckBox2
text: catalog.i18nc("@option:check","Heated printer bed (self built)") text: catalog.i18nc("@option:check","Heated printer bed (self built)")
y: extruderCheckBox.height * 2 y: extruderCheckBox.height * 2
checked: base.addOriginalProgress.upgrades[2] checked: false
onClicked: { onClicked: {
if (heatedBedCheckBox1.checked == true) if (heatedBedCheckBox1.checked == true)
heatedBedCheckBox1.checked = false heatedBedCheckBox1.checked = false

View File

@ -14,35 +14,40 @@ Item
property int leftRow: wizardPage.width*0.40 property int leftRow: wizardPage.width*0.40
property int rightRow: wizardPage.width*0.60 property int rightRow: wizardPage.width*0.60
anchors.fill: parent; anchors.fill: parent;
property bool alreadyTested: base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length-1]
property bool x_min_pressed: false property bool x_min_pressed: false
property bool y_min_pressed: false property bool y_min_pressed: false
property bool z_min_pressed: false property bool z_min_pressed: false
property bool heater_works: false property bool heater_works: false
property int extruder_target_temp: 0 property int extruder_target_temp: 0
property int bed_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: { property variant printer_connection: {
if (UM.USBPrinterManager.connectedPrinterList.rowCount() != 0){ if (UM.USBPrinterManager.connectedPrinterList.rowCount() != 0){
base.addOriginalProgress.checkUp[0] = true wizardPage.checkupProgress.connection = true
checkTotalCheckUp()
return UM.USBPrinterManager.connectedPrinterList.getItem(0).printer return UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
} }
else { else {
return null return null
} }
} }
//property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
UM.I18nCatalog { id: catalog; name:"cura"}
function checkTotalCheckUp(){ function checkTotalCheckUp(){
var allDone = true var allDone = true
for (var i = 0; i < (base.addOriginalProgress.checkUp.length - 1); i++){ for(var property in checkupProgress){
if (base.addOriginalProgress.checkUp[i] == false){ if (checkupProgress[property] == false){
allDone = false allDone = false
} }
} }
if (allDone == true){ if (allDone == true){
base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length] = true
skipCheckButton.enabled = false skipCheckButton.enabled = false
resultText.visible = true resultText.visible = true
} }
@ -91,7 +96,7 @@ Item
id: startCheckButton id: startCheckButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
enabled: !alreadyTested //enabled: !alreadyTested
text: catalog.i18nc("@action:button","Start Printer Check"); text: catalog.i18nc("@action:button","Start Printer Check");
onClicked: { onClicked: {
checkupContent.visible = true checkupContent.visible = true
@ -107,7 +112,7 @@ Item
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2 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.left: parent.width < wizardPage.width ? startCheckButton.right : parent.left
anchors.leftMargin: parent.width < wizardPage.width ? UM.Theme.sizes.default_margin.width : 0 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"); text: catalog.i18nc("@action:button","Skip Printer Check");
onClicked: { onClicked: {
base.currentPage += 1 base.currentPage += 1
@ -119,7 +124,7 @@ Item
id: checkupContent id: checkupContent
anchors.top: startStopButtons.bottom anchors.top: startStopButtons.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height anchors.topMargin: UM.Theme.sizes.default_margin.height
visible: alreadyTested visible: false
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
Label Label
{ {
@ -156,7 +161,7 @@ Item
anchors.left: endstopXLabel.right anchors.left: endstopXLabel.right
anchors.top: connectionLabel.bottom anchors.top: connectionLabel.bottom
wrapMode: Text.WordWrap 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 Label
@ -175,7 +180,7 @@ Item
anchors.left: endstopYLabel.right anchors.left: endstopYLabel.right
anchors.top: endstopXLabel.bottom anchors.top: endstopXLabel.bottom
wrapMode: Text.WordWrap 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 Label
@ -194,7 +199,7 @@ Item
anchors.left: endstopZLabel.right anchors.left: endstopZLabel.right
anchors.top: endstopYLabel.bottom anchors.top: endstopYLabel.bottom
wrapMode: Text.WordWrap 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 Label
@ -233,10 +238,6 @@ Item
{ {
if(printer_connection != null) if(printer_connection != null)
{ {
if (alreadyTested){
nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
}
else {
nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking") nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking")
printer_connection.heatupNozzle(190) printer_connection.heatupNozzle(190)
wizardPage.extruder_target_temp = 190 wizardPage.extruder_target_temp = 190
@ -244,7 +245,6 @@ Item
} }
} }
} }
}
Label Label
{ {
id: nozzleTemp id: nozzleTemp
@ -294,10 +294,6 @@ Item
{ {
if(printer_connection != null) if(printer_connection != null)
{ {
if (alreadyTested){
bedTempStatus.text = catalog.i18nc("@info:status","Works")
}
else {
bedTempStatus.text = catalog.i18nc("@info:progress","Checking") bedTempStatus.text = catalog.i18nc("@info:progress","Checking")
printer_connection.heatupBed(60) printer_connection.heatupBed(60)
wizardPage.bed_target_temp = 60 wizardPage.bed_target_temp = 60
@ -305,7 +301,6 @@ Item
} }
} }
} }
}
Label Label
{ {
id: bedTemp id: bedTemp
@ -320,7 +315,7 @@ Item
Label Label
{ {
id: resultText id: resultText
visible: base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length-1] visible: false
anchors.top: bedTemp.bottom anchors.top: bedTemp.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height anchors.topMargin: UM.Theme.sizes.default_margin.height
anchors.left: parent.left anchors.left: parent.left
@ -338,19 +333,16 @@ Item
{ {
if(key == "x_min") if(key == "x_min")
{ {
base.addOriginalProgress.checkUp[1] = true
x_min_pressed = true x_min_pressed = true
checkTotalCheckUp() checkTotalCheckUp()
} }
if(key == "y_min") if(key == "y_min")
{ {
base.addOriginalProgress.checkUp[2] = true
y_min_pressed = true y_min_pressed = true
checkTotalCheckUp() checkTotalCheckUp()
} }
if(key == "z_min") if(key == "z_min")
{ {
base.addOriginalProgress.checkUp[3] = true
z_min_pressed = true z_min_pressed = true
checkTotalCheckUp() checkTotalCheckUp()
} }
@ -363,7 +355,7 @@ Item
if(printer_connection != null) if(printer_connection != null)
{ {
nozzleTempStatus.text = catalog.i18nc("@info:status","Works") nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
base.addOriginalProgress.checkUp[4] = true wizardPage.checkupProgress.nozzleTemp = true
checkTotalCheckUp() checkTotalCheckUp()
printer_connection.heatupNozzle(0) 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) if(printer_connection.bedTemperature > wizardPage.bed_target_temp - 5 && printer_connection.bedTemperature < wizardPage.bed_target_temp + 5)
{ {
bedTempStatus.text = catalog.i18nc("@info:status","Works") bedTempStatus.text = catalog.i18nc("@info:status","Works")
base.addOriginalProgress.checkUp[5] = true wizardPage.checkupProgress.bedTemp = true
checkTotalCheckUp() checkTotalCheckUp()
printer_connection.heatupBed(0) printer_connection.heatupBed(0)
} }

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="415.582px"
height="415.582px"
viewBox="0 0 415.582 415.582"
style="enable-background:new 0 0 415.582 415.582;"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="check.svg"><metadata
id="metadata11"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs9" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1134"
id="namedview7"
showgrid="false"
inkscape:zoom="1.61"
inkscape:cx="211.31288"
inkscape:cy="137.35337"
inkscape:window-x="1440"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" /><g
id="g3"><path
d="m 411.47,96.426 -34.319,-34.32 c -5.48192,-5.482079 -14.34421,-5.455083 -19.853,0 L 152.348,265.058 56.282,174.994 c -5.48,-5.482 -14.37,-5.482 -19.851,0 l -32.319,32.32 c -5.482,5.481 -5.482,14.37 0,19.852 l 138.311,138.31 c 2.741,2.742 6.334,4.112 9.926,4.112 3.593,0 7.186,-1.37 9.926,-4.112 L 411.47,116.277 c 2.633,-2.632 4.111,-6.203 4.111,-9.925 10e-4,-3.724 -1.47804,-7.29296 -4.111,-9.926 z"
id="path5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssccccscscccs" /></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -66,6 +66,7 @@
"text_hover": [35, 35, 35, 255], "text_hover": [35, 35, 35, 255],
"text_pressed": [12, 169, 227, 255], "text_pressed": [12, 169, 227, 255],
"error": [255, 140, 0, 255],
"sidebar_header_bar": [12, 169, 227, 255], "sidebar_header_bar": [12, 169, 227, 255],
"button": [139, 143, 153, 255], "button": [139, 143, 153, 255],