mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-23 22:54:01 -06:00
Merge branch 'master' of github.com:Ultimaker/Cura into feature_extruder_buttons
This commit is contained in:
commit
33d92f9596
27 changed files with 698 additions and 192 deletions
|
@ -1,10 +1,21 @@
|
|||
# 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.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
|
||||
|
||||
class CuraActions(QObject):
|
||||
def __init__(self, parent = None):
|
||||
|
@ -23,5 +34,58 @@ 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()
|
||||
for node in Selection.getAllSelectedObjects():
|
||||
if node.callDecoration("getActiveExtruder") == extruder_id:
|
||||
continue
|
||||
operation.addOperation(SetObjectExtruderOperation(node, extruder_id))
|
||||
operation.push()
|
||||
|
||||
def _openUrl(self, url):
|
||||
QDesktopServices.openUrl(url)
|
||||
QDesktopServices.openUrl(url)
|
||||
|
|
|
@ -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
|
||||
|
@ -109,6 +110,10 @@ class CuraApplication(QtApplication):
|
|||
Q_ENUMS(ResourceTypes)
|
||||
|
||||
def __init__(self):
|
||||
# this list of dir names will be used by UM to detect an old cura directory
|
||||
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
||||
Resources.addExpectedDirNameInData(dir_name)
|
||||
|
||||
Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources"))
|
||||
if not hasattr(sys, "frozen"):
|
||||
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources"))
|
||||
|
@ -214,6 +219,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")
|
||||
|
@ -803,6 +809,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
|
||||
|
@ -823,6 +830,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
|
||||
|
@ -850,13 +858,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
|
||||
|
@ -1316,3 +1333,10 @@ 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:
|
||||
Selection.add(node)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -8,12 +8,13 @@ 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.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 +35,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 +121,34 @@ 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()
|
||||
for node in Selection.getAllSelectedObjects():
|
||||
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()
|
||||
|
||||
|
@ -444,6 +476,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()
|
||||
|
|
|
@ -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
|
||||
|
@ -140,6 +148,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)
|
||||
|
@ -152,7 +161,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
|
||||
|
|
27
cura/Settings/SetObjectExtruderOperation.py
Normal file
27
cura/Settings/SetObjectExtruderOperation.py
Normal file
|
@ -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)
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -283,10 +283,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
#
|
||||
# /param temperature The new target temperature of the bed.
|
||||
def _setTargetBedTemperature(self, temperature):
|
||||
if self._target_bed_temperature == temperature:
|
||||
if not self._updateTargetBedTemperature(temperature):
|
||||
return
|
||||
self._target_bed_temperature = temperature
|
||||
self.targetBedTemperatureChanged.emit()
|
||||
|
||||
url = QUrl("http://" + self._address + self._api_prefix + "printer/bed/temperature/target")
|
||||
data = str(temperature)
|
||||
|
@ -294,6 +292,17 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
put_request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
self._manager.put(put_request, data.encode())
|
||||
|
||||
## Updates the target bed temperature from the printer, and emit a signal if it was changed.
|
||||
#
|
||||
# /param temperature The new target temperature of the bed.
|
||||
# /return boolean, True if the temperature was changed, false if the new temperature has the same value as the already stored temperature
|
||||
def _updateTargetBedTemperature(self, temperature):
|
||||
if self._target_bed_temperature == temperature:
|
||||
return False
|
||||
self._target_bed_temperature = temperature
|
||||
self.targetBedTemperatureChanged.emit()
|
||||
return True
|
||||
|
||||
def _stopCamera(self):
|
||||
self._camera_timer.stop()
|
||||
if self._image_reply:
|
||||
|
@ -528,7 +537,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
bed_temperature = self._json_printer_state["bed"]["temperature"]["current"]
|
||||
self._setBedTemperature(bed_temperature)
|
||||
target_bed_temperature = self._json_printer_state["bed"]["temperature"]["target"]
|
||||
self._setTargetBedTemperature(target_bed_temperature)
|
||||
self._updateTargetBedTemperature(target_bed_temperature)
|
||||
|
||||
head_x = self._json_printer_state["heads"][0]["position"]["x"]
|
||||
head_y = self._json_printer_state["heads"][0]["position"]["y"]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import copy
|
||||
import io
|
||||
from typing import Optional
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from UM.Resources import Resources
|
||||
|
@ -11,7 +12,7 @@ from UM.Util import parseBool
|
|||
from cura.CuraApplication import CuraApplication
|
||||
|
||||
import UM.Dictionary
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.InstanceContainer import InstanceContainer, InvalidInstanceError
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
## Handles serializing and deserializing material containers from an XML file
|
||||
|
@ -370,8 +371,30 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
self._dirty = False
|
||||
self._path = ""
|
||||
|
||||
def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]:
|
||||
return "material"
|
||||
|
||||
def getVersionFromSerialized(self, serialized: str) -> Optional[int]:
|
||||
version = None
|
||||
data = ET.fromstring(serialized)
|
||||
metadata = data.iterfind("./um:metadata/*", self.__namespaces)
|
||||
for entry in metadata:
|
||||
tag_name = _tag_without_namespace(entry)
|
||||
if tag_name == "version":
|
||||
try:
|
||||
version = int(entry.text)
|
||||
except Exception as e:
|
||||
raise InvalidInstanceError("Invalid version string '%s': %s" % (entry.text, e))
|
||||
break
|
||||
if version is None:
|
||||
raise InvalidInstanceError("Missing version in metadata")
|
||||
return version
|
||||
|
||||
## Overridden from InstanceContainer
|
||||
def deserialize(self, serialized):
|
||||
# update the serialized data first
|
||||
from UM.Settings.Interfaces import ContainerInterface
|
||||
serialized = ContainerInterface.deserialize(self, serialized)
|
||||
data = ET.fromstring(serialized)
|
||||
|
||||
# Reset previous metadata
|
||||
|
@ -406,10 +429,10 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
continue
|
||||
meta_data[tag_name] = entry.text
|
||||
|
||||
if not "description" in meta_data:
|
||||
if "description" not in meta_data:
|
||||
meta_data["description"] = ""
|
||||
|
||||
if not "adhesion_info" in meta_data:
|
||||
if "adhesion_info" not in meta_data:
|
||||
meta_data["adhesion_info"] = ""
|
||||
|
||||
property_values = {}
|
||||
|
@ -583,7 +606,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
"Ultimaker 2 Extended": "ultimaker2_extended",
|
||||
"Ultimaker 2 Extended+": "ultimaker2_extended_plus",
|
||||
"Ultimaker Original": "ultimaker_original",
|
||||
"Ultimaker Original+": "ultimaker_original_plus"
|
||||
"Ultimaker Original+": "ultimaker_original_plus",
|
||||
"IMADE3D JellyBOX": "imade3d_jellybox"
|
||||
}
|
||||
|
||||
# Map of recognised namespaces with a proper prefix.
|
||||
|
|
|
@ -845,7 +845,7 @@
|
|||
"unit": "mm",
|
||||
"default_value": 0.8,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
|
||||
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
|
||||
"maximum_value": "machine_height",
|
||||
"type": "float",
|
||||
"value": "top_bottom_thickness",
|
||||
|
@ -860,7 +860,7 @@
|
|||
"minimum_value": "0",
|
||||
"maximum_value_warning": "100",
|
||||
"type": "int",
|
||||
"minimum_value_warning": "4",
|
||||
"minimum_value_warning": "2",
|
||||
"value": "0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / resolveOrValue('layer_height'), 4))",
|
||||
"settable_per_mesh": true
|
||||
}
|
||||
|
@ -873,7 +873,7 @@
|
|||
"unit": "mm",
|
||||
"default_value": 0.6,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
|
||||
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
|
||||
"type": "float",
|
||||
"value": "top_bottom_thickness",
|
||||
"maximum_value": "machine_height",
|
||||
|
@ -885,7 +885,7 @@
|
|||
"label": "Bottom Layers",
|
||||
"description": "The number of bottom layers. When calculated by the bottom thickness, this value is rounded to a whole number.",
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "4",
|
||||
"minimum_value_warning": "2",
|
||||
"default_value": 6,
|
||||
"type": "int",
|
||||
"value": "999999 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / resolveOrValue('layer_height'), 4))",
|
||||
|
@ -1301,7 +1301,7 @@
|
|||
"type": "int",
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "4",
|
||||
"maximum_value": "(20 - math.log(infill_line_distance) / math.log(2)) if infill_line_distance > 0 and not spaghetti_infill_enabled else 0",
|
||||
"maximum_value": "0 if spaghetti_infill_enabled else (999999 if infill_line_distance == 0 else (20 - math.log(infill_line_distance) / math.log(2)))",
|
||||
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv' and not spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
|
@ -2332,7 +2332,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
|
@ -2346,7 +2345,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
|
@ -2360,7 +2358,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
|
@ -2375,7 +2372,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_wall",
|
||||
|
@ -2389,7 +2385,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_wall",
|
||||
|
@ -2405,7 +2400,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
|
@ -2419,7 +2413,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
|
@ -2438,7 +2431,6 @@
|
|||
"default_value": 20,
|
||||
"value": "jerk_support",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled') and support_enable",
|
||||
"limit_to_extruder": "support_infill_extruder_nr",
|
||||
|
@ -2454,7 +2446,6 @@
|
|||
"default_value": 20,
|
||||
"value": "jerk_support",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
|
||||
"limit_to_extruder": "support_interface_extruder_nr",
|
||||
|
@ -2470,7 +2461,6 @@
|
|||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
|
@ -2487,7 +2477,6 @@
|
|||
"type": "float",
|
||||
"default_value": 30,
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"value": "jerk_print if magic_spiralize else 30",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
|
@ -2502,7 +2491,6 @@
|
|||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
"settable_per_mesh": true,
|
||||
|
@ -2517,7 +2505,6 @@
|
|||
"default_value": 20,
|
||||
"value": "jerk_layer_0",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
"settable_per_mesh": true
|
||||
|
@ -2531,7 +2518,6 @@
|
|||
"default_value": 20,
|
||||
"value": "jerk_layer_0 * jerk_travel / jerk_print",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
"settable_per_extruder": true,
|
||||
|
@ -2547,7 +2533,6 @@
|
|||
"type": "float",
|
||||
"default_value": 20,
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"value": "jerk_layer_0",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
"machine_center_is_zero": { "default_value": false },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_start_gcode": {
|
||||
"default_value": ";---------------------------------------\n; ; ; Jellybox Start Script Begin ; ; ;\n;_______________________________________\n; M92 E140 ;optionally adjust steps per mm for your filament\n\n; Print Settings Summary\n; (leave these alone: this is only a list of the slicing settings)\n; (overwriting these values will NOT change your printer's behavior)\n; sliced for : {machine_name}\n; nozzle diameter : {machine_nozzle_size}\n; filament diameter : {material_diameter}\n; layer height : {layer_height}\n; 1st layer height : {layer_height_0}\n; line width : {line_width}\n; outer wall wipe dist. : {wall_0_wipe_dist}\n; infill line width : {infill_line_width}\n; wall thickness : {wall_thickness}\n; top thickness : {top_thickness}\n; bottom thickness : {bottom_thickness}\n; infill density : {infill_sparse_density}\n; infill pattern : {infill_pattern}\n; print temperature : {material_print_temperature}\n; 1st layer print temp. : {material_print_temperature_layer_0}\n; heated bed temperature : {material_bed_temperature}\n; 1st layer bed temp. : {material_bed_temperature_layer_0}\n; regular fan speed : {cool_fan_speed_min}\n; max fan speed : {cool_fan_speed_max}\n; retraction amount : {retraction_amount}\n; retr. retract speed : {retraction_retract_speed}\n; retr. prime speed : {retraction_prime_speed}\n; build plate adhesion : {adhesion_type}\n; support ? {support_enable}\n; spiralized ? {magic_spiralize}\n\nM117 Preparing ;write Preparing\nM140 S{material_bed_temperature_layer_0} ;set bed temperature and move on\nM104 S{material_print_temperature_layer_0} ;set extruder temperature and move on\nM206 X10.0 Y0.0 ;set x homing offset for default bed leveling\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nM82 ;set extruder to absolute mode\nG28 ;home all axes\nM203 Z4 ;slow Z speed down for greater accuracy when probing\nG29 ;auto bed leveling procedure\nM203 Z7 ;pick up z speed again for printing\nM190 S{material_bed_temperature_layer_0} ;wait for the bed to reach desired temperature\nM109 S{material_print_temperature_layer_0} ;wait for the extruder to reach desired temperature\nG92 E0 ;reset the extruder position\nG1 F1500 E15 ;extrude 15mm of feed stock\nG92 E0 ;reset the extruder position again\nM117 Print starting ;write Print starting\n;---------------------------------------------\n; ; ; Jellybox Printer Start Script End ; ; ;\n;_____________________________________________\n"
|
||||
"default_value": ";---------------------------------------\n; ; ; Jellybox Start Script Begin ; ; ;\n;_______________________________________\n; M92 E140 ;optionally adjust steps per mm for your filament\n\n; Print Settings Summary\n; (leave these alone: this is only a list of the slicing settings)\n; (overwriting these values will NOT change your printer's behavior)\n; sliced for : {machine_name}\n; nozzle diameter : {machine_nozzle_size}\n; filament diameter : {material_diameter}\n; layer height : {layer_height}\n; 1st layer height : {layer_height_0}\n; line width : {line_width}\n; outer wall wipe dist. : {wall_0_wipe_dist}\n; infill line width : {infill_line_width}\n; wall thickness : {wall_thickness}\n; top thickness : {top_thickness}\n; bottom thickness : {bottom_thickness}\n; infill density : {infill_sparse_density}\n; infill pattern : {infill_pattern}\n; print temperature : {material_print_temperature}\n; 1st layer print temp. : {material_print_temperature_layer_0}\n; heated bed temperature : {material_bed_temperature}\n; 1st layer bed temp. : {material_bed_temperature_layer_0}\n; regular fan speed : {cool_fan_speed_min}\n; max fan speed : {cool_fan_speed_max}\n; retraction amount : {retraction_amount}\n; retr. retract speed : {retraction_retract_speed}\n; retr. prime speed : {retraction_prime_speed}\n; build plate adhesion : {adhesion_type}\n; support ? {support_enable}\n; spiralized ? {magic_spiralize}\n\nM117 Preparing ;write Preparing\nM140 S{material_bed_temperature_layer_0} ;set bed temperature and move on\nM109 S{material_print_temperature} ; wait for the extruder to reach desired temperature\nM206 X10.0 Y0.0 ;set x homing offset for default bed leveling\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nM82 ;set extruder to absolute mode\nG28 ;home all axes\nM203 Z4 ;slow Z speed down for greater accuracy when probing\nG29 ;auto bed leveling procedure\nM203 Z7 ;pick up z speed again for printing\nM190 S{material_bed_temperature_layer_0} ;wait for the bed to reach desired temperature\nM109 S{material_print_temperature_layer_0} ;wait for the extruder to reach desired temperature\nG92 E0 ;reset the extruder position\nG1 F1500 E15 ;extrude 15mm of feed stock\nG92 E0 ;reset the extruder position again\nM117 Print starting ;write Print starting\n;---------------------------------------------\n; ; ; Jellybox Printer Start Script End ; ; ;\n;_____________________________________________\n"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "\n;---------------------------------\n;;; Jellybox End Script Begin ;;;\n;_________________________________\nM117 Finishing Up ;write Finishing Up\n\nM104 S0 ;extruder heater off\nM140 S0 ;bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG90 ;absolute positioning\nG28 X ;home x, so the head is out of the way\nG1 Y100 ;move Y forward, so the print is more accessible\nM84 ;steppers off\n\nM117 Print finished ;write Print finished\n;---------------------------------------\n;;; Jellybox End Script End ;;;\n;_______________________________________"
|
||||
|
|
130
resources/definitions/rigid3d_zero2.def.json
Normal file
130
resources/definitions/rigid3d_zero2.def.json
Normal file
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"id": "rigid3d_zero2",
|
||||
"name": "Rigid3D Zero2",
|
||||
"version": 2,
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "Rigid3D",
|
||||
"manufacturer": "Rigid3D",
|
||||
"category": "Other",
|
||||
"has_materials": false,
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "rigid3d_zero2_platform.stl",
|
||||
"platform_offset": [ 5, 0, -35]
|
||||
},
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "Rigid3D Zero2" },
|
||||
"machine_head_with_fans_polygon": {
|
||||
"default_value": [[ 30, 30], [ 30, 70], [ 30, 70], [ 30, 30]]
|
||||
},
|
||||
"z_seam_type": {
|
||||
"default_value": "random"
|
||||
},
|
||||
"machine_heated_bed": {
|
||||
"default_value": true
|
||||
},
|
||||
"layer_height": {
|
||||
"default_value": 0.2
|
||||
},
|
||||
"layer_height_0": {
|
||||
"default_value": 0.2
|
||||
},
|
||||
"wall_thickness": {
|
||||
"default_value": 0.8
|
||||
},
|
||||
"top_bottom_thickness": {
|
||||
"default_value": 0.8
|
||||
},
|
||||
"xy_offset": {
|
||||
"default_value": -0.2
|
||||
},
|
||||
"material_print_temperature": {
|
||||
"value": 235
|
||||
},
|
||||
"material_bed_temperature": {
|
||||
"default_value": 100
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"speed_print": {
|
||||
"default_value": 40
|
||||
},
|
||||
"speed_layer_0": {
|
||||
"value": 15
|
||||
},
|
||||
"speed_tarvel": {
|
||||
"value": 100
|
||||
},
|
||||
"support_enable": {
|
||||
"default_value": false
|
||||
},
|
||||
"infill_sparse_density": {
|
||||
"default_value": 15
|
||||
},
|
||||
"infill_pattern": {
|
||||
"default_value": "lines",
|
||||
"value": "lines"
|
||||
},
|
||||
"retraction_amount": {
|
||||
"default_value": 1
|
||||
},
|
||||
"machine_width": {
|
||||
"default_value": 200
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 200
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 200
|
||||
},
|
||||
"machine_center_is_zero": {
|
||||
"default_value": false
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"gantry_height": {
|
||||
"default_value": 25
|
||||
},
|
||||
"machine_gcode_flavor": {
|
||||
"default_value": "RepRap"
|
||||
},
|
||||
"cool_fan_enabled": {
|
||||
"default_value": false
|
||||
},
|
||||
"cool_fan_speed": {
|
||||
"default_value": 50,
|
||||
"value": 50
|
||||
},
|
||||
"cool_fan_speed_min": {
|
||||
"default_value": 0
|
||||
},
|
||||
"cool_fan_full_at_height": {
|
||||
"default_value": 1.0,
|
||||
"value": 1.0
|
||||
},
|
||||
"support_z_distance": {
|
||||
"default_value": 0.2
|
||||
},
|
||||
"support_interface_enable": {
|
||||
"default_value": true
|
||||
},
|
||||
"support_interface_height": {
|
||||
"default_value": 0.8
|
||||
},
|
||||
"support_interface_density": {
|
||||
"default_value": 70
|
||||
},
|
||||
"support_interface_pattern": {
|
||||
"default_value": "grid"
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G21\nG28 ; Home extruder\nM107 ; Turn off fan\nG91 ; Relative positioning\nG1 Z5 F180;\nG1 X100 Y100 F3000;\nG1 Z-5 F180;\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nG92 E0 ; Reset extruder position\n"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "G1 X0 Y180 ; Get extruder out of way.\nM107 ; Turn off fan\nG91 ; Relative positioning\nG0 Z20 ; Lift extruder up\nT0\nG1 E-1 ; Reduce filament pressure\nM104 T0 S0 ; Turn extruder heater off\nG90 ; Absolute positioning\nG92 E0 ; Reset extruder position\nM140 S0 ; Disable heated bed\nM84 ; Turn steppers off\n"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,7 +70,7 @@
|
|||
"machine_start_gcode": { "default_value": "" },
|
||||
"machine_end_gcode": { "default_value": "" },
|
||||
"prime_tower_position_x": { "default_value": 175 },
|
||||
"prime_tower_position_y": { "default_value": 179 },
|
||||
"prime_tower_position_y": { "default_value": 178 },
|
||||
"prime_tower_wipe_enabled": { "default_value": false },
|
||||
|
||||
"acceleration_enabled": { "value": "True" },
|
||||
|
|
BIN
resources/meshes/rigid3d_zero2_platform.stl
Normal file
BIN
resources/meshes/rigid3d_zero2_platform.stl
Normal file
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -180,7 +180,7 @@ UM.Dialog
|
|||
anchors.bottom:parent.bottom
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
text: catalog.i18nc("@label", "Printer Name:")
|
||||
anchors.verticalCenter: machineName.verticalCenter
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -132,7 +132,7 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: boundingSpec
|
||||
anchors.top: jobNameRow.bottom
|
||||
|
@ -169,7 +169,7 @@ Item {
|
|||
color: UM.Theme.getColor("text_subtext")
|
||||
source: UM.Theme.getIcon("print_time")
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: timeSpec
|
||||
anchors.right: lengthIcon.left
|
||||
|
@ -192,7 +192,7 @@ Item {
|
|||
color: UM.Theme.getColor("text_subtext")
|
||||
source: UM.Theme.getIcon("category_material")
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: lengthSpec
|
||||
anchors.right: parent.right
|
||||
|
|
138
resources/qml/Menus/ContextMenu.qml
Normal file
138
resources/qml/Menus/ContextMenu.qml
Normal file
|
@ -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(base.findItemIndex(extruderHeader) + 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" }
|
||||
}
|
|
@ -66,7 +66,7 @@ UM.ManagementPage
|
|||
visible: base.currentItem != null
|
||||
anchors.fill: parent
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: machineName
|
||||
text: base.currentItem && base.currentItem.name ? base.currentItem.name : ""
|
||||
|
@ -146,26 +146,28 @@ UM.ManagementPage
|
|||
property var connectedPrinter: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null
|
||||
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
text: catalog.i18nc("@label", "Printer type:")
|
||||
visible: base.currentItem && "definition_name" in base.currentItem.metadata
|
||||
}
|
||||
Label {
|
||||
Text
|
||||
{
|
||||
text: (base.currentItem && "definition_name" in base.currentItem.metadata) ? base.currentItem.metadata.definition_name : ""
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
text: catalog.i18nc("@label", "Connection:")
|
||||
visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId
|
||||
}
|
||||
Label {
|
||||
Text
|
||||
{
|
||||
width: parent.width * 0.7
|
||||
text: machineInfo.printerConnected ? machineInfo.connectedPrinter.connectionText : catalog.i18nc("@info:status", "The printer is not connected.")
|
||||
visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
text: catalog.i18nc("@label", "State:")
|
||||
visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId && machineInfo.printerAcceptsCommands
|
||||
|
|
|
@ -273,17 +273,28 @@ TabView
|
|||
{
|
||||
id: spinBox
|
||||
anchors.left: label.right
|
||||
value: parseFloat(provider.properties.value);
|
||||
width: base.secondColumnWidth;
|
||||
value: {
|
||||
if (!isNaN(parseFloat(materialPropertyProvider.properties.value)))
|
||||
{
|
||||
return parseFloat(materialPropertyProvider.properties.value);
|
||||
}
|
||||
if (!isNaN(parseFloat(machinePropertyProvider.properties.value)))
|
||||
{
|
||||
return parseFloat(machinePropertyProvider.properties.value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
width: base.secondColumnWidth
|
||||
readOnly: !base.editingEnabled
|
||||
suffix: model.unit
|
||||
suffix: " " + model.unit
|
||||
maximumValue: 99999
|
||||
decimals: model.unit == "mm" ? 2 : 0
|
||||
|
||||
onEditingFinished: provider.setPropertyValue("value", value)
|
||||
onEditingFinished: materialPropertyProvider.setPropertyValue("value", value)
|
||||
}
|
||||
|
||||
UM.ContainerPropertyProvider { id: provider; containerId: base.containerId; watchedProperties: [ "value" ]; key: model.key }
|
||||
UM.ContainerPropertyProvider { id: materialPropertyProvider; containerId: base.containerId; watchedProperties: [ "value" ]; key: model.key }
|
||||
UM.ContainerPropertyProvider { id: machinePropertyProvider; containerId: Cura.MachineManager.activeDefinitionId; watchedProperties: [ "value" ]; key: model.key }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -649,6 +649,7 @@ Column
|
|||
sourceComponent: monitorItem
|
||||
property string label: catalog.i18nc("@label", "Estimated time left")
|
||||
property string value: connectedPrinter != null ? getPrettyTime(connectedPrinter.timeTotal - connectedPrinter.timeElapsed) : ""
|
||||
visible: connectedPrinter != null && (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused")
|
||||
}
|
||||
|
||||
Component
|
||||
|
|
93
resources/qml/Sidebar.qml
Normal file → Executable file
93
resources/qml/Sidebar.qml
Normal file → Executable file
|
@ -407,14 +407,81 @@ Rectangle
|
|||
}
|
||||
}
|
||||
ExclusiveGroup { id: modeMenuGroup; }
|
||||
ListView{
|
||||
id: modesList
|
||||
property var index: 0
|
||||
model: modesListModel
|
||||
delegate: wizardDelegate
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
|
||||
Text
|
||||
{
|
||||
id: toggleLeftText
|
||||
anchors.right: modeToggleSwitch.left
|
||||
anchors.rightMargin: UM.Theme.getSize("toggle_button_text_anchoring_margin").width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: ""
|
||||
color: UM.Theme.getColor("toggle_active_text")
|
||||
font: UM.Theme.getFont("default")
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
modeToggleSwitch.checked = false;
|
||||
}
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
clicked.connect(modeToggleSwitch.clicked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Switch
|
||||
{
|
||||
id: modeToggleSwitch
|
||||
checked: false
|
||||
anchors.right: toggleRightText.left
|
||||
anchors.rightMargin: UM.Theme.getSize("toggle_button_text_anchoring_margin").width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
onClicked:
|
||||
{
|
||||
var index = 0;
|
||||
if (checked)
|
||||
{
|
||||
index = 1;
|
||||
}
|
||||
updateActiveMode(index);
|
||||
}
|
||||
|
||||
function updateActiveMode(index)
|
||||
{
|
||||
base.currentModeIndex = index;
|
||||
UM.Preferences.setValue("cura/active_mode", index);
|
||||
}
|
||||
|
||||
style: UM.Theme.styles.toggle_button
|
||||
}
|
||||
|
||||
Text
|
||||
{
|
||||
id: toggleRightText
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: ""
|
||||
color: UM.Theme.getColor("toggle_active_text")
|
||||
font: UM.Theme.getFont("default")
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
onClicked:
|
||||
{
|
||||
modeToggleSwitch.checked = true;
|
||||
}
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
clicked.connect(modeToggleSwitch.clicked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,10 +608,14 @@ Rectangle
|
|||
})
|
||||
sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true });
|
||||
|
||||
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
|
||||
if(index)
|
||||
toggleLeftText.text = modesListModel.get(0).text;
|
||||
toggleRightText.text = modesListModel.get(1).text;
|
||||
|
||||
var index = parseInt(UM.Preferences.getValue("cura/active_mode"));
|
||||
if (index)
|
||||
{
|
||||
currentModeIndex = index;
|
||||
modeToggleSwitch.checked = index > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,4 +638,4 @@ Rectangle
|
|||
watchedProperties: [ "value" ]
|
||||
storeIndex: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ cool_min_layer_time_fan_speed_max = 5
|
|||
cool_min_speed = 5
|
||||
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
|
||||
|
|
|
@ -8,6 +8,44 @@ import QtQuick.Controls.Styles 1.1
|
|||
import UM 1.1 as UM
|
||||
|
||||
QtObject {
|
||||
property Component toggle_button: 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");
|
||||
} else {
|
||||
return UM.Theme.getColor("sidebar_header_bar");
|
||||
}
|
||||
}
|
||||
Behavior on border.color { ColorAnimation { duration: 50; } }
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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");
|
||||
} else {
|
||||
return UM.Theme.getColor("sidebar_header_bar");
|
||||
}
|
||||
}
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property Component sidebar_header_button: Component {
|
||||
ButtonStyle {
|
||||
background: Rectangle {
|
||||
|
|
|
@ -319,6 +319,11 @@
|
|||
|
||||
"infill_button_margin": [0.5, 0.5],
|
||||
|
||||
"jobspecs_line": [2.0, 2.0]
|
||||
"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]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue