diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 203c00b445..9c22d5ae3a 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -600,20 +600,21 @@ class BuildVolume(SceneNode): result_areas[extruder_id].append(polygon) #Don't perform the offset on these. # Add prime tower location as disallowed area. - prime_tower_collision = False - prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders) - for extruder_id in prime_tower_areas: - for prime_tower_area in prime_tower_areas[extruder_id]: - for area in result_areas[extruder_id]: - if prime_tower_area.intersectsPolygon(area) is not None: - prime_tower_collision = True + if len(used_extruders) > 1: #No prime tower in single-extrusion. + prime_tower_collision = False + prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders) + for extruder_id in prime_tower_areas: + for prime_tower_area in prime_tower_areas[extruder_id]: + for area in result_areas[extruder_id]: + if prime_tower_area.intersectsPolygon(area) is not None: + prime_tower_collision = True + break + if prime_tower_collision: #Already found a collision. break - if prime_tower_collision: #Already found a collision. - break - if not prime_tower_collision: - result_areas[extruder_id].extend(prime_tower_areas[extruder_id]) - else: - self._error_areas.extend(prime_tower_areas[extruder_id]) + if not prime_tower_collision: + result_areas[extruder_id].extend(prime_tower_areas[extruder_id]) + else: + self._error_areas.extend(prime_tower_areas[extruder_id]) self._has_errors = len(self._error_areas) > 0 @@ -955,4 +956,4 @@ class BuildVolume(SceneNode): _tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"] _ooze_shield_settings = ["ooze_shield_enabled", "ooze_shield_dist"] _distance_settings = ["infill_wipe_dist", "travel_avoid_distance", "support_offset", "support_enable", "travel_avoid_other_parts"] - _extruder_settings = ["support_enable", "support_interface_enable", "support_infill_extruder_nr", "support_extruder_nr_layer_0", "support_interface_extruder_nr", "brim_line_count", "adhesion_extruder_nr", "adhesion_type"] #Settings that can affect which extruders are used. + _extruder_settings = ["support_enable", "support_bottom_enable", "support_roof_enable", "support_infill_extruder_nr", "support_extruder_nr_layer_0", "support_bottom_extruder_nr", "support_roof_extruder_nr", "brim_line_count", "adhesion_extruder_nr", "adhesion_type"] #Settings that can affect which extruders are used. diff --git a/cura/CuraActions.py b/cura/CuraActions.py index df26a9a9a6..eeebd3b6b2 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -1,10 +1,23 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + from PyQt5.QtCore import QObject, QUrl from PyQt5.QtGui import QDesktopServices from UM.FlameProfiler import pyqtSlot from UM.Event import CallFunctionEvent from UM.Application import Application +from UM.Math.Vector import Vector +from UM.Scene.Selection import Selection +from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator +from UM.Operations.GroupedOperation import GroupedOperation +from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation +from UM.Operations.SetTransformOperation import SetTransformOperation +from cura.SetParentOperation import SetParentOperation +from cura.MultiplyObjectsJob import MultiplyObjectsJob +from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation +from cura.Settings.ExtruderManager import ExtruderManager class CuraActions(QObject): def __init__(self, parent = None): @@ -23,5 +36,84 @@ class CuraActions(QObject): event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {}) Application.getInstance().functionEvent(event) + ## Center all objects in the selection + @pyqtSlot() + def centerSelection(self) -> None: + operation = GroupedOperation() + for node in Selection.getAllSelectedObjects(): + current_node = node + while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): + current_node = current_node.getParent() + + center_operation = SetTransformOperation(current_node, Vector()) + operation.addOperation(center_operation) + operation.push() + + ## Multiply all objects in the selection + # + # \param count The number of times to multiply the selection. + @pyqtSlot(int) + def multiplySelection(self, count: int) -> None: + job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, 8) + job.start() + + ## Delete all selected objects. + @pyqtSlot() + def deleteSelection(self) -> None: + if not Application.getInstance().getController().getToolsEnabled(): + return + + removed_group_nodes = [] + op = GroupedOperation() + nodes = Selection.getAllSelectedObjects() + for node in nodes: + op.addOperation(RemoveSceneNodeOperation(node)) + group_node = node.getParent() + if group_node and group_node.callDecoration("isGroup") and group_node not in removed_group_nodes: + remaining_nodes_in_group = list(set(group_node.getChildren()) - set(nodes)) + if len(remaining_nodes_in_group) == 1: + removed_group_nodes.append(group_node) + op.addOperation(SetParentOperation(remaining_nodes_in_group[0], group_node.getParent())) + op.addOperation(RemoveSceneNodeOperation(group_node)) + op.push() + + ## Set the extruder that should be used to print the selection. + # + # \param extruder_id The ID of the extruder stack to use for the selected objects. + @pyqtSlot(str) + def setExtruderForSelection(self, extruder_id: str) -> None: + operation = GroupedOperation() + + nodes_to_change = [] + for node in Selection.getAllSelectedObjects(): + # Do not change any nodes that already have the right extruder set. + if node.callDecoration("getActiveExtruder") == extruder_id: + continue + + # If the node is a group, apply the active extruder to all children of the group. + if node.callDecoration("isGroup"): + for grouped_node in BreadthFirstIterator(node): + if grouped_node.callDecoration("getActiveExtruder") == extruder_id: + continue + + if grouped_node.callDecoration("isGroup"): + continue + + nodes_to_change.append(grouped_node) + continue + + nodes_to_change.append(node) + + if not nodes_to_change: + # If there are no changes to make, we still need to reset the selected extruders. + # This is a workaround for checked menu items being deselected while still being + # selected. + ExtruderManager.getInstance().resetSelectedObjectExtruders() + return + + for node in nodes_to_change: + operation.addOperation(SetObjectExtruderOperation(node, extruder_id)) + operation.push() + def _openUrl(self, url): - QDesktopServices.openUrl(url) \ No newline at end of file + QDesktopServices.openUrl(url) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a60f846c20..f099c4db77 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -26,6 +26,7 @@ from UM.Message import Message from UM.i18n import i18nCatalog from UM.Workspace.WorkspaceReader import WorkspaceReader from UM.Platform import Platform +from UM.Decorators import deprecated from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation @@ -221,6 +222,7 @@ class CuraApplication(QtApplication): self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) self.getController().toolOperationStopped.connect(self._onToolOperationStopped) + self.getController().contextMenuRequested.connect(self._onContextMenuRequested) Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") @@ -810,6 +812,7 @@ class CuraApplication(QtApplication): # Remove all selected objects from the scene. @pyqtSlot() + @deprecated("Moved to CuraActions", "2.6") def deleteSelection(self): if not self.getController().getToolsEnabled(): return @@ -830,6 +833,7 @@ class CuraApplication(QtApplication): ## Remove an object from the scene. # Note that this only removes an object if it is selected. @pyqtSlot("quint64") + @deprecated("Use deleteSelection instead", "2.6") def deleteObject(self, object_id): if not self.getController().getToolsEnabled(): return @@ -857,13 +861,22 @@ class CuraApplication(QtApplication): # \param count number of copies # \param min_offset minimum offset to other objects. @pyqtSlot("quint64", int) + @deprecated("Use CuraActions::multiplySelection", "2.6") def multiplyObject(self, object_id, count, min_offset = 8): - job = MultiplyObjectsJob(object_id, count, min_offset) + node = self.getController().getScene().findObject(object_id) + if not node: + node = Selection.getSelectedObject(0) + + while node.getParent() and node.getParent().callDecoration("isGroup"): + node = node.getParent() + + job = MultiplyObjectsJob([node], count, min_offset) job.start() return ## Center object on platform. @pyqtSlot("quint64") + @deprecated("Use CuraActions::centerSelection", "2.6") def centerObject(self, object_id): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: # Workaround for tool handles overlapping the selected object @@ -1323,3 +1336,13 @@ class CuraApplication(QtApplication): except Exception as e: Logger.log("e", "Could not check file %s: %s", file_url, e) return False + + def _onContextMenuRequested(self, x: float, y: float) -> None: + # Ensure we select the object if we request a context menu over an object without having a selection. + if not Selection.hasSelection(): + node = self.getController().getScene().findObject(self.getRenderer().getRenderPass("selection").getIdAtPosition(x, y)) + if node: + while(node.getParent() and node.getParent().callDecoration("isGroup")): + node = node.getParent() + + Selection.add(node) diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 40dbc221d6..a795e0bc10 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -24,9 +24,9 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation class MultiplyObjectsJob(Job): - def __init__(self, object_id, count, min_offset = 8): + def __init__(self, objects, count, min_offset = 8): super().__init__() - self._object_id = object_id + self._objects = objects self._count = count self._min_offset = min_offset @@ -35,38 +35,42 @@ class MultiplyObjectsJob(Job): dismissable=False, progress=0) status_message.show() scene = Application.getInstance().getController().getScene() - node = scene.findObject(self._object_id) - if not node and self._object_id != 0: # Workaround for tool handles overlapping the selected object - node = Selection.getSelectedObject(0) - - # If object is part of a group, multiply group - current_node = node - while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): - current_node = current_node.getParent() + total_progress = len(self._objects) * self._count + current_progress = 0 root = scene.getRoot() arranger = Arrange.create(scene_root=root) - node_too_big = False - if node.getBoundingBox().width < 300 or node.getBoundingBox().depth < 300: - offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset) - else: - node_too_big = True nodes = [] - found_solution_for_all = True - for i in range(self._count): - # We do place the nodes one by one, as we want to yield in between. - if not node_too_big: - node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr) - if node_too_big or not solution_found: - found_solution_for_all = False - new_location = node.getPosition() - new_location = new_location.set(z = 100 - i * 20) - node.setPosition(new_location) + for node in self._objects: + # If object is part of a group, multiply group + current_node = node + while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): + current_node = current_node.getParent() + + node_too_big = False + if node.getBoundingBox().width < 300 or node.getBoundingBox().depth < 300: + offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset) + else: + node_too_big = True + + found_solution_for_all = True + for i in range(self._count): + # We do place the nodes one by one, as we want to yield in between. + if not node_too_big: + node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr) + if node_too_big or not solution_found: + found_solution_for_all = False + new_location = node.getPosition() + new_location = new_location.set(z = 100 - i * 20) + node.setPosition(new_location) + + nodes.append(node) + current_progress += 1 + status_message.setProgress((current_progress / total_progress) * 100) + Job.yieldThread() - nodes.append(node) Job.yieldThread() - status_message.setProgress((i + 1) / self._count * 100) if nodes: op = GroupedOperation() diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index d21480b11b..21cd164ed4 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -8,12 +8,14 @@ from UM.Application import Application #To get the global container stack to fin from UM.Logger import Logger from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode +from UM.Scene.Selection import Selection +from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.SettingFunction import SettingFunction from UM.Settings.ContainerStack import ContainerStack from UM.Settings.DefinitionContainer import DefinitionContainer -from typing import Optional +from typing import Optional, List ## Manages all existing extruder stacks. # @@ -34,10 +36,13 @@ class ExtruderManager(QObject): super().__init__(parent) self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs. self._active_extruder_index = 0 + self._selected_object_extruders = [] Application.getInstance().globalContainerStackChanged.connect(self.__globalContainerStackChanged) self._global_container_stack_definition_id = None self._addCurrentMachineExtruders() + Selection.selectionChanged.connect(self.resetSelectedObjectExtruders) + ## Gets the unique identifier of the currently active extruder stack. # # The currently active extruder stack is the stack that is currently being @@ -117,6 +122,48 @@ class ExtruderManager(QObject): except IndexError: return "" + ## Emitted whenever the selectedObjectExtruders property changes. + selectedObjectExtrudersChanged = pyqtSignal() + + ## Provides a list of extruder IDs used by the current selected objects. + @pyqtProperty("QVariantList", notify = selectedObjectExtrudersChanged) + def selectedObjectExtruders(self) -> List[str]: + if not self._selected_object_extruders: + object_extruders = set() + + # First, build a list of the actual selected objects (including children of groups, excluding group nodes) + selected_nodes = [] + for node in Selection.getAllSelectedObjects(): + if node.callDecoration("isGroup"): + for grouped_node in BreadthFirstIterator(node): + if grouped_node.callDecoration("isGroup"): + continue + + selected_nodes.append(grouped_node) + else: + selected_nodes.append(node) + + # Then, figure out which nodes are used by those selected nodes. + for node in selected_nodes: + extruder = node.callDecoration("getActiveExtruder") + if extruder: + object_extruders.add(extruder) + else: + global_stack = Application.getInstance().getGlobalContainerStack() + object_extruders.add(self._extruder_trains[global_stack.getId()]["0"].getId()) + + self._selected_object_extruders = list(object_extruders) + + return self._selected_object_extruders + + ## Reset the internal list used for the selectedObjectExtruders property + # + # This will trigger a recalculation of the extruders used for the + # selection. + def resetSelectedObjectExtruders(self) -> None: + self._selected_object_extruders = [] + self.selectedObjectExtrudersChanged.emit() + def getActiveExtruderStack(self) -> ContainerStack: global_container_stack = Application.getInstance().getGlobalContainerStack() @@ -357,7 +404,8 @@ class ExtruderManager(QObject): #Get the extruders of all meshes in the scene. support_enabled = False - support_interface_enabled = False + support_bottom_enabled = False + support_roof_enabled = False scene_root = Application.getInstance().getController().getScene().getRoot() meshes = [node for node in DepthFirstIterator(scene_root) if type(node) is SceneNode and node.isSelectable()] #Only use the nodes that will be printed. for mesh in meshes: @@ -370,18 +418,22 @@ class ExtruderManager(QObject): per_mesh_stack = mesh.callDecoration("getStack") if per_mesh_stack: support_enabled |= per_mesh_stack.getProperty("support_enable", "value") - support_interface_enabled |= per_mesh_stack.getProperty("support_interface_enable", "value") + support_bottom_enabled |= per_mesh_stack.getProperty("support_bottom_enable", "value") + support_roof_enabled |= per_mesh_stack.getProperty("support_roof_enable", "value") else: #Take the setting from the build extruder stack. extruder_stack = container_registry.findContainerStacks(id = extruder_stack_id)[0] support_enabled |= extruder_stack.getProperty("support_enable", "value") - support_interface_enabled |= extruder_stack.getProperty("support_enable", "value") + support_bottom_enabled |= extruder_stack.getProperty("support_bottom_enable", "value") + support_roof_enabled |= extruder_stack.getProperty("support_roof_enable", "value") #The support extruders. if support_enabled: used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_infill_extruder_nr", "value"))]) used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_extruder_nr_layer_0", "value"))]) - if support_interface_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_interface_extruder_nr", "value"))]) + if support_bottom_enabled: + used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_bottom_extruder_nr", "value"))]) + if support_roof_enabled: + used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_roof_extruder_nr", "value"))]) #The platform adhesion extruder. Not used if using none. if global_stack.getProperty("adhesion_type", "value") != "none": @@ -444,6 +496,8 @@ class ExtruderManager(QObject): self.globalContainerStackDefinitionChanged.emit() self.activeExtruderChanged.emit() + self.resetSelectedObjectExtruders() + ## Adds the extruders of the currently active machine. def _addCurrentMachineExtruders(self) -> None: global_stack = Application.getInstance().getGlobalContainerStack() diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 5632a83a27..74680bb293 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty +from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, pyqtSlot import UM.Qt.ListModel from UM.Application import Application @@ -33,6 +33,12 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): # The ID of the definition of the extruder. DefinitionRole = Qt.UserRole + 5 + # The material of the extruder. + MaterialRole = Qt.UserRole + 6 + + # The variant of the extruder. + VariantRole = Qt.UserRole + 7 + ## List of colours to display if there is no material or the material has no known # colour. defaultColors = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"] @@ -49,6 +55,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self.addRoleName(self.ColorRole, "color") self.addRoleName(self.IndexRole, "index") self.addRoleName(self.DefinitionRole, "definition") + self.addRoleName(self.MaterialRole, "material") + self.addRoleName(self.VariantRole, "variant") self._add_global = False self._simple_names = False @@ -141,6 +149,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): for extruder in manager.getMachineExtruders(global_container_stack.getId()): extruder_name = extruder.getName() material = extruder.findContainer({ "type": "material" }) + variant = extruder.findContainer({"type": "variant"}) position = extruder.getMetaDataEntry("position", default = "0") # Get the position try: position = int(position) @@ -156,7 +165,9 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "name": extruder_name, "color": color, "index": position, - "definition": extruder.getBottom().getId() + "definition": extruder.getBottom().getId(), + "material": material.getName() if material else "", + "variant": variant.getName() if variant else "", } items.append(item) changed = True diff --git a/cura/Settings/SetObjectExtruderOperation.py b/cura/Settings/SetObjectExtruderOperation.py new file mode 100644 index 0000000000..31c996529a --- /dev/null +++ b/cura/Settings/SetObjectExtruderOperation.py @@ -0,0 +1,27 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from UM.Scene.SceneNode import SceneNode +from UM.Operations.Operation import Operation + +from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator + +## Simple operation to set the extruder a certain object should be printed with. +class SetObjectExtruderOperation(Operation): + def __init__(self, node: SceneNode, extruder_id: str) -> None: + self._node = node + self._extruder_id = extruder_id + self._previous_extruder_id = None + self._decorator_added = False + + def undo(self): + if self._previous_extruder_id: + self._node.callDecoration("setActiveExtruder", self._previous_extruder_id) + + def redo(self): + stack = self._node.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway. + if not stack: + self._node.addDecorator(SettingOverrideDecorator()) + + self._previous_extruder_id = self._node.callDecoration("getActiveExtruder") + self._node.callDecoration("setActiveExtruder", self._extruder_id) diff --git a/cura/Settings/SettingInheritanceManager.py b/cura/Settings/SettingInheritanceManager.py index 2f81526813..ff0d1d81c0 100644 --- a/cura/Settings/SettingInheritanceManager.py +++ b/cura/Settings/SettingInheritanceManager.py @@ -109,10 +109,13 @@ class SettingInheritanceManager(QObject): self._settings_with_inheritance_warning.remove(key) settings_with_inheritance_warning_changed = True - # Find the topmost parent (Assumed to be a category) parent = definitions[0].parent - while parent.parent is not None: - parent = parent.parent + # Find the topmost parent (Assumed to be a category) + if parent is not None: + while parent.parent is not None: + parent = parent.parent + else: + parent = definitions[0] # Already at a category if parent.key not in self._settings_with_inheritance_warning and has_overwritten_inheritance: # Category was not in the list yet, so needs to be added now. diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 76c155cb99..d754b6bc6d 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -109,6 +109,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): def setActiveExtruder(self, extruder_stack_id): self._extruder_stack = extruder_stack_id self._updateNextStack() + ExtruderManager.getInstance().resetSelectedObjectExtruders() self.activeExtruderChanged.emit() def getStack(self): diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 981145bebd..f32993fd20 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -13,9 +13,9 @@ from UM.Resources import Resources from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then. from UM.Platform import Platform from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator +from UM.Qt.Duration import DurationFormat from PyQt5.QtCore import QObject, pyqtSlot - from cura.Settings.ExtruderManager import ExtruderManager from . import ProcessSlicedLayersJob from . import StartSliceJob @@ -442,6 +442,15 @@ class CuraEngineBackend(QObject, Backend): self.backendStateChange.emit(BackendState.Done) self.processingProgress.emit(1.0) + for line in self._scene.gcode_list: + replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601))) + replaced = replaced.replace("{filament_amount}", str(Application.getInstance().getPrintInformation().materialLengths)) + replaced = replaced.replace("{filament_weight}", str(Application.getInstance().getPrintInformation().materialWeights)) + replaced = replaced.replace("{filament_cost}", str(Application.getInstance().getPrintInformation().materialCosts)) + replaced = replaced.replace("{jobname}", str(Application.getInstance().getPrintInformation().jobName)) + + self._scene.gcode_list[self._scene.gcode_list.index(line)] = replaced + self._slicing = False self._need_slicing = False Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time ) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index c8cbbe8040..2ad4b3db9c 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -4,6 +4,7 @@ import numpy from string import Formatter from enum import IntEnum +import time from UM.Job import Job from UM.Application import Application @@ -247,8 +248,18 @@ class StartSliceJob(Job): Job.yieldThread() start_gcode = settings["machine_start_gcode"] - settings["material_bed_temp_prepend"] = "{material_bed_temperature}" not in start_gcode #Pre-compute material material_bed_temp_prepend and material_print_temp_prepend - settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode + #Pre-compute material material_bed_temp_prepend and material_print_temp_prepend + bed_temperature_settings = {"material_bed_temperature", "material_bed_temperature_layer_0"} + settings["material_bed_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in bed_temperature_settings)) + print_temperature_settings = {"material_print_temperature", "material_print_temperature_layer_0", "default_material_print_temperature", "material_initial_print_temperature", "material_final_print_temperature", "material_standby_temperature"} + settings["material_print_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in print_temperature_settings)) + + settings["print_bed_temperature"] = settings["material_bed_temperature"] + settings["print_temperature"] = settings["material_print_temperature"] + + settings["time"] = time.strftime('%H:%M:%S') + settings["date"] = time.strftime('%d-%m-%Y') + settings["day"] = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][int(time.strftime('%w'))] for key, value in settings.items(): #Add all submessages for each individual setting. setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings") diff --git a/plugins/LayerView/LayerView.qml b/plugins/LayerView/LayerView.qml old mode 100644 new mode 100755 index 6ea855e20b..3078b278df --- a/plugins/LayerView/LayerView.qml +++ b/plugins/LayerView/LayerView.qml @@ -7,6 +7,7 @@ import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.1 import UM 1.0 as UM +import Cura 1.0 as Cura Item { @@ -58,6 +59,7 @@ Item anchors.left: parent.left text: catalog.i18nc("@label","View Mode: Layers") font.bold: true + color: UM.Theme.getColor("text") } Label @@ -75,6 +77,7 @@ Item text: catalog.i18nc("@label","Color scheme") visible: !UM.LayerView.compatibilityMode Layout.fillWidth: true + color: UM.Theme.getColor("text") } ListModel // matches LayerView.py @@ -102,6 +105,7 @@ Item Layout.preferredWidth: UM.Theme.getSize("layerview_row").width model: layerViewTypes visible: !UM.LayerView.compatibilityMode + style: UM.Theme.styles.combobox property int layer_view_type: UM.Preferences.getValue("layerview/layer_view_type") currentIndex: layer_view_type // index matches type_id @@ -161,106 +165,88 @@ Item } Repeater { - model: UM.LayerView.extruderCount + model: Cura.ExtrudersModel{} CheckBox { checked: view_settings.extruder_opacities[index] > 0.5 || view_settings.extruder_opacities[index] == undefined || view_settings.extruder_opacities[index] == "" onClicked: { view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0 UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|")); } - text: catalog.i18nc("@label", "Extruder %1").arg(index + 1) + text: model.name visible: !UM.LayerView.compatibilityMode enabled: index + 1 <= 4 + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + width: UM.Theme.getSize("layerview_legend_size").width + height: UM.Theme.getSize("layerview_legend_size").height + color: model.color + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + visible: !view_settings.show_legend + } Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height Layout.preferredWidth: UM.Theme.getSize("layerview_row").width + style: UM.Theme.styles.checkbox } } - CheckBox { - checked: view_settings.show_travel_moves - onClicked: { - UM.Preferences.setValue("layerview/show_travel_moves", checked); + Repeater { + model: ListModel { + id: typesLegenModel + Component.onCompleted: + { + typesLegenModel.append({ + label: catalog.i18nc("@label", "Show Travels"), + initialValue: view_settings.show_travel_moves, + preference: "layerview/show_travel_moves", + colorId: "layerview_move_combing" + }); + typesLegenModel.append({ + label: catalog.i18nc("@label", "Show Helpers"), + initialValue: view_settings.show_helpers, + preference: "layerview/show_helpers", + colorId: "layerview_support" + }); + typesLegenModel.append({ + label: catalog.i18nc("@label", "Show Shell"), + initialValue: view_settings.show_skin, + preference: "layerview/show_skin", + colorId: "layerview_inset_0" + }); + typesLegenModel.append({ + label: catalog.i18nc("@label", "Show Infill"), + initialValue: view_settings.show_infill, + preference: "layerview/show_infill", + colorId: "layerview_infill" + }); + } } - text: catalog.i18nc("@label", "Show Travels") - Rectangle { - anchors.top: parent.top - anchors.topMargin: 2 - anchors.right: parent.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor("layerview_move_combing") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: view_settings.show_legend + + CheckBox { + checked: model.initialValue + onClicked: { + UM.Preferences.setValue(model.preference, checked); + } + text: label + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + width: UM.Theme.getSize("layerview_legend_size").width + height: UM.Theme.getSize("layerview_legend_size").height + color: UM.Theme.getColor(model.colorId) + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + visible: view_settings.show_legend + } + Layout.fillWidth: true + Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height + Layout.preferredWidth: UM.Theme.getSize("layerview_row").width + style: UM.Theme.styles.checkbox } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - } - CheckBox { - checked: view_settings.show_helpers - onClicked: { - UM.Preferences.setValue("layerview/show_helpers", checked); - } - text: catalog.i18nc("@label", "Show Helpers") - Rectangle { - anchors.top: parent.top - anchors.topMargin: 2 - anchors.right: parent.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor("layerview_support") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: view_settings.show_legend - } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - } - CheckBox { - checked: view_settings.show_skin - onClicked: { - UM.Preferences.setValue("layerview/show_skin", checked); - } - text: catalog.i18nc("@label", "Show Shell") - Rectangle { - anchors.top: parent.top - anchors.topMargin: 2 - anchors.right: parent.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor("layerview_inset_0") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: view_settings.show_legend - } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - } - CheckBox { - checked: view_settings.show_infill - onClicked: { - UM.Preferences.setValue("layerview/show_infill", checked); - } - text: catalog.i18nc("@label", "Show Infill") - Rectangle { - anchors.top: parent.top - anchors.topMargin: 2 - anchors.right: parent.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor("layerview_infill") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: view_settings.show_legend - } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width } + CheckBox { checked: view_settings.only_show_top_layers onClicked: { @@ -268,6 +254,7 @@ Item } text: catalog.i18nc("@label", "Only Show Top Layers") visible: UM.LayerView.compatibilityMode + style: UM.Theme.styles.checkbox } CheckBox { checked: view_settings.top_layer_count == 5 @@ -276,51 +263,43 @@ Item } text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top") visible: UM.LayerView.compatibilityMode + style: UM.Theme.styles.checkbox } - Label - { - id: topBottomLabel - anchors.left: parent.left - text: catalog.i18nc("@label","Top / Bottom") - Rectangle { - anchors.top: parent.top - anchors.topMargin: 2 - anchors.right: parent.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor("layerview_skin") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") + Repeater { + model: ListModel { + id: typesLegenModelNoCheck + Component.onCompleted: + { + typesLegenModelNoCheck.append({ + label: catalog.i18nc("@label", "Top / Bottom"), + colorId: "layerview_skin" + }); + typesLegenModelNoCheck.append({ + label: catalog.i18nc("@label", "Inner Wall"), + colorId: "layerview_inset_x" + }); + } } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - visible: view_settings.show_legend - } - Label - { - id: innerWallLabel - anchors.left: parent.left - text: catalog.i18nc("@label","Inner Wall") - Rectangle { - anchors.top: parent.top - anchors.topMargin: 2 - anchors.right: parent.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor("layerview_inset_x") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: view_settings.show_legend + Label { + text: label + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + width: UM.Theme.getSize("layerview_legend_size").width + height: UM.Theme.getSize("layerview_legend_size").height + color: UM.Theme.getColor(model.colorId) + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + visible: view_settings.show_legend + } + Layout.fillWidth: true + Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height + Layout.preferredWidth: UM.Theme.getSize("layerview_row").width + color: UM.Theme.getColor("text") } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - visible: view_settings.show_legend } - } Item diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index cb65da635b..c3c7249155 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -26,129 +26,6 @@ Item { spacing: UM.Theme.getSize("default_margin").height - Row - { - spacing: UM.Theme.getSize("default_margin").width - Label - { - text: catalog.i18nc("@label Followed by extruder selection drop-down.", "Print model with") - anchors.verticalCenter: extruderSelector.verticalCenter - - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - visible: extruderSelector.visible - } - ComboBox - { - id: extruderSelector - - model: Cura.ExtrudersModel - { - id: extrudersModel - onModelChanged: extruderSelector.color = extrudersModel.getItem(extruderSelector.currentIndex).color - } - property string color: extrudersModel.getItem(extruderSelector.currentIndex).color - visible: machineExtruderCount.properties.value > 1 - textRole: "name" - width: UM.Theme.getSize("setting_control").width - height: UM.Theme.getSize("section").height - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.NoButton - onWheel: wheel.accepted = true; - } - - style: ComboBoxStyle - { - background: Rectangle - { - color: - { - if(extruderSelector.hovered || base.activeFocus) - { - return UM.Theme.getColor("setting_control_highlight"); - } - else - { - return UM.Theme.getColor("setting_control"); - } - } - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("setting_control_border") - } - label: Item - { - Rectangle - { - id: swatch - height: UM.Theme.getSize("setting_control").height / 2 - width: height - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_lining").width - anchors.verticalCenter: parent.verticalCenter - - color: extruderSelector.color - border.width: UM.Theme.getSize("default_lining").width - border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : UM.Theme.getColor("setting_control_border") - } - Label - { - anchors.left: swatch.right - anchors.leftMargin: UM.Theme.getSize("default_lining").width - anchors.right: downArrow.left - anchors.rightMargin: UM.Theme.getSize("default_lining").width - anchors.verticalCenter: parent.verticalCenter - - text: extruderSelector.currentText - font: UM.Theme.getFont("default") - color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") - - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - } - - UM.RecolorImage - { - id: downArrow - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2 - anchors.verticalCenter: parent.verticalCenter - - source: UM.Theme.getIcon("arrow_bottom") - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width + 5 - sourceSize.height: width + 5 - - color: UM.Theme.getColor("setting_control_text") - } - } - } - - onActivated: - { - UM.ActiveTool.setProperty("SelectedActiveExtruder", extrudersModel.getItem(index).id); - extruderSelector.color = extrudersModel.getItem(index).color; - } - onModelChanged: updateCurrentIndex(); - - function updateCurrentIndex() - { - for(var i = 0; i < extrudersModel.rowCount(); ++i) - { - if(extrudersModel.getItem(i).id == UM.ActiveTool.properties.getValue("SelectedActiveExtruder")) - { - extruderSelector.currentIndex = i; - extruderSelector.color = extrudersModel.getItem(i).color; - return; - } - } - extruderSelector.currentIndex = -1; - } - } - } - Column { // This is to ensure that the panel is first increasing in size up to 200 and then shows a scrollbar. diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index 865401804c..b2d14942ba 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -112,4 +112,4 @@ class PerObjectSettingsTool(Tool): self._single_model_selected = False # Group is selected, so tool needs to be disabled else: self._single_model_selected = True - Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, (self._advanced_mode or self._multi_extrusion) and self._single_model_selected) \ No newline at end of file + Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, self._advanced_mode and self._single_model_selected) diff --git a/plugins/VersionUpgrade/VersionUpgrade24to25/VersionUpgrade24to25.py b/plugins/VersionUpgrade/VersionUpgrade24to25/VersionUpgrade24to25.py index 99a0f95a77..1af2e7405a 100644 --- a/plugins/VersionUpgrade/VersionUpgrade24to25/VersionUpgrade24to25.py +++ b/plugins/VersionUpgrade/VersionUpgrade24to25/VersionUpgrade24to25.py @@ -10,6 +10,10 @@ _removed_settings = { #Settings that were removed in 2.5. "start_layers_at_same_position" } +_split_settings = { #These settings should be copied to all settings it was split into. + "support_interface_line_distance": {"support_roof_line_distance", "support_bottom_line_distance"} +} + ## A collection of functions that convert the configuration of the user in Cura # 2.4 to a configuration for Cura 2.5. # @@ -42,8 +46,16 @@ class VersionUpgrade24to25(VersionUpgrade): #Remove settings from the visible_settings. if parser.has_section("general") and "visible_settings" in parser["general"]: visible_settings = parser["general"]["visible_settings"].split(";") - visible_settings = filter(lambda setting: setting not in _removed_settings, visible_settings) - parser["general"]["visible_settings"] = ";".join(visible_settings) + new_visible_settings = [] + for setting in visible_settings: + if setting in _removed_settings: + continue #Skip. + if setting in _split_settings: + for replaced_setting in _split_settings[setting]: + new_visible_settings.append(replaced_setting) + continue #Don't add the original. + new_visible_settings.append(setting) #No special handling, so just add the original visible setting back. + parser["general"]["visible_settings"] = ";".join(new_visible_settings) #Change the version number in the file. if parser.has_section("general"): #It better have! @@ -66,6 +78,10 @@ class VersionUpgrade24to25(VersionUpgrade): if parser.has_section("values"): for removed_setting in (_removed_settings & parser["values"].keys()): #Both in keys that need to be removed and in keys present in the file. del parser["values"][removed_setting] + for replaced_setting in (_split_settings.keys() & parser["values"].keys()): + for replacement in _split_settings[replaced_setting]: + parser["values"][replacement] = parser["values"][replaced_setting] #Copy to replacement before removing the original! + del replaced_setting #Change the version number in the file. if parser.has_section("general"): diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ca05191185..b9c43fac2f 100755 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -746,7 +746,7 @@ "support_interface_line_width": { "label": "Support Interface Line Width", - "description": "Width of a single support interface line.", + "description": "Width of a single line of support roof or floor.", "unit": "mm", "default_value": 0.4, "minimum_value": "0.001", @@ -757,7 +757,42 @@ "limit_to_extruder": "support_interface_extruder_nr", "value": "line_width", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": + { + "support_roof_line_width": + { + "label": "Support Roof Line Width", + "description": "Width of a single support roof line.", + "unit": "mm", + "default_value": 0.4, + "minimum_value": "0.001", + "minimum_value_warning": "0.4 * machine_nozzle_size", + "maximum_value_warning": "2 * machine_nozzle_size", + "type": "float", + "enabled": "support_enable and support_roof_enable", + "limit_to_extruder": "support_roof_extruder_nr", + "value": "support_interface_line_width", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "support_bottom_line_width": + { + "label": "Support Floor Line Width", + "description": "Width of a single support floor line.", + "unit": "mm", + "default_value": 0.4, + "minimum_value": "0.001", + "minimum_value_warning": "0.4 * machine_nozzle_size", + "maximum_value_warning": "2 * machine_nozzle_size", + "type": "float", + "enabled": "support_enable and support_bottom_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "value": "support_interface_line_width", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } }, "prime_tower_line_width": { @@ -1923,7 +1958,7 @@ "speed_support_interface": { "label": "Support Interface Speed", - "description": "The speed at which the roofs and bottoms of support are printed. Printing the them at lower speeds can improve overhang quality.", + "description": "The speed at which the roofs and floors of support are printed. Printing them at lower speeds can improve overhang quality.", "unit": "mm/s", "type": "float", "default_value": 40, @@ -1934,7 +1969,42 @@ "limit_to_extruder": "support_interface_extruder_nr", "value": "speed_support / 1.5", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": + { + "speed_support_roof": + { + "label": "Support Roof Speed", + "description": "The speed at which the roofs of support are printed. Printing them at lower speeds can improve overhang quality.", + "unit": "mm/s", + "type": "float", + "default_value": 40, + "minimum_value": "0.1", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "150", + "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "limit_to_extruder": "support_roof_extruder_nr", + "value": "speed_support_interface", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "speed_support_bottom": + { + "label": "Support Floor Speed", + "description": "The speed at which the floor of support is printed. Printing it at lower speed can improve adhesion of support on top of your model.", + "unit": "mm/s", + "type": "float", + "default_value": 40, + "minimum_value": "0.1", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "150", + "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "value": "speed_support_interface", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } } } }, @@ -2209,7 +2279,7 @@ "acceleration_support_interface": { "label": "Support Interface Acceleration", - "description": "The acceleration with which the roofs and bottoms of support are printed. Printing them at lower accelerations can improve overhang quality.", + "description": "The acceleration with which the roofs and floors of support are printed. Printing them at lower acceleration can improve overhang quality.", "unit": "mm/s²", "type": "float", "default_value": 3000, @@ -2220,7 +2290,42 @@ "enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", "limit_to_extruder": "support_interface_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": + { + "acceleration_support_roof": + { + "label": "Support Roof Acceleration", + "description": "The acceleration with which the roofs of support are printed. Printing them at lower acceleration can improve overhang quality.", + "unit": "mm/s²", + "type": "float", + "default_value": 3000, + "value": "acceleration_support_interface", + "minimum_value": "0.1", + "minimum_value_warning": "100", + "maximum_value_warning": "10000", + "enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "limit_to_extruder": "support_roof_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "acceleration_support_bottom": + { + "label": "Support Floor Acceleration", + "description": "The acceleration with which the floors of support are printed. Printing them at lower acceleration can improve adhesion of support on top of your model.", + "unit": "mm/s²", + "type": "float", + "default_value": 3000, + "value": "acceleration_support_interface", + "minimum_value": "0.1", + "minimum_value_warning": "100", + "maximum_value_warning": "10000", + "enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } } } }, @@ -2440,7 +2545,7 @@ "jerk_support_interface": { "label": "Support Interface Jerk", - "description": "The maximum instantaneous velocity change with which the roofs and bottoms of support are printed.", + "description": "The maximum instantaneous velocity change with which the roofs and floors of support are printed.", "unit": "mm/s", "type": "float", "default_value": 20, @@ -2450,7 +2555,42 @@ "enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", "limit_to_extruder": "support_interface_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": + { + "jerk_support_roof": + { + "label": "Support Roof Jerk", + "description": "The maximum instantaneous velocity change with which the roofs of support are printed.", + "unit": "mm/s", + "type": "float", + "default_value": 20, + "value": "jerk_support_interface", + "minimum_value": "0.1", + "minimum_value_warning": "5", + "maximum_value_warning": "50", + "enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "limit_to_extruder": "support_roof_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "jerk_support_bottom": + { + "label": "Support Floor Jerk", + "description": "The maximum instantaneous velocity change with which the floors of support are printed.", + "unit": "mm/s", + "type": "float", + "default_value": 20, + "value": "jerk_support_interface", + "minimum_value": "0.1", + "minimum_value_warning": "5", + "maximum_value_warning": "50", + "enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } } } }, @@ -2878,13 +3018,38 @@ "support_interface_extruder_nr": { "label": "Support Interface Extruder", - "description": "The extruder train to use for printing the roofs and bottoms of the support. This is used in multi-extrusion.", + "description": "The extruder train to use for printing the roofs and floors of the support. This is used in multi-extrusion.", "type": "extruder", "default_value": "0", "value": "support_extruder_nr", "enabled": "support_enable and machine_extruder_count > 1", "settable_per_mesh": false, - "settable_per_extruder": false + "settable_per_extruder": false, + "children": + { + "support_roof_extruder_nr": + { + "label": "Support Roof Extruder", + "description": "The extruder train to use for printing the roofs of the support. This is used in multi-extrusion.", + "type": "extruder", + "default_value": "0", + "value": "support_interface_extruder_nr", + "enabled": "support_enable and machine_extruder_count > 1", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "support_bottom_extruder_nr": + { + "label": "Support Floor Extruder", + "description": "The extruder train to use for printing the floors of the support. This is used in multi-extrusion.", + "type": "extruder", + "default_value": "0", + "value": "support_interface_extruder_nr", + "enabled": "support_enable and machine_extruder_count > 1", + "settable_per_mesh": false, + "settable_per_extruder": false + } + } } } }, @@ -2914,7 +3079,7 @@ "maximum_value": "90", "maximum_value_warning": "80", "default_value": 50, - "limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr", + "limit_to_extruder": "support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr", "enabled": "support_enable", "settable_per_mesh": true }, @@ -3006,7 +3171,7 @@ "type": "float", "enabled": "support_enable", "value": "extruderValue(support_extruder_nr, 'support_z_distance')", - "limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr", + "limit_to_extruder": "support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr", "settable_per_mesh": true }, "support_bottom_distance": @@ -3018,7 +3183,7 @@ "maximum_value_warning": "machine_nozzle_size", "default_value": 0.1, "value": "extruderValue(support_extruder_nr, 'support_z_distance') if resolveOrValue('support_type') == 'everywhere' else 0", - "limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr", + "limit_to_extruder": "support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr", "type": "float", "enabled": "support_enable and resolveOrValue('support_type') == 'everywhere'", "settable_per_mesh": true @@ -3070,16 +3235,29 @@ "support_bottom_stair_step_height": { "label": "Support Stair Step Height", - "description": "The height of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures.", + "description": "The height of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures. Set to zero to turn off the stair-like behaviour.", "unit": "mm", "type": "float", "default_value": 0.3, - "limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr", + "limit_to_extruder": "support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr", "minimum_value": "0", "maximum_value_warning": "1.0", "enabled": "support_enable", "settable_per_mesh": true }, + "support_bottom_stair_step_width": + { + "label": "Support Stair Step Maximum Width", + "description": "The maximum width of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures.", + "unit": "mm", + "type": "float", + "default_value": 5.0, + "limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr", + "minimum_value": "0", + "maximum_value_warning": "10.0", + "enabled": "support_enable", + "settable_per_mesh": true + }, "support_join_distance": { "label": "Support Join Distance", @@ -3114,7 +3292,32 @@ "default_value": false, "limit_to_extruder": "support_interface_extruder_nr", "enabled": "support_enable", - "settable_per_mesh": true + "settable_per_mesh": true, + "children": + { + "support_roof_enable": + { + "label": "Enable Support Roof", + "description": "Generate a dense slab of material between the top of support and the model. This will create a skin between the model and support.", + "type": "bool", + "default_value": false, + "value": "support_interface_enable", + "limit_to_extruder": "support_roof_extruder_nr", + "enabled": "support_enable", + "settable_per_mesh": true + }, + "support_bottom_enable": + { + "label": "Enable Support Floor", + "description": "Generate a dense slab of material between the bottom of the support and the model. This will create a skin between the model and support.", + "type": "bool", + "default_value": false, + "value": "support_interface_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "enabled": "support_enable", + "settable_per_mesh": true + } + } }, "support_interface_height": { @@ -3141,32 +3344,31 @@ "minimum_value": "0", "minimum_value_warning": "0.2 + resolveOrValue('layer_height')", "maximum_value_warning": "10", - "value": "extruderValue(support_interface_extruder_nr, 'support_interface_height')", - "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "value": "extruderValue(support_roof_extruder_nr, 'support_interface_height')", + "limit_to_extruder": "support_roof_extruder_nr", + "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", "settable_per_mesh": true }, "support_bottom_height": { - "label": "Support Bottom Thickness", - "description": "The thickness of the support bottoms. This controls the number of dense layers are printed on top of places of a model on which support rests.", + "label": "Support Floor Thickness", + "description": "The thickness of the support floors. This controls the number of dense layers that are printed on top of places of a model on which support rests.", "unit": "mm", "type": "float", "default_value": 1, - "value": "extruderValue(support_interface_extruder_nr, 'support_interface_height')", + "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_height')", "minimum_value": "0", - "minimum_value_warning": "min(0.2 + resolveOrValue('layer_height'), extruderValue(support_interface_extruder_nr, 'support_bottom_stair_step_height'))", + "minimum_value_warning": "min(0.2 + resolveOrValue('layer_height'), extruderValue(support_bottom_extruder_nr, 'support_bottom_stair_step_height'))", "maximum_value_warning": "10", - "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", "settable_per_mesh": true } } }, - "support_interface_skip_height": - { + "support_interface_skip_height": { "label": "Support Interface Resolution", - "description": "When checking where there's model above the support, take steps of the given height. Lower values will slice slower, while higher values may cause normal support to be printed in some places where there should have been support interface.", + "description": "When checking where there's model above and below the support, take steps of the given height. Lower values will slice slower, while higher values may cause normal support to be printed in some places where there should have been support interface.", "unit": "mm", "type": "float", "default_value": 0.3, @@ -3179,7 +3381,7 @@ "support_interface_density": { "label": "Support Interface Density", - "description": "Adjusts the density of the roofs and bottoms of the support structure. A higher value results in better overhangs, but the supports are harder to remove.", + "description": "Adjusts the density of the roofs and floors of the support structure. A higher value results in better overhangs, but the supports are harder to remove.", "unit": "%", "type": "float", "default_value": 100, @@ -3191,20 +3393,69 @@ "settable_per_extruder": true, "children": { - "support_interface_line_distance": + "support_roof_density": { - "label": "Support Interface Line Distance", - "description": "Distance between the printed support interface lines. This setting is calculated by the Support Interface Density, but can be adjusted separately.", - "unit": "mm", + "label": "Support Roof Density", + "description": "The density of the roofs of the support structure. A higher value results in better overhangs, but the supports are harder to remove.", + "unit": "%", "type": "float", - "default_value": 0.4, + "default_value": 100, "minimum_value": "0", - "minimum_value_warning": "support_interface_line_width - 0.0001", - "value": "0 if support_interface_density == 0 else (support_interface_line_width * 100) / support_interface_density * (2 if support_interface_pattern == 'grid' else (3 if support_interface_pattern == 'triangles' else 1))", - "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "maximum_value": "100", + "limit_to_extruder": "support_roof_extruder_nr", + "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": + { + "support_roof_line_distance": + { + "label": "Support Roof Line Distance", + "description": "Distance between the printed support roof lines. This setting is calculated by the Support Roof Density, but can be adjusted separately.", + "unit": "mm", + "type": "float", + "default_value": 0.4, + "minimum_value": "0", + "minimum_value_warning": "support_roof_line_width - 0.0001", + "value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == 'grid' else (3 if support_roof_pattern == 'triangles' else 1))", + "limit_to_extruder": "support_roof_extruder_nr", + "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } + }, + "support_bottom_density": + { + "label": "Support Floor Density", + "description": "The density of the floors of the support structure. A higher value results in better adhesion of the support on top of the model.", + "unit": "%", + "type": "float", + "default_value": 100, + "minimum_value": "0", + "maximum_value": "100", + "limit_to_extruder": "support_bottom_extruder_nr", + "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "settable_per_mesh": false, + "settable_per_extruder": true, + "children": + { + "support_bottom_line_distance": + { + "label": "Support Floor Line Distance", + "description": "Distance between the printed support floor lines. This setting is calculated by the Support Floor Density, but can be adjusted separately.", + "unit": "mm", + "type": "float", + "default_value": 0.4, + "minimum_value": "0", + "minimum_value_warning": "support_bottom_line_width - 0.0001", + "value": "0 if support_bottom_density == 0 else (support_bottom_line_width * 100) / support_bottom_density * (2 if support_bottom_pattern == 'grid' else (3 if support_bottom_pattern == 'triangles' else 1))", + "limit_to_extruder": "support_bottom_extruder_nr", + "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } } } }, @@ -3226,7 +3477,52 @@ "limit_to_extruder": "support_interface_extruder_nr", "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": + { + "support_roof_pattern": + { + "label": "Support Roof Pattern", + "description": "The pattern with which the roofs of the support are printed.", + "type": "enum", + "options": + { + "lines": "Lines", + "grid": "Grid", + "triangles": "Triangles", + "concentric": "Concentric", + "concentric_3d": "Concentric 3D", + "zigzag": "Zig Zag" + }, + "default_value": "concentric", + "value": "support_interface_pattern", + "limit_to_extruder": "support_roof_extruder_nr", + "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "support_bottom_pattern": + { + "label": "Support Floor Pattern", + "description": "The pattern with which the floors of the support are printed.", + "type": "enum", + "options": + { + "lines": "Lines", + "grid": "Grid", + "triangles": "Triangles", + "concentric": "Concentric", + "concentric_3d": "Concentric 3D", + "zigzag": "Zig Zag" + }, + "default_value": "concentric", + "value": "support_interface_pattern", + "limit_to_extruder": "support_bottom_extruder_nr", + "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } }, "support_use_towers": { diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index b5f5823ece..b9eef11a55 100755 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -18,6 +18,8 @@ Item property alias redo: redoAction; property alias deleteSelection: deleteSelectionAction; + property alias centerSelection: centerSelectionAction; + property alias multiplySelection: multiplySelectionAction; property alias deleteObject: deleteObjectAction; property alias centerObject: centerObjectAction; @@ -181,11 +183,28 @@ Item Action { id: deleteSelectionAction; - text: catalog.i18nc("@action:inmenu menubar:edit","Delete &Selection"); - enabled: UM.Controller.toolsEnabled; + text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete &Selected Model", "Delete &Selected Models", UM.Selection.selectionCount); + enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection; iconName: "edit-delete"; shortcut: StandardKey.Delete; - onTriggered: CuraApplication.deleteSelection(); + onTriggered: CuraActions.deleteSelection(); + } + + Action + { + id: centerSelectionAction; + text: catalog.i18ncp("@action:inmenu menubar:edit", "Center Selected Model", "Center Selected Models", UM.Selection.selectionCount); + enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection; + iconName: "align-vertical-center"; + onTriggered: CuraActions.centerSelection(); + } + + Action + { + id: multiplySelectionAction; + text: catalog.i18ncp("@action:inmenu menubar:edit", "Multiply Selected Model", "Multiply Selected Models", UM.Selection.selectionCount); + enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection; + iconName: "edit-duplicate"; } Action diff --git a/resources/qml/AddMachineDialog.qml b/resources/qml/AddMachineDialog.qml index ba3f40260d..756badc4d2 100644 --- a/resources/qml/AddMachineDialog.qml +++ b/resources/qml/AddMachineDialog.qml @@ -180,7 +180,7 @@ UM.Dialog anchors.bottom:parent.bottom spacing: UM.Theme.getSize("default_margin").width - Text + Label { text: catalog.i18nc("@label", "Printer Name:") anchors.verticalCenter: machineName.verticalCenter diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index b0e6d09080..0a48725011 100755 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -594,102 +594,8 @@ UM.MainWindow } } - Menu - { - id: objectContextMenu; - - property variant objectId: -1; - MenuItem { action: Cura.Actions.centerObject; } - MenuItem { action: Cura.Actions.deleteObject; } - MenuItem { action: Cura.Actions.multiplyObject; } - MenuSeparator { } - MenuItem { action: Cura.Actions.selectAll; } - MenuItem { action: Cura.Actions.arrangeAll; } - MenuItem { action: Cura.Actions.deleteAll; } - MenuItem { action: Cura.Actions.reloadAll; } - MenuItem { action: Cura.Actions.resetAllTranslation; } - MenuItem { action: Cura.Actions.resetAll; } - MenuSeparator { } - MenuItem { action: Cura.Actions.groupObjects; } - MenuItem { action: Cura.Actions.mergeObjects; } - MenuItem { action: Cura.Actions.unGroupObjects; } - - Connections - { - target: Cura.Actions.deleteObject - onTriggered: - { - if(objectContextMenu.objectId != 0) - { - CuraApplication.deleteObject(objectContextMenu.objectId); - objectContextMenu.objectId = 0; - } - } - } - - MultiplyObjectOptions - { - id: multiplyObjectOptions - } - - Connections - { - target: Cura.Actions.multiplyObject - onTriggered: - { - if(objectContextMenu.objectId != 0) - { - multiplyObjectOptions.objectId = objectContextMenu.objectId; - multiplyObjectOptions.visible = true; - multiplyObjectOptions.reset(); - objectContextMenu.objectId = 0; - } - } - } - - Connections - { - target: Cura.Actions.centerObject - onTriggered: - { - if(objectContextMenu.objectId != 0) - { - CuraApplication.centerObject(objectContextMenu.objectId); - objectContextMenu.objectId = 0; - } - } - } - } - - Menu - { - id: contextMenu; - MenuItem { action: Cura.Actions.selectAll; } - MenuItem { action: Cura.Actions.arrangeAll; } - MenuItem { action: Cura.Actions.deleteAll; } - MenuItem { action: Cura.Actions.reloadAll; } - MenuItem { action: Cura.Actions.resetAllTranslation; } - MenuItem { action: Cura.Actions.resetAll; } - MenuSeparator { } - MenuItem { action: Cura.Actions.groupObjects; } - MenuItem { action: Cura.Actions.mergeObjects; } - MenuItem { action: Cura.Actions.unGroupObjects; } - } - - Connections - { - target: UM.Controller - onContextMenuRequested: - { - if(objectId == 0) - { - contextMenu.popup(); - } else - { - objectContextMenu.objectId = objectId; - objectContextMenu.popup(); - } - } + ContextMenu { + id: contextMenu } Connections diff --git a/resources/qml/ExtruderButton.qml b/resources/qml/ExtruderButton.qml new file mode 100644 index 0000000000..ba503dba2b --- /dev/null +++ b/resources/qml/ExtruderButton.qml @@ -0,0 +1,80 @@ +// Copyright (c) 2017 Ultimaker B.V. +// Cura is released under the terms of the AGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Button +{ + id: base + + property var extruder; + + text: catalog.i18ncp("@label", "Print Selected Model with %1", "Print Selected Models With %1", UM.Selection.selectionCount).arg(extruder.name) + + style: UM.Theme.styles.tool_button; + iconSource: checked ? UM.Theme.getIcon("material_selected") : UM.Theme.getIcon("material_not_selected"); + + checked: ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1 + enabled: UM.Selection.hasSelection + + property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button"); + + Rectangle + { + anchors.fill: parent + anchors.margins: UM.Theme.getSize("default_lining").width; + + color: "transparent" + + border.width: base.checked ? UM.Theme.getSize("default_lining").width : 0; + border.color: UM.Theme.getColor("button_text") + } + + Item + { + anchors + { + right: parent.right; + top: parent.top; + margins: UM.Theme.getSize("default_lining").width * 3 + } + width: UM.Theme.getSize("default_margin").width + height: UM.Theme.getSize("default_margin").height + + Text + { + anchors.centerIn: parent; + text: index + 1; + color: parent.enabled ? UM.Theme.getColor("button_text") : UM.Theme.getColor("button_disabled_text") + font: UM.Theme.getFont("default_bold"); + } + } + + Rectangle + { + anchors + { + left: parent.left; + top: parent.top; + margins: UM.Theme.getSize("default_lining").width * 3 + } + + color: model.color + + width: UM.Theme.getSize("default_margin").width + height: UM.Theme.getSize("default_margin").height + + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining"); + } + + onClicked: + { + forceActiveFocus() //First grab focus, so all the text fields are updated + CuraActions.setExtruderForSelection(extruder.id); + } +} diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml new file mode 100644 index 0000000000..8d1a6dc02c --- /dev/null +++ b/resources/qml/Menus/ContextMenu.qml @@ -0,0 +1,138 @@ +// Copyright (c) 2016 Ultimaker B.V. +// Cura is released under the terms of the AGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.1 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Menu +{ + id: base + + property bool shouldShowExtruders: machineExtruderCount.properties.value > 1; + + // Selection-related actions. + MenuItem { action: Cura.Actions.centerSelection; } + MenuItem { action: Cura.Actions.deleteSelection; } + MenuItem { action: Cura.Actions.multiplySelection; } + + // Extruder selection - only visible if there is more than 1 extruder + MenuSeparator { visible: base.shouldShowExtruders } + MenuItem { id: extruderHeader; text: catalog.i18ncp("@label", "Print Selected Model With:", "Print Selected Models With:", UM.Selection.selectionCount); enabled: false; visible: base.shouldShowExtruders } + Instantiator + { + model: Cura.ExtrudersModel { id: extrudersModel } + MenuItem { + text: "%1: %2 - %3".arg(model.name).arg(model.material).arg(model.variant) + visible: base.shouldShowExtruders + enabled: UM.Selection.hasSelection + checkable: true + checked: ExtruderManager.selectedObjectExtruders.indexOf(model.id) != -1 + onTriggered: CuraActions.setExtruderForSelection(model.id) + shortcut: "Ctrl+" + (model.index + 1) + } + onObjectAdded: base.insertItem(index, object) + onObjectRemoved: base.removeItem(object) + } + + // Global actions + MenuSeparator {} + MenuItem { action: Cura.Actions.selectAll; } + MenuItem { action: Cura.Actions.arrangeAll; } + MenuItem { action: Cura.Actions.deleteAll; } + MenuItem { action: Cura.Actions.reloadAll; } + MenuItem { action: Cura.Actions.resetAllTranslation; } + MenuItem { action: Cura.Actions.resetAll; } + + // Group actions + MenuSeparator {} + MenuItem { action: Cura.Actions.groupObjects; } + MenuItem { action: Cura.Actions.mergeObjects; } + MenuItem { action: Cura.Actions.unGroupObjects; } + + Connections + { + target: UM.Controller + onContextMenuRequested: base.popup(); + } + + Connections + { + target: Cura.Actions.multiplySelection + onTriggered: multiplyDialog.open() + } + + UM.SettingPropertyProvider + { + id: machineExtruderCount + + containerStackId: Cura.MachineManager.activeMachineId + key: "machine_extruder_count" + watchedProperties: [ "value" ] + } + + Dialog + { + id: multiplyDialog + + title: catalog.i18ncp("@title:window", "Multiply Selected Model", "Multiply Selected Models", UM.Selection.selectionCount) + + width: 400 * Screen.devicePixelRatio + height: 80 * Screen.devicePixelRatio + + onAccepted: CuraActions.multiplySelection(copiesField.value) + + signal reset() + onReset: + { + copiesField.value = 1; + copiesField.focus = true; + } + + standardButtons: StandardButton.Ok | StandardButton.Cancel + + Row + { + spacing: UM.Theme.getSize("default_margin").width + + Label + { + text: catalog.i18nc("@label", "Number of Copies") + anchors.verticalCenter: copiesField.verticalCenter + } + + SpinBox + { + id: copiesField + minimumValue: 1 + maximumValue: 99 + } + } + } + + // Find the index of an item in the list of child items of this menu. + // + // This is primarily intended as a helper function so we do not have to + // hard-code the position of the extruder selection actions. + // + // \param item The item to find the index of. + // + // \return The index of the item or -1 if it was not found. + function findItemIndex(item) + { + for(var i in base.items) + { + if(base.items[i] == item) + { + return i; + } + } + return -1; + } + + UM.I18nCatalog { id: catalog; name: "cura" } +} diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index bb397baf08..689f7aafa9 100755 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -25,6 +25,17 @@ UM.PreferencesPage } } + function setDefaultTheme(defaultThemeCode) + { + for(var i = 0; i < themeList.count; i++) + { + if (themeComboBox.model.get(i).code == defaultThemeCode) + { + themeComboBox.currentIndex = i + } + } + } + function setDefaultDiscardOrKeepProfile(code) { for (var i = 0; i < choiceOnProfileOverrideDropDownButton.model.count; i++) @@ -55,6 +66,10 @@ UM.PreferencesPage var defaultLanguage = UM.Preferences.getValue("general/language") setDefaultLanguage(defaultLanguage) + UM.Preferences.resetPreference("general/theme") + var defaultTheme = UM.Preferences.getValue("general/theme") + setDefaultTheme(defaultTheme) + UM.Preferences.resetPreference("physics/automatic_push_free") pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free")) UM.Preferences.resetPreference("physics/automatic_drop_down") @@ -95,6 +110,8 @@ UM.PreferencesPage width: parent.width height: parent.height + flickableItem.flickableDirection: Flickable.VerticalFlick; + Column { //: Model used to check if a plugin exists @@ -109,9 +126,11 @@ UM.PreferencesPage text: catalog.i18nc("@label","Interface") } - Row + GridLayout { - spacing: UM.Theme.getSize("default_margin").width + id: interfaceGrid + columns: 4 + Label { id: languageLabel @@ -172,22 +191,75 @@ UM.PreferencesPage { id: currencyLabel text: catalog.i18nc("@label","Currency:") - anchors.verticalCenter: languageComboBox.verticalCenter + anchors.verticalCenter: currencyField.verticalCenter } + TextField { id: currencyField text: UM.Preferences.getValue("cura/currency") onTextChanged: UM.Preferences.setValue("cura/currency", text) } + + Label + { + id: themeLabel + text: catalog.i18nc("@label","Theme:") + anchors.verticalCenter: themeComboBox.verticalCenter + } + + ComboBox + { + id: themeComboBox + + model: ListModel + { + id: themeList + + Component.onCompleted: { + append({ text: catalog.i18nc("@item:inlistbox", "Ultimaker"), code: "cura" }) + } + } + + currentIndex: + { + var code = UM.Preferences.getValue("general/theme"); + for(var i = 0; i < themeList.count; ++i) + { + if(model.get(i).code == code) + { + return i + } + } + } + onActivated: UM.Preferences.setValue("general/theme", model.get(index).code) + + Component.onCompleted: + { + // Because ListModel is stupid and does not allow using qsTr() for values. + for(var i = 0; i < themeList.count; ++i) + { + themeList.setProperty(i, "text", catalog.i18n(themeList.get(i).text)); + } + + // Glorious hack time. ComboBox does not update the text properly after changing the + // model. So change the indices around to force it to update. + currentIndex += 1; + currentIndex -= 1; + } + + } } - Label + + + + Label { id: languageCaption //: Language change warning - text: catalog.i18nc("@label", "You will need to restart the application for language changes to have effect.") + text: catalog.i18nc("@label", "You will need to restart the application for these changes to have effect.") wrapMode: Text.WordWrap font.italic: true } @@ -209,14 +281,13 @@ UM.PreferencesPage CheckBox { id: autoSliceCheckbox - checked: boolCheck(UM.Preferences.getValue("general/auto_slice")) onClicked: UM.Preferences.setValue("general/auto_slice", checked) text: catalog.i18nc("@option:check","Slice automatically"); } } - + Item { //: Spacer diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index ba5106c767..132d1d2f41 100755 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -408,18 +408,34 @@ Rectangle } ExclusiveGroup { id: modeMenuGroup; } - Text + Label { id: toggleLeftText anchors.right: modeToggleSwitch.left - anchors.rightMargin: UM.Theme.getSize("toggle_button_text_anchoring_margin").width + anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter text: "" - color: UM.Theme.getColor("toggle_active_text") + color: + { + if(toggleLeftTextMouseArea.containsMouse) + { + return UM.Theme.getColor("mode_switch_text_hover"); + } + else if(!modeToggleSwitch.checked) + { + return UM.Theme.getColor("mode_switch_text_checked"); + } + else + { + return UM.Theme.getColor("mode_switch_text"); + } + } font: UM.Theme.getFont("default") MouseArea { + id: toggleLeftTextMouseArea + hoverEnabled: true anchors.fill: parent onClicked: { @@ -438,9 +454,19 @@ Rectangle id: modeToggleSwitch checked: false anchors.right: toggleRightText.left - anchors.rightMargin: UM.Theme.getSize("toggle_button_text_anchoring_margin").width + anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter + property bool _hovered: modeToggleSwitchMouseArea.containsMouse || toggleLeftTextMouseArea.containsMouse || toggleRightTextMouseArea.containsMouse + + MouseArea + { + id: modeToggleSwitchMouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + onClicked: { var index = 0; @@ -457,20 +483,36 @@ Rectangle UM.Preferences.setValue("cura/active_mode", index); } - style: UM.Theme.styles.toggle_button + style: UM.Theme.styles.mode_switch } - Text + Label { id: toggleRightText anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter text: "" - color: UM.Theme.getColor("toggle_active_text") + color: + { + if(toggleRightTextMouseArea.containsMouse) + { + return UM.Theme.getColor("mode_switch_text_hover"); + } + else if(modeToggleSwitch.checked) + { + return UM.Theme.getColor("mode_switch_text_checked"); + } + else + { + return UM.Theme.getColor("mode_switch_text"); + } + } font: UM.Theme.getFont("default") MouseArea { + id: toggleRightTextMouseArea + hoverEnabled: true anchors.fill: parent onClicked: { diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 1e4a390ba9..86185727b2 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -240,6 +240,8 @@ Item CheckBox { id: enableSupportCheckBox + property alias _hovered: enableSupportMouseArea.containsMouse + anchors.top: parent.top anchors.left: enableSupportLabel.right anchors.leftMargin: UM.Theme.getSize("default_margin").width diff --git a/resources/qml/Toolbar.qml b/resources/qml/Toolbar.qml index 60fc6fd723..5100a0dacb 100644 --- a/resources/qml/Toolbar.qml +++ b/resources/qml/Toolbar.qml @@ -6,28 +6,33 @@ import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import QtQuick.Layouts 1.1 -import UM 1.0 as UM +import UM 1.2 as UM +import Cura 1.0 as Cura -Item { +Item +{ id: base; width: buttons.width; height: buttons.height property int activeY - ColumnLayout { + Column + { id: buttons; anchors.bottom: parent.bottom; anchors.left: parent.left; spacing: UM.Theme.getSize("button_lining").width - Repeater { + Repeater + { id: repeat model: UM.ToolModel { } - Button { + Button + { text: model.name iconSource: UM.Theme.getIcon(model.icon); @@ -45,9 +50,11 @@ Item { } //Workaround since using ToolButton"s onClicked would break the binding of the checked property, instead //just catch the click so we do not trigger that behaviour. - MouseArea { + MouseArea + { anchors.fill: parent; - onClicked: { + onClicked: + { forceActiveFocus() //First grab focus, so all the text fields are updated if(parent.checked) { @@ -61,9 +68,19 @@ Item { } } } + + Item { height: UM.Theme.getSize("default_margin").height; width: 1; visible: extruders.count > 0 } + + Repeater + { + id: extruders + model: Cura.ExtrudersModel { id: extrudersModel } + ExtruderButton { extruder: model } + } } - UM.PointingRectangle { + UM.PointingRectangle + { id: panelBorder; anchors.left: parent.right; @@ -75,7 +92,8 @@ Item { target: Qt.point(parent.right, base.activeY + UM.Theme.getSize("button").height/2) arrowSize: UM.Theme.getSize("default_arrow").width - width: { + width: + { if (panel.item && panel.width > 0){ return Math.max(panel.width + 2 * UM.Theme.getSize("default_margin").width) } @@ -90,7 +108,8 @@ Item { color: UM.Theme.getColor("lining"); - UM.PointingRectangle { + UM.PointingRectangle + { id: panelBackground; color: UM.Theme.getColor("tool_panel_background"); @@ -105,7 +124,8 @@ Item { } } - Loader { + Loader + { id: panel x: UM.Theme.getSize("default_margin").width; @@ -116,6 +136,8 @@ Item { } } + // This rectangle displays the information about the current angle etc. when + // dragging a tool handle. Rectangle { x: -base.x + base.mouseX + UM.Theme.getSize("default_margin").width diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg index 12463ab831..94b40e427c 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg @@ -1,66 +1,66 @@ -[general] -version = 2 -name = Draft Print -definition = ultimaker3 - -[metadata] -type = quality -quality_type = draft -material = generic_pc_ultimaker3_AA_0.4 -weight = -2 - -[values] -acceleration_enabled = True -acceleration_print = 4000 -adhesion_type = raft -brim_width = 20 -cool_fan_full_at_height = =layer_height_0 + layer_height -cool_fan_speed_max = 90 -cool_min_layer_time_fan_speed_max = 5 -cool_min_speed = 6 -infill_line_width = =round(line_width * 0.4 / 0.35, 2) -infill_overlap = 0 -infill_overlap_mm = 0.05 -infill_pattern = triangles -infill_wipe_dist = 0.1 -jerk_enabled = True -jerk_print = 25 -layer_height = 0.2 -machine_min_cool_heat_time_window = 15 -machine_nozzle_cool_down_speed = 0.85 -machine_nozzle_heat_up_speed = 1.5 -material_final_print_temperature = =material_print_temperature - 10 -material_initial_print_temperature = =material_print_temperature - 5 -material_print_temperature = =default_material_print_temperature + 10 -material_standby_temperature = 100 -multiple_mesh_overlap = 0 -ooze_shield_angle = 40 -prime_tower_enable = True -prime_tower_size = 16 -prime_tower_wipe_enabled = True -raft_airgap = 0.25 -retraction_count_max = 80 -retraction_extrusion_window = 1 -retraction_hop = 2 -retraction_hop_enabled = True -retraction_hop_only_when_collides = True -retraction_min_travel = 0.8 -retraction_prime_speed = 15 -skin_overlap = 30 -speed_layer_0 = 25 -speed_print = 50 -speed_topbottom = 25 -speed_travel = 250 -speed_wall = =math.ceil(speed_print * 40 / 50) -speed_wall_0 = =math.ceil(speed_wall * 25 / 40) -support_bottom_distance = =support_z_distance -support_interface_density = 87.5 -support_interface_pattern = lines -switch_extruder_prime_speed = 15 -switch_extruder_retraction_amount = 20 -switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 -wall_0_inset = 0 -wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) -wall_thickness = 1.2 -xy_offset = -0.15 +[general] +version = 2 +name = Draft Print +definition = ultimaker3 + +[metadata] +type = quality +quality_type = draft +material = generic_pc_ultimaker3_AA_0.4 +weight = -2 + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = raft +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 90 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 6 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap = 0 +infill_overlap_mm = 0.05 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +layer_height = 0.2 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 10 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_size = 16 +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_enabled = True +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 +speed_travel = 250 +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +travel_avoid_distance = 3 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 +xy_offset = -0.15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg index 9353a6c6fa..5d848d67dc 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg @@ -1,65 +1,65 @@ -[general] -version = 2 -name = Fast Print -definition = ultimaker3 - -[metadata] -type = quality -quality_type = fast -material = generic_pc_ultimaker3_AA_0.4 -weight = -1 - -[values] -acceleration_enabled = True -acceleration_print = 4000 -adhesion_type = raft -brim_width = 20 -cool_fan_full_at_height = =layer_height_0 + layer_height -cool_fan_speed_max = 85 -cool_min_layer_time_fan_speed_max = 5 -cool_min_speed = 7 -infill_line_width = =round(line_width * 0.4 / 0.35, 2) -infill_overlap_mm = 0.05 -infill_pattern = triangles -infill_wipe_dist = 0.1 -jerk_enabled = True -jerk_print = 25 -layer_height = 0.15 -machine_min_cool_heat_time_window = 15 -machine_nozzle_cool_down_speed = 0.85 -machine_nozzle_heat_up_speed = 1.5 -material_final_print_temperature = =material_print_temperature - 10 -material_initial_print_temperature = =material_print_temperature - 5 -material_print_temperature = =default_material_print_temperature + 10 -material_standby_temperature = 100 -multiple_mesh_overlap = 0 -ooze_shield_angle = 40 -prime_tower_enable = True -prime_tower_size = 16 -prime_tower_wipe_enabled = True -raft_airgap = 0.25 -retraction_count_max = 80 -retraction_extrusion_window = 1 -retraction_hop = 2 -retraction_hop_enabled = True -retraction_hop_only_when_collides = True -retraction_min_travel = 0.8 -retraction_prime_speed = 15 -skin_overlap = 30 -speed_layer_0 = 25 -speed_print = 50 -speed_topbottom = 25 -speed_travel = 250 -speed_wall = =math.ceil(speed_print * 40 / 50) -speed_wall_0 = =math.ceil(speed_wall * 25 / 40) -support_bottom_distance = =support_z_distance -support_interface_density = 87.5 -support_interface_pattern = lines -switch_extruder_prime_speed = 15 -switch_extruder_retraction_amount = 20 -switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 -wall_0_inset = 0 -wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) -wall_thickness = 1.2 -xy_offset = -0.15 +[general] +version = 2 +name = Fast Print +definition = ultimaker3 + +[metadata] +type = quality +quality_type = fast +material = generic_pc_ultimaker3_AA_0.4 +weight = -1 + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = raft +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 85 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 7 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap_mm = 0.05 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +layer_height = 0.15 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 10 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_size = 16 +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_enabled = True +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 +speed_travel = 250 +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +travel_avoid_distance = 3 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 +xy_offset = -0.15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg index 01fe47a6a2..451aa19f60 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg @@ -1,66 +1,66 @@ -[general] -version = 2 -name = High Quality -definition = ultimaker3 - -[metadata] -type = quality -quality_type = high -material = generic_pc_ultimaker3_AA_0.4 -weight = 1 - -[values] -acceleration_enabled = True -acceleration_print = 4000 -adhesion_type = raft -brim_width = 20 -cool_fan_full_at_height = =layer_height_0 + layer_height -cool_fan_speed_max = 50 -cool_min_layer_time_fan_speed_max = 5 -cool_min_speed = 8 -infill_line_width = =round(line_width * 0.4 / 0.35, 2) -infill_overlap = 0 -infill_overlap_mm = 0.05 -infill_pattern = triangles -infill_wipe_dist = 0.1 -jerk_enabled = True -jerk_print = 25 -layer_height = 0.06 -machine_min_cool_heat_time_window = 15 -machine_nozzle_cool_down_speed = 0.85 -machine_nozzle_heat_up_speed = 1.5 -material_final_print_temperature = =material_print_temperature - 10 -material_initial_print_temperature = =material_print_temperature - 5 -material_print_temperature = =default_material_print_temperature - 10 -material_standby_temperature = 100 -multiple_mesh_overlap = 0 -ooze_shield_angle = 40 -prime_tower_enable = True -prime_tower_size = 16 -prime_tower_wipe_enabled = True -raft_airgap = 0.25 -retraction_count_max = 80 -retraction_extrusion_window = 1 -retraction_hop = 2 -retraction_hop_enabled = True -retraction_hop_only_when_collides = True -retraction_min_travel = 0.8 -retraction_prime_speed = 15 -skin_overlap = 30 -speed_layer_0 = 25 -speed_print = 50 -speed_topbottom = 25 -speed_travel = 250 -speed_wall = =math.ceil(speed_print * 40 / 50) -speed_wall_0 = =math.ceil(speed_wall * 25 / 40) -support_bottom_distance = =support_z_distance -support_interface_density = 87.5 -support_interface_pattern = lines -switch_extruder_prime_speed = 15 -switch_extruder_retraction_amount = 20 -switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 -wall_0_inset = 0 -wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) -wall_thickness = 1.2 -xy_offset = -0.15 +[general] +version = 2 +name = High Quality +definition = ultimaker3 + +[metadata] +type = quality +quality_type = high +material = generic_pc_ultimaker3_AA_0.4 +weight = 1 + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = raft +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 50 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 8 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap = 0 +infill_overlap_mm = 0.05 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +layer_height = 0.06 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature - 10 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_size = 16 +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_enabled = True +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 +speed_travel = 250 +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +travel_avoid_distance = 3 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 +xy_offset = -0.15 diff --git a/resources/themes/cura/icons/material_not_selected.svg b/resources/themes/cura/icons/material_not_selected.svg new file mode 100644 index 0000000000..9b3cad88bd --- /dev/null +++ b/resources/themes/cura/icons/material_not_selected.svg @@ -0,0 +1,77 @@ + + + + + + image/svg+xml + + Artboard 3 + + + + + + Artboard 3 + Created with Sketch. + + + + + + + + + + diff --git a/resources/themes/cura/icons/material_selected.svg b/resources/themes/cura/icons/material_selected.svg new file mode 100644 index 0000000000..6589eac416 --- /dev/null +++ b/resources/themes/cura/icons/material_selected.svg @@ -0,0 +1,78 @@ + + + + + + image/svg+xml + + Artboard 3 Copy + + + + + + Artboard 3 Copy + Created with Sketch. + + + + + + + + + + diff --git a/resources/themes/cura/styles.qml b/resources/themes/cura/styles.qml old mode 100644 new mode 100755 index a7c7dcb6cd..ffe866f2c6 --- a/resources/themes/cura/styles.qml +++ b/resources/themes/cura/styles.qml @@ -8,19 +8,25 @@ import QtQuick.Controls.Styles 1.1 import UM 1.1 as UM QtObject { - property Component toggle_button: Component { + property Component mode_switch: Component { SwitchStyle { groove: Rectangle { - implicitWidth: UM.Theme.getSize("toggle_button_background_implicit_size").width - implicitHeight: UM.Theme.getSize("toggle_button_background_implicit_size").height - radius: UM.Theme.getSize("toggle_button_radius").width - border.color: { - if (control.pressed || (control.checkable && control.checked)) { - return UM.Theme.getColor("sidebar_header_active"); - } else if(control.hovered) { - return UM.Theme.getColor("sidebar_header_hover"); + implicitWidth: UM.Theme.getSize("mode_switch").width + implicitHeight: UM.Theme.getSize("mode_switch").height + radius: implicitHeight / 2 + color: { + if(control.hovered || control._hovered) { + return UM.Theme.getColor("mode_switch_hover"); } else { - return UM.Theme.getColor("sidebar_header_bar"); + return UM.Theme.getColor("mode_switch"); + } + } + Behavior on color { ColorAnimation { duration: 50; } } + border.color: { + if(control.hovered || control._hovered) { + return UM.Theme.getColor("mode_switch_border_hover"); + } else { + return UM.Theme.getColor("mode_switch_border"); } } Behavior on border.color { ColorAnimation { duration: 50; } } @@ -28,9 +34,9 @@ QtObject { } handle: Rectangle { - implicitWidth: UM.Theme.getSize("toggle_button_knob_implicit_size").width - implicitHeight: UM.Theme.getSize("toggle_button_knob_implicit_size").height - radius: UM.Theme.getSize("toggle_button_radius").width + implicitWidth: implicitHeight + implicitHeight: UM.Theme.getSize("mode_switch").height + radius: implicitHeight / 2 color: { if (control.pressed || (control.checkable && control.checked)) { @@ -206,7 +212,9 @@ QtObject { property bool down: control.pressed || (control.checkable && control.checked); color: { - if(control.checkable && control.checked && control.hovered) { + if(control.customColor !== undefined && control.customColor !== null) { + return control.customColor + } else if(control.checkable && control.checked && control.hovered) { return Theme.getColor("button_active_hover"); } else if(control.pressed || (control.checkable && control.checked)) { return Theme.getColor("button_active"); diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json index 084ee27bb2..5f0b3656c8 100644 --- a/resources/themes/cura/theme.json +++ b/resources/themes/cura/theme.json @@ -175,6 +175,15 @@ "checkbox_mark": [24, 41, 77, 255], "checkbox_text": [24, 41, 77, 255], + "mode_switch": [255, 255, 255, 255], + "mode_switch_hover": [255, 255, 255, 255], + "mode_switch_border": [127, 127, 127, 255], + "mode_switch_border_hover": [12, 169, 227, 255], + "mode_switch_handle": [24, 41, 77, 255], + "mode_switch_text": [24, 41, 77, 255], + "mode_switch_text_hover": [24, 41, 77, 255], + "mode_switch_text_checked": [12, 169, 227, 255], + "tooltip": [12, 169, 227, 255], "tooltip_text": [255, 255, 255, 255], @@ -238,7 +247,7 @@ }, "sizes": { - "window_minimum_size": [70, 54], + "window_minimum_size": [70, 50], "window_margin": [1.0, 1.0], "default_margin": [1.0, 1.0], "default_lining": [0.08, 0.08], @@ -301,6 +310,7 @@ "layerview_row_spacing": [0.0, 0.5], "checkbox": [2.0, 2.0], + "mode_switch": [2.0, 1.0], "tooltip": [20.0, 10.0], "tooltip_margins": [1.0, 1.0], @@ -319,11 +329,6 @@ "infill_button_margin": [0.5, 0.5], - "jobspecs_line": [2.0, 2.0], - - "toggle_button_text_anchoring_margin": [1.0, 1.0], - "toggle_button_radius": [1.0, 1.0], - "toggle_button_background_implicit_size": [2.0, 1.0], - "toggle_button_knob_implicit_size": [1.0, 1.0] + "jobspecs_line": [2.0, 2.0] } }