CuraApplication.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. # Copyright (c) 2015 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from UM.Qt.QtApplication import QtApplication
  4. from UM.Scene.SceneNode import SceneNode
  5. from UM.Scene.Camera import Camera
  6. from UM.Scene.Platform import Platform
  7. from UM.Math.Vector import Vector
  8. from UM.Math.Quaternion import Quaternion
  9. from UM.Math.AxisAlignedBox import AxisAlignedBox
  10. from UM.Resources import Resources
  11. from UM.Scene.ToolHandle import ToolHandle
  12. from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
  13. from UM.Mesh.ReadMeshJob import ReadMeshJob
  14. from UM.Logger import Logger
  15. from UM.Preferences import Preferences
  16. from UM.JobQueue import JobQueue
  17. from UM.Scene.Selection import Selection
  18. from UM.Scene.GroupDecorator import GroupDecorator
  19. from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
  20. from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
  21. from UM.Operations.GroupedOperation import GroupedOperation
  22. from UM.Operations.SetTransformOperation import SetTransformOperation
  23. from UM.i18n import i18nCatalog
  24. from . import PlatformPhysics
  25. from . import BuildVolume
  26. from . import CameraAnimation
  27. from . import PrintInformation
  28. from . import CuraActions
  29. from . import MultiMaterialDecorator
  30. from . import ZOffsetDecorator
  31. from . import CuraSplashScreen
  32. from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
  33. from PyQt5.QtGui import QColor, QIcon
  34. from PyQt5.QtQml import qmlRegisterUncreatableType
  35. import platform
  36. import sys
  37. import os.path
  38. import numpy
  39. import copy
  40. numpy.seterr(all="ignore")
  41. if platform.system() == "Linux": # Needed for platform.linux_distribution, which is not available on Windows and OSX
  42. # For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
  43. if platform.linux_distribution()[0] in ("Ubuntu", ): # TODO: Needs a "if X11_GFX == 'nvidia'" here. The workaround is only needed on Ubuntu+NVidia drivers. Other drivers are not affected, but fine with this fix.
  44. import ctypes
  45. from ctypes.util import find_library
  46. ctypes.CDLL(find_library('GL'), ctypes.RTLD_GLOBAL)
  47. try:
  48. from cura.CuraVersion import CuraVersion
  49. except ImportError:
  50. CuraVersion = "master" # [CodeStyle: Reflecting imported value]
  51. class CuraApplication(QtApplication):
  52. class ResourceTypes:
  53. QmlFiles = Resources.UserType + 1
  54. Firmware = Resources.UserType + 2
  55. Q_ENUMS(ResourceTypes)
  56. def __init__(self):
  57. Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura"))
  58. if not hasattr(sys, "frozen"):
  59. Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
  60. self._open_file_queue = [] #Files to open when plug-ins are loaded.
  61. super().__init__(name = "cura", version = CuraVersion)
  62. self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
  63. self.setRequiredPlugins([
  64. "CuraEngineBackend",
  65. "MeshView",
  66. "LayerView",
  67. "STLReader",
  68. "SelectionTool",
  69. "CameraTool",
  70. "GCodeWriter",
  71. "LocalFileOutputDevice"
  72. ])
  73. self._physics = None
  74. self._volume = None
  75. self._platform = None
  76. self._output_devices = {}
  77. self._print_information = None
  78. self._i18n_catalog = None
  79. self._previous_active_tool = None
  80. self._platform_activity = False
  81. self._scene_boundingbox = AxisAlignedBox()
  82. self._job_name = None
  83. self._center_after_select = False
  84. self.getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineChanged)
  85. self.getMachineManager().addMachineRequested.connect(self._onAddMachineRequested)
  86. self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
  87. self.getController().toolOperationStopped.connect(self._onToolOperationStopped)
  88. Resources.addType(self.ResourceTypes.QmlFiles, "qml")
  89. Resources.addType(self.ResourceTypes.Firmware, "firmware")
  90. Preferences.getInstance().addPreference("cura/active_machine", "")
  91. Preferences.getInstance().addPreference("cura/active_mode", "simple")
  92. Preferences.getInstance().addPreference("cura/recent_files", "")
  93. Preferences.getInstance().addPreference("cura/categories_expanded", "")
  94. Preferences.getInstance().addPreference("view/center_on_select", True)
  95. Preferences.getInstance().addPreference("mesh/scale_to_fit", True)
  96. Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode")
  97. JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
  98. self._recent_files = []
  99. files = Preferences.getInstance().getValue("cura/recent_files").split(";")
  100. for f in files:
  101. if not os.path.isfile(f):
  102. continue
  103. self._recent_files.append(QUrl.fromLocalFile(f))
  104. @pyqtSlot(result = QUrl)
  105. def getDefaultPath(self):
  106. return QUrl.fromLocalFile(os.path.expanduser("~/"))
  107. ## Handle loading of all plugin types (and the backend explicitly)
  108. # \sa PluginRegistery
  109. def _loadPlugins(self):
  110. self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura"))
  111. if not hasattr(sys, "frozen"):
  112. self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
  113. self._plugin_registry.loadPlugin("ConsoleLogger")
  114. self._plugin_registry.loadPlugin("CuraEngineBackend")
  115. self._plugin_registry.loadPlugins()
  116. if self.getBackend() == None:
  117. raise RuntimeError("Could not load the backend plugin!")
  118. self._plugins_loaded = True
  119. def addCommandLineOptions(self, parser):
  120. super().addCommandLineOptions(parser)
  121. parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
  122. parser.add_argument("--debug", dest="debug-mode", action="store_true", default=False, help="Enable detailed crash reports.")
  123. def run(self):
  124. self._i18n_catalog = i18nCatalog("cura");
  125. i18nCatalog.setTagReplacements({
  126. "filename": "font color=\"black\"",
  127. "message": "font color=UM.Theme.colors.message_text;",
  128. })
  129. self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
  130. controller = self.getController()
  131. controller.setActiveView("SolidView")
  132. controller.setCameraTool("CameraTool")
  133. controller.setSelectionTool("SelectionTool")
  134. t = controller.getTool("TranslateTool")
  135. if t:
  136. t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis])
  137. Selection.selectionChanged.connect(self.onSelectionChanged)
  138. root = controller.getScene().getRoot()
  139. self._platform = Platform(root)
  140. self._volume = BuildVolume.BuildVolume(root)
  141. self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
  142. self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
  143. camera = Camera("3d", root)
  144. camera.setPosition(Vector(-80, 250, 700))
  145. camera.setPerspective(True)
  146. camera.lookAt(Vector(0, 0, 0))
  147. controller.getScene().setActiveCamera("3d")
  148. self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0))
  149. self._camera_animation = CameraAnimation.CameraAnimation()
  150. self._camera_animation.setCameraTool(self.getController().getTool("CameraTool"))
  151. self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface..."))
  152. self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
  153. self.initializeEngine()
  154. if self._engine.rootObjects:
  155. self.closeSplash()
  156. for file in self.getCommandLineOption("file", []):
  157. self._openFile(file)
  158. for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading.
  159. self._openFile(file_name)
  160. self.exec_()
  161. # Handle Qt events
  162. def event(self, event):
  163. if event.type() == QEvent.FileOpen:
  164. if self._plugins_loaded:
  165. self._openFile(event.file())
  166. else:
  167. self._open_file_queue.append(event.file())
  168. return super().event(event)
  169. def getPrintInformation(self):
  170. return self._print_information
  171. def registerObjects(self, engine):
  172. engine.rootContext().setContextProperty("Printer", self)
  173. self._print_information = PrintInformation.PrintInformation()
  174. engine.rootContext().setContextProperty("PrintInformation", self._print_information)
  175. self._cura_actions = CuraActions.CuraActions(self)
  176. engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
  177. qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
  178. def onSelectionChanged(self):
  179. if Selection.hasSelection():
  180. if not self.getController().getActiveTool():
  181. if self._previous_active_tool:
  182. self.getController().setActiveTool(self._previous_active_tool)
  183. self._previous_active_tool = None
  184. else:
  185. self.getController().setActiveTool("TranslateTool")
  186. if Preferences.getInstance().getValue("view/center_on_select"):
  187. self._center_after_select = True
  188. else:
  189. if self.getController().getActiveTool():
  190. self._previous_active_tool = self.getController().getActiveTool().getPluginId()
  191. self.getController().setActiveTool(None)
  192. else:
  193. self._previous_active_tool = None
  194. def _onToolOperationStopped(self, event):
  195. if self._center_after_select:
  196. self._center_after_select = False
  197. self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
  198. self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
  199. self._camera_animation.start()
  200. requestAddPrinter = pyqtSignal()
  201. activityChanged = pyqtSignal()
  202. sceneBoundingBoxChanged = pyqtSignal()
  203. @pyqtProperty(bool, notify = activityChanged)
  204. def getPlatformActivity(self):
  205. return self._platform_activity
  206. @pyqtProperty(str, notify = sceneBoundingBoxChanged)
  207. def getSceneBoundingBoxString(self):
  208. return self._i18n_catalog.i18nc("@info", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_boundingbox.width.item(), 'depth': self._scene_boundingbox.depth.item(), 'height' : self._scene_boundingbox.height.item()}
  209. def updatePlatformActivity(self, node = None):
  210. count = 0
  211. scene_boundingbox = None
  212. for node in DepthFirstIterator(self.getController().getScene().getRoot()):
  213. if type(node) is not SceneNode or not node.getMeshData():
  214. continue
  215. count += 1
  216. if not scene_boundingbox:
  217. scene_boundingbox = copy.deepcopy(node.getBoundingBox())
  218. else:
  219. scene_boundingbox += node.getBoundingBox()
  220. if not scene_boundingbox:
  221. scene_boundingbox = AxisAlignedBox()
  222. if repr(self._scene_boundingbox) != repr(scene_boundingbox):
  223. self._scene_boundingbox = scene_boundingbox
  224. self.sceneBoundingBoxChanged.emit()
  225. self._platform_activity = True if count > 0 else False
  226. self.activityChanged.emit()
  227. @pyqtSlot(str)
  228. def setJobName(self, name):
  229. name = os.path.splitext(name)[0] #when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its extension. This cuts the extension off if nescessary.
  230. if self._job_name != name:
  231. self._job_name = name
  232. self.jobNameChanged.emit()
  233. jobNameChanged = pyqtSignal()
  234. @pyqtProperty(str, notify = jobNameChanged)
  235. def jobName(self):
  236. return self._job_name
  237. # Remove all selected objects from the scene.
  238. @pyqtSlot()
  239. def deleteSelection(self):
  240. if not self.getController().getToolsEnabled():
  241. return
  242. op = GroupedOperation()
  243. nodes = Selection.getAllSelectedObjects()
  244. for node in nodes:
  245. op.addOperation(RemoveSceneNodeOperation(node))
  246. op.push()
  247. pass
  248. ## Remove an object from the scene.
  249. # Note that this only removes an object if it is selected.
  250. @pyqtSlot("quint64")
  251. def deleteObject(self, object_id):
  252. if not self.getController().getToolsEnabled():
  253. return
  254. node = self.getController().getScene().findObject(object_id)
  255. if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
  256. node = Selection.getSelectedObject(0)
  257. if node:
  258. if node.getParent():
  259. group_node = node.getParent()
  260. if not group_node.callDecoration("isGroup"):
  261. op = RemoveSceneNodeOperation(node)
  262. else:
  263. while group_node.getParent().callDecoration("isGroup"):
  264. group_node = group_node.getParent()
  265. op = RemoveSceneNodeOperation(group_node)
  266. op.push()
  267. ## Create a number of copies of existing object.
  268. @pyqtSlot("quint64", int)
  269. def multiplyObject(self, object_id, count):
  270. node = self.getController().getScene().findObject(object_id)
  271. if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
  272. node = Selection.getSelectedObject(0)
  273. if node:
  274. op = GroupedOperation()
  275. for _ in range(count):
  276. if node.getParent() and node.getParent().callDecoration("isGroup"):
  277. new_node = copy.deepcopy(node.getParent()) #Copy the group node.
  278. new_node.callDecoration("setConvexHull",None)
  279. op.addOperation(AddSceneNodeOperation(new_node,node.getParent().getParent()))
  280. else:
  281. new_node = copy.deepcopy(node)
  282. new_node.callDecoration("setConvexHull", None)
  283. op.addOperation(AddSceneNodeOperation(new_node, node.getParent()))
  284. op.push()
  285. ## Center object on platform.
  286. @pyqtSlot("quint64")
  287. def centerObject(self, object_id):
  288. node = self.getController().getScene().findObject(object_id)
  289. if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
  290. node = Selection.getSelectedObject(0)
  291. if not node:
  292. return
  293. if node.getParent() and node.getParent().callDecoration("isGroup"):
  294. node = node.getParent()
  295. if node:
  296. op = SetTransformOperation(node, Vector())
  297. op.push()
  298. ## Delete all mesh data on the scene.
  299. @pyqtSlot()
  300. def deleteAll(self):
  301. if not self.getController().getToolsEnabled():
  302. return
  303. nodes = []
  304. for node in DepthFirstIterator(self.getController().getScene().getRoot()):
  305. if type(node) is not SceneNode:
  306. continue
  307. if not node.getMeshData() and not node.callDecoration("isGroup"):
  308. continue #Node that doesnt have a mesh and is not a group.
  309. if node.getParent() and node.getParent().callDecoration("isGroup"):
  310. continue #Grouped nodes don't need resetting as their parent (the group) is resetted)
  311. nodes.append(node)
  312. if nodes:
  313. op = GroupedOperation()
  314. for node in nodes:
  315. op.addOperation(RemoveSceneNodeOperation(node))
  316. op.push()
  317. ## Reset all translation on nodes with mesh data.
  318. @pyqtSlot()
  319. def resetAllTranslation(self):
  320. nodes = []
  321. for node in DepthFirstIterator(self.getController().getScene().getRoot()):
  322. if type(node) is not SceneNode:
  323. continue
  324. if not node.getMeshData() and not node.callDecoration("isGroup"):
  325. continue #Node that doesnt have a mesh and is not a group.
  326. if node.getParent() and node.getParent().callDecoration("isGroup"):
  327. continue #Grouped nodes don't need resetting as their parent (the group) is resetted)
  328. nodes.append(node)
  329. if nodes:
  330. op = GroupedOperation()
  331. for node in nodes:
  332. node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
  333. op.addOperation(SetTransformOperation(node, Vector(0,0,0)))
  334. op.push()
  335. ## Reset all transformations on nodes with mesh data.
  336. @pyqtSlot()
  337. def resetAll(self):
  338. nodes = []
  339. for node in DepthFirstIterator(self.getController().getScene().getRoot()):
  340. if type(node) is not SceneNode:
  341. continue
  342. if not node.getMeshData() and not node.callDecoration("isGroup"):
  343. continue #Node that doesnt have a mesh and is not a group.
  344. if node.getParent() and node.getParent().callDecoration("isGroup"):
  345. continue #Grouped nodes don't need resetting as their parent (the group) is resetted)
  346. nodes.append(node)
  347. if nodes:
  348. op = GroupedOperation()
  349. for node in nodes:
  350. # Ensure that the object is above the build platform
  351. node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
  352. op.addOperation(SetTransformOperation(node, Vector(0,0,0), Quaternion(), Vector(1, 1, 1)))
  353. op.push()
  354. ## Reload all mesh data on the screen from file.
  355. @pyqtSlot()
  356. def reloadAll(self):
  357. nodes = []
  358. for node in DepthFirstIterator(self.getController().getScene().getRoot()):
  359. if type(node) is not SceneNode or not node.getMeshData():
  360. continue
  361. nodes.append(node)
  362. if not nodes:
  363. return
  364. for node in nodes:
  365. if not node.getMeshData():
  366. continue
  367. file_name = node.getMeshData().getFileName()
  368. if file_name:
  369. job = ReadMeshJob(file_name)
  370. job._node = node
  371. job.finished.connect(self._reloadMeshFinished)
  372. job.start()
  373. ## Get logging data of the backend engine
  374. # \returns \type{string} Logging data
  375. @pyqtSlot(result=str)
  376. def getEngineLog(self):
  377. log = ""
  378. for entry in self.getBackend().getLog():
  379. log += entry.decode()
  380. return log
  381. recentFilesChanged = pyqtSignal()
  382. @pyqtProperty("QVariantList", notify = recentFilesChanged)
  383. def recentFiles(self):
  384. return self._recent_files
  385. @pyqtSlot("QStringList")
  386. def setExpandedCategories(self, categories):
  387. categories = list(set(categories))
  388. categories.sort()
  389. joined = ";".join(categories)
  390. if joined != Preferences.getInstance().getValue("cura/categories_expanded"):
  391. Preferences.getInstance().setValue("cura/categories_expanded", joined)
  392. self.expandedCategoriesChanged.emit()
  393. expandedCategoriesChanged = pyqtSignal()
  394. @pyqtProperty("QStringList", notify = expandedCategoriesChanged)
  395. def expandedCategories(self):
  396. return Preferences.getInstance().getValue("cura/categories_expanded").split(";")
  397. @pyqtSlot(str, result = "QVariant")
  398. def getSettingValue(self, key):
  399. if not self.getMachineManager().getWorkingProfile():
  400. return None
  401. return self.getMachineManager().getWorkingProfile().getSettingValue(key)
  402. #return self.getActiveMachine().getSettingValueByKey(key)
  403. ## Change setting by key value pair
  404. @pyqtSlot(str, "QVariant")
  405. def setSettingValue(self, key, value):
  406. if not self.getMachineManager().getWorkingProfile():
  407. return
  408. self.getMachineManager().getWorkingProfile().setSettingValue(key, value)
  409. @pyqtSlot()
  410. def mergeSelected(self):
  411. self.groupSelected()
  412. try:
  413. group_node = Selection.getAllSelectedObjects()[0]
  414. except Exception as e:
  415. Logger.log("d", "mergeSelected: Exception:", e)
  416. return
  417. multi_material_decorator = MultiMaterialDecorator.MultiMaterialDecorator()
  418. group_node.addDecorator(multi_material_decorator)
  419. # Reset the position of each node
  420. for node in group_node.getChildren():
  421. new_position = node.getMeshData().getCenterPosition()
  422. new_position = new_position.scale(node.getScale())
  423. node.setPosition(new_position)
  424. # Use the previously found center of the group bounding box as the new location of the group
  425. group_node.setPosition(group_node.getBoundingBox().center)
  426. @pyqtSlot()
  427. def groupSelected(self):
  428. group_node = SceneNode()
  429. group_decorator = GroupDecorator()
  430. group_node.addDecorator(group_decorator)
  431. group_node.setParent(self.getController().getScene().getRoot())
  432. group_node.setSelectable(True)
  433. center = Selection.getSelectionCenter()
  434. group_node.setPosition(center)
  435. group_node.setCenterPosition(center)
  436. for node in Selection.getAllSelectedObjects():
  437. world = node.getWorldPosition()
  438. node.setParent(group_node)
  439. node.setPosition(world - center)
  440. for node in group_node.getChildren():
  441. Selection.remove(node)
  442. Selection.add(group_node)
  443. @pyqtSlot()
  444. def ungroupSelected(self):
  445. ungrouped_nodes = []
  446. selected_objects = Selection.getAllSelectedObjects()[:] #clone the list
  447. for node in selected_objects:
  448. if node.callDecoration("isGroup" ):
  449. children_to_move = []
  450. for child in node.getChildren():
  451. if type(child) is SceneNode:
  452. children_to_move.append(child)
  453. for child in children_to_move:
  454. position = child.getWorldPosition()
  455. child.setParent(node.getParent())
  456. child.setPosition(position - node.getParent().getWorldPosition())
  457. child.scale(node.getScale())
  458. child.rotate(node.getOrientation())
  459. Selection.add(child)
  460. child.callDecoration("setConvexHull",None)
  461. node.setParent(None)
  462. ungrouped_nodes.append(node)
  463. for node in ungrouped_nodes:
  464. Selection.remove(node)
  465. def _createSplashScreen(self):
  466. return CuraSplashScreen.CuraSplashScreen()
  467. def _onActiveMachineChanged(self):
  468. machine = self.getMachineManager().getActiveMachineInstance()
  469. if machine:
  470. pass
  471. #Preferences.getInstance().setValue("cura/active_machine", machine.getName())
  472. #self._volume.setWidth(machine.getSettingValueByKey("machine_width"))
  473. #self._volume.setHeight(machine.getSettingValueByKey("machine_height"))
  474. #self._volume.setDepth(machine.getSettingValueByKey("machine_depth"))
  475. #disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
  476. #areas = []
  477. #if disallowed_areas:
  478. #for area in disallowed_areas:
  479. #areas.append(Polygon(numpy.array(area, numpy.float32)))
  480. #self._volume.setDisallowedAreas(areas)
  481. #self._volume.rebuild()
  482. #offset = machine.getSettingValueByKey("machine_platform_offset")
  483. #if offset:
  484. #self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
  485. #else:
  486. #self._platform.setPosition(Vector(0.0, 0.0, 0.0))
  487. def _onFileLoaded(self, job):
  488. node = job.getResult()
  489. if node != None:
  490. self.setJobName(os.path.basename(job.getFileName()))
  491. node.setSelectable(True)
  492. node.setName(os.path.basename(job.getFileName()))
  493. op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
  494. op.push()
  495. self.getController().getScene().sceneChanged.emit(node) #Force scene change.
  496. def _onJobFinished(self, job):
  497. if type(job) is not ReadMeshJob or not job.getResult():
  498. return
  499. f = QUrl.fromLocalFile(job.getFileName())
  500. if f in self._recent_files:
  501. self._recent_files.remove(f)
  502. self._recent_files.insert(0, f)
  503. if len(self._recent_files) > 10:
  504. del self._recent_files[10]
  505. pref = ""
  506. for path in self._recent_files:
  507. pref += path.toLocalFile() + ";"
  508. Preferences.getInstance().setValue("cura/recent_files", pref)
  509. self.recentFilesChanged.emit()
  510. def _reloadMeshFinished(self, job):
  511. # TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
  512. job._node.setMeshData(job.getResult().getMeshData())
  513. #job.getResult().setParent(self.getController().getScene().getRoot())
  514. #job._node.setParent(self.getController().getScene().getRoot())
  515. #job._node.meshDataChanged.emit(job._node)
  516. def _openFile(self, file):
  517. job = ReadMeshJob(os.path.abspath(file))
  518. job.finished.connect(self._onFileLoaded)
  519. job.start()
  520. def _onAddMachineRequested(self):
  521. self.requestAddPrinter.emit()