SetParentOperation.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. # Copyright (c) 2016 Ultimaker B.V.
  2. # Uranium is released under the terms of the LGPLv3 or higher.
  3. from typing import Optional
  4. from UM.Scene.SceneNode import SceneNode
  5. from UM.Operations import Operation
  6. from UM.Math.Vector import Vector
  7. ## An operation that parents a scene node to another scene node.
  8. class SetParentOperation(Operation.Operation):
  9. ## Initialises this SetParentOperation.
  10. #
  11. # \param node The node which will be reparented.
  12. # \param parent_node The node which will be the parent.
  13. def __init__(self, node: SceneNode, parent_node: Optional[SceneNode]) -> None:
  14. super().__init__()
  15. self._node = node
  16. self._parent = parent_node
  17. self._old_parent = node.getParent() # To restore the previous parent in case of an undo.
  18. ## Undoes the set-parent operation, restoring the old parent.
  19. def undo(self) -> None:
  20. self._set_parent(self._old_parent)
  21. ## Re-applies the set-parent operation.
  22. def redo(self) -> None:
  23. self._set_parent(self._parent)
  24. ## Sets the parent of the node while applying transformations to the world-transform of the node stays the same.
  25. #
  26. # \param new_parent The new parent. Note: this argument can be None, which would hide the node from the scene.
  27. def _set_parent(self, new_parent: Optional[SceneNode]) -> None:
  28. if new_parent:
  29. current_parent = self._node.getParent()
  30. if current_parent:
  31. # Special casing for groups that have been removed.
  32. # In that case we want to put them back where they belong before checking the depth difference.
  33. # If we don't, we always get 0.
  34. old_parent = new_parent.callDecoration("getOldParent")
  35. if old_parent:
  36. new_parent.callDecoration("getNode").setParent(old_parent)
  37. # Based on the depth difference, we need to do something different.
  38. depth_difference = current_parent.getDepth() - new_parent.getDepth()
  39. child_transformation = self._node.getLocalTransformation()
  40. if depth_difference > 0:
  41. parent_transformation = current_parent.getLocalTransformation()
  42. # A node in the chain was removed, so we need to squash the parent info into all the nodes, so positions remain the same.
  43. self._node.setTransformation(parent_transformation.multiply(child_transformation))
  44. else:
  45. # A node is inserted into the chain, so use the inverse of the parent to set the transformation of it's children.
  46. parent_transformation = new_parent.getLocalTransformation()
  47. result = parent_transformation.getInverse().multiply(child_transformation, copy = True)
  48. self._node.setTransformation(result)
  49. self._node.setParent(new_parent)
  50. ## Returns a programmer-readable representation of this operation.
  51. #
  52. # \return A programmer-readable representation of this operation.
  53. def __repr__(self) -> str:
  54. return "SetParentOperation(node = {0}, parent_node={1})".format(self._node, self._parent)