mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-15 10:47:49 -06:00
Merge branch '3.4' into fix_retraction_amount
This commit is contained in:
commit
36e72ae744
41 changed files with 258 additions and 134 deletions
|
@ -19,7 +19,10 @@ endif()
|
||||||
|
|
||||||
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
|
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
|
||||||
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
|
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
|
||||||
set(CURA_PACKAGES_VERSION "" CACHE STRING "Packages version of Cura")
|
set(CURA_SDK_VERSION "" CACHE STRING "SDK version of Cura")
|
||||||
|
set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root")
|
||||||
|
set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version")
|
||||||
|
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)
|
configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)
|
||||||
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
|
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.Math.Polygon import Polygon
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from cura.Arranging.ShapeArray import ShapeArray
|
from cura.Arranging.ShapeArray import ShapeArray
|
||||||
from cura.Scene import ZOffsetDecorator
|
from cura.Scene import ZOffsetDecorator
|
||||||
|
@ -45,7 +46,7 @@ class Arrange:
|
||||||
# \param scene_root Root for finding all scene nodes
|
# \param scene_root Root for finding all scene nodes
|
||||||
# \param fixed_nodes Scene nodes to be placed
|
# \param fixed_nodes Scene nodes to be placed
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5, x = 350, y = 250):
|
def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5, x = 350, y = 250, min_offset = 8):
|
||||||
arranger = Arrange(x, y, x // 2, y // 2, scale = scale)
|
arranger = Arrange(x, y, x // 2, y // 2, scale = scale)
|
||||||
arranger.centerFirst()
|
arranger.centerFirst()
|
||||||
|
|
||||||
|
@ -58,9 +59,10 @@ class Arrange:
|
||||||
|
|
||||||
# Place all objects fixed nodes
|
# Place all objects fixed nodes
|
||||||
for fixed_node in fixed_nodes:
|
for fixed_node in fixed_nodes:
|
||||||
vertices = fixed_node.callDecoration("getConvexHull")
|
vertices = fixed_node.callDecoration("getConvexHullHead") or fixed_node.callDecoration("getConvexHull")
|
||||||
if not vertices:
|
if not vertices:
|
||||||
continue
|
continue
|
||||||
|
vertices = vertices.getMinkowskiHull(Polygon.approximatedCircle(min_offset))
|
||||||
points = copy.deepcopy(vertices._points)
|
points = copy.deepcopy(vertices._points)
|
||||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||||
arranger.place(0, 0, shape_arr)
|
arranger.place(0, 0, shape_arr)
|
||||||
|
@ -81,12 +83,12 @@ class Arrange:
|
||||||
## Find placement for a node (using offset shape) and place it (using hull shape)
|
## Find placement for a node (using offset shape) and place it (using hull shape)
|
||||||
# return the nodes that should be placed
|
# return the nodes that should be placed
|
||||||
# \param node
|
# \param node
|
||||||
# \param offset_shape_arr ShapeArray with offset, used to find location
|
# \param offset_shape_arr ShapeArray with offset, for placing the shape
|
||||||
# \param hull_shape_arr ShapeArray without offset, for placing the shape
|
# \param hull_shape_arr ShapeArray without offset, used to find location
|
||||||
def findNodePlacement(self, node, offset_shape_arr, hull_shape_arr, step = 1):
|
def findNodePlacement(self, node, offset_shape_arr, hull_shape_arr, step = 1):
|
||||||
new_node = copy.deepcopy(node)
|
new_node = copy.deepcopy(node)
|
||||||
best_spot = self.bestSpot(
|
best_spot = self.bestSpot(
|
||||||
offset_shape_arr, start_prio = self._last_priority, step = step)
|
hull_shape_arr, start_prio = self._last_priority, step = step)
|
||||||
x, y = best_spot.x, best_spot.y
|
x, y = best_spot.x, best_spot.y
|
||||||
|
|
||||||
# Save the last priority.
|
# Save the last priority.
|
||||||
|
@ -102,7 +104,7 @@ class Arrange:
|
||||||
if x is not None: # We could find a place
|
if x is not None: # We could find a place
|
||||||
new_node.setPosition(Vector(x, center_y, y))
|
new_node.setPosition(Vector(x, center_y, y))
|
||||||
found_spot = True
|
found_spot = True
|
||||||
self.place(x, y, hull_shape_arr) # place the object in arranger
|
self.place(x, y, offset_shape_arr) # place the object in arranger
|
||||||
else:
|
else:
|
||||||
Logger.log("d", "Could not find spot!"),
|
Logger.log("d", "Could not find spot!"),
|
||||||
found_spot = False
|
found_spot = False
|
||||||
|
|
|
@ -110,7 +110,7 @@ class ArrangeObjectsAllBuildPlatesJob(Job):
|
||||||
arrange_array.add()
|
arrange_array.add()
|
||||||
arranger = arrange_array.get(current_build_plate_number)
|
arranger = arrange_array.get(current_build_plate_number)
|
||||||
|
|
||||||
best_spot = arranger.bestSpot(offset_shape_arr, start_prio=start_priority)
|
best_spot = arranger.bestSpot(hull_shape_arr, start_prio=start_priority)
|
||||||
x, y = best_spot.x, best_spot.y
|
x, y = best_spot.x, best_spot.y
|
||||||
node.removeDecorator(ZOffsetDecorator)
|
node.removeDecorator(ZOffsetDecorator)
|
||||||
if node.getBoundingBox():
|
if node.getBoundingBox():
|
||||||
|
@ -118,7 +118,7 @@ class ArrangeObjectsAllBuildPlatesJob(Job):
|
||||||
else:
|
else:
|
||||||
center_y = 0
|
center_y = 0
|
||||||
if x is not None: # We could find a place
|
if x is not None: # We could find a place
|
||||||
arranger.place(x, y, hull_shape_arr) # place the object in the arranger
|
arranger.place(x, y, offset_shape_arr) # place the object in the arranger
|
||||||
|
|
||||||
node.callDecoration("setBuildPlateNumber", current_build_plate_number)
|
node.callDecoration("setBuildPlateNumber", current_build_plate_number)
|
||||||
grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True))
|
grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True))
|
||||||
|
|
|
@ -37,12 +37,15 @@ class ArrangeObjectsJob(Job):
|
||||||
machine_width = global_container_stack.getProperty("machine_width", "value")
|
machine_width = global_container_stack.getProperty("machine_width", "value")
|
||||||
machine_depth = global_container_stack.getProperty("machine_depth", "value")
|
machine_depth = global_container_stack.getProperty("machine_depth", "value")
|
||||||
|
|
||||||
arranger = Arrange.create(x = machine_width, y = machine_depth, fixed_nodes = self._fixed_nodes)
|
arranger = Arrange.create(x = machine_width, y = machine_depth, fixed_nodes = self._fixed_nodes, min_offset = self._min_offset)
|
||||||
|
|
||||||
# Collect nodes to be placed
|
# Collect nodes to be placed
|
||||||
nodes_arr = [] # fill with (size, node, offset_shape_arr, hull_shape_arr)
|
nodes_arr = [] # fill with (size, node, offset_shape_arr, hull_shape_arr)
|
||||||
for node in self._nodes:
|
for node in self._nodes:
|
||||||
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = self._min_offset)
|
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = self._min_offset)
|
||||||
|
if offset_shape_arr is None:
|
||||||
|
Logger.log("w", "Node [%s] could not be converted to an array for arranging...", str(node))
|
||||||
|
continue
|
||||||
nodes_arr.append((offset_shape_arr.arr.shape[0] * offset_shape_arr.arr.shape[1], node, offset_shape_arr, hull_shape_arr))
|
nodes_arr.append((offset_shape_arr.arr.shape[0] * offset_shape_arr.arr.shape[1], node, offset_shape_arr, hull_shape_arr))
|
||||||
|
|
||||||
# Sort the nodes with the biggest area first.
|
# Sort the nodes with the biggest area first.
|
||||||
|
@ -63,7 +66,7 @@ class ArrangeObjectsJob(Job):
|
||||||
start_priority = last_priority
|
start_priority = last_priority
|
||||||
else:
|
else:
|
||||||
start_priority = 0
|
start_priority = 0
|
||||||
best_spot = arranger.bestSpot(offset_shape_arr, start_prio=start_priority)
|
best_spot = arranger.bestSpot(hull_shape_arr, start_prio = start_priority)
|
||||||
x, y = best_spot.x, best_spot.y
|
x, y = best_spot.x, best_spot.y
|
||||||
node.removeDecorator(ZOffsetDecorator)
|
node.removeDecorator(ZOffsetDecorator)
|
||||||
if node.getBoundingBox():
|
if node.getBoundingBox():
|
||||||
|
@ -74,7 +77,7 @@ class ArrangeObjectsJob(Job):
|
||||||
last_size = size
|
last_size = size
|
||||||
last_priority = best_spot.priority
|
last_priority = best_spot.priority
|
||||||
|
|
||||||
arranger.place(x, y, hull_shape_arr) # take place before the next one
|
arranger.place(x, y, offset_shape_arr) # take place before the next one
|
||||||
grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True))
|
grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True))
|
||||||
else:
|
else:
|
||||||
Logger.log("d", "Arrange all: could not find spot!")
|
Logger.log("d", "Arrange all: could not find spot!")
|
||||||
|
|
|
@ -452,7 +452,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
## A reusable dialogbox
|
## A reusable dialogbox
|
||||||
#
|
#
|
||||||
showMessageBox = pyqtSignal(str, str, str, str, str, int, int, arguments = ["title", "footer", "text", "informativeText", "detailedText", "buttons", "icon"])
|
showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])
|
||||||
|
|
||||||
def messageBox(self, title, text, informativeText = "", detailedText = "", buttons = QMessageBox.Ok, icon = QMessageBox.NoIcon, callback = None, callback_arguments = []):
|
def messageBox(self, title, text, informativeText = "", detailedText = "", buttons = QMessageBox.Ok, icon = QMessageBox.NoIcon, callback = None, callback_arguments = []):
|
||||||
self._message_box_callback = callback
|
self._message_box_callback = callback
|
||||||
|
@ -1500,11 +1500,15 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
def _reloadMeshFinished(self, job):
|
def _reloadMeshFinished(self, job):
|
||||||
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
|
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
|
||||||
mesh_data = job.getResult()[0].getMeshData()
|
job_result = job.getResult()
|
||||||
if mesh_data:
|
if len(job_result) == 0:
|
||||||
job._node.setMeshData(mesh_data)
|
Logger.log("e", "Reloading the mesh failed.")
|
||||||
else:
|
return
|
||||||
|
mesh_data = job_result[0].getMeshData()
|
||||||
|
if not mesh_data:
|
||||||
Logger.log("w", "Could not find a mesh in reloaded node.")
|
Logger.log("w", "Could not find a mesh in reloaded node.")
|
||||||
|
return
|
||||||
|
job._node.setMeshData(mesh_data)
|
||||||
|
|
||||||
def _openFile(self, filename):
|
def _openFile(self, filename):
|
||||||
self.readLocalFile(QUrl.fromLocalFile(filename))
|
self.readLocalFile(QUrl.fromLocalFile(filename))
|
||||||
|
@ -1568,10 +1572,11 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
f = file.toLocalFile()
|
f = file.toLocalFile()
|
||||||
extension = os.path.splitext(f)[1]
|
extension = os.path.splitext(f)[1]
|
||||||
|
extension = extension.lower()
|
||||||
filename = os.path.basename(f)
|
filename = os.path.basename(f)
|
||||||
if len(self._currently_loading_files) > 0:
|
if len(self._currently_loading_files) > 0:
|
||||||
# If a non-slicable file is already being loaded, we prevent loading of any further non-slicable files
|
# If a non-slicable file is already being loaded, we prevent loading of any further non-slicable files
|
||||||
if extension.lower() in self._non_sliceable_extensions:
|
if extension in self._non_sliceable_extensions:
|
||||||
message = Message(
|
message = Message(
|
||||||
self._i18n_catalog.i18nc("@info:status",
|
self._i18n_catalog.i18nc("@info:status",
|
||||||
"Only one G-code file can be loaded at a time. Skipped importing {0}",
|
"Only one G-code file can be loaded at a time. Skipped importing {0}",
|
||||||
|
@ -1580,7 +1585,8 @@ class CuraApplication(QtApplication):
|
||||||
return
|
return
|
||||||
# If file being loaded is non-slicable file, then prevent loading of any other files
|
# If file being loaded is non-slicable file, then prevent loading of any other files
|
||||||
extension = os.path.splitext(self._currently_loading_files[0])[1]
|
extension = os.path.splitext(self._currently_loading_files[0])[1]
|
||||||
if extension.lower() in self._non_sliceable_extensions:
|
extension = extension.lower()
|
||||||
|
if extension in self._non_sliceable_extensions:
|
||||||
message = Message(
|
message = Message(
|
||||||
self._i18n_catalog.i18nc("@info:status",
|
self._i18n_catalog.i18nc("@info:status",
|
||||||
"Can't open any other file if G-code is loading. Skipped importing {0}",
|
"Can't open any other file if G-code is loading. Skipped importing {0}",
|
||||||
|
|
|
@ -158,14 +158,17 @@ class CuraPackageManager(QObject):
|
||||||
# Add bundled plugins
|
# Add bundled plugins
|
||||||
if package_id in self._bundled_package_dict:
|
if package_id in self._bundled_package_dict:
|
||||||
package_info = self._bundled_package_dict[package_id]["package_info"]
|
package_info = self._bundled_package_dict[package_id]["package_info"]
|
||||||
|
package_info["is_installed"] = True
|
||||||
|
|
||||||
# Add installed plugins
|
# Add installed plugins
|
||||||
if package_id in self._installed_package_dict:
|
if package_id in self._installed_package_dict:
|
||||||
package_info = self._installed_package_dict[package_id]["package_info"]
|
package_info = self._installed_package_dict[package_id]["package_info"]
|
||||||
|
package_info["is_installed"] = True
|
||||||
|
|
||||||
# Add to install plugins
|
# Add to install plugins
|
||||||
if package_id in self._to_install_package_dict:
|
if package_id in self._to_install_package_dict:
|
||||||
package_info = self._to_install_package_dict[package_id]["package_info"]
|
package_info = self._to_install_package_dict[package_id]["package_info"]
|
||||||
|
package_info["is_installed"] = False
|
||||||
|
|
||||||
if package_info is None:
|
if package_info is None:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -4,4 +4,6 @@
|
||||||
CuraVersion = "@CURA_VERSION@"
|
CuraVersion = "@CURA_VERSION@"
|
||||||
CuraBuildType = "@CURA_BUILDTYPE@"
|
CuraBuildType = "@CURA_BUILDTYPE@"
|
||||||
CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
|
CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
|
||||||
CuraPackagesVersion = "@CURA_PACKAGES_VERSION@"
|
CuraSDKVersion = "@CURA_SDK_VERSION@"
|
||||||
|
CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@"
|
||||||
|
CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@"
|
||||||
|
|
|
@ -291,9 +291,10 @@ class MaterialManager(QObject):
|
||||||
material_id_metadata_dict = dict()
|
material_id_metadata_dict = dict()
|
||||||
for node in nodes_to_check:
|
for node in nodes_to_check:
|
||||||
if node is not None:
|
if node is not None:
|
||||||
|
# Only exclude the materials that are explicitly specified in the "exclude_materials" field.
|
||||||
|
# Do not exclude other materials that are of the same type.
|
||||||
for material_id, node in node.material_map.items():
|
for material_id, node in node.material_map.items():
|
||||||
fallback_id = self.getFallbackMaterialIdByMaterialType(node.metadata["material"])
|
if material_id in machine_exclude_materials:
|
||||||
if fallback_id in machine_exclude_materials:
|
|
||||||
Logger.log("d", "Exclude material [%s] for machine [%s]",
|
Logger.log("d", "Exclude material [%s] for machine [%s]",
|
||||||
material_id, machine_definition.getId())
|
material_id, machine_definition.getId())
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -39,6 +39,8 @@ class BaseMaterialsModel(ListModel):
|
||||||
|
|
||||||
self._extruder_position = 0
|
self._extruder_position = 0
|
||||||
self._extruder_stack = None
|
self._extruder_stack = None
|
||||||
|
# Update the stack and the model data when the machine changes
|
||||||
|
self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack)
|
||||||
|
|
||||||
def _updateExtruderStack(self):
|
def _updateExtruderStack(self):
|
||||||
global_stack = self._machine_manager.activeMachine
|
global_stack = self._machine_manager.activeMachine
|
||||||
|
@ -50,9 +52,11 @@ class BaseMaterialsModel(ListModel):
|
||||||
self._extruder_stack = global_stack.extruders.get(str(self._extruder_position))
|
self._extruder_stack = global_stack.extruders.get(str(self._extruder_position))
|
||||||
if self._extruder_stack is not None:
|
if self._extruder_stack is not None:
|
||||||
self._extruder_stack.pyqtContainersChanged.connect(self._update)
|
self._extruder_stack.pyqtContainersChanged.connect(self._update)
|
||||||
|
# Force update the model when the extruder stack changes
|
||||||
|
self._update()
|
||||||
|
|
||||||
def setExtruderPosition(self, position: int):
|
def setExtruderPosition(self, position: int):
|
||||||
if self._extruder_position != position:
|
if self._extruder_stack is None or self._extruder_position != position:
|
||||||
self._extruder_position = position
|
self._extruder_position = position
|
||||||
self._updateExtruderStack()
|
self._updateExtruderStack()
|
||||||
self.extruderPositionChanged.emit()
|
self.extruderPositionChanged.emit()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
from UM.Operations.GroupedOperation import GroupedOperation
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
|
@ -36,7 +38,7 @@ class MultiplyObjectsJob(Job):
|
||||||
|
|
||||||
root = scene.getRoot()
|
root = scene.getRoot()
|
||||||
scale = 0.5
|
scale = 0.5
|
||||||
arranger = Arrange.create(x = machine_width, y = machine_depth, scene_root = root, scale = scale)
|
arranger = Arrange.create(x = machine_width, y = machine_depth, scene_root = root, scale = scale, min_offset = self._min_offset)
|
||||||
processed_nodes = []
|
processed_nodes = []
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
||||||
|
@ -64,6 +66,8 @@ class MultiplyObjectsJob(Job):
|
||||||
# We do place the nodes one by one, as we want to yield in between.
|
# We do place the nodes one by one, as we want to yield in between.
|
||||||
if not node_too_big:
|
if not node_too_big:
|
||||||
new_node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr)
|
new_node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr)
|
||||||
|
else:
|
||||||
|
new_node = copy.deepcopy(node)
|
||||||
if node_too_big or not solution_found:
|
if node_too_big or not solution_found:
|
||||||
found_solution_for_all = False
|
found_solution_for_all = False
|
||||||
new_location = new_node.getPosition()
|
new_location = new_node.getPosition()
|
||||||
|
|
|
@ -329,6 +329,8 @@ class PrintInformation(QObject):
|
||||||
baseNameChanged = pyqtSignal()
|
baseNameChanged = pyqtSignal()
|
||||||
|
|
||||||
def setBaseName(self, base_name: str, is_project_file: bool = False):
|
def setBaseName(self, base_name: str, is_project_file: bool = False):
|
||||||
|
self._is_user_specified_job_name = False
|
||||||
|
|
||||||
# Ensure that we don't use entire path but only filename
|
# Ensure that we don't use entire path but only filename
|
||||||
name = os.path.basename(base_name)
|
name = os.path.basename(base_name)
|
||||||
|
|
||||||
|
@ -355,11 +357,12 @@ class PrintInformation(QObject):
|
||||||
data = mime_type.stripExtension(name)
|
data = mime_type.stripExtension(name)
|
||||||
except:
|
except:
|
||||||
Logger.log("w", "Unsupported Mime Type Database file extension")
|
Logger.log("w", "Unsupported Mime Type Database file extension")
|
||||||
|
data = 'unnamed'
|
||||||
|
|
||||||
if data is not None and check_name is not None:
|
if data is not None and check_name is not None:
|
||||||
self._base_name = data
|
self._base_name = data
|
||||||
else:
|
else:
|
||||||
self._base_name = ''
|
self._base_name = 'unnamed'
|
||||||
|
|
||||||
self._updateJobName()
|
self._updateJobName()
|
||||||
|
|
||||||
|
|
|
@ -475,7 +475,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
extruder_definition = extruder_definitions[0]
|
extruder_definition = extruder_definitions[0]
|
||||||
unique_name = self.uniqueName(machine.getName() + " " + new_extruder_id) if create_new_ids else machine.getName() + " " + new_extruder_id
|
unique_name = self.uniqueName(machine.getName() + " " + new_extruder_id) if create_new_ids else machine.getName() + " " + new_extruder_id
|
||||||
|
|
||||||
extruder_stack = ExtruderStack.ExtruderStack(unique_name, parent = machine)
|
extruder_stack = ExtruderStack.ExtruderStack(unique_name)
|
||||||
extruder_stack.setName(extruder_definition.getName())
|
extruder_stack.setName(extruder_definition.getName())
|
||||||
extruder_stack.setDefinition(extruder_definition)
|
extruder_stack.setDefinition(extruder_definition)
|
||||||
extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
|
extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
|
||||||
|
|
|
@ -39,8 +39,8 @@ from . import Exceptions
|
||||||
# This also means that operations on the stack that modifies the container ordering is prohibited and
|
# This also means that operations on the stack that modifies the container ordering is prohibited and
|
||||||
# will raise an exception.
|
# will raise an exception.
|
||||||
class CuraContainerStack(ContainerStack):
|
class CuraContainerStack(ContainerStack):
|
||||||
def __init__(self, container_id: str, *args, **kwargs):
|
def __init__(self, container_id: str):
|
||||||
super().__init__(container_id, *args, **kwargs)
|
super().__init__(container_id)
|
||||||
|
|
||||||
self._container_registry = ContainerRegistry.getInstance()
|
self._container_registry = ContainerRegistry.getInstance()
|
||||||
|
|
||||||
|
|
|
@ -99,8 +99,7 @@ class CuraStackBuilder:
|
||||||
position = position,
|
position = position,
|
||||||
variant_container = extruder_variant_container,
|
variant_container = extruder_variant_container,
|
||||||
material_container = material_container,
|
material_container = material_container,
|
||||||
quality_container = application.empty_quality_container,
|
quality_container = application.empty_quality_container
|
||||||
global_stack = new_global_stack,
|
|
||||||
)
|
)
|
||||||
new_extruder.setNextStack(new_global_stack)
|
new_extruder.setNextStack(new_global_stack)
|
||||||
new_global_stack.addExtruder(new_extruder)
|
new_global_stack.addExtruder(new_extruder)
|
||||||
|
@ -139,11 +138,11 @@ class CuraStackBuilder:
|
||||||
@classmethod
|
@classmethod
|
||||||
def createExtruderStack(cls, new_stack_id: str, extruder_definition: DefinitionContainerInterface, machine_definition_id: str,
|
def createExtruderStack(cls, new_stack_id: str, extruder_definition: DefinitionContainerInterface, machine_definition_id: str,
|
||||||
position: int,
|
position: int,
|
||||||
variant_container, material_container, quality_container, global_stack) -> ExtruderStack:
|
variant_container, material_container, quality_container) -> ExtruderStack:
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
application = CuraApplication.getInstance()
|
application = CuraApplication.getInstance()
|
||||||
|
|
||||||
stack = ExtruderStack(new_stack_id, parent = global_stack)
|
stack = ExtruderStack(new_stack_id)
|
||||||
stack.setName(extruder_definition.getName())
|
stack.setName(extruder_definition.getName())
|
||||||
stack.setDefinition(extruder_definition)
|
stack.setDefinition(extruder_definition)
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ if TYPE_CHECKING:
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
class ExtruderStack(CuraContainerStack):
|
class ExtruderStack(CuraContainerStack):
|
||||||
def __init__(self, container_id: str, *args, **kwargs):
|
def __init__(self, container_id: str):
|
||||||
super().__init__(container_id, *args, **kwargs)
|
super().__init__(container_id)
|
||||||
|
|
||||||
self.addMetaDataEntry("type", "extruder_train") # For backward compatibility
|
self.addMetaDataEntry("type", "extruder_train") # For backward compatibility
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ from .CuraContainerStack import CuraContainerStack
|
||||||
## Represents the Global or Machine stack and its related containers.
|
## Represents the Global or Machine stack and its related containers.
|
||||||
#
|
#
|
||||||
class GlobalStack(CuraContainerStack):
|
class GlobalStack(CuraContainerStack):
|
||||||
def __init__(self, container_id: str, *args, **kwargs):
|
def __init__(self, container_id: str):
|
||||||
super().__init__(container_id, *args, **kwargs)
|
super().__init__(container_id)
|
||||||
|
|
||||||
self.addMetaDataEntry("type", "machine") # For backward compatibility
|
self.addMetaDataEntry("type", "machine") # For backward compatibility
|
||||||
|
|
||||||
|
|
|
@ -1041,6 +1041,10 @@ class MachineManager(QObject):
|
||||||
self.activeQualityChangesGroupChanged.emit()
|
self.activeQualityChangesGroupChanged.emit()
|
||||||
|
|
||||||
def _setQualityGroup(self, quality_group, empty_quality_changes: bool = True) -> None:
|
def _setQualityGroup(self, quality_group, empty_quality_changes: bool = True) -> None:
|
||||||
|
if quality_group is None:
|
||||||
|
self._setEmptyQuality()
|
||||||
|
return
|
||||||
|
|
||||||
if quality_group.node_for_global.getContainer() is None:
|
if quality_group.node_for_global.getContainer() is None:
|
||||||
return
|
return
|
||||||
for node in quality_group.nodes_for_extruders.values():
|
for node in quality_group.nodes_for_extruders.values():
|
||||||
|
@ -1051,10 +1055,6 @@ class MachineManager(QObject):
|
||||||
if empty_quality_changes:
|
if empty_quality_changes:
|
||||||
self._current_quality_changes_group = None
|
self._current_quality_changes_group = None
|
||||||
|
|
||||||
if quality_group is None:
|
|
||||||
self._setEmptyQuality()
|
|
||||||
return
|
|
||||||
|
|
||||||
# Set quality and quality_changes for the GlobalStack
|
# Set quality and quality_changes for the GlobalStack
|
||||||
self._global_container_stack.quality = quality_group.node_for_global.getContainer()
|
self._global_container_stack.quality = quality_group.node_for_global.getContainer()
|
||||||
if empty_quality_changes:
|
if empty_quality_changes:
|
||||||
|
@ -1289,6 +1289,10 @@ class MachineManager(QObject):
|
||||||
self._global_container_stack.variant = self._empty_variant_container
|
self._global_container_stack.variant = self._empty_variant_container
|
||||||
self._updateQualityWithMaterial()
|
self._updateQualityWithMaterial()
|
||||||
|
|
||||||
|
# See if we need to show the Discard or Keep changes screen
|
||||||
|
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
|
||||||
|
self._application.discardOrKeepProfileChanges()
|
||||||
|
|
||||||
## Find all container stacks that has the pair 'key = value' in its metadata and replaces the value with 'new_value'
|
## Find all container stacks that has the pair 'key = value' in its metadata and replaces the value with 'new_value'
|
||||||
def replaceContainersMetadata(self, key: str, value: str, new_value: str) -> None:
|
def replaceContainersMetadata(self, key: str, value: str, new_value: str) -> None:
|
||||||
machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
|
machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
|
||||||
|
@ -1340,6 +1344,10 @@ class MachineManager(QObject):
|
||||||
self._setMaterial(position, container_node)
|
self._setMaterial(position, container_node)
|
||||||
self._updateQualityWithMaterial()
|
self._updateQualityWithMaterial()
|
||||||
|
|
||||||
|
# See if we need to show the Discard or Keep changes screen
|
||||||
|
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
|
||||||
|
self._application.discardOrKeepProfileChanges()
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def setVariantByName(self, position: str, variant_name: str) -> None:
|
def setVariantByName(self, position: str, variant_name: str) -> None:
|
||||||
machine_definition_id = self._global_container_stack.definition.id
|
machine_definition_id = self._global_container_stack.definition.id
|
||||||
|
@ -1355,6 +1363,10 @@ class MachineManager(QObject):
|
||||||
self._updateMaterialWithVariant(position)
|
self._updateMaterialWithVariant(position)
|
||||||
self._updateQualityWithMaterial()
|
self._updateQualityWithMaterial()
|
||||||
|
|
||||||
|
# See if we need to show the Discard or Keep changes screen
|
||||||
|
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
|
||||||
|
self._application.discardOrKeepProfileChanges()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def setQualityGroupByQualityType(self, quality_type: str) -> None:
|
def setQualityGroupByQualityType(self, quality_type: str) -> None:
|
||||||
if self._global_container_stack is None:
|
if self._global_container_stack is None:
|
||||||
|
|
|
@ -15,7 +15,6 @@ from UM.Math.Vector import Vector
|
||||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||||
from UM.Mesh.MeshReader import MeshReader
|
from UM.Mesh.MeshReader import MeshReader
|
||||||
from UM.Scene.GroupDecorator import GroupDecorator
|
from UM.Scene.GroupDecorator import GroupDecorator
|
||||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
|
||||||
|
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
@ -26,15 +25,6 @@ from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
||||||
|
|
||||||
MYPY = False
|
MYPY = False
|
||||||
|
|
||||||
|
|
||||||
MimeTypeDatabase.addMimeType(
|
|
||||||
MimeType(
|
|
||||||
name = "application/x-cura-project-file",
|
|
||||||
comment = "Cura Project File",
|
|
||||||
suffixes = ["curaproject.3mf"]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not MYPY:
|
if not MYPY:
|
||||||
import xml.etree.cElementTree as ET
|
import xml.etree.cElementTree as ET
|
||||||
|
|
|
@ -13,8 +13,24 @@ from . import ThreeMFWorkspaceReader
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Platform import Platform
|
from UM.Platform import Platform
|
||||||
|
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
MimeTypeDatabase.addMimeType(
|
||||||
|
MimeType(
|
||||||
|
name = "application/x-cura-project-file",
|
||||||
|
comment = "Cura Project File",
|
||||||
|
suffixes = ["curaproject.3mf"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
MimeTypeDatabase.addMimeType(
|
||||||
|
MimeType(
|
||||||
|
name = "application/x-cura-project-file",
|
||||||
|
comment = "Cura Project File",
|
||||||
|
suffixes = ["3mf"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def getMetaData() -> Dict:
|
def getMetaData() -> Dict:
|
||||||
# Workarround for osx not supporting double file extensions correctly.
|
# Workarround for osx not supporting double file extensions correctly.
|
||||||
if Platform.isOSX():
|
if Platform.isOSX():
|
||||||
|
|
|
@ -64,20 +64,25 @@ class FirmwareUpdateCheckerJob(Job):
|
||||||
if (checked_version != "") and (checked_version != current_version):
|
if (checked_version != "") and (checked_version != current_version):
|
||||||
Logger.log("i", "SHOWING FIRMWARE UPDATE MESSAGE")
|
Logger.log("i", "SHOWING FIRMWARE UPDATE MESSAGE")
|
||||||
|
|
||||||
footer_text = i18n_catalog.i18nc("@action:info", "Read more on how to update printer firmware")
|
|
||||||
footer_link = "?url=https://ultimaker.com/en/resources/23129-updating-the-firmware?utm_source=cura&utm_medium=software&utm_campaign=hw-update"
|
|
||||||
|
|
||||||
footer_message = footer_text + " " + footer_link
|
|
||||||
|
|
||||||
message = Message(i18n_catalog.i18nc(
|
message = Message(i18n_catalog.i18nc(
|
||||||
"@info Don't translate {machine_name}, since it gets replaced by a printer name!",
|
"@info Don't translate {machine_name}, since it gets replaced by a printer name!",
|
||||||
"New features are available for your {machine_name}! It is recommended to update the firmware on your printer.").format(
|
"New features are available for your {machine_name}! It is recommended to update the firmware on your printer.").format(
|
||||||
machine_name=machine_name),
|
machine_name=machine_name),
|
||||||
title=i18n_catalog.i18nc(
|
title=i18n_catalog.i18nc(
|
||||||
"@info:title The %s gets replaced with the printer name.",
|
"@info:title The %s gets replaced with the printer name.",
|
||||||
"New %s firmware available") % machine_name,
|
"New %s firmware available") % machine_name)
|
||||||
footer = footer_message)
|
|
||||||
|
|
||||||
|
message.addAction("download",
|
||||||
|
i18n_catalog.i18nc("@action:button", "How to update"),
|
||||||
|
"[no_icon]",
|
||||||
|
"[no_description]",
|
||||||
|
button_style=Message.ActionButtonStyle.LINK,
|
||||||
|
button_align=Message.ActionButtonStyle.BUTTON_ALIGN_LEFT)
|
||||||
|
|
||||||
|
|
||||||
|
# If we do this in a cool way, the download url should be available in the JSON file
|
||||||
|
if self._set_download_url_callback:
|
||||||
|
self._set_download_url_callback("https://ultimaker.com/en/resources/20500-upgrade-firmware")
|
||||||
message.actionTriggered.connect(self._callback)
|
message.actionTriggered.connect(self._callback)
|
||||||
message.show()
|
message.show()
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,11 @@ class SliceInfo(QObject, Extension):
|
||||||
dismissable = False,
|
dismissable = False,
|
||||||
title = catalog.i18nc("@info:title", "Collecting Data"))
|
title = catalog.i18nc("@info:title", "Collecting Data"))
|
||||||
|
|
||||||
self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = None,
|
|
||||||
description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing."))
|
|
||||||
self.send_slice_info_message.addAction("MoreInfo", name = catalog.i18nc("@action:button", "More info"), icon = None,
|
self.send_slice_info_message.addAction("MoreInfo", name = catalog.i18nc("@action:button", "More info"), icon = None,
|
||||||
description = catalog.i18nc("@action:tooltip", "See more information on what data Cura sends."), button_style = Message.ActionButtonStyle.LINK)
|
description = catalog.i18nc("@action:tooltip", "See more information on what data Cura sends."), button_style = Message.ActionButtonStyle.LINK)
|
||||||
|
|
||||||
|
self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = None,
|
||||||
|
description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing."))
|
||||||
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
|
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
|
||||||
self.send_slice_info_message.show()
|
self.send_slice_info_message.show()
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,9 @@ Item
|
||||||
frameVisible: false
|
frameVisible: false
|
||||||
selectionMode: 0
|
selectionMode: 0
|
||||||
model: packageData.supported_configs
|
model: packageData.supported_configs
|
||||||
headerDelegate: Item
|
headerDelegate: Rectangle
|
||||||
{
|
{
|
||||||
|
color: UM.Theme.getColor("sidebar")
|
||||||
height: UM.Theme.getSize("toolbox_chart_row").height
|
height: UM.Theme.getSize("toolbox_chart_row").height
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,7 @@ Column
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: UM.Theme.getSize("default_margin").height
|
spacing: UM.Theme.getSize("default_margin").height
|
||||||
|
/* Hidden for 3.4
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: heading
|
id: heading
|
||||||
|
@ -20,6 +21,7 @@ Column
|
||||||
color: UM.Theme.getColor("text_medium")
|
color: UM.Theme.getColor("text_medium")
|
||||||
font: UM.Theme.getFont("medium")
|
font: UM.Theme.getFont("medium")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
GridLayout
|
GridLayout
|
||||||
{
|
{
|
||||||
id: grid
|
id: grid
|
||||||
|
|
|
@ -18,6 +18,8 @@ ScrollView
|
||||||
spacing: UM.Theme.getSize("default_margin").height
|
spacing: UM.Theme.getSize("default_margin").height
|
||||||
padding: UM.Theme.getSize("wide_margin").height
|
padding: UM.Theme.getSize("wide_margin").height
|
||||||
height: childrenRect.height + 2 * padding
|
height: childrenRect.height + 2 * padding
|
||||||
|
|
||||||
|
/* Hide for 3.4
|
||||||
ToolboxDownloadsShowcase
|
ToolboxDownloadsShowcase
|
||||||
{
|
{
|
||||||
id: showcase
|
id: showcase
|
||||||
|
@ -29,6 +31,8 @@ ScrollView
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: UM.Theme.getSize("default_lining").height
|
height: UM.Theme.getSize("default_lining").height
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
ToolboxDownloadsGrid
|
ToolboxDownloadsGrid
|
||||||
{
|
{
|
||||||
id: allPlugins
|
id: allPlugins
|
||||||
|
|
|
@ -33,6 +33,8 @@ Item
|
||||||
toolbox.viewPage = "overview"
|
toolbox.viewPage = "overview"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hide for 3.4
|
||||||
ToolboxTabButton
|
ToolboxTabButton
|
||||||
{
|
{
|
||||||
text: catalog.i18nc("@title:tab", "Materials")
|
text: catalog.i18nc("@title:tab", "Materials")
|
||||||
|
@ -45,6 +47,7 @@ Item
|
||||||
toolbox.viewPage = "overview"
|
toolbox.viewPage = "overview"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
ToolboxTabButton
|
ToolboxTabButton
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,6 +65,7 @@ ScrollView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Hidden in 3.4
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
visible: toolbox.materialsInstalledModel.items.length > 0
|
visible: toolbox.materialsInstalledModel.items.length > 0
|
||||||
|
@ -102,5 +103,6 @@ ScrollView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ Item
|
||||||
{
|
{
|
||||||
color: UM.Theme.getColor("lining")
|
color: UM.Theme.getColor("lining")
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: UM.Theme.getSize("default_lining").height
|
height: Math.floor(UM.Theme.getSize("default_lining").height)
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
}
|
}
|
||||||
Row
|
Row
|
||||||
|
@ -40,14 +40,14 @@ Item
|
||||||
Column
|
Column
|
||||||
{
|
{
|
||||||
id: pluginInfo
|
id: pluginInfo
|
||||||
topPadding: UM.Theme.getSize("default_margin").height / 2
|
topPadding: Math.floor(UM.Theme.getSize("default_margin").height / 2)
|
||||||
property var color: model.type === "plugin" && !isEnabled ? UM.Theme.getColor("lining") : UM.Theme.getColor("text")
|
property var color: model.type === "plugin" && !isEnabled ? UM.Theme.getColor("lining") : UM.Theme.getColor("text")
|
||||||
width: tileRow.width - (authorInfo.width + pluginActions.width + 2 * tileRow.spacing + ((disableButton.visible) ? disableButton.width + tileRow.spacing : 0))
|
width: Math.floor(tileRow.width - (authorInfo.width + pluginActions.width + 2 * tileRow.spacing + ((disableButton.visible) ? disableButton.width + tileRow.spacing : 0)))
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
text: model.name
|
text: model.name
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: UM.Theme.getSize("toolbox_property_label").height
|
height: Math.floor(UM.Theme.getSize("toolbox_property_label").height)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
font: UM.Theme.getFont("default_bold")
|
font: UM.Theme.getFont("default_bold")
|
||||||
color: pluginInfo.color
|
color: pluginInfo.color
|
||||||
|
@ -81,7 +81,7 @@ Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: UM.Theme.getSize("toolbox_property_label").height
|
height: Math.floor(UM.Theme.getSize("toolbox_property_label").height)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
|
|
@ -13,6 +13,16 @@ Column
|
||||||
width: UM.Theme.getSize("toolbox_action_button").width
|
width: UM.Theme.getSize("toolbox_action_button").width
|
||||||
spacing: UM.Theme.getSize("narrow_margin").height
|
spacing: UM.Theme.getSize("narrow_margin").height
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
visible: !model.is_installed
|
||||||
|
text: catalog.i18nc("@label", "Will install upon restarting")
|
||||||
|
color: UM.Theme.getColor("lining")
|
||||||
|
font: UM.Theme.getFont("default")
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
ToolboxProgressButton
|
ToolboxProgressButton
|
||||||
{
|
{
|
||||||
id: updateButton
|
id: updateButton
|
||||||
|
@ -39,7 +49,7 @@ Column
|
||||||
{
|
{
|
||||||
id: removeButton
|
id: removeButton
|
||||||
text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall")
|
text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall")
|
||||||
visible: !model.is_bundled
|
visible: !model.is_bundled && model.is_installed
|
||||||
enabled: !toolbox.isDownloading
|
enabled: !toolbox.isDownloading
|
||||||
style: ButtonStyle
|
style: ButtonStyle
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,7 +150,7 @@ Item
|
||||||
{
|
{
|
||||||
id: loader
|
id: loader
|
||||||
visible: active
|
visible: active
|
||||||
source: "../images/loading.gif"
|
source: visible ? "../images/loading.gif" : ""
|
||||||
width: UM.Theme.getSize("toolbox_loader").width
|
width: UM.Theme.getSize("toolbox_loader").width
|
||||||
height: UM.Theme.getSize("toolbox_loader").height
|
height: UM.Theme.getSize("toolbox_loader").height
|
||||||
anchors.right: button.left
|
anchors.right: button.left
|
||||||
|
|
|
@ -29,8 +29,9 @@ class PackagesModel(ListModel):
|
||||||
self.addRoleName(Qt.UserRole + 12, "last_updated")
|
self.addRoleName(Qt.UserRole + 12, "last_updated")
|
||||||
self.addRoleName(Qt.UserRole + 13, "is_bundled")
|
self.addRoleName(Qt.UserRole + 13, "is_bundled")
|
||||||
self.addRoleName(Qt.UserRole + 14, "is_enabled")
|
self.addRoleName(Qt.UserRole + 14, "is_enabled")
|
||||||
self.addRoleName(Qt.UserRole + 15, "has_configs")
|
self.addRoleName(Qt.UserRole + 15, "is_installed") # Scheduled pkgs are included in the model but should not be marked as actually installed
|
||||||
self.addRoleName(Qt.UserRole + 16, "supported_configs")
|
self.addRoleName(Qt.UserRole + 16, "has_configs")
|
||||||
|
self.addRoleName(Qt.UserRole + 17, "supported_configs")
|
||||||
|
|
||||||
# List of filters for queries. The result is the union of the each list of results.
|
# List of filters for queries. The result is the union of the each list of results.
|
||||||
self._filter = {} # type: Dict[str, str]
|
self._filter = {} # type: Dict[str, str]
|
||||||
|
@ -73,6 +74,7 @@ class PackagesModel(ListModel):
|
||||||
"last_updated": package["last_updated"] if "last_updated" in package else None,
|
"last_updated": package["last_updated"] if "last_updated" in package else None,
|
||||||
"is_bundled": package["is_bundled"] if "is_bundled" in package else False,
|
"is_bundled": package["is_bundled"] if "is_bundled" in package else False,
|
||||||
"is_enabled": package["is_enabled"] if "is_enabled" in package else False,
|
"is_enabled": package["is_enabled"] if "is_enabled" in package else False,
|
||||||
|
"is_installed": package["is_installed"] if "is_installed" in package else False,
|
||||||
"has_configs": has_configs,
|
"has_configs": has_configs,
|
||||||
"supported_configs": configs_model
|
"supported_configs": configs_model
|
||||||
})
|
})
|
||||||
|
|
|
@ -28,7 +28,8 @@ i18n_catalog = i18nCatalog("cura")
|
||||||
## The Toolbox class is responsible of communicating with the server through the API
|
## The Toolbox class is responsible of communicating with the server through the API
|
||||||
class Toolbox(QObject, Extension):
|
class Toolbox(QObject, Extension):
|
||||||
|
|
||||||
DEFAULT_PACKAGES_API_ROOT = "https://api.ultimaker.com"
|
DEFAULT_CLOUD_API_ROOT = "https://api.ultimaker.com"
|
||||||
|
DEFAULT_CLOUD_API_VERSION = 1
|
||||||
|
|
||||||
def __init__(self, parent=None) -> None:
|
def __init__(self, parent=None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
@ -37,16 +38,10 @@ class Toolbox(QObject, Extension):
|
||||||
self._package_manager = None
|
self._package_manager = None
|
||||||
self._plugin_registry = Application.getInstance().getPluginRegistry()
|
self._plugin_registry = Application.getInstance().getPluginRegistry()
|
||||||
|
|
||||||
self._sdk_version = self._getPackagesVersion()
|
self._sdk_version = None
|
||||||
|
self._cloud_api_version = None
|
||||||
self._cloud_api_version = 1
|
self._cloud_api_root = None
|
||||||
self._cloud_api_root = self._getPackagesApiRoot()
|
self._api_url = None
|
||||||
|
|
||||||
self._api_url = "{cloud_api_root}/cura-packages/v{cloud_api_version}/cura/v{sdk_version}".format(
|
|
||||||
cloud_api_root = self._cloud_api_root,
|
|
||||||
cloud_api_version = self._cloud_api_version,
|
|
||||||
sdk_version = self._sdk_version
|
|
||||||
)
|
|
||||||
|
|
||||||
# Network:
|
# Network:
|
||||||
self._get_packages_request = None
|
self._get_packages_request = None
|
||||||
|
@ -67,12 +62,7 @@ class Toolbox(QObject, Extension):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
self._request_urls = {
|
self._request_urls = {}
|
||||||
"authors": QUrl("{base_url}/authors".format(base_url = self._api_url)),
|
|
||||||
"packages": QUrl("{base_url}/packages".format(base_url = self._api_url)),
|
|
||||||
"plugins_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)),
|
|
||||||
"materials_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url))
|
|
||||||
}
|
|
||||||
self._to_update = [] # Package_ids that are waiting to be updated
|
self._to_update = [] # Package_ids that are waiting to be updated
|
||||||
|
|
||||||
# Data:
|
# Data:
|
||||||
|
@ -164,22 +154,50 @@ class Toolbox(QObject, Extension):
|
||||||
# this is initialized. Therefore, we wait until the application is ready.
|
# this is initialized. Therefore, we wait until the application is ready.
|
||||||
def _onAppInitialized(self) -> None:
|
def _onAppInitialized(self) -> None:
|
||||||
self._package_manager = Application.getInstance().getCuraPackageManager()
|
self._package_manager = Application.getInstance().getCuraPackageManager()
|
||||||
|
self._sdk_version = self._getSDKVersion()
|
||||||
|
self._cloud_api_version = self._getCloudAPIVersion()
|
||||||
|
self._cloud_api_root = self._getCloudAPIRoot()
|
||||||
|
self._api_url = "{cloud_api_root}/cura-packages/v{cloud_api_version}/cura/v{sdk_version}".format(
|
||||||
|
cloud_api_root=self._cloud_api_root,
|
||||||
|
cloud_api_version=self._cloud_api_version,
|
||||||
|
sdk_version=self._sdk_version
|
||||||
|
)
|
||||||
|
self._request_urls = {
|
||||||
|
"authors": QUrl("{base_url}/authors".format(base_url=self._api_url)),
|
||||||
|
"packages": QUrl("{base_url}/packages".format(base_url=self._api_url)),
|
||||||
|
"plugins_showcase": QUrl("{base_url}/showcase".format(base_url=self._api_url)),
|
||||||
|
"materials_showcase": QUrl("{base_url}/showcase".format(base_url=self._api_url))
|
||||||
|
}
|
||||||
|
|
||||||
# Get the API root for the packages API depending on Cura version settings.
|
# Get the API root for the packages API depending on Cura version settings.
|
||||||
def _getPackagesApiRoot(self) -> str:
|
def _getCloudAPIRoot(self) -> str:
|
||||||
if not hasattr(cura, "CuraVersion"):
|
if not hasattr(cura, "CuraVersion"):
|
||||||
return self.DEFAULT_PACKAGES_API_ROOT
|
return self.DEFAULT_CLOUD_API_ROOT
|
||||||
if not hasattr(cura.CuraVersion, "CuraPackagesApiRoot"):
|
if not hasattr(cura.CuraVersion, "CuraCloudAPIRoot"):
|
||||||
return self.DEFAULT_PACKAGES_API_ROOT
|
return self.DEFAULT_CLOUD_API_ROOT
|
||||||
return cura.CuraVersion.CuraPackagesApiRoot
|
if not cura.CuraVersion.CuraCloudAPIRoot:
|
||||||
|
return self.DEFAULT_CLOUD_API_ROOT
|
||||||
|
return cura.CuraVersion.CuraCloudAPIRoot
|
||||||
|
|
||||||
|
# Get the cloud API version from CuraVersion
|
||||||
|
def _getCloudAPIVersion(self) -> int:
|
||||||
|
if not hasattr(cura, "CuraVersion"):
|
||||||
|
return self.DEFAULT_CLOUD_API_VERSION
|
||||||
|
if not hasattr(cura.CuraVersion, "CuraCloudAPIVersion"):
|
||||||
|
return self.DEFAULT_CLOUD_API_VERSION
|
||||||
|
if not cura.CuraVersion.CuraCloudAPIVersion:
|
||||||
|
return self.DEFAULT_CLOUD_API_VERSION
|
||||||
|
return cura.CuraVersion.CuraCloudAPIVersion
|
||||||
|
|
||||||
# Get the packages version depending on Cura version settings.
|
# Get the packages version depending on Cura version settings.
|
||||||
def _getPackagesVersion(self) -> int:
|
def _getSDKVersion(self) -> int:
|
||||||
if not hasattr(cura, "CuraVersion"):
|
if not hasattr(cura, "CuraVersion"):
|
||||||
return self._plugin_registry.APIVersion
|
return self._plugin_registry.APIVersion
|
||||||
if not hasattr(cura.CuraVersion, "CuraPackagesVersion"):
|
if not hasattr(cura.CuraVersion, "CuraSDKVersion"):
|
||||||
return self._plugin_registry.APIVersion
|
return self._plugin_registry.APIVersion
|
||||||
return cura.CuraVersion.CuraPackagesVersion
|
if not cura.CuraVersion.CuraSDKVersion:
|
||||||
|
return self._plugin_registry.APIVersion
|
||||||
|
return cura.CuraVersion.CuraSDKVersion
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def browsePackages(self) -> None:
|
def browsePackages(self) -> None:
|
||||||
|
|
|
@ -6,6 +6,9 @@ import io #To serialise the preference files afterwards.
|
||||||
|
|
||||||
from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this.
|
from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this.
|
||||||
|
|
||||||
|
_renamed_settings = {
|
||||||
|
"infill_hollow": "infill_support_enabled"
|
||||||
|
}
|
||||||
|
|
||||||
## Upgrades configurations from the state they were in at version 3.3 to the
|
## Upgrades configurations from the state they were in at version 3.3 to the
|
||||||
# state they should be in at version 3.4.
|
# state they should be in at version 3.4.
|
||||||
|
@ -38,6 +41,17 @@ class VersionUpgrade33to34(VersionUpgrade):
|
||||||
# Update version number.
|
# Update version number.
|
||||||
parser["general"]["version"] = "4"
|
parser["general"]["version"] = "4"
|
||||||
|
|
||||||
|
if "values" in parser:
|
||||||
|
#If infill_hollow was enabled and the overhang angle was adjusted, copy that overhang angle to the new infill support angle.
|
||||||
|
if "infill_hollow" in parser["values"] and parser["values"]["infill_hollow"] and "support_angle" in parser["values"]:
|
||||||
|
parser["values"]["infill_support_angle"] = parser["values"]["support_angle"]
|
||||||
|
|
||||||
|
#Renamed settings.
|
||||||
|
for original, replacement in _renamed_settings.items():
|
||||||
|
if original in parser["values"]:
|
||||||
|
parser["values"][replacement] = parser["values"][original]
|
||||||
|
del parser["values"][original]
|
||||||
|
|
||||||
result = io.StringIO()
|
result = io.StringIO()
|
||||||
parser.write(result)
|
parser.write(result)
|
||||||
return [filename], [result.getvalue()]
|
return [filename], [result.getvalue()]
|
|
@ -1807,6 +1807,30 @@
|
||||||
"limit_to_extruder": "infill_extruder_nr",
|
"limit_to_extruder": "infill_extruder_nr",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
|
"infill_support_enabled":
|
||||||
|
{
|
||||||
|
"label": "Infill Support",
|
||||||
|
"description": "Print infill structures only where tops of the model should be supported. Enabling this reduces print time and material usage, but leads to ununiform object strength.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"enabled": "infill_sparse_density > 0",
|
||||||
|
"limit_to_extruder": "infill_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
|
"infill_support_angle":
|
||||||
|
{
|
||||||
|
"label": "Infill Overhang Angle",
|
||||||
|
"description": "The minimum angle of internal overhangs for which infill is added. At a value of 0° objects are totally filled with infill, 90° will not provide any infill.",
|
||||||
|
"unit": "°",
|
||||||
|
"type": "float",
|
||||||
|
"minimum_value": "0",
|
||||||
|
"minimum_value_warning": "2",
|
||||||
|
"maximum_value": "90",
|
||||||
|
"default_value": 40,
|
||||||
|
"enabled": "infill_sparse_density > 0 and infill_support_enabled",
|
||||||
|
"limit_to_extruder": "infill_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
"skin_preshrink":
|
"skin_preshrink":
|
||||||
{
|
{
|
||||||
"label": "Skin Removal Width",
|
"label": "Skin Removal Width",
|
||||||
|
@ -5788,7 +5812,7 @@
|
||||||
"description": "The file location of an image of which the brightness values determine the minimal density at the corresponding location in the support.",
|
"description": "The file location of an image of which the brightness values determine the minimal density at the corresponding location in the support.",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"default_value": "",
|
"default_value": "",
|
||||||
"enabled": "infill_pattern == 'cross' or infill_pattern == 'cross_3d'",
|
"enabled": "support_pattern == 'cross' or support_pattern == 'cross_3d'",
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
|
@ -5918,14 +5942,6 @@
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
"infill_hollow":
|
|
||||||
{
|
|
||||||
"label": "Hollow Out Objects",
|
|
||||||
"description": "Remove all infill and make the inside of the object eligible for support.",
|
|
||||||
"type": "bool",
|
|
||||||
"default_value": false,
|
|
||||||
"settable_per_mesh": true
|
|
||||||
},
|
|
||||||
"magic_fuzzy_skin_enabled":
|
"magic_fuzzy_skin_enabled":
|
||||||
{
|
{
|
||||||
"label": "Fuzzy Skin",
|
"label": "Fuzzy Skin",
|
||||||
|
@ -6662,14 +6678,6 @@
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"enabled": "bridge_settings_enabled and bridge_enable_more_layers",
|
"enabled": "bridge_settings_enabled and bridge_enable_more_layers",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
|
||||||
"wall_try_line_thickness":
|
|
||||||
{
|
|
||||||
"label": "Try Multiple Line Thicknesses",
|
|
||||||
"description": "When creating inner walls, try various line thicknesses to fit the wall lines better in narrow spaces. This reduces or increases the inner wall line width by up to 0.01mm.",
|
|
||||||
"default_value": false,
|
|
||||||
"type": "bool",
|
|
||||||
"settable_per_mesh": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -323,10 +323,11 @@ UM.MainWindow
|
||||||
{
|
{
|
||||||
if (drop.urls.length > 0)
|
if (drop.urls.length > 0)
|
||||||
{
|
{
|
||||||
// As the drop area also supports plugins, first check if it's a plugin that was dropped.
|
|
||||||
if (drop.urls.length == 1)
|
var nonPackages = [];
|
||||||
|
for (var i = 0; i < drop.urls.length; i++)
|
||||||
{
|
{
|
||||||
var filename = drop.urls[0];
|
var filename = drop.urls[i];
|
||||||
if (filename.endsWith(".curapackage"))
|
if (filename.endsWith(".curapackage"))
|
||||||
{
|
{
|
||||||
// Try to install plugin & close.
|
// Try to install plugin & close.
|
||||||
|
@ -334,11 +335,13 @@ UM.MainWindow
|
||||||
packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting.");
|
packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting.");
|
||||||
packageInstallDialog.icon = StandardIcon.Information;
|
packageInstallDialog.icon = StandardIcon.Information;
|
||||||
packageInstallDialog.open();
|
packageInstallDialog.open();
|
||||||
return;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nonPackages.push(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
openDialog.handleOpenFileUrls(nonPackages);
|
||||||
openDialog.handleOpenFileUrls(drop.urls);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,9 @@ Item {
|
||||||
text: PrintInformation.jobName
|
text: PrintInformation.jobName
|
||||||
horizontalAlignment: TextInput.AlignRight
|
horizontalAlignment: TextInput.AlignRight
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
PrintInformation.setJobName(text, true);
|
text = text == "" ? "unnamed" : text;
|
||||||
if (printJobTextfield.text != ''){
|
PrintInformation.setJobName(printJobTextfield.text, true);
|
||||||
printJobTextfield.focus = false;
|
printJobTextfield.focus = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
validator: RegExpValidator {
|
validator: RegExpValidator {
|
||||||
regExp: /^[^\\ \/ \*\?\|\[\]]*$/
|
regExp: /^[^\\ \/ \*\?\|\[\]]*$/
|
||||||
|
|
|
@ -92,6 +92,7 @@ Rectangle
|
||||||
anchors.verticalCenter: buildplateIcon.verticalCenter
|
anchors.verticalCenter: buildplateIcon.verticalCenter
|
||||||
anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2)
|
anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2)
|
||||||
text: configuration.buildplateConfiguration
|
text: configuration.buildplateConfiguration
|
||||||
|
renderType: Text.NativeRendering
|
||||||
color: textColor
|
color: textColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ Column
|
||||||
{
|
{
|
||||||
id: extruderLabel
|
id: extruderLabel
|
||||||
text: catalog.i18nc("@label:extruder label", "Extruder")
|
text: catalog.i18nc("@label:extruder label", "Extruder")
|
||||||
|
renderType: Text.NativeRendering
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
|
@ -59,6 +60,7 @@ Column
|
||||||
id: extruderNumberText
|
id: extruderNumberText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: printCoreConfiguration.position + 1
|
text: printCoreConfiguration.position + 1
|
||||||
|
renderType: Text.NativeRendering
|
||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
color: mainColor
|
color: mainColor
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,7 @@ Column
|
||||||
{
|
{
|
||||||
id: materialLabel
|
id: materialLabel
|
||||||
text: printCoreConfiguration.material.name
|
text: printCoreConfiguration.material.name
|
||||||
|
renderType: Text.NativeRendering
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
width: parent.width
|
width: parent.width
|
||||||
font: UM.Theme.getFont("default_bold")
|
font: UM.Theme.getFont("default_bold")
|
||||||
|
@ -79,6 +82,7 @@ Column
|
||||||
{
|
{
|
||||||
id: printCoreTypeLabel
|
id: printCoreTypeLabel
|
||||||
text: printCoreConfiguration.hotendID
|
text: printCoreConfiguration.hotendID
|
||||||
|
renderType: Text.NativeRendering
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
width: parent.width
|
width: parent.width
|
||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
|
|
|
@ -13,7 +13,7 @@ Button
|
||||||
id: base
|
id: base
|
||||||
property var outputDevice: null
|
property var outputDevice: null
|
||||||
property var matched: updateOnSync()
|
property var matched: updateOnSync()
|
||||||
text: matched == true ? "Yes" : "No"
|
text: matched == true ? catalog.i18nc("@label:extruder label", "Yes") : catalog.i18nc("@label:extruder label", "No")
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,7 @@ Menu
|
||||||
exclusiveGroup: group
|
exclusiveGroup: group
|
||||||
onTriggered:
|
onTriggered:
|
||||||
{
|
{
|
||||||
var activeExtruderIndex = Cura.ExtruderManager.activeExtruderIndex;
|
Cura.MachineManager.setMaterial(extruderIndex, model.container_node);
|
||||||
Cura.MachineManager.setMaterial(activeExtruderIndex, model.container_node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onObjectAdded: brandMaterialsMenu.insertItem(index, object)
|
onObjectAdded: brandMaterialsMenu.insertItem(index, object)
|
||||||
|
|
|
@ -100,8 +100,8 @@ Item {
|
||||||
if (saveToButton.enabled) {
|
if (saveToButton.enabled) {
|
||||||
saveToButton.clicked();
|
saveToButton.clicked();
|
||||||
}
|
}
|
||||||
// prepare button
|
// slice button
|
||||||
if (prepareButton.enabled) {
|
if (sliceButton.enabled) {
|
||||||
sliceOrStopSlicing();
|
sliceOrStopSlicing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ Item {
|
||||||
Row {
|
Row {
|
||||||
id: additionalComponentsRow
|
id: additionalComponentsRow
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: saveToButton.visible ? saveToButton.left : (prepareButton.visible ? prepareButton.left : parent.right)
|
anchors.right: saveToButton.visible ? saveToButton.left : (sliceButton.visible ? sliceButton.left : parent.right)
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
|
||||||
spacing: UM.Theme.getSize("default_margin").width
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
|
@ -159,14 +159,14 @@ Item {
|
||||||
onPreferenceChanged:
|
onPreferenceChanged:
|
||||||
{
|
{
|
||||||
var autoSlice = UM.Preferences.getValue("general/auto_slice");
|
var autoSlice = UM.Preferences.getValue("general/auto_slice");
|
||||||
prepareButton.autoSlice = autoSlice;
|
sliceButton.autoSlice = autoSlice;
|
||||||
saveToButton.autoSlice = autoSlice;
|
saveToButton.autoSlice = autoSlice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare button, only shows if auto_slice is off
|
// Slice button, only shows if auto_slice is off
|
||||||
Button {
|
Button {
|
||||||
id: prepareButton
|
id: sliceButton
|
||||||
|
|
||||||
tooltip: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
|
tooltip: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
|
||||||
// 1 = not started, 2 = Processing
|
// 1 = not started, 2 = Processing
|
||||||
|
@ -180,7 +180,7 @@ Item {
|
||||||
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
|
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
|
|
||||||
// 1 = not started, 4 = error, 5 = disabled
|
// 1 = not started, 4 = error, 5 = disabled
|
||||||
text: [1, 4, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel")
|
text: [1, 4, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@label:Printjob", "Slice") : catalog.i18nc("@label:Printjob", "Cancel")
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
sliceOrStopSlicing();
|
sliceOrStopSlicing();
|
||||||
|
|
|
@ -87,6 +87,7 @@ gradual_infill_steps
|
||||||
gradual_infill_step_height
|
gradual_infill_step_height
|
||||||
infill_before_walls
|
infill_before_walls
|
||||||
min_infill_area
|
min_infill_area
|
||||||
|
infill_support_enabled
|
||||||
skin_preshrink
|
skin_preshrink
|
||||||
top_skin_preshrink
|
top_skin_preshrink
|
||||||
bottom_skin_preshrink
|
bottom_skin_preshrink
|
||||||
|
@ -369,7 +370,6 @@ spaghetti_infill_extra_volume
|
||||||
support_conical_enabled
|
support_conical_enabled
|
||||||
support_conical_angle
|
support_conical_angle
|
||||||
support_conical_min_width
|
support_conical_min_width
|
||||||
infill_hollow
|
|
||||||
magic_fuzzy_skin_enabled
|
magic_fuzzy_skin_enabled
|
||||||
magic_fuzzy_skin_thickness
|
magic_fuzzy_skin_thickness
|
||||||
magic_fuzzy_skin_point_density
|
magic_fuzzy_skin_point_density
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue