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_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(cura/CuraVersion.py.in CuraVersion.py @ONLY)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Logger import Logger
|
||||
from UM.Math.Polygon import Polygon
|
||||
from UM.Math.Vector import Vector
|
||||
from cura.Arranging.ShapeArray import ShapeArray
|
||||
from cura.Scene import ZOffsetDecorator
|
||||
|
@ -45,7 +46,7 @@ class Arrange:
|
|||
# \param scene_root Root for finding all scene nodes
|
||||
# \param fixed_nodes Scene nodes to be placed
|
||||
@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.centerFirst()
|
||||
|
||||
|
@ -58,9 +59,10 @@ class Arrange:
|
|||
|
||||
# Place all objects 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:
|
||||
continue
|
||||
vertices = vertices.getMinkowskiHull(Polygon.approximatedCircle(min_offset))
|
||||
points = copy.deepcopy(vertices._points)
|
||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||
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)
|
||||
# return the nodes that should be placed
|
||||
# \param node
|
||||
# \param offset_shape_arr ShapeArray with offset, used to find location
|
||||
# \param hull_shape_arr ShapeArray without offset, for placing the shape
|
||||
# \param offset_shape_arr ShapeArray with 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):
|
||||
new_node = copy.deepcopy(node)
|
||||
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
|
||||
|
||||
# Save the last priority.
|
||||
|
@ -102,7 +104,7 @@ class Arrange:
|
|||
if x is not None: # We could find a place
|
||||
new_node.setPosition(Vector(x, center_y, y))
|
||||
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:
|
||||
Logger.log("d", "Could not find spot!"),
|
||||
found_spot = False
|
||||
|
|
|
@ -110,7 +110,7 @@ class ArrangeObjectsAllBuildPlatesJob(Job):
|
|||
arrange_array.add()
|
||||
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
|
||||
node.removeDecorator(ZOffsetDecorator)
|
||||
if node.getBoundingBox():
|
||||
|
@ -118,7 +118,7 @@ class ArrangeObjectsAllBuildPlatesJob(Job):
|
|||
else:
|
||||
center_y = 0
|
||||
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)
|
||||
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_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
|
||||
nodes_arr = [] # fill with (size, node, offset_shape_arr, hull_shape_arr)
|
||||
for node in self._nodes:
|
||||
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))
|
||||
|
||||
# Sort the nodes with the biggest area first.
|
||||
|
@ -63,7 +66,7 @@ class ArrangeObjectsJob(Job):
|
|||
start_priority = last_priority
|
||||
else:
|
||||
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
|
||||
node.removeDecorator(ZOffsetDecorator)
|
||||
if node.getBoundingBox():
|
||||
|
@ -74,7 +77,7 @@ class ArrangeObjectsJob(Job):
|
|||
last_size = size
|
||||
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))
|
||||
else:
|
||||
Logger.log("d", "Arrange all: could not find spot!")
|
||||
|
|
|
@ -452,7 +452,7 @@ class CuraApplication(QtApplication):
|
|||
|
||||
## 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 = []):
|
||||
self._message_box_callback = callback
|
||||
|
@ -1500,11 +1500,15 @@ class CuraApplication(QtApplication):
|
|||
|
||||
def _reloadMeshFinished(self, job):
|
||||
# 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()
|
||||
if mesh_data:
|
||||
job._node.setMeshData(mesh_data)
|
||||
else:
|
||||
job_result = job.getResult()
|
||||
if len(job_result) == 0:
|
||||
Logger.log("e", "Reloading the mesh failed.")
|
||||
return
|
||||
mesh_data = job_result[0].getMeshData()
|
||||
if not mesh_data:
|
||||
Logger.log("w", "Could not find a mesh in reloaded node.")
|
||||
return
|
||||
job._node.setMeshData(mesh_data)
|
||||
|
||||
def _openFile(self, filename):
|
||||
self.readLocalFile(QUrl.fromLocalFile(filename))
|
||||
|
@ -1568,10 +1572,11 @@ class CuraApplication(QtApplication):
|
|||
|
||||
f = file.toLocalFile()
|
||||
extension = os.path.splitext(f)[1]
|
||||
extension = extension.lower()
|
||||
filename = os.path.basename(f)
|
||||
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 extension.lower() in self._non_sliceable_extensions:
|
||||
if extension in self._non_sliceable_extensions:
|
||||
message = Message(
|
||||
self._i18n_catalog.i18nc("@info:status",
|
||||
"Only one G-code file can be loaded at a time. Skipped importing {0}",
|
||||
|
@ -1580,7 +1585,8 @@ class CuraApplication(QtApplication):
|
|||
return
|
||||
# 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]
|
||||
if extension.lower() in self._non_sliceable_extensions:
|
||||
extension = extension.lower()
|
||||
if extension in self._non_sliceable_extensions:
|
||||
message = Message(
|
||||
self._i18n_catalog.i18nc("@info:status",
|
||||
"Can't open any other file if G-code is loading. Skipped importing {0}",
|
||||
|
|
|
@ -158,14 +158,17 @@ class CuraPackageManager(QObject):
|
|||
# Add bundled plugins
|
||||
if package_id in self._bundled_package_dict:
|
||||
package_info = self._bundled_package_dict[package_id]["package_info"]
|
||||
package_info["is_installed"] = True
|
||||
|
||||
# Add installed plugins
|
||||
if package_id in self._installed_package_dict:
|
||||
package_info = self._installed_package_dict[package_id]["package_info"]
|
||||
package_info["is_installed"] = True
|
||||
|
||||
# Add to install plugins
|
||||
if package_id in self._to_install_package_dict:
|
||||
package_info = self._to_install_package_dict[package_id]["package_info"]
|
||||
package_info["is_installed"] = False
|
||||
|
||||
if package_info is None:
|
||||
continue
|
||||
|
|
|
@ -4,4 +4,6 @@
|
|||
CuraVersion = "@CURA_VERSION@"
|
||||
CuraBuildType = "@CURA_BUILDTYPE@"
|
||||
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()
|
||||
for node in nodes_to_check:
|
||||
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():
|
||||
fallback_id = self.getFallbackMaterialIdByMaterialType(node.metadata["material"])
|
||||
if fallback_id in machine_exclude_materials:
|
||||
if material_id in machine_exclude_materials:
|
||||
Logger.log("d", "Exclude material [%s] for machine [%s]",
|
||||
material_id, machine_definition.getId())
|
||||
continue
|
||||
|
|
|
@ -39,6 +39,8 @@ class BaseMaterialsModel(ListModel):
|
|||
|
||||
self._extruder_position = 0
|
||||
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):
|
||||
global_stack = self._machine_manager.activeMachine
|
||||
|
@ -50,9 +52,11 @@ class BaseMaterialsModel(ListModel):
|
|||
self._extruder_stack = global_stack.extruders.get(str(self._extruder_position))
|
||||
if self._extruder_stack is not None:
|
||||
self._extruder_stack.pyqtContainersChanged.connect(self._update)
|
||||
# Force update the model when the extruder stack changes
|
||||
self._update()
|
||||
|
||||
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._updateExtruderStack()
|
||||
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.
|
||||
|
||||
import copy
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Message import Message
|
||||
|
@ -36,7 +38,7 @@ class MultiplyObjectsJob(Job):
|
|||
|
||||
root = scene.getRoot()
|
||||
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 = []
|
||||
nodes = []
|
||||
|
||||
|
@ -64,6 +66,8 @@ class MultiplyObjectsJob(Job):
|
|||
# We do place the nodes one by one, as we want to yield in between.
|
||||
if not node_too_big:
|
||||
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:
|
||||
found_solution_for_all = False
|
||||
new_location = new_node.getPosition()
|
||||
|
|
|
@ -329,6 +329,8 @@ class PrintInformation(QObject):
|
|||
baseNameChanged = pyqtSignal()
|
||||
|
||||
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
|
||||
name = os.path.basename(base_name)
|
||||
|
||||
|
@ -355,11 +357,12 @@ class PrintInformation(QObject):
|
|||
data = mime_type.stripExtension(name)
|
||||
except:
|
||||
Logger.log("w", "Unsupported Mime Type Database file extension")
|
||||
data = 'unnamed'
|
||||
|
||||
if data is not None and check_name is not None:
|
||||
self._base_name = data
|
||||
else:
|
||||
self._base_name = ''
|
||||
self._base_name = 'unnamed'
|
||||
|
||||
self._updateJobName()
|
||||
|
||||
|
|
|
@ -475,7 +475,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||
extruder_definition = extruder_definitions[0]
|
||||
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.setDefinition(extruder_definition)
|
||||
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
|
||||
# will raise an exception.
|
||||
class CuraContainerStack(ContainerStack):
|
||||
def __init__(self, container_id: str, *args, **kwargs):
|
||||
super().__init__(container_id, *args, **kwargs)
|
||||
def __init__(self, container_id: str):
|
||||
super().__init__(container_id)
|
||||
|
||||
self._container_registry = ContainerRegistry.getInstance()
|
||||
|
||||
|
|
|
@ -99,8 +99,7 @@ class CuraStackBuilder:
|
|||
position = position,
|
||||
variant_container = extruder_variant_container,
|
||||
material_container = material_container,
|
||||
quality_container = application.empty_quality_container,
|
||||
global_stack = new_global_stack,
|
||||
quality_container = application.empty_quality_container
|
||||
)
|
||||
new_extruder.setNextStack(new_global_stack)
|
||||
new_global_stack.addExtruder(new_extruder)
|
||||
|
@ -139,11 +138,11 @@ class CuraStackBuilder:
|
|||
@classmethod
|
||||
def createExtruderStack(cls, new_stack_id: str, extruder_definition: DefinitionContainerInterface, machine_definition_id: str,
|
||||
position: int,
|
||||
variant_container, material_container, quality_container, global_stack) -> ExtruderStack:
|
||||
variant_container, material_container, quality_container) -> ExtruderStack:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
application = CuraApplication.getInstance()
|
||||
|
||||
stack = ExtruderStack(new_stack_id, parent = global_stack)
|
||||
stack = ExtruderStack(new_stack_id)
|
||||
stack.setName(extruder_definition.getName())
|
||||
stack.setDefinition(extruder_definition)
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ if TYPE_CHECKING:
|
|||
#
|
||||
#
|
||||
class ExtruderStack(CuraContainerStack):
|
||||
def __init__(self, container_id: str, *args, **kwargs):
|
||||
super().__init__(container_id, *args, **kwargs)
|
||||
def __init__(self, container_id: str):
|
||||
super().__init__(container_id)
|
||||
|
||||
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.
|
||||
#
|
||||
class GlobalStack(CuraContainerStack):
|
||||
def __init__(self, container_id: str, *args, **kwargs):
|
||||
super().__init__(container_id, *args, **kwargs)
|
||||
def __init__(self, container_id: str):
|
||||
super().__init__(container_id)
|
||||
|
||||
self.addMetaDataEntry("type", "machine") # For backward compatibility
|
||||
|
||||
|
|
|
@ -1041,6 +1041,10 @@ class MachineManager(QObject):
|
|||
self.activeQualityChangesGroupChanged.emit()
|
||||
|
||||
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:
|
||||
return
|
||||
for node in quality_group.nodes_for_extruders.values():
|
||||
|
@ -1051,10 +1055,6 @@ class MachineManager(QObject):
|
|||
if empty_quality_changes:
|
||||
self._current_quality_changes_group = None
|
||||
|
||||
if quality_group is None:
|
||||
self._setEmptyQuality()
|
||||
return
|
||||
|
||||
# Set quality and quality_changes for the GlobalStack
|
||||
self._global_container_stack.quality = quality_group.node_for_global.getContainer()
|
||||
if empty_quality_changes:
|
||||
|
@ -1289,6 +1289,10 @@ class MachineManager(QObject):
|
|||
self._global_container_stack.variant = self._empty_variant_container
|
||||
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'
|
||||
def replaceContainersMetadata(self, key: str, value: str, new_value: str) -> None:
|
||||
machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
|
||||
|
@ -1340,6 +1344,10 @@ class MachineManager(QObject):
|
|||
self._setMaterial(position, container_node)
|
||||
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)
|
||||
def setVariantByName(self, position: str, variant_name: str) -> None:
|
||||
machine_definition_id = self._global_container_stack.definition.id
|
||||
|
@ -1355,6 +1363,10 @@ class MachineManager(QObject):
|
|||
self._updateMaterialWithVariant(position)
|
||||
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)
|
||||
def setQualityGroupByQualityType(self, quality_type: str) -> 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.MeshReader import MeshReader
|
||||
from UM.Scene.GroupDecorator import GroupDecorator
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||
|
@ -26,15 +25,6 @@ from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
|||
|
||||
MYPY = False
|
||||
|
||||
|
||||
MimeTypeDatabase.addMimeType(
|
||||
MimeType(
|
||||
name = "application/x-cura-project-file",
|
||||
comment = "Cura Project File",
|
||||
suffixes = ["curaproject.3mf"]
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
if not MYPY:
|
||||
import xml.etree.cElementTree as ET
|
||||
|
|
|
@ -13,8 +13,24 @@ from . import ThreeMFWorkspaceReader
|
|||
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Platform import Platform
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||
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:
|
||||
# Workarround for osx not supporting double file extensions correctly.
|
||||
if Platform.isOSX():
|
||||
|
|
|
@ -64,20 +64,25 @@ class FirmwareUpdateCheckerJob(Job):
|
|||
if (checked_version != "") and (checked_version != current_version):
|
||||
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(
|
||||
"@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(
|
||||
machine_name=machine_name),
|
||||
title=i18n_catalog.i18nc(
|
||||
"@info:title The %s gets replaced with the printer name.",
|
||||
"New %s firmware available") % machine_name,
|
||||
footer = footer_message)
|
||||
"New %s firmware available") % machine_name)
|
||||
|
||||
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.show()
|
||||
|
||||
|
|
|
@ -46,10 +46,11 @@ class SliceInfo(QObject, Extension):
|
|||
dismissable = False,
|
||||
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,
|
||||
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.show()
|
||||
|
||||
|
|
|
@ -31,8 +31,9 @@ Item
|
|||
frameVisible: false
|
||||
selectionMode: 0
|
||||
model: packageData.supported_configs
|
||||
headerDelegate: Item
|
||||
headerDelegate: Rectangle
|
||||
{
|
||||
color: UM.Theme.getColor("sidebar")
|
||||
height: UM.Theme.getSize("toolbox_chart_row").height
|
||||
Label
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@ Column
|
|||
height: childrenRect.height
|
||||
width: parent.width
|
||||
spacing: UM.Theme.getSize("default_margin").height
|
||||
/* Hidden for 3.4
|
||||
Label
|
||||
{
|
||||
id: heading
|
||||
|
@ -20,6 +21,7 @@ Column
|
|||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("medium")
|
||||
}
|
||||
*/
|
||||
GridLayout
|
||||
{
|
||||
id: grid
|
||||
|
|
|
@ -18,6 +18,8 @@ ScrollView
|
|||
spacing: UM.Theme.getSize("default_margin").height
|
||||
padding: UM.Theme.getSize("wide_margin").height
|
||||
height: childrenRect.height + 2 * padding
|
||||
|
||||
/* Hide for 3.4
|
||||
ToolboxDownloadsShowcase
|
||||
{
|
||||
id: showcase
|
||||
|
@ -29,6 +31,8 @@ ScrollView
|
|||
width: parent.width
|
||||
height: UM.Theme.getSize("default_lining").height
|
||||
}
|
||||
*/
|
||||
|
||||
ToolboxDownloadsGrid
|
||||
{
|
||||
id: allPlugins
|
||||
|
|
|
@ -33,6 +33,8 @@ Item
|
|||
toolbox.viewPage = "overview"
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide for 3.4
|
||||
ToolboxTabButton
|
||||
{
|
||||
text: catalog.i18nc("@title:tab", "Materials")
|
||||
|
@ -45,6 +47,7 @@ Item
|
|||
toolbox.viewPage = "overview"
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
ToolboxTabButton
|
||||
{
|
||||
|
|
|
@ -65,6 +65,7 @@ ScrollView
|
|||
}
|
||||
}
|
||||
}
|
||||
/* Hidden in 3.4
|
||||
Label
|
||||
{
|
||||
visible: toolbox.materialsInstalledModel.items.length > 0
|
||||
|
@ -102,5 +103,6 @@ ScrollView
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ Item
|
|||
{
|
||||
color: UM.Theme.getColor("lining")
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("default_lining").height
|
||||
height: Math.floor(UM.Theme.getSize("default_lining").height)
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
Row
|
||||
|
@ -40,14 +40,14 @@ Item
|
|||
Column
|
||||
{
|
||||
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")
|
||||
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
|
||||
{
|
||||
text: model.name
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("toolbox_property_label").height
|
||||
height: Math.floor(UM.Theme.getSize("toolbox_property_label").height)
|
||||
wrapMode: Text.WordWrap
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
color: pluginInfo.color
|
||||
|
@ -81,7 +81,7 @@ Item
|
|||
}
|
||||
}
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("toolbox_property_label").height
|
||||
height: Math.floor(UM.Theme.getSize("toolbox_property_label").height)
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
|
|
|
@ -13,6 +13,16 @@ Column
|
|||
width: UM.Theme.getSize("toolbox_action_button").width
|
||||
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
|
||||
{
|
||||
id: updateButton
|
||||
|
@ -39,7 +49,7 @@ Column
|
|||
{
|
||||
id: removeButton
|
||||
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
|
||||
style: ButtonStyle
|
||||
{
|
||||
|
|
|
@ -150,7 +150,7 @@ Item
|
|||
{
|
||||
id: loader
|
||||
visible: active
|
||||
source: "../images/loading.gif"
|
||||
source: visible ? "../images/loading.gif" : ""
|
||||
width: UM.Theme.getSize("toolbox_loader").width
|
||||
height: UM.Theme.getSize("toolbox_loader").height
|
||||
anchors.right: button.left
|
||||
|
|
|
@ -29,8 +29,9 @@ class PackagesModel(ListModel):
|
|||
self.addRoleName(Qt.UserRole + 12, "last_updated")
|
||||
self.addRoleName(Qt.UserRole + 13, "is_bundled")
|
||||
self.addRoleName(Qt.UserRole + 14, "is_enabled")
|
||||
self.addRoleName(Qt.UserRole + 15, "has_configs")
|
||||
self.addRoleName(Qt.UserRole + 16, "supported_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, "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.
|
||||
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,
|
||||
"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_installed": package["is_installed"] if "is_installed" in package else False,
|
||||
"has_configs": has_configs,
|
||||
"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
|
||||
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:
|
||||
super().__init__(parent)
|
||||
|
@ -37,16 +38,10 @@ class Toolbox(QObject, Extension):
|
|||
self._package_manager = None
|
||||
self._plugin_registry = Application.getInstance().getPluginRegistry()
|
||||
|
||||
self._sdk_version = self._getPackagesVersion()
|
||||
|
||||
self._cloud_api_version = 1
|
||||
self._cloud_api_root = self._getPackagesApiRoot()
|
||||
|
||||
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._sdk_version = None
|
||||
self._cloud_api_version = None
|
||||
self._cloud_api_root = None
|
||||
self._api_url = None
|
||||
|
||||
# Network:
|
||||
self._get_packages_request = None
|
||||
|
@ -67,12 +62,7 @@ class Toolbox(QObject, Extension):
|
|||
)
|
||||
)
|
||||
]
|
||||
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._request_urls = {}
|
||||
self._to_update = [] # Package_ids that are waiting to be updated
|
||||
|
||||
# Data:
|
||||
|
@ -164,22 +154,50 @@ class Toolbox(QObject, Extension):
|
|||
# this is initialized. Therefore, we wait until the application is ready.
|
||||
def _onAppInitialized(self) -> None:
|
||||
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.
|
||||
def _getPackagesApiRoot(self) -> str:
|
||||
def _getCloudAPIRoot(self) -> str:
|
||||
if not hasattr(cura, "CuraVersion"):
|
||||
return self.DEFAULT_PACKAGES_API_ROOT
|
||||
if not hasattr(cura.CuraVersion, "CuraPackagesApiRoot"):
|
||||
return self.DEFAULT_PACKAGES_API_ROOT
|
||||
return cura.CuraVersion.CuraPackagesApiRoot
|
||||
return self.DEFAULT_CLOUD_API_ROOT
|
||||
if not hasattr(cura.CuraVersion, "CuraCloudAPIRoot"):
|
||||
return self.DEFAULT_CLOUD_API_ROOT
|
||||
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.
|
||||
def _getPackagesVersion(self) -> int:
|
||||
def _getSDKVersion(self) -> int:
|
||||
if not hasattr(cura, "CuraVersion"):
|
||||
return self._plugin_registry.APIVersion
|
||||
if not hasattr(cura.CuraVersion, "CuraPackagesVersion"):
|
||||
if not hasattr(cura.CuraVersion, "CuraSDKVersion"):
|
||||
return self._plugin_registry.APIVersion
|
||||
return cura.CuraVersion.CuraPackagesVersion
|
||||
if not cura.CuraVersion.CuraSDKVersion:
|
||||
return self._plugin_registry.APIVersion
|
||||
return cura.CuraVersion.CuraSDKVersion
|
||||
|
||||
@pyqtSlot()
|
||||
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.
|
||||
|
||||
_renamed_settings = {
|
||||
"infill_hollow": "infill_support_enabled"
|
||||
}
|
||||
|
||||
## Upgrades configurations from the state they were in at version 3.3 to the
|
||||
# state they should be in at version 3.4.
|
||||
|
@ -38,6 +41,17 @@ class VersionUpgrade33to34(VersionUpgrade):
|
|||
# Update version number.
|
||||
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()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
|
@ -1807,6 +1807,30 @@
|
|||
"limit_to_extruder": "infill_extruder_nr",
|
||||
"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":
|
||||
{
|
||||
"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.",
|
||||
"type": "str",
|
||||
"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",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": true
|
||||
|
@ -5918,14 +5942,6 @@
|
|||
"limit_to_extruder": "support_infill_extruder_nr",
|
||||
"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":
|
||||
{
|
||||
"label": "Fuzzy Skin",
|
||||
|
@ -6662,14 +6678,6 @@
|
|||
"type": "float",
|
||||
"enabled": "bridge_settings_enabled and bridge_enable_more_layers",
|
||||
"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)
|
||||
{
|
||||
// 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"))
|
||||
{
|
||||
// Try to install plugin & close.
|
||||
|
@ -334,11 +335,13 @@ UM.MainWindow
|
|||
packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting.");
|
||||
packageInstallDialog.icon = StandardIcon.Information;
|
||||
packageInstallDialog.open();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonPackages.push(filename);
|
||||
}
|
||||
}
|
||||
|
||||
openDialog.handleOpenFileUrls(drop.urls);
|
||||
openDialog.handleOpenFileUrls(nonPackages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,10 +81,9 @@ Item {
|
|||
text: PrintInformation.jobName
|
||||
horizontalAlignment: TextInput.AlignRight
|
||||
onEditingFinished: {
|
||||
PrintInformation.setJobName(text, true);
|
||||
if (printJobTextfield.text != ''){
|
||||
printJobTextfield.focus = false;
|
||||
}
|
||||
text = text == "" ? "unnamed" : text;
|
||||
PrintInformation.setJobName(printJobTextfield.text, true);
|
||||
printJobTextfield.focus = false;
|
||||
}
|
||||
validator: RegExpValidator {
|
||||
regExp: /^[^\\ \/ \*\?\|\[\]]*$/
|
||||
|
|
|
@ -92,6 +92,7 @@ Rectangle
|
|||
anchors.verticalCenter: buildplateIcon.verticalCenter
|
||||
anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2)
|
||||
text: configuration.buildplateConfiguration
|
||||
renderType: Text.NativeRendering
|
||||
color: textColor
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ Column
|
|||
{
|
||||
id: extruderLabel
|
||||
text: catalog.i18nc("@label:extruder label", "Extruder")
|
||||
renderType: Text.NativeRendering
|
||||
elide: Text.ElideRight
|
||||
anchors.left: parent.left
|
||||
font: UM.Theme.getFont("default")
|
||||
|
@ -59,6 +60,7 @@ Column
|
|||
id: extruderNumberText
|
||||
anchors.centerIn: parent
|
||||
text: printCoreConfiguration.position + 1
|
||||
renderType: Text.NativeRendering
|
||||
font: UM.Theme.getFont("default")
|
||||
color: mainColor
|
||||
}
|
||||
|
@ -69,6 +71,7 @@ Column
|
|||
{
|
||||
id: materialLabel
|
||||
text: printCoreConfiguration.material.name
|
||||
renderType: Text.NativeRendering
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
|
@ -79,6 +82,7 @@ Column
|
|||
{
|
||||
id: printCoreTypeLabel
|
||||
text: printCoreConfiguration.hotendID
|
||||
renderType: Text.NativeRendering
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
font: UM.Theme.getFont("default")
|
||||
|
|
|
@ -13,7 +13,7 @@ Button
|
|||
id: base
|
||||
property var outputDevice: null
|
||||
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
|
||||
height: parent.height
|
||||
|
||||
|
|
|
@ -63,8 +63,7 @@ Menu
|
|||
exclusiveGroup: group
|
||||
onTriggered:
|
||||
{
|
||||
var activeExtruderIndex = Cura.ExtruderManager.activeExtruderIndex;
|
||||
Cura.MachineManager.setMaterial(activeExtruderIndex, model.container_node);
|
||||
Cura.MachineManager.setMaterial(extruderIndex, model.container_node);
|
||||
}
|
||||
}
|
||||
onObjectAdded: brandMaterialsMenu.insertItem(index, object)
|
||||
|
|
|
@ -100,8 +100,8 @@ Item {
|
|||
if (saveToButton.enabled) {
|
||||
saveToButton.clicked();
|
||||
}
|
||||
// prepare button
|
||||
if (prepareButton.enabled) {
|
||||
// slice button
|
||||
if (sliceButton.enabled) {
|
||||
sliceOrStopSlicing();
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ Item {
|
|||
Row {
|
||||
id: additionalComponentsRow
|
||||
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
|
||||
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
|
@ -159,14 +159,14 @@ Item {
|
|||
onPreferenceChanged:
|
||||
{
|
||||
var autoSlice = UM.Preferences.getValue("general/auto_slice");
|
||||
prepareButton.autoSlice = autoSlice;
|
||||
sliceButton.autoSlice = autoSlice;
|
||||
saveToButton.autoSlice = autoSlice;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare button, only shows if auto_slice is off
|
||||
// Slice button, only shows if auto_slice is off
|
||||
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")
|
||||
// 1 = not started, 2 = Processing
|
||||
|
@ -180,7 +180,7 @@ Item {
|
|||
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
|
||||
|
||||
// 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:
|
||||
{
|
||||
sliceOrStopSlicing();
|
||||
|
|
|
@ -87,6 +87,7 @@ gradual_infill_steps
|
|||
gradual_infill_step_height
|
||||
infill_before_walls
|
||||
min_infill_area
|
||||
infill_support_enabled
|
||||
skin_preshrink
|
||||
top_skin_preshrink
|
||||
bottom_skin_preshrink
|
||||
|
@ -369,7 +370,6 @@ spaghetti_infill_extra_volume
|
|||
support_conical_enabled
|
||||
support_conical_angle
|
||||
support_conical_min_width
|
||||
infill_hollow
|
||||
magic_fuzzy_skin_enabled
|
||||
magic_fuzzy_skin_thickness
|
||||
magic_fuzzy_skin_point_density
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue