mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-17 03:37:48 -06:00
Refactor grouping/ungrouping into an operation that is undoable
CURA-1543
This commit is contained in:
parent
0b0e53dcf5
commit
4830943113
2 changed files with 72 additions and 23 deletions
|
@ -23,6 +23,7 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||||
from UM.Operations.GroupedOperation import GroupedOperation
|
from UM.Operations.GroupedOperation import GroupedOperation
|
||||||
from UM.Operations.SetTransformOperation import SetTransformOperation
|
from UM.Operations.SetTransformOperation import SetTransformOperation
|
||||||
|
from cura.SetParentOperation import SetParentOperation
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
|
||||||
|
@ -543,6 +544,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def groupSelected(self):
|
def groupSelected(self):
|
||||||
|
# Create a group-node
|
||||||
group_node = SceneNode()
|
group_node = SceneNode()
|
||||||
group_decorator = GroupDecorator()
|
group_decorator = GroupDecorator()
|
||||||
group_node.addDecorator(group_decorator)
|
group_node.addDecorator(group_decorator)
|
||||||
|
@ -552,40 +554,37 @@ class CuraApplication(QtApplication):
|
||||||
group_node.setPosition(center)
|
group_node.setPosition(center)
|
||||||
group_node.setCenterPosition(center)
|
group_node.setCenterPosition(center)
|
||||||
|
|
||||||
for node in Selection.getAllSelectedObjects():
|
# Move selected nodes into the group-node
|
||||||
world = node.getWorldPosition()
|
op = GroupedOperation()
|
||||||
node.setParent(group_node)
|
nodes = Selection.getAllSelectedObjects()
|
||||||
node.setPosition(world - center)
|
for node in nodes:
|
||||||
|
op.addOperation(SetParentOperation(node, group_node))
|
||||||
|
op.push()
|
||||||
|
|
||||||
|
# Deselect individual nodes and select the groupnode instead
|
||||||
for node in group_node.getChildren():
|
for node in group_node.getChildren():
|
||||||
Selection.remove(node)
|
Selection.remove(node)
|
||||||
|
|
||||||
Selection.add(group_node)
|
Selection.add(group_node)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def ungroupSelected(self):
|
def ungroupSelected(self):
|
||||||
ungrouped_nodes = []
|
|
||||||
selected_objects = Selection.getAllSelectedObjects()[:] #clone the list
|
selected_objects = Selection.getAllSelectedObjects()[:] #clone the list
|
||||||
for node in selected_objects:
|
for node in selected_objects:
|
||||||
if node.callDecoration("isGroup" ):
|
if node.callDecoration("isGroup"):
|
||||||
children_to_move = []
|
op = GroupedOperation()
|
||||||
for child in node.getChildren():
|
|
||||||
if type(child) is SceneNode:
|
|
||||||
children_to_move.append(child)
|
|
||||||
|
|
||||||
for child in children_to_move:
|
group_parent = node.getParent()
|
||||||
position = child.getWorldPosition()
|
children = node.getChildren()[:] #clone the list
|
||||||
child.setParent(node.getParent())
|
for child in children:
|
||||||
child.setPosition(position - node.getParent().getWorldPosition())
|
# Set the parent of the children to the parent of the group-node
|
||||||
child.scale(node.getScale())
|
op.addOperation(SetParentOperation(child, group_parent))
|
||||||
child.rotate(node.getOrientation())
|
|
||||||
|
|
||||||
|
# Add all individual nodes to the selection
|
||||||
Selection.add(child)
|
Selection.add(child)
|
||||||
child.callDecoration("setConvexHull",None)
|
child.callDecoration("setConvexHull", None)
|
||||||
node.setParent(None)
|
|
||||||
ungrouped_nodes.append(node)
|
op.push()
|
||||||
for node in ungrouped_nodes:
|
# Note: The group removes itself from the scene once all its children have left it, see GroupDecorator._onChildrenChanged
|
||||||
Selection.remove(node)
|
|
||||||
|
|
||||||
def _createSplashScreen(self):
|
def _createSplashScreen(self):
|
||||||
return CuraSplashScreen.CuraSplashScreen()
|
return CuraSplashScreen.CuraSplashScreen()
|
||||||
|
|
50
cura/SetParentOperation.py
Normal file
50
cura/SetParentOperation.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Copyright (c) 2016 Ultimaker B.V.
|
||||||
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
from UM.Operations import Operation
|
||||||
|
|
||||||
|
from UM.Math.Vector import Vector
|
||||||
|
|
||||||
|
## An operation that parents a scene node to another scene node.
|
||||||
|
|
||||||
|
class SetParentOperation(Operation.Operation):
|
||||||
|
## Initialises this SetParentOperation.
|
||||||
|
#
|
||||||
|
# \param node The node which will be reparented.
|
||||||
|
# \param parent_node The node which will be the parent.
|
||||||
|
def __init__(self, node, parent_node):
|
||||||
|
super().__init__()
|
||||||
|
self._node = node
|
||||||
|
self._parent = parent_node
|
||||||
|
self._old_parent = node.getParent() # To restore the previous parent in case of an undo.
|
||||||
|
|
||||||
|
## Undoes the set-parent operation, restoring the old parent.
|
||||||
|
def undo(self):
|
||||||
|
self._set_parent(self._old_parent)
|
||||||
|
|
||||||
|
## Re-applies the set-parent operation.
|
||||||
|
def redo(self):
|
||||||
|
self._set_parent(self._parent)
|
||||||
|
|
||||||
|
## Sets the parent of the node while applying transformations to the world-transform of the node stays the same.
|
||||||
|
#
|
||||||
|
# \param new_parent The new parent. Note: this argument can be None, which would hide the node from the scene.
|
||||||
|
def _set_parent(self, new_parent):
|
||||||
|
if new_parent:
|
||||||
|
self._node.setPosition(self._node.getWorldPosition() - new_parent.getWorldPosition())
|
||||||
|
current_parent = self._node.getParent()
|
||||||
|
if current_parent:
|
||||||
|
self._node.scale(current_parent.getScale() / new_parent.getScale())
|
||||||
|
self._node.rotate(current_parent.getOrientation())
|
||||||
|
else:
|
||||||
|
self._node.scale(Vector(1, 1, 1) / new_parent.getScale())
|
||||||
|
self._node.rotate(new_parent.getOrientation().getInverse())
|
||||||
|
|
||||||
|
self._node.setParent(new_parent)
|
||||||
|
|
||||||
|
## Returns a programmer-readable representation of this operation.
|
||||||
|
#
|
||||||
|
# \return A programmer-readable representation of this operation.
|
||||||
|
def __repr__(self):
|
||||||
|
return "SetParentOperation(node = {0}, parent_node={1})".format(self._node, self._parent)
|
Loading…
Add table
Add a link
Reference in a new issue