CuraActions.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. # Copyright (c) 2017 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from PyQt5.QtCore import QObject, QUrl
  4. from PyQt5.QtGui import QDesktopServices
  5. from UM.FlameProfiler import pyqtSlot
  6. from UM.Event import CallFunctionEvent
  7. from UM.Application import Application
  8. from UM.Math.Vector import Vector
  9. from UM.Scene.Selection import Selection
  10. from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
  11. from UM.Operations.GroupedOperation import GroupedOperation
  12. from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
  13. from UM.Operations.SetTransformOperation import SetTransformOperation
  14. from cura.SetParentOperation import SetParentOperation
  15. from cura.MultiplyObjectsJob import MultiplyObjectsJob
  16. from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation
  17. from cura.Settings.ExtruderManager import ExtruderManager
  18. class CuraActions(QObject):
  19. def __init__(self, parent = None):
  20. super().__init__(parent)
  21. @pyqtSlot()
  22. def openDocumentation(self):
  23. # Starting a web browser from a signal handler connected to a menu will crash on windows.
  24. # So instead, defer the call to the next run of the event loop, since that does work.
  25. # Note that weirdly enough, only signal handlers that open a web browser fail like that.
  26. event = CallFunctionEvent(self._openUrl, [QUrl("http://ultimaker.com/en/support/software")], {})
  27. Application.getInstance().functionEvent(event)
  28. @pyqtSlot()
  29. def openBugReportPage(self):
  30. event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {})
  31. Application.getInstance().functionEvent(event)
  32. ## Reset camera position and direction to default
  33. @pyqtSlot()
  34. def homeCamera(self) -> None:
  35. scene = Application.getInstance().getController().getScene()
  36. camera = scene.getActiveCamera()
  37. camera.setPosition(Vector(-80, 250, 700))
  38. camera.setPerspective(True)
  39. camera.lookAt(Vector(0, 0, 0))
  40. ## Center all objects in the selection
  41. @pyqtSlot()
  42. def centerSelection(self) -> None:
  43. operation = GroupedOperation()
  44. for node in Selection.getAllSelectedObjects():
  45. current_node = node
  46. while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
  47. current_node = current_node.getParent()
  48. center_operation = SetTransformOperation(current_node, Vector())
  49. operation.addOperation(center_operation)
  50. operation.push()
  51. ## Multiply all objects in the selection
  52. #
  53. # \param count The number of times to multiply the selection.
  54. @pyqtSlot(int)
  55. def multiplySelection(self, count: int) -> None:
  56. job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, 8)
  57. job.start()
  58. ## Delete all selected objects.
  59. @pyqtSlot()
  60. def deleteSelection(self) -> None:
  61. if not Application.getInstance().getController().getToolsEnabled():
  62. return
  63. removed_group_nodes = []
  64. op = GroupedOperation()
  65. nodes = Selection.getAllSelectedObjects()
  66. for node in nodes:
  67. op.addOperation(RemoveSceneNodeOperation(node))
  68. group_node = node.getParent()
  69. if group_node and group_node.callDecoration("isGroup") and group_node not in removed_group_nodes:
  70. remaining_nodes_in_group = list(set(group_node.getChildren()) - set(nodes))
  71. if len(remaining_nodes_in_group) == 1:
  72. removed_group_nodes.append(group_node)
  73. op.addOperation(SetParentOperation(remaining_nodes_in_group[0], group_node.getParent()))
  74. op.addOperation(RemoveSceneNodeOperation(group_node))
  75. op.push()
  76. ## Set the extruder that should be used to print the selection.
  77. #
  78. # \param extruder_id The ID of the extruder stack to use for the selected objects.
  79. @pyqtSlot(str)
  80. def setExtruderForSelection(self, extruder_id: str) -> None:
  81. operation = GroupedOperation()
  82. nodes_to_change = []
  83. for node in Selection.getAllSelectedObjects():
  84. # Do not change any nodes that already have the right extruder set.
  85. if node.callDecoration("getActiveExtruder") == extruder_id:
  86. continue
  87. # If the node is a group, apply the active extruder to all children of the group.
  88. if node.callDecoration("isGroup"):
  89. for grouped_node in BreadthFirstIterator(node):
  90. if grouped_node.callDecoration("getActiveExtruder") == extruder_id:
  91. continue
  92. if grouped_node.callDecoration("isGroup"):
  93. continue
  94. nodes_to_change.append(grouped_node)
  95. continue
  96. nodes_to_change.append(node)
  97. if not nodes_to_change:
  98. # If there are no changes to make, we still need to reset the selected extruders.
  99. # This is a workaround for checked menu items being deselected while still being
  100. # selected.
  101. ExtruderManager.getInstance().resetSelectedObjectExtruders()
  102. return
  103. for node in nodes_to_change:
  104. operation.addOperation(SetObjectExtruderOperation(node, extruder_id))
  105. operation.push()
  106. def _openUrl(self, url):
  107. QDesktopServices.openUrl(url)