mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-16 03:07:53 -06:00
Allow to set print sequence manually
This commit is contained in:
parent
6aaee84b95
commit
2b05a370ca
53 changed files with 1021 additions and 88 deletions
|
@ -161,6 +161,10 @@ pycharm_targets:
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestGCodeListDecorator.py
|
name: pytest in TestGCodeListDecorator.py
|
||||||
script_name: tests/TestGCodeListDecorator.py
|
script_name: tests/TestGCodeListDecorator.py
|
||||||
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
|
module_name: Cura
|
||||||
|
name: pytest in TestHitChecker.py
|
||||||
|
script_name: tests/TestHitChecker.py
|
||||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestIntentManager.py
|
name: pytest in TestIntentManager.py
|
||||||
|
@ -189,6 +193,10 @@ pycharm_targets:
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestPrintInformation.py
|
name: pytest in TestPrintInformation.py
|
||||||
script_name: tests/TestPrintInformation.py
|
script_name: tests/TestPrintInformation.py
|
||||||
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
|
module_name: Cura
|
||||||
|
name: pytest in TestPrintOrderManager.py
|
||||||
|
script_name: tests/TestPrintOrderManager.py
|
||||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestProfileRequirements.py
|
name: pytest in TestProfileRequirements.py
|
||||||
|
|
|
@ -125,6 +125,7 @@ from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel
|
||||||
from .Machines.Models.MachineListModel import MachineListModel
|
from .Machines.Models.MachineListModel import MachineListModel
|
||||||
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
||||||
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
||||||
|
from .PrintOrderManager import PrintOrderManager
|
||||||
from .SingleInstance import SingleInstance
|
from .SingleInstance import SingleInstance
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -202,6 +203,7 @@ class CuraApplication(QtApplication):
|
||||||
self._container_manager = None
|
self._container_manager = None
|
||||||
|
|
||||||
self._object_manager = None
|
self._object_manager = None
|
||||||
|
self._print_order_manager = None
|
||||||
self._extruders_model = None
|
self._extruders_model = None
|
||||||
self._extruders_model_with_optional = None
|
self._extruders_model_with_optional = None
|
||||||
self._build_plate_model = None
|
self._build_plate_model = None
|
||||||
|
@ -899,6 +901,7 @@ class CuraApplication(QtApplication):
|
||||||
# initialize info objects
|
# initialize info objects
|
||||||
self._print_information = PrintInformation.PrintInformation(self)
|
self._print_information = PrintInformation.PrintInformation(self)
|
||||||
self._cura_actions = CuraActions.CuraActions(self)
|
self._cura_actions = CuraActions.CuraActions(self)
|
||||||
|
self._print_order_manager = PrintOrderManager(self.getObjectsModel().getNodes)
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
# Initialize setting visibility presets model.
|
# Initialize setting visibility presets model.
|
||||||
self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self.getPreferences(), parent = self)
|
self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self.getPreferences(), parent = self)
|
||||||
|
@ -979,6 +982,7 @@ class CuraApplication(QtApplication):
|
||||||
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis])
|
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis])
|
||||||
|
|
||||||
Selection.selectionChanged.connect(self.onSelectionChanged)
|
Selection.selectionChanged.connect(self.onSelectionChanged)
|
||||||
|
self._print_order_manager.printOrderChanged.connect(self._onPrintOrderChanged)
|
||||||
|
|
||||||
# Set default background color for scene
|
# Set default background color for scene
|
||||||
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
||||||
|
@ -1218,6 +1222,7 @@ class CuraApplication(QtApplication):
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
engine.rootContext().setContextProperty("Printer", self)
|
engine.rootContext().setContextProperty("Printer", self)
|
||||||
engine.rootContext().setContextProperty("CuraApplication", self)
|
engine.rootContext().setContextProperty("CuraApplication", self)
|
||||||
|
engine.rootContext().setContextProperty("PrintOrderManager", self._print_order_manager)
|
||||||
engine.rootContext().setContextProperty("PrintInformation", self._print_information)
|
engine.rootContext().setContextProperty("PrintInformation", self._print_information)
|
||||||
engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
|
engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
|
||||||
engine.rootContext().setContextProperty("CuraSDKVersion", ApplicationMetadata.CuraSDKVersion)
|
engine.rootContext().setContextProperty("CuraSDKVersion", ApplicationMetadata.CuraSDKVersion)
|
||||||
|
@ -1715,8 +1720,12 @@ class CuraApplication(QtApplication):
|
||||||
Selection.remove(node)
|
Selection.remove(node)
|
||||||
Selection.add(group_node)
|
Selection.add(group_node)
|
||||||
|
|
||||||
|
all_nodes = self.getObjectsModel().getNodes()
|
||||||
|
PrintOrderManager.updatePrintOrdersAfterGroupOperation(all_nodes, group_node, selected_nodes)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def ungroupSelected(self) -> None:
|
def ungroupSelected(self) -> None:
|
||||||
|
all_nodes = self.getObjectsModel().getNodes()
|
||||||
selected_objects = Selection.getAllSelectedObjects().copy()
|
selected_objects = Selection.getAllSelectedObjects().copy()
|
||||||
for node in selected_objects:
|
for node in selected_objects:
|
||||||
if node.callDecoration("isGroup"):
|
if node.callDecoration("isGroup"):
|
||||||
|
@ -1724,21 +1733,30 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
group_parent = node.getParent()
|
group_parent = node.getParent()
|
||||||
children = node.getChildren().copy()
|
children = node.getChildren().copy()
|
||||||
for child in children:
|
|
||||||
# Ungroup only 1 level deep
|
|
||||||
if child.getParent() != node:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
# Ungroup only 1 level deep
|
||||||
|
children_to_ungroup = list(filter(lambda child: child.getParent() == node, children))
|
||||||
|
for child in children_to_ungroup:
|
||||||
# Set the parent of the children to the parent of the group-node
|
# Set the parent of the children to the parent of the group-node
|
||||||
op.addOperation(SetParentOperation(child, group_parent))
|
op.addOperation(SetParentOperation(child, group_parent))
|
||||||
|
|
||||||
# Add all individual nodes to the selection
|
# Add all individual nodes to the selection
|
||||||
Selection.add(child)
|
Selection.add(child)
|
||||||
|
|
||||||
|
PrintOrderManager.updatePrintOrdersAfterUngroupOperation(all_nodes, node, children_to_ungroup)
|
||||||
op.push()
|
op.push()
|
||||||
# Note: The group removes itself from the scene once all its children have left it,
|
# Note: The group removes itself from the scene once all its children have left it,
|
||||||
# see GroupDecorator._onChildrenChanged
|
# see GroupDecorator._onChildrenChanged
|
||||||
|
|
||||||
|
def _onPrintOrderChanged(self) -> None:
|
||||||
|
# update object list
|
||||||
|
scene = self.getController().getScene()
|
||||||
|
scene.sceneChanged.emit(scene.getRoot())
|
||||||
|
|
||||||
|
# reset if already was sliced
|
||||||
|
Application.getInstance().getBackend().needsSlicing()
|
||||||
|
Application.getInstance().getBackend().tickle()
|
||||||
|
|
||||||
def _createSplashScreen(self) -> Optional[CuraSplashScreen.CuraSplashScreen]:
|
def _createSplashScreen(self) -> Optional[CuraSplashScreen.CuraSplashScreen]:
|
||||||
if self._is_headless:
|
if self._is_headless:
|
||||||
return None
|
return None
|
||||||
|
|
88
cura/HitChecker.py
Normal file
88
cura/HitChecker.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
from typing import List, Dict
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
|
class HitChecker:
|
||||||
|
"""Checks if nodes can be printed without causing any collisions and interference"""
|
||||||
|
|
||||||
|
def __init__(self, nodes: List[CuraSceneNode]) -> None:
|
||||||
|
self._hit_map = self._buildHitMap(nodes)
|
||||||
|
|
||||||
|
def anyTwoNodesBlockEachOther(self, nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True if any 2 nodes block each other"""
|
||||||
|
for a in nodes:
|
||||||
|
for b in nodes:
|
||||||
|
if self._hit_map[a][b] and self._hit_map[b][a]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def canPrintBefore(self, node: CuraSceneNode, other_nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True if node doesn't block other_nodes and can be printed before them"""
|
||||||
|
no_hits = all(not self._hit_map[node][other_node] for other_node in other_nodes)
|
||||||
|
return no_hits
|
||||||
|
|
||||||
|
def canPrintAfter(self, node: CuraSceneNode, other_nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True if node doesn't hit other nodes and can be printed after them"""
|
||||||
|
no_hits = all(not self._hit_map[other_node][node] for other_node in other_nodes)
|
||||||
|
return no_hits
|
||||||
|
|
||||||
|
def calculateScore(self, a: CuraSceneNode, b: CuraSceneNode) -> int:
|
||||||
|
"""Calculate score simply sums the number of other objects it 'blocks'
|
||||||
|
|
||||||
|
:param a: node
|
||||||
|
:param b: node
|
||||||
|
:return: sum of the number of other objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
score_a = sum(self._hit_map[a].values())
|
||||||
|
score_b = sum(self._hit_map[b].values())
|
||||||
|
return score_a - score_b
|
||||||
|
|
||||||
|
def canPrintNodesInProvidedOrder(self, ordered_nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True If nodes don't have any hits in provided order"""
|
||||||
|
for node_index, node in enumerate(ordered_nodes):
|
||||||
|
nodes_before = ordered_nodes[:node_index - 1] if node_index - 1 >= 0 else []
|
||||||
|
nodes_after = ordered_nodes[node_index + 1:] if node_index + 1 < len(ordered_nodes) else []
|
||||||
|
if not self.canPrintBefore(node, nodes_after) or not self.canPrintAfter(node, nodes_before):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _buildHitMap(nodes: List[CuraSceneNode]) -> Dict[CuraSceneNode, CuraSceneNode]:
|
||||||
|
"""Pre-computes all hits between all objects
|
||||||
|
|
||||||
|
:nodes: nodes that need to be checked for collisions
|
||||||
|
:return: dictionary where hit_map[node1][node2] is False if there node1 can be printed before node2
|
||||||
|
"""
|
||||||
|
hit_map = {j: {i: HitChecker._checkHit(j, i) for i in nodes} for j in nodes}
|
||||||
|
return hit_map
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _checkHit(a: CuraSceneNode, b: CuraSceneNode) -> bool:
|
||||||
|
"""Checks if a can be printed before b
|
||||||
|
|
||||||
|
:param a: node
|
||||||
|
:param b: node
|
||||||
|
:return: False if a can be printed before b
|
||||||
|
"""
|
||||||
|
|
||||||
|
if a == b:
|
||||||
|
return False
|
||||||
|
|
||||||
|
a_hit_hull = a.callDecoration("getConvexHullBoundary")
|
||||||
|
b_hit_hull = b.callDecoration("getConvexHullHeadFull")
|
||||||
|
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
||||||
|
|
||||||
|
if overlap:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Adhesion areas must never overlap, regardless of printing order
|
||||||
|
# This would cause over-extrusion
|
||||||
|
a_hit_hull = a.callDecoration("getAdhesionArea")
|
||||||
|
b_hit_hull = b.callDecoration("getAdhesionArea")
|
||||||
|
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
||||||
|
|
||||||
|
if overlap:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
|
@ -7,6 +7,11 @@ from UM.Scene.Iterator import Iterator
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from functools import cmp_to_key
|
from functools import cmp_to_key
|
||||||
|
|
||||||
|
from cura.HitChecker import HitChecker
|
||||||
|
from cura.PrintOrderManager import PrintOrderManager
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
class OneAtATimeIterator(Iterator.Iterator):
|
class OneAtATimeIterator(Iterator.Iterator):
|
||||||
"""Iterator that returns a list of nodes in the order that they need to be printed
|
"""Iterator that returns a list of nodes in the order that they need to be printed
|
||||||
|
|
||||||
|
@ -16,8 +21,6 @@ class OneAtATimeIterator(Iterator.Iterator):
|
||||||
|
|
||||||
def __init__(self, scene_node) -> None:
|
def __init__(self, scene_node) -> None:
|
||||||
super().__init__(scene_node) # Call super to make multiple inheritance work.
|
super().__init__(scene_node) # Call super to make multiple inheritance work.
|
||||||
self._hit_map = [[]] # type: List[List[bool]] # For each node, which other nodes this hits. A grid of booleans on which nodes hit which.
|
|
||||||
self._original_node_list = [] # type: List[SceneNode] # The nodes that need to be checked for collisions.
|
|
||||||
|
|
||||||
def _fillStack(self) -> None:
|
def _fillStack(self) -> None:
|
||||||
"""Fills the ``_node_stack`` with a list of scene nodes that need to be printed in order. """
|
"""Fills the ``_node_stack`` with a list of scene nodes that need to be printed in order. """
|
||||||
|
@ -38,104 +41,50 @@ class OneAtATimeIterator(Iterator.Iterator):
|
||||||
self._node_stack = node_list[:]
|
self._node_stack = node_list[:]
|
||||||
return
|
return
|
||||||
|
|
||||||
# Copy the list
|
hit_checker = HitChecker(node_list)
|
||||||
self._original_node_list = node_list[:]
|
|
||||||
|
|
||||||
# Initialise the hit map (pre-compute all hits between all objects)
|
if PrintOrderManager.isUserDefinedPrintOrderEnabled():
|
||||||
self._hit_map = [[self._checkHit(i, j) for i in node_list] for j in node_list]
|
self._node_stack = self._getNodesOrderedByUser(hit_checker, node_list)
|
||||||
|
else:
|
||||||
|
self._node_stack = self._getNodesOrderedAutomatically(hit_checker, node_list)
|
||||||
|
|
||||||
# Check if we have to files that block each other. If this is the case, there is no solution!
|
# update print orders so that user can try to arrange the nodes automatically first
|
||||||
for a in range(0, len(node_list)):
|
# and if result is not satisfactory he/she can switch to manual mode and change it
|
||||||
for b in range(0, len(node_list)):
|
for index, node in enumerate(self._node_stack):
|
||||||
if a != b and self._hit_map[a][b] and self._hit_map[b][a]:
|
node.printOrder = index + 1
|
||||||
return
|
|
||||||
|
@staticmethod
|
||||||
|
def _getNodesOrderedByUser(hit_checker: HitChecker, node_list: List[CuraSceneNode]) -> List[CuraSceneNode]:
|
||||||
|
nodes_ordered_by_user = sorted(node_list, key=lambda n: n.printOrder)
|
||||||
|
if hit_checker.canPrintNodesInProvidedOrder(nodes_ordered_by_user):
|
||||||
|
return nodes_ordered_by_user
|
||||||
|
return [] # No solution
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _getNodesOrderedAutomatically(hit_checker: HitChecker, node_list: List[CuraSceneNode]) -> List[CuraSceneNode]:
|
||||||
|
# Check if we have two files that block each other. If this is the case, there is no solution!
|
||||||
|
if hit_checker.anyTwoNodesBlockEachOther(node_list):
|
||||||
|
return [] # No solution
|
||||||
|
|
||||||
# Sort the original list so that items that block the most other objects are at the beginning.
|
# Sort the original list so that items that block the most other objects are at the beginning.
|
||||||
# This does not decrease the worst case running time, but should improve it in most cases.
|
# This does not decrease the worst case running time, but should improve it in most cases.
|
||||||
sorted(node_list, key = cmp_to_key(self._calculateScore))
|
sorted(node_list, key = cmp_to_key(hit_checker.calculateScore))
|
||||||
|
|
||||||
todo_node_list = [_ObjectOrder([], node_list)]
|
todo_node_list = [_ObjectOrder([], node_list)]
|
||||||
while len(todo_node_list) > 0:
|
while len(todo_node_list) > 0:
|
||||||
current = todo_node_list.pop()
|
current = todo_node_list.pop()
|
||||||
for node in current.todo:
|
for node in current.todo:
|
||||||
# Check if the object can be placed with what we have and still allows for a solution in the future
|
# Check if the object can be placed with what we have and still allows for a solution in the future
|
||||||
if not self._checkHitMultiple(node, current.order) and not self._checkBlockMultiple(node, current.todo):
|
if hit_checker.canPrintAfter(node, current.order) and hit_checker.canPrintBefore(node, current.todo):
|
||||||
# We found a possible result. Create new todo & order list.
|
# We found a possible result. Create new todo & order list.
|
||||||
new_todo_list = current.todo[:]
|
new_todo_list = current.todo[:]
|
||||||
new_todo_list.remove(node)
|
new_todo_list.remove(node)
|
||||||
new_order = current.order[:] + [node]
|
new_order = current.order[:] + [node]
|
||||||
if len(new_todo_list) == 0:
|
if len(new_todo_list) == 0:
|
||||||
# We have no more nodes to check, so quit looking.
|
# We have no more nodes to check, so quit looking.
|
||||||
self._node_stack = new_order
|
return new_order # Solution found!
|
||||||
return
|
|
||||||
todo_node_list.append(_ObjectOrder(new_order, new_todo_list))
|
todo_node_list.append(_ObjectOrder(new_order, new_todo_list))
|
||||||
self._node_stack = [] #No result found!
|
return [] # No result found!
|
||||||
|
|
||||||
|
|
||||||
# Check if first object can be printed before the provided list (using the hit map)
|
|
||||||
def _checkHitMultiple(self, node: SceneNode, other_nodes: List[SceneNode]) -> bool:
|
|
||||||
node_index = self._original_node_list.index(node)
|
|
||||||
for other_node in other_nodes:
|
|
||||||
other_node_index = self._original_node_list.index(other_node)
|
|
||||||
if self._hit_map[node_index][other_node_index]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _checkBlockMultiple(self, node: SceneNode, other_nodes: List[SceneNode]) -> bool:
|
|
||||||
"""Check for a node whether it hits any of the other nodes.
|
|
||||||
|
|
||||||
:param node: The node to check whether it collides with the other nodes.
|
|
||||||
:param other_nodes: The nodes to check for collisions.
|
|
||||||
:return: returns collision between nodes
|
|
||||||
"""
|
|
||||||
|
|
||||||
node_index = self._original_node_list.index(node)
|
|
||||||
for other_node in other_nodes:
|
|
||||||
other_node_index = self._original_node_list.index(other_node)
|
|
||||||
if self._hit_map[other_node_index][node_index] and node_index != other_node_index:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _calculateScore(self, a: SceneNode, b: SceneNode) -> int:
|
|
||||||
"""Calculate score simply sums the number of other objects it 'blocks'
|
|
||||||
|
|
||||||
:param a: node
|
|
||||||
:param b: node
|
|
||||||
:return: sum of the number of other objects
|
|
||||||
"""
|
|
||||||
|
|
||||||
score_a = sum(self._hit_map[self._original_node_list.index(a)])
|
|
||||||
score_b = sum(self._hit_map[self._original_node_list.index(b)])
|
|
||||||
return score_a - score_b
|
|
||||||
|
|
||||||
def _checkHit(self, a: SceneNode, b: SceneNode) -> bool:
|
|
||||||
"""Checks if a can be printed before b
|
|
||||||
|
|
||||||
:param a: node
|
|
||||||
:param b: node
|
|
||||||
:return: true if a can be printed before b
|
|
||||||
"""
|
|
||||||
|
|
||||||
if a == b:
|
|
||||||
return False
|
|
||||||
|
|
||||||
a_hit_hull = a.callDecoration("getConvexHullBoundary")
|
|
||||||
b_hit_hull = b.callDecoration("getConvexHullHeadFull")
|
|
||||||
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
|
||||||
|
|
||||||
if overlap:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Adhesion areas must never overlap, regardless of printing order
|
|
||||||
# This would cause over-extrusion
|
|
||||||
a_hit_hull = a.callDecoration("getAdhesionArea")
|
|
||||||
b_hit_hull = b.callDecoration("getAdhesionArea")
|
|
||||||
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
|
||||||
|
|
||||||
if overlap:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class _ObjectOrder:
|
class _ObjectOrder:
|
||||||
|
|
171
cura/PrintOrderManager.py
Normal file
171
cura/PrintOrderManager.py
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
from typing import List, Callable, Optional, Any
|
||||||
|
|
||||||
|
from PyQt6.QtCore import pyqtProperty, pyqtSignal, QObject, pyqtSlot
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Scene.Selection import Selection
|
||||||
|
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
|
class PrintOrderManager(QObject):
|
||||||
|
"""Allows to order the object list to set the print sequence manually"""
|
||||||
|
|
||||||
|
def __init__(self, get_nodes: Callable[[], List[CuraSceneNode]]) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._get_nodes = get_nodes
|
||||||
|
self._configureEvents()
|
||||||
|
|
||||||
|
_settingsChanged = pyqtSignal()
|
||||||
|
_uiActionsOutdated = pyqtSignal()
|
||||||
|
printOrderChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def swapSelectedAndPreviousNodes(self) -> None:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
self._swapPrintOrders(selected_node, previous_node)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def swapSelectedAndNextNodes(self) -> None:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
self._swapPrintOrders(selected_node, next_node)
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify=_uiActionsOutdated)
|
||||||
|
def previousNodeName(self) -> str:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
return self._getNodeName(previous_node)
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify=_uiActionsOutdated)
|
||||||
|
def nextNodeName(self) -> str:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
return self._getNodeName(next_node)
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=_uiActionsOutdated)
|
||||||
|
def shouldEnablePrintBeforeAction(self) -> bool:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
can_swap_with_previous_node = selected_node is not None and previous_node is not None
|
||||||
|
return can_swap_with_previous_node
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=_uiActionsOutdated)
|
||||||
|
def shouldEnablePrintAfterAction(self) -> bool:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
can_swap_with_next_node = selected_node is not None and next_node is not None
|
||||||
|
return can_swap_with_next_node
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=_settingsChanged)
|
||||||
|
def shouldShowEditPrintOrderActions(self) -> bool:
|
||||||
|
return PrintOrderManager.isUserDefinedPrintOrderEnabled()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def isUserDefinedPrintOrderEnabled() -> bool:
|
||||||
|
stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
is_enabled = stack and \
|
||||||
|
stack.getProperty("print_sequence", "value") == "one_at_a_time" and \
|
||||||
|
stack.getProperty("user_defined_print_order_enabled", "value")
|
||||||
|
return is_enabled
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def initializePrintOrders(nodes: List[CuraSceneNode]) -> None:
|
||||||
|
"""Just created (loaded from file) nodes have print order 0.
|
||||||
|
|
||||||
|
This method initializes print orders with max value to put nodes at the end of object list"""
|
||||||
|
max_print_order = max(map(lambda n: n.printOrder, nodes), default=0)
|
||||||
|
for node in nodes:
|
||||||
|
if node.printOrder == 0:
|
||||||
|
max_print_order += 1
|
||||||
|
node.printOrder = max_print_order
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def updatePrintOrdersAfterGroupOperation(
|
||||||
|
all_nodes: List[CuraSceneNode],
|
||||||
|
group_node: CuraSceneNode,
|
||||||
|
grouped_nodes: List[CuraSceneNode]
|
||||||
|
) -> None:
|
||||||
|
group_node.printOrder = min(map(lambda n: n.printOrder, grouped_nodes))
|
||||||
|
|
||||||
|
all_nodes.append(group_node)
|
||||||
|
for node in grouped_nodes:
|
||||||
|
all_nodes.remove(node)
|
||||||
|
|
||||||
|
# reassign print orders so there won't be gaps like 1 2 5 6 7
|
||||||
|
sorted_nodes = sorted(all_nodes, key=lambda n: n.printOrder)
|
||||||
|
for i, node in enumerate(sorted_nodes):
|
||||||
|
node.printOrder = i + 1
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def updatePrintOrdersAfterUngroupOperation(
|
||||||
|
all_nodes: List[CuraSceneNode],
|
||||||
|
group_node: CuraSceneNode,
|
||||||
|
ungrouped_nodes: List[CuraSceneNode]
|
||||||
|
) -> None:
|
||||||
|
all_nodes.remove(group_node)
|
||||||
|
nodes_to_update_print_order = filter(lambda n: n.printOrder > group_node.printOrder, all_nodes)
|
||||||
|
for node in nodes_to_update_print_order:
|
||||||
|
node.printOrder += len(ungrouped_nodes) - 1
|
||||||
|
|
||||||
|
for i, child in enumerate(ungrouped_nodes):
|
||||||
|
child.printOrder = group_node.printOrder + i
|
||||||
|
all_nodes.append(child)
|
||||||
|
|
||||||
|
def _swapPrintOrders(self, node1: CuraSceneNode, node2: CuraSceneNode) -> None:
|
||||||
|
if node1 and node2:
|
||||||
|
node1.printOrder, node2.printOrder = node2.printOrder, node1.printOrder # swap print orders
|
||||||
|
self.printOrderChanged.emit() # update object list first
|
||||||
|
self._uiActionsOutdated.emit() # then update UI actions
|
||||||
|
|
||||||
|
def _getSelectedAndNeighborNodes(self
|
||||||
|
) -> (Optional[CuraSceneNode], Optional[CuraSceneNode], Optional[CuraSceneNode]):
|
||||||
|
nodes = self._get_nodes()
|
||||||
|
ordered_nodes = sorted(nodes, key=lambda n: n.printOrder)
|
||||||
|
selected_node = PrintOrderManager._getSingleSelectedNode()
|
||||||
|
if selected_node and selected_node in ordered_nodes:
|
||||||
|
selected_node_index = ordered_nodes.index(selected_node)
|
||||||
|
else:
|
||||||
|
selected_node_index = None
|
||||||
|
|
||||||
|
if selected_node_index is not None and selected_node_index - 1 >= 0:
|
||||||
|
previous_node = ordered_nodes[selected_node_index - 1]
|
||||||
|
else:
|
||||||
|
previous_node = None
|
||||||
|
|
||||||
|
if selected_node_index is not None and selected_node_index + 1 < len(ordered_nodes):
|
||||||
|
next_node = ordered_nodes[selected_node_index + 1]
|
||||||
|
else:
|
||||||
|
next_node = None
|
||||||
|
|
||||||
|
return selected_node, previous_node, next_node
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _getNodeName(node: CuraSceneNode, max_length: int = 30) -> str:
|
||||||
|
node_name = node.getName() if node else ""
|
||||||
|
truncated_node_name = node_name[:max_length]
|
||||||
|
return truncated_node_name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _getSingleSelectedNode() -> Optional[CuraSceneNode]:
|
||||||
|
if len(Selection.getAllSelectedObjects()) == 1:
|
||||||
|
selected_node = Selection.getSelectedObject(0)
|
||||||
|
return selected_node
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _configureEvents(self) -> None:
|
||||||
|
Selection.selectionChanged.connect(self._onSelectionChanged)
|
||||||
|
self._global_stack = None
|
||||||
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
|
def _onGlobalStackChanged(self) -> None:
|
||||||
|
if self._global_stack:
|
||||||
|
self._global_stack.propertyChanged.disconnect(self._onSettingsChanged)
|
||||||
|
self._global_stack.containersChanged.disconnect(self._onSettingsChanged)
|
||||||
|
|
||||||
|
self._global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
|
||||||
|
if self._global_stack:
|
||||||
|
self._global_stack.propertyChanged.connect(self._onSettingsChanged)
|
||||||
|
self._global_stack.containersChanged.connect(self._onSettingsChanged)
|
||||||
|
|
||||||
|
def _onSettingsChanged(self, *args: Any) -> None:
|
||||||
|
self._settingsChanged.emit()
|
||||||
|
|
||||||
|
def _onSelectionChanged(self) -> None:
|
||||||
|
self._uiActionsOutdated.emit()
|
|
@ -25,10 +25,19 @@ class CuraSceneNode(SceneNode):
|
||||||
if not no_setting_override:
|
if not no_setting_override:
|
||||||
self.addDecorator(SettingOverrideDecorator()) # Now we always have a getActiveExtruderPosition, unless explicitly disabled
|
self.addDecorator(SettingOverrideDecorator()) # Now we always have a getActiveExtruderPosition, unless explicitly disabled
|
||||||
self._outside_buildarea = False
|
self._outside_buildarea = False
|
||||||
|
self._print_order = 0
|
||||||
|
|
||||||
def setOutsideBuildArea(self, new_value: bool) -> None:
|
def setOutsideBuildArea(self, new_value: bool) -> None:
|
||||||
self._outside_buildarea = new_value
|
self._outside_buildarea = new_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def printOrder(self):
|
||||||
|
return self._print_order
|
||||||
|
|
||||||
|
@printOrder.setter
|
||||||
|
def printOrder(self, new_value):
|
||||||
|
self._print_order = new_value
|
||||||
|
|
||||||
def isOutsideBuildArea(self) -> bool:
|
def isOutsideBuildArea(self) -> bool:
|
||||||
return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0
|
return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0
|
||||||
|
|
||||||
|
@ -157,3 +166,6 @@ class CuraSceneNode(SceneNode):
|
||||||
|
|
||||||
def transformChanged(self) -> None:
|
def transformChanged(self) -> None:
|
||||||
self._transformChanged()
|
self._transformChanged()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "{print_order}. {name}".format(print_order = self._print_order, name = self.getName())
|
||||||
|
|
|
@ -14,6 +14,9 @@ from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
|
||||||
|
from cura.PrintOrderManager import PrintOrderManager
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,6 +79,9 @@ class ObjectsModel(ListModel):
|
||||||
self._build_plate_number = nr
|
self._build_plate_number = nr
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
|
def getNodes(self) -> List[CuraSceneNode]:
|
||||||
|
return list(map(lambda n: n["node"], self.items))
|
||||||
|
|
||||||
def _updateSceneDelayed(self, source) -> None:
|
def _updateSceneDelayed(self, source) -> None:
|
||||||
if not isinstance(source, Camera):
|
if not isinstance(source, Camera):
|
||||||
self._update_timer.start()
|
self._update_timer.start()
|
||||||
|
@ -175,6 +181,10 @@ class ObjectsModel(ListModel):
|
||||||
|
|
||||||
all_nodes = self._renameNodes(name_to_node_info_dict)
|
all_nodes = self._renameNodes(name_to_node_info_dict)
|
||||||
|
|
||||||
|
user_defined_print_order_enabled = PrintOrderManager.isUserDefinedPrintOrderEnabled()
|
||||||
|
if user_defined_print_order_enabled:
|
||||||
|
PrintOrderManager.initializePrintOrders(all_nodes)
|
||||||
|
|
||||||
for node in all_nodes:
|
for node in all_nodes:
|
||||||
if hasattr(node, "isOutsideBuildArea"):
|
if hasattr(node, "isOutsideBuildArea"):
|
||||||
is_outside_build_area = node.isOutsideBuildArea() # type: ignore
|
is_outside_build_area = node.isOutsideBuildArea() # type: ignore
|
||||||
|
@ -223,8 +233,13 @@ class ObjectsModel(ListModel):
|
||||||
# for anti overhang meshes and groups the extruder nr is irrelevant
|
# for anti overhang meshes and groups the extruder nr is irrelevant
|
||||||
extruder_number = -1
|
extruder_number = -1
|
||||||
|
|
||||||
|
if not user_defined_print_order_enabled:
|
||||||
|
name = node.getName()
|
||||||
|
else:
|
||||||
|
name = "{print_order}. {name}".format(print_order = node.printOrder, name = node.getName())
|
||||||
|
|
||||||
nodes.append({
|
nodes.append({
|
||||||
"name": node.getName(),
|
"name": name,
|
||||||
"selected": Selection.isSelected(node),
|
"selected": Selection.isSelected(node),
|
||||||
"outside_build_area": is_outside_build_area,
|
"outside_build_area": is_outside_build_area,
|
||||||
"buildplate_number": node_build_plate_number,
|
"buildplate_number": node_build_plate_number,
|
||||||
|
@ -234,5 +249,5 @@ class ObjectsModel(ListModel):
|
||||||
"node": node
|
"node": node
|
||||||
})
|
})
|
||||||
|
|
||||||
nodes = sorted(nodes, key=lambda n: n["name"])
|
nodes = sorted(nodes, key=lambda n: n["name"] if not user_defined_print_order_enabled else n["node"].printOrder)
|
||||||
self.setItems(nodes)
|
self.setItems(nodes)
|
||||||
|
|
|
@ -177,6 +177,9 @@ class ThreeMFReader(MeshReader):
|
||||||
else:
|
else:
|
||||||
Logger.log("w", "Unable to find extruder in position %s", setting_value)
|
Logger.log("w", "Unable to find extruder in position %s", setting_value)
|
||||||
continue
|
continue
|
||||||
|
if key == "print_order":
|
||||||
|
um_node.printOrder = int(setting_value)
|
||||||
|
continue
|
||||||
if key in known_setting_keys:
|
if key in known_setting_keys:
|
||||||
setting_container.setProperty(key, "value", setting_value)
|
setting_container.setProperty(key, "value", setting_value)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -20,6 +20,7 @@ from cura.CuraApplication import CuraApplication
|
||||||
from cura.CuraPackageManager import CuraPackageManager
|
from cura.CuraPackageManager import CuraPackageManager
|
||||||
from cura.Settings import CuraContainerStack
|
from cura.Settings import CuraContainerStack
|
||||||
from cura.Utils.Threading import call_on_qt_thread
|
from cura.Utils.Threading import call_on_qt_thread
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
from cura.Snapshot import Snapshot
|
from cura.Snapshot import Snapshot
|
||||||
|
|
||||||
from PyQt6.QtCore import QBuffer
|
from PyQt6.QtCore import QBuffer
|
||||||
|
@ -137,6 +138,9 @@ class ThreeMFWriter(MeshWriter):
|
||||||
for key in changed_setting_keys:
|
for key in changed_setting_keys:
|
||||||
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
|
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
|
||||||
|
|
||||||
|
if isinstance(um_node, CuraSceneNode):
|
||||||
|
savitar_node.setSetting("cura:print_order", str(um_node.printOrder))
|
||||||
|
|
||||||
# Store the metadata.
|
# Store the metadata.
|
||||||
for key, value in um_node.metadata.items():
|
for key, value in um_node.metadata.items():
|
||||||
savitar_node.setSetting(key, value)
|
savitar_node.setSetting(key, value)
|
||||||
|
|
|
@ -7060,6 +7060,16 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
},
|
},
|
||||||
|
"user_defined_print_order_enabled":
|
||||||
|
{
|
||||||
|
"label": "Set Print Sequence Manually",
|
||||||
|
"description": "Allows to order the object list to set the print sequence manually. First object from the list will be printed first.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"enabled": "print_sequence == 'one_at_a_time'"
|
||||||
|
},
|
||||||
"infill_mesh":
|
"infill_mesh":
|
||||||
{
|
{
|
||||||
"label": "Infill Mesh",
|
"label": "Infill Mesh",
|
||||||
|
|
|
@ -4946,6 +4946,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Rozdělit modely"
|
msgstr "Rozdělit modely"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Tisknout před"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Tisknout po"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Odinstalovat"
|
msgstr "Odinstalovat"
|
||||||
|
|
|
@ -2583,6 +2583,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Tisková sekvence"
|
msgstr "Tisková sekvence"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Nastavit tiskovou sekvenci ručně"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Umožňuje řadit seznam objektů pro ruční nastavení tiskové sekvence. První objekt ze seznamu bude vytisknut jako první."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Rychlost tisku"
|
msgstr "Rychlost tisku"
|
||||||
|
|
|
@ -4565,6 +4565,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -4930,6 +4930,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Gruppierung für Modelle aufheben"
|
msgstr "Gruppierung für Modelle aufheben"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Vor dem Drucken"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Nach dem Drucken"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Deinstallieren"
|
msgstr "Deinstallieren"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Druckreihenfolge"
|
msgstr "Druckreihenfolge"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Druckreihenfolge manuell einstellen"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Ermöglicht das Ordnen der Objektliste, um die Druckreihenfolge manuell festzulegen. Das erste Objekt aus der Liste wird zuerst gedruckt."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Druckgeschwindigkeit"
|
msgstr "Druckgeschwindigkeit"
|
||||||
|
|
|
@ -4931,6 +4931,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Desagrupar modelos"
|
msgstr "Desagrupar modelos"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimir antes"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimir después"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Desinstalar"
|
msgstr "Desinstalar"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Secuencia de impresión"
|
msgstr "Secuencia de impresión"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Establecer secuencia de impresión manualmente"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permite ordenar la lista de objetos para establecer la secuencia de impresión manualmente. El primer objeto de la lista se imprimirá primero."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocidad de impresión"
|
msgstr "Velocidad de impresión"
|
||||||
|
|
|
@ -4596,6 +4596,14 @@ msgctxt "print_sequence option one_at_a_time"
|
||||||
msgid "One at a Time"
|
msgid "One at a Time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "infill_mesh label"
|
msgctxt "infill_mesh label"
|
||||||
msgid "Infill Mesh"
|
msgid "Infill Mesh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -4899,6 +4899,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Poista mallien ryhmitys"
|
msgstr "Poista mallien ryhmitys"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Tulosta ennen"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Tulosta jälkeen"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2578,6 +2578,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Tulostusjärjestys"
|
msgstr "Tulostusjärjestys"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Aseta tulostusjärjestys manuaalisesti"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Mahdollistaa kohteiden järjestämisen tulostusjärjestyksen manuaaliseen asettamiseen. Listan ensimmäinen kohde tulostetaan ensin."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Tulostusnopeus"
|
msgstr "Tulostusnopeus"
|
||||||
|
|
|
@ -4928,6 +4928,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Dégrouper les modèles"
|
msgstr "Dégrouper les modèles"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimer avant"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimer après"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Désinstaller"
|
msgstr "Désinstaller"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Séquence d'impression"
|
msgstr "Séquence d'impression"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Définir la séquence d'impression manuellement"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permet de classer la liste des objets pour définir manuellement la séquence d'impression. Le premier objet de la liste sera imprimé en premier."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Vitesse d’impression"
|
msgstr "Vitesse d’impression"
|
||||||
|
|
|
@ -4913,6 +4913,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Csoport bontása"
|
msgstr "Csoport bontása"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Nyomtatás előtt"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Nyomtatás után"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2585,6 +2585,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Nyomtatási sorrend"
|
msgstr "Nyomtatási sorrend"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Nyomtatási sorrend kézi beállítása"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Lehetővé teszi az objektumlista rendezését a nyomtatási sorrend kézi beállításához. A lista első objektuma lesz először nyomtatva."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Nyomtatási sebesség"
|
msgstr "Nyomtatási sebesség"
|
||||||
|
|
|
@ -4931,6 +4931,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Separa modelli"
|
msgstr "Separa modelli"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Stampa prima"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Stampa dopo"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Disinstalla"
|
msgstr "Disinstalla"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sequenza di stampa"
|
msgstr "Sequenza di stampa"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Imposta manualmente la sequenza di stampa"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Consente di ordinare l'elenco degli oggetti per impostare manualmente la sequenza di stampa. Il primo oggetto dell'elenco sarà stampato per primo."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocità di stampa"
|
msgstr "Velocità di stampa"
|
||||||
|
|
|
@ -4914,6 +4914,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "モデルを非グループ化"
|
msgstr "モデルを非グループ化"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "印刷前"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "印刷後"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "アンインストール"
|
msgstr "アンインストール"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "印刷頻度"
|
msgstr "印刷頻度"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "手動で印刷順序を設定する"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "オブジェクトリストを並べ替えて、手動で印刷順序を設定することができます。リストの最初のオブジェクトが最初に印刷されます。"
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "印刷速度"
|
msgstr "印刷速度"
|
||||||
|
|
|
@ -4917,6 +4917,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "모델 그룹 해제"
|
msgstr "모델 그룹 해제"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "인쇄 전"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "인쇄 후"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "설치 제거"
|
msgstr "설치 제거"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "프린팅 순서"
|
msgstr "프린팅 순서"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "수동으로 인쇄 순서 설정"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "객체 목록을 정렬하여 수동으로 인쇄 순서를 설정할 수 있습니다. 목록의 첫 번째 객체가 먼저 인쇄됩니다."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "프린팅 속도"
|
msgstr "프린팅 속도"
|
||||||
|
|
|
@ -4925,6 +4925,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Groeperen van Modellen Opheffen"
|
msgstr "Groeperen van Modellen Opheffen"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Afdrukken voor"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Afdrukken na"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "De-installeren"
|
msgstr "De-installeren"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Printvolgorde"
|
msgstr "Printvolgorde"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Handmatig afdrukvolgorde instellen"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Maakt het mogelijk de objectlijst te ordenen om de afdrukvolgorde handmatig in te stellen. Het eerste object van de lijst wordt als eerste afgedrukt."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Printsnelheid"
|
msgstr "Printsnelheid"
|
||||||
|
|
|
@ -4916,6 +4916,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Rozgrupuj modele"
|
msgstr "Rozgrupuj modele"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Drukuj przed"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Drukuj po"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2584,6 +2584,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sekwencja Wydruku"
|
msgstr "Sekwencja Wydruku"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Ręczne ustawienie kolejności drukowania"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Umożliwia ręczne ustawienie kolejności drukowania na liście obiektów. Pierwszy obiekt z listy zostanie wydrukowany jako pierwszy."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Prędkość Druku"
|
msgstr "Prędkość Druku"
|
||||||
|
|
|
@ -4942,6 +4942,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Desagrupar Modelos"
|
msgstr "Desagrupar Modelos"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimir antes"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimir depois"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Desinstalar"
|
msgstr "Desinstalar"
|
||||||
|
|
|
@ -2585,6 +2585,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sequência de Impressão"
|
msgstr "Sequência de Impressão"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Definir sequência de impressão manualmente"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permite ordenar a lista de objetos para definir a sequência de impressão manualmente. O primeiro objeto da lista será impresso primeiro."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocidade de Impressão"
|
msgstr "Velocidade de Impressão"
|
||||||
|
|
|
@ -4932,6 +4932,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Desagrupar Modelos"
|
msgstr "Desagrupar Modelos"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimir antes"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimir depois"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Desinstalar"
|
msgstr "Desinstalar"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sequência de impressão"
|
msgstr "Sequência de impressão"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Definir sequência de impressão manualmente"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permite ordenar a lista de objetos para definir a sequência de impressão manualmente. O primeiro objeto da lista será impresso primeiro."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocidade de Impressão"
|
msgstr "Velocidade de Impressão"
|
||||||
|
|
|
@ -4955,6 +4955,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Разгруппировать модели"
|
msgstr "Разгруппировать модели"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Печатать до"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Печатать после"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Удалить"
|
msgstr "Удалить"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Последовательная печать"
|
msgstr "Последовательная печать"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Установить последовательность печати вручную"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Позволяет упорядочить список объектов для ручной настройки последовательности печати. Первый объект из списка будет напечатан первым."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Скорость печати"
|
msgstr "Скорость печати"
|
||||||
|
|
|
@ -4931,6 +4931,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Model Grubunu Çöz"
|
msgstr "Model Grubunu Çöz"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Önce Yazdır"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Sonra Yazdır"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Kaldır"
|
msgstr "Kaldır"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Yazdırma Dizisi"
|
msgstr "Yazdırma Dizisi"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Baskı Sırasını Manuel Olarak Ayarla"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Nesne listesini sıralayarak baskı sırasını manuel olarak ayarlamayı sağlar. Listeden ilk nesne ilk olarak basılacak."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Yazdırma Hızı"
|
msgstr "Yazdırma Hızı"
|
||||||
|
|
|
@ -4919,6 +4919,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "拆分模型"
|
msgstr "拆分模型"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "打印前"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "打印后"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "卸载"
|
msgstr "卸载"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "打印序列"
|
msgstr "打印序列"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "手动设置打印顺序"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "允许对对象列表进行排序,以手动设置打印顺序。列表中的第一个对象将首先被打印。"
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "打印速度"
|
msgstr "打印速度"
|
||||||
|
|
|
@ -4911,6 +4911,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "取消模型群組"
|
msgstr "取消模型群組"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "列印前"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "列印後"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2585,6 +2585,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "列印順序"
|
msgstr "列印順序"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "手動設置列印順序"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "允許手動設置物件列表以設定列印順序。列表中的第一個物件將首先被列印。"
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "列印速度"
|
msgstr "列印速度"
|
||||||
|
|
|
@ -35,6 +35,9 @@ Item
|
||||||
property alias mergeObjects: mergeObjectsAction
|
property alias mergeObjects: mergeObjectsAction
|
||||||
//property alias unMergeObjects: unMergeObjectsAction
|
//property alias unMergeObjects: unMergeObjectsAction
|
||||||
|
|
||||||
|
property alias printObjectBeforePrevious: printObjectBeforePreviousAction
|
||||||
|
property alias printObjectAfterNext: printObjectAfterNextAction
|
||||||
|
|
||||||
property alias multiplyObject: multiplyObjectAction
|
property alias multiplyObject: multiplyObjectAction
|
||||||
|
|
||||||
property alias selectAll: selectAllAction
|
property alias selectAll: selectAllAction
|
||||||
|
@ -406,6 +409,26 @@ Item
|
||||||
onTriggered: CuraApplication.ungroupSelected()
|
onTriggered: CuraApplication.ungroupSelected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action
|
||||||
|
{
|
||||||
|
id: printObjectBeforePreviousAction
|
||||||
|
text: catalog.i18nc("@action:inmenu menubar:edit","Print Before") + " " + PrintOrderManager.previousNodeName
|
||||||
|
enabled: PrintOrderManager.shouldEnablePrintBeforeAction
|
||||||
|
icon.name: "print-before"
|
||||||
|
shortcut: "PgUp"
|
||||||
|
onTriggered: PrintOrderManager.swapSelectedAndPreviousNodes()
|
||||||
|
}
|
||||||
|
|
||||||
|
Action
|
||||||
|
{
|
||||||
|
id: printObjectAfterNextAction
|
||||||
|
text: catalog.i18nc("@action:inmenu menubar:edit","Print After") + " " + PrintOrderManager.nextNodeName
|
||||||
|
enabled: PrintOrderManager.shouldEnablePrintAfterAction
|
||||||
|
icon.name: "print-after"
|
||||||
|
shortcut: "PgDown"
|
||||||
|
onTriggered: PrintOrderManager.swapSelectedAndNextNodes()
|
||||||
|
}
|
||||||
|
|
||||||
Action
|
Action
|
||||||
{
|
{
|
||||||
id: mergeObjectsAction
|
id: mergeObjectsAction
|
||||||
|
|
|
@ -78,6 +78,19 @@ Cura.Menu
|
||||||
Cura.MenuItem { action: Cura.Actions.mergeObjects }
|
Cura.MenuItem { action: Cura.Actions.mergeObjects }
|
||||||
Cura.MenuItem { action: Cura.Actions.unGroupObjects }
|
Cura.MenuItem { action: Cura.Actions.unGroupObjects }
|
||||||
|
|
||||||
|
// Edit print sequence actions
|
||||||
|
Cura.MenuSeparator { visible: PrintOrderManager.shouldShowEditPrintOrderActions }
|
||||||
|
Cura.MenuItem
|
||||||
|
{
|
||||||
|
action: Cura.Actions.printObjectBeforePrevious
|
||||||
|
visible: PrintOrderManager.shouldShowEditPrintOrderActions
|
||||||
|
}
|
||||||
|
Cura.MenuItem
|
||||||
|
{
|
||||||
|
action: Cura.Actions.printObjectAfterNext
|
||||||
|
visible: PrintOrderManager.shouldShowEditPrintOrderActions
|
||||||
|
}
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: UM.Controller
|
target: UM.Controller
|
||||||
|
|
|
@ -25,4 +25,17 @@ Cura.Menu
|
||||||
Cura.MenuItem { action: Cura.Actions.groupObjects }
|
Cura.MenuItem { action: Cura.Actions.groupObjects }
|
||||||
Cura.MenuItem { action: Cura.Actions.mergeObjects }
|
Cura.MenuItem { action: Cura.Actions.mergeObjects }
|
||||||
Cura.MenuItem { action: Cura.Actions.unGroupObjects }
|
Cura.MenuItem { action: Cura.Actions.unGroupObjects }
|
||||||
|
|
||||||
|
// Edit print sequence actions
|
||||||
|
Cura.MenuSeparator { visible: PrintOrderManager.shouldShowEditPrintOrderActions }
|
||||||
|
Cura.MenuItem
|
||||||
|
{
|
||||||
|
action: Cura.Actions.printObjectBeforePrevious
|
||||||
|
visible: PrintOrderManager.shouldShowEditPrintOrderActions
|
||||||
|
}
|
||||||
|
Cura.MenuItem
|
||||||
|
{
|
||||||
|
action: Cura.Actions.printObjectAfterNext
|
||||||
|
visible: PrintOrderManager.shouldShowEditPrintOrderActions
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -136,6 +136,7 @@ prime_tower_brim_enable
|
||||||
|
|
||||||
[blackmagic]
|
[blackmagic]
|
||||||
print_sequence
|
print_sequence
|
||||||
|
user_defined_print_order_enabled
|
||||||
magic_mesh_surface_mode
|
magic_mesh_surface_mode
|
||||||
magic_spiralize
|
magic_spiralize
|
||||||
smooth_spiralized_contours
|
smooth_spiralized_contours
|
||||||
|
|
|
@ -386,6 +386,7 @@ meshfix_fluid_motion_angle
|
||||||
|
|
||||||
[blackmagic]
|
[blackmagic]
|
||||||
print_sequence
|
print_sequence
|
||||||
|
user_defined_print_order_enabled
|
||||||
infill_mesh
|
infill_mesh
|
||||||
infill_mesh_order
|
infill_mesh_order
|
||||||
cutting_mesh
|
cutting_mesh
|
||||||
|
|
141
tests/TestHitChecker.py
Normal file
141
tests/TestHitChecker.py
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from cura.HitChecker import HitChecker
|
||||||
|
from cura.OneAtATimeIterator import OneAtATimeIterator
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
|
def test_anyTwoNodesBlockEachOther_True():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
# node1 and node2 block each other
|
||||||
|
hit_map = {
|
||||||
|
node1: {node1: 0, node2: 1},
|
||||||
|
node2: {node1: 1, node2: 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(HitChecker, "_buildHitMap", return_value=hit_map):
|
||||||
|
hit_checker = HitChecker([node1, node2])
|
||||||
|
assert hit_checker.anyTwoNodesBlockEachOther([node1, node2])
|
||||||
|
assert hit_checker.anyTwoNodesBlockEachOther([node2, node1])
|
||||||
|
|
||||||
|
|
||||||
|
def test_anyTwoNodesBlockEachOther_False():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
# node1 blocks node2, but node2 doesn't block node1
|
||||||
|
hit_map = {
|
||||||
|
node1: {node1: 0, node2: 1},
|
||||||
|
node2: {node1: 0, node2: 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(HitChecker, "_buildHitMap", return_value=hit_map):
|
||||||
|
hit_checker = HitChecker([node1, node2])
|
||||||
|
assert not hit_checker.anyTwoNodesBlockEachOther([node1, node2])
|
||||||
|
assert not hit_checker.anyTwoNodesBlockEachOther([node2, node1])
|
||||||
|
|
||||||
|
|
||||||
|
def test_canPrintBefore():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
# nodes can be printed only in order node1 -> node2 -> node3
|
||||||
|
hit_map = {
|
||||||
|
node1: {node1: 0, node2: 0, node3: 0},
|
||||||
|
node2: {node1: 1, node2: 0, node3: 0},
|
||||||
|
node3: {node1: 1, node2: 1, node3: 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(HitChecker, "_buildHitMap", return_value=hit_map):
|
||||||
|
hit_checker = HitChecker([node1, node2, node3])
|
||||||
|
|
||||||
|
assert hit_checker.canPrintBefore(node1, [node2])
|
||||||
|
assert hit_checker.canPrintBefore(node1, [node3])
|
||||||
|
assert hit_checker.canPrintBefore(node1, [node2, node3])
|
||||||
|
assert hit_checker.canPrintBefore(node1, [node3, node2])
|
||||||
|
|
||||||
|
assert hit_checker.canPrintBefore(node2, [node3])
|
||||||
|
assert not hit_checker.canPrintBefore(node2, [node1])
|
||||||
|
assert not hit_checker.canPrintBefore(node2, [node1, node3])
|
||||||
|
assert not hit_checker.canPrintBefore(node2, [node3, node1])
|
||||||
|
|
||||||
|
assert not hit_checker.canPrintBefore(node3, [node1])
|
||||||
|
assert not hit_checker.canPrintBefore(node3, [node2])
|
||||||
|
assert not hit_checker.canPrintBefore(node3, [node1, node2])
|
||||||
|
assert not hit_checker.canPrintBefore(node3, [node2, node1])
|
||||||
|
|
||||||
|
|
||||||
|
def test_canPrintAfter():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
|
||||||
|
# nodes can be printed only in order node1 -> node2 -> node3
|
||||||
|
hit_map = {
|
||||||
|
node1: {node1: 0, node2: 0, node3: 0},
|
||||||
|
node2: {node1: 1, node2: 0, node3: 0},
|
||||||
|
node3: {node1: 1, node2: 1, node3: 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(HitChecker, "_buildHitMap", return_value=hit_map):
|
||||||
|
hit_checker = HitChecker([node1, node2, node3])
|
||||||
|
|
||||||
|
assert not hit_checker.canPrintAfter(node1, [node2])
|
||||||
|
assert not hit_checker.canPrintAfter(node1, [node3])
|
||||||
|
assert not hit_checker.canPrintAfter(node1, [node2, node3])
|
||||||
|
assert not hit_checker.canPrintAfter(node1, [node3, node2])
|
||||||
|
|
||||||
|
assert hit_checker.canPrintAfter(node2, [node1])
|
||||||
|
assert not hit_checker.canPrintAfter(node2, [node3])
|
||||||
|
assert not hit_checker.canPrintAfter(node2, [node1, node3])
|
||||||
|
assert not hit_checker.canPrintAfter(node2, [node3, node1])
|
||||||
|
|
||||||
|
assert hit_checker.canPrintAfter(node3, [node1])
|
||||||
|
assert hit_checker.canPrintAfter(node3, [node2])
|
||||||
|
assert hit_checker.canPrintAfter(node3, [node1, node2])
|
||||||
|
assert hit_checker.canPrintAfter(node3, [node2, node1])
|
||||||
|
|
||||||
|
|
||||||
|
def test_calculateScore():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
|
||||||
|
hit_map = {
|
||||||
|
node1: {node1: 0, node2: 0, node3: 0}, # sum is 0
|
||||||
|
node2: {node1: 1, node2: 0, node3: 0}, # sum is 1
|
||||||
|
node3: {node1: 1, node2: 1, node3: 0}, # sum is 2
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(HitChecker, "_buildHitMap", return_value=hit_map):
|
||||||
|
hit_checker = HitChecker([node1, node2, node3])
|
||||||
|
|
||||||
|
# score is a diff between sums
|
||||||
|
assert hit_checker.calculateScore(node1, node2) == -1
|
||||||
|
assert hit_checker.calculateScore(node2, node1) == 1
|
||||||
|
assert hit_checker.calculateScore(node1, node3) == -2
|
||||||
|
assert hit_checker.calculateScore(node3, node1) == 2
|
||||||
|
assert hit_checker.calculateScore(node2, node3) == -1
|
||||||
|
assert hit_checker.calculateScore(node3, node2) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_canPrintNodesInProvidedOrder():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
|
||||||
|
# nodes can be printed only in order node1 -> node2 -> node3
|
||||||
|
hit_map = {
|
||||||
|
node1: {node1: 0, node2: 0, node3: 0}, # 0
|
||||||
|
node2: {node1: 1, node2: 0, node3: 0}, # 1
|
||||||
|
node3: {node1: 1, node2: 1, node3: 0}, # 2
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(HitChecker, "_buildHitMap", return_value=hit_map):
|
||||||
|
hit_checker = HitChecker([node1, node2, node3])
|
||||||
|
assert hit_checker.canPrintNodesInProvidedOrder([node1, node2, node3])
|
||||||
|
assert not hit_checker.canPrintNodesInProvidedOrder([node1, node3, node2])
|
||||||
|
assert not hit_checker.canPrintNodesInProvidedOrder([node2, node1, node3])
|
||||||
|
assert not hit_checker.canPrintNodesInProvidedOrder([node2, node3, node1])
|
||||||
|
assert not hit_checker.canPrintNodesInProvidedOrder([node3, node1, node2])
|
||||||
|
assert not hit_checker.canPrintNodesInProvidedOrder([node3, node2, node1])
|
175
tests/TestPrintOrderManager.py
Normal file
175
tests/TestPrintOrderManager.py
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
from cura.PrintOrderManager import PrintOrderManager
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
|
def test_getNodeName():
|
||||||
|
node1 = CuraSceneNode(name="cat", no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(name="dog", no_setting_override=True)
|
||||||
|
assert PrintOrderManager._getNodeName(node1) == "cat"
|
||||||
|
assert PrintOrderManager._getNodeName(node2) == "dog"
|
||||||
|
assert PrintOrderManager._getNodeName(None) == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_getNodeName_truncatesLongName():
|
||||||
|
node = CuraSceneNode(name="some_name_longer_than_30_characters", no_setting_override=True)
|
||||||
|
assert PrintOrderManager._getNodeName(node) == "some_name_longer_than_30_chara"
|
||||||
|
assert PrintOrderManager._getNodeName(node, max_length=10) == "some_name_"
|
||||||
|
|
||||||
|
|
||||||
|
def test_getSingleSelectedNode():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
with patch("UM.Scene.Selection.Selection.getAllSelectedObjects", MagicMock(return_value=[node1])):
|
||||||
|
with patch("UM.Scene.Selection.Selection.getSelectedObject", MagicMock(return_value=node1)):
|
||||||
|
assert PrintOrderManager._getSingleSelectedNode() == node1
|
||||||
|
|
||||||
|
|
||||||
|
def test_getSingleSelectedNode_returnsNoneIfNothingSelected():
|
||||||
|
with patch("UM.Scene.Selection.Selection.getAllSelectedObjects", MagicMock(return_value=[])):
|
||||||
|
assert PrintOrderManager._getSingleSelectedNode() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_getSingleSelectedNode_returnsNoneIfMultipleObjectsSelected():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
with patch("UM.Scene.Selection.Selection.getAllSelectedObjects", MagicMock(return_value=[node1, node2])):
|
||||||
|
assert PrintOrderManager._getSingleSelectedNode() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_neighborNodeNamesCorrect_WhenSomeNodeSelected():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True, name="node1")
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True, name="node2")
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True, name="node3")
|
||||||
|
node1.printOrder = 1
|
||||||
|
node2.printOrder = 2
|
||||||
|
node3.printOrder = 3
|
||||||
|
with patch.object(PrintOrderManager, "_configureEvents", return_value=None):
|
||||||
|
with patch.object(PrintOrderManager, "_getSingleSelectedNode", return_value=node1):
|
||||||
|
print_order_manager = PrintOrderManager(get_nodes=lambda: [node1, node2, node3])
|
||||||
|
|
||||||
|
assert print_order_manager.previousNodeName == ""
|
||||||
|
assert print_order_manager.nextNodeName == "node2"
|
||||||
|
assert not print_order_manager.shouldEnablePrintBeforeAction
|
||||||
|
assert print_order_manager.shouldEnablePrintAfterAction
|
||||||
|
|
||||||
|
print_order_manager.swapSelectedAndNextNodes() # swaps node1 with node2, result: [node2, node1, node3]
|
||||||
|
assert print_order_manager.previousNodeName == "node2"
|
||||||
|
assert print_order_manager.nextNodeName == "node3"
|
||||||
|
assert print_order_manager.shouldEnablePrintBeforeAction
|
||||||
|
assert print_order_manager.shouldEnablePrintAfterAction
|
||||||
|
|
||||||
|
print_order_manager.swapSelectedAndNextNodes() # swaps node1 with node3, result: [node2, node3, node1]
|
||||||
|
assert print_order_manager.previousNodeName == "node3"
|
||||||
|
assert print_order_manager.nextNodeName == ""
|
||||||
|
assert print_order_manager.shouldEnablePrintBeforeAction
|
||||||
|
assert not print_order_manager.shouldEnablePrintAfterAction
|
||||||
|
|
||||||
|
print_order_manager.swapSelectedAndPreviousNodes() # swaps node1 with node3, result: [node2, node1, node3]
|
||||||
|
assert print_order_manager.previousNodeName == "node2"
|
||||||
|
assert print_order_manager.nextNodeName == "node3"
|
||||||
|
assert print_order_manager.shouldEnablePrintBeforeAction
|
||||||
|
assert print_order_manager.shouldEnablePrintAfterAction
|
||||||
|
|
||||||
|
print_order_manager.swapSelectedAndPreviousNodes() # swaps node1 with node2, result: [node1, node2, node3]
|
||||||
|
assert print_order_manager.previousNodeName == ""
|
||||||
|
assert print_order_manager.nextNodeName == "node2"
|
||||||
|
assert not print_order_manager.shouldEnablePrintBeforeAction
|
||||||
|
assert print_order_manager.shouldEnablePrintAfterAction
|
||||||
|
|
||||||
|
|
||||||
|
def test_neighborNodeNamesEmpty_WhenNothingSelected():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True, name="node1")
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True, name="node2")
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True, name="node3")
|
||||||
|
node1.printOrder = 1
|
||||||
|
node2.printOrder = 2
|
||||||
|
node3.printOrder = 3
|
||||||
|
with patch.object(PrintOrderManager, "_configureEvents", return_value=None):
|
||||||
|
with patch.object(PrintOrderManager, "_getSingleSelectedNode", return_value=None):
|
||||||
|
print_order_manager = PrintOrderManager(get_nodes=lambda: [node1, node2, node3])
|
||||||
|
assert print_order_manager.previousNodeName == ""
|
||||||
|
assert print_order_manager.nextNodeName == ""
|
||||||
|
assert not print_order_manager.shouldEnablePrintBeforeAction
|
||||||
|
assert not print_order_manager.shouldEnablePrintAfterAction
|
||||||
|
|
||||||
|
|
||||||
|
def test_initializePrintOrders():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
|
||||||
|
# assume print orders are 0
|
||||||
|
assert node1.printOrder == 0
|
||||||
|
assert node2.printOrder == 0
|
||||||
|
|
||||||
|
PrintOrderManager.initializePrintOrders([node1, node2])
|
||||||
|
|
||||||
|
# assert print orders initialized
|
||||||
|
assert node1.printOrder == 1
|
||||||
|
assert node2.printOrder == 2
|
||||||
|
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node4 = CuraSceneNode(no_setting_override=True)
|
||||||
|
# assume print orders are 0
|
||||||
|
assert node3.printOrder == 0
|
||||||
|
assert node4.printOrder == 0
|
||||||
|
|
||||||
|
PrintOrderManager.initializePrintOrders([node2, node1, node3, node4])
|
||||||
|
|
||||||
|
# assert print orders not changed for node1 and node2 and initialized for node3 and node4
|
||||||
|
assert node1.printOrder == 1
|
||||||
|
assert node2.printOrder == 2
|
||||||
|
assert node3.printOrder == 3
|
||||||
|
assert node4.printOrder == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_updatePrintOrdersAfterGroupOperation():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node4 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node5 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node1.printOrder = 1
|
||||||
|
node2.printOrder = 2
|
||||||
|
node3.printOrder = 3
|
||||||
|
node4.printOrder = 4
|
||||||
|
node5.printOrder = 5
|
||||||
|
|
||||||
|
all_nodes = [node1, node2, node3, node4, node5]
|
||||||
|
grouped_nodes = [node2, node4]
|
||||||
|
group_node = CuraSceneNode(no_setting_override=True)
|
||||||
|
|
||||||
|
PrintOrderManager.updatePrintOrdersAfterGroupOperation(all_nodes, group_node, grouped_nodes)
|
||||||
|
|
||||||
|
assert node1.printOrder == 1
|
||||||
|
assert group_node.printOrder == 2
|
||||||
|
assert node3.printOrder == 3
|
||||||
|
assert node5.printOrder == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_updatePrintOrdersAfterUngroupOperation():
|
||||||
|
node1 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node2 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node3 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node1.printOrder = 1
|
||||||
|
node2.printOrder = 2
|
||||||
|
node3.printOrder = 3
|
||||||
|
|
||||||
|
all_nodes = [node1, node2, node3]
|
||||||
|
node4 = CuraSceneNode(no_setting_override=True)
|
||||||
|
node5 = CuraSceneNode(no_setting_override=True)
|
||||||
|
|
||||||
|
group_node = node2
|
||||||
|
ungrouped_nodes = [node4, node5]
|
||||||
|
PrintOrderManager.updatePrintOrdersAfterUngroupOperation(all_nodes, group_node, ungrouped_nodes)
|
||||||
|
|
||||||
|
assert node1.printOrder == 1
|
||||||
|
assert node4.printOrder == 2
|
||||||
|
assert node5.printOrder == 3
|
||||||
|
assert node3.printOrder == 4
|
||||||
|
|
||||||
|
assert node1 in all_nodes
|
||||||
|
assert node2 not in all_nodes
|
||||||
|
assert node3 in all_nodes
|
||||||
|
assert node4 in all_nodes
|
||||||
|
assert node5 in all_nodes
|
Loading…
Add table
Add a link
Reference in a new issue