Cura.qml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. // Copyright (c) 2015 Ultimaker B.V.
  2. // Cura is released under the terms of the AGPLv3 or higher.
  3. import QtQuick 2.2
  4. import QtQuick.Controls 1.1
  5. import QtQuick.Controls.Styles 1.1
  6. import QtQuick.Layouts 1.1
  7. import QtQuick.Dialogs 1.1
  8. import UM 1.1 as UM
  9. UM.MainWindow
  10. {
  11. id: base
  12. //: Cura application window title
  13. title: catalog.i18nc("@title:window","Cura");
  14. viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
  15. Item
  16. {
  17. id: backgroundItem;
  18. anchors.fill: parent;
  19. UM.I18nCatalog{id: catalog; name:"cura"}
  20. signal hasMesh(string name) //this signal sends the filebase name so it can be used for the JobSpecs.qml
  21. function getMeshName(path){
  22. //takes the path the complete path of the meshname and returns only the filebase
  23. var fileName = path.slice(path.lastIndexOf("/") + 1)
  24. var fileBase = fileName.slice(0, fileName.lastIndexOf("."))
  25. return fileBase
  26. }
  27. //DeleteSelection on the keypress backspace event
  28. Keys.onPressed: {
  29. if (event.key == Qt.Key_Backspace)
  30. {
  31. if(objectContextMenu.objectId != 0)
  32. {
  33. Printer.deleteObject(objectContextMenu.objectId);
  34. }
  35. }
  36. }
  37. UM.ApplicationMenu
  38. {
  39. id: menu
  40. window: base
  41. Menu
  42. {
  43. id: fileMenu
  44. //: File menu
  45. title: catalog.i18nc("@title:menu menubar:toplevel","&File");
  46. MenuItem {
  47. action: actions.open;
  48. }
  49. Menu
  50. {
  51. id: recentFilesMenu;
  52. title: catalog.i18nc("@title:menu menubar:file", "Open &Recent")
  53. iconName: "document-open-recent";
  54. enabled: Printer.recentFiles.length > 0;
  55. Instantiator
  56. {
  57. model: Printer.recentFiles
  58. MenuItem
  59. {
  60. text:
  61. {
  62. var path = modelData.toString()
  63. return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
  64. }
  65. onTriggered: {
  66. UM.MeshFileHandler.readLocalFile(modelData);
  67. var meshName = backgroundItem.getMeshName(modelData.toString())
  68. backgroundItem.hasMesh(meshName)
  69. }
  70. }
  71. onObjectAdded: recentFilesMenu.insertItem(index, object)
  72. onObjectRemoved: recentFilesMenu.removeItem(object)
  73. }
  74. }
  75. MenuSeparator { }
  76. MenuItem
  77. {
  78. text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
  79. enabled: UM.Selection.hasSelection;
  80. iconName: "document-save-as";
  81. onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName, false);
  82. }
  83. Menu
  84. {
  85. id: saveAllMenu
  86. title: catalog.i18nc("@title:menu menubar:file","Save &All")
  87. iconName: "document-save-all";
  88. enabled: devicesModel.rowCount() > 0 && UM.Backend.progress > 0.99;
  89. Instantiator
  90. {
  91. model: UM.OutputDevicesModel { id: devicesModel; }
  92. MenuItem
  93. {
  94. text: model.description;
  95. onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, Printer.jobName, false);
  96. }
  97. onObjectAdded: saveAllMenu.insertItem(index, object)
  98. onObjectRemoved: saveAllMenu.removeItem(object)
  99. }
  100. }
  101. MenuItem { action: actions.reloadAll; }
  102. MenuSeparator { }
  103. MenuItem { action: actions.quit; }
  104. }
  105. Menu
  106. {
  107. //: Edit menu
  108. title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
  109. MenuItem { action: actions.undo; }
  110. MenuItem { action: actions.redo; }
  111. MenuSeparator { }
  112. MenuItem { action: actions.deleteSelection; }
  113. MenuItem { action: actions.deleteAll; }
  114. MenuItem { action: actions.resetAllTranslation; }
  115. MenuItem { action: actions.resetAll; }
  116. MenuSeparator { }
  117. MenuItem { action: actions.groupObjects;}
  118. MenuItem { action: actions.mergeObjects;}
  119. MenuItem { action: actions.unGroupObjects;}
  120. }
  121. Menu
  122. {
  123. title: catalog.i18nc("@title:menu menubar:toplevel","&View");
  124. id: top_view_menu
  125. Instantiator
  126. {
  127. model: UM.ViewModel { }
  128. MenuItem
  129. {
  130. text: model.name;
  131. checkable: true;
  132. checked: model.active;
  133. exclusiveGroup: view_menu_top_group;
  134. onTriggered: UM.Controller.setActiveView(model.id);
  135. }
  136. onObjectAdded: top_view_menu.insertItem(index, object)
  137. onObjectRemoved: top_view_menu.removeItem(object)
  138. }
  139. ExclusiveGroup { id: view_menu_top_group; }
  140. }
  141. Menu
  142. {
  143. id: machineMenu;
  144. //: Machine menu
  145. title: catalog.i18nc("@title:menu menubar:toplevel","&Printer");
  146. Instantiator
  147. {
  148. model: UM.MachineInstancesModel { }
  149. MenuItem
  150. {
  151. text: model.name;
  152. checkable: true;
  153. checked: model.active;
  154. exclusiveGroup: machineMenuGroup;
  155. onTriggered: UM.MachineManager.setActiveMachineInstance(model.name)
  156. }
  157. onObjectAdded: machineMenu.insertItem(index, object)
  158. onObjectRemoved: machineMenu.removeItem(object)
  159. }
  160. ExclusiveGroup { id: machineMenuGroup; }
  161. MenuSeparator { }
  162. Instantiator
  163. {
  164. model: UM.MachineVariantsModel { }
  165. MenuItem {
  166. text: model.name;
  167. checkable: true;
  168. checked: model.active;
  169. exclusiveGroup: machineVariantsGroup;
  170. onTriggered: UM.MachineManager.setActiveMachineVariant(model.name)
  171. }
  172. onObjectAdded: machineMenu.insertItem(index, object)
  173. onObjectRemoved: machineMenu.removeItem(object)
  174. }
  175. ExclusiveGroup { id: machineVariantsGroup; }
  176. MenuSeparator { visible: UM.MachineManager.hasVariants; }
  177. MenuItem { action: actions.addMachine; }
  178. MenuItem { action: actions.configureMachines; }
  179. }
  180. Menu
  181. {
  182. id: profileMenu
  183. title: catalog.i18nc("@title:menu menubar:toplevel", "P&rofile")
  184. Instantiator
  185. {
  186. model: UM.ProfilesModel { }
  187. MenuItem {
  188. text: model.name;
  189. checkable: true;
  190. checked: model.active;
  191. exclusiveGroup: profileMenuGroup;
  192. onTriggered: UM.MachineManager.setActiveProfile(model.name)
  193. }
  194. onObjectAdded: profileMenu.insertItem(index, object)
  195. onObjectRemoved: profileMenu.removeItem(object)
  196. }
  197. ExclusiveGroup { id: profileMenuGroup; }
  198. MenuSeparator { }
  199. MenuItem { action: actions.addProfile; }
  200. MenuItem { action: actions.manageProfiles; }
  201. }
  202. Menu
  203. {
  204. id: extension_menu
  205. //: Extensions menu
  206. title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions");
  207. Instantiator
  208. {
  209. model: UM.Models.extensionModel
  210. Menu
  211. {
  212. id: sub_menu
  213. title: model.name;
  214. visible: actions != null
  215. enabled:actions != null
  216. Instantiator
  217. {
  218. model: actions
  219. MenuItem
  220. {
  221. text: model.text
  222. onTriggered: UM.Models.extensionModel.subMenuTriggered(name, model.text)
  223. }
  224. onObjectAdded: sub_menu.insertItem(index, object)
  225. onObjectRemoved: sub_menu.removeItem(object)
  226. }
  227. }
  228. onObjectAdded: extension_menu.insertItem(index, object)
  229. onObjectRemoved: extension_menu.removeItem(object)
  230. }
  231. }
  232. Menu
  233. {
  234. //: Settings menu
  235. title: catalog.i18nc("@title:menu menubar:toplevel","&Settings");
  236. MenuItem { action: actions.preferences; }
  237. }
  238. Menu
  239. {
  240. //: Help menu
  241. title: catalog.i18nc("@title:menu menubar:toplevel","&Help");
  242. MenuItem { action: actions.showEngineLog; }
  243. MenuItem { action: actions.documentation; }
  244. MenuItem { action: actions.reportBug; }
  245. MenuSeparator { }
  246. MenuItem { action: actions.about; }
  247. }
  248. }
  249. Item
  250. {
  251. id: contentItem;
  252. y: menu.height
  253. width: parent.width;
  254. height: parent.height - menu.height;
  255. Keys.forwardTo: menu
  256. DropArea
  257. {
  258. anchors.fill: parent;
  259. onDropped:
  260. {
  261. if(drop.urls.length > 0)
  262. {
  263. for(var i in drop.urls)
  264. {
  265. UM.MeshFileHandler.readLocalFile(drop.urls[i]);
  266. if (i == drop.urls.length - 1)
  267. {
  268. var meshName = backgroundItem.getMeshName(drop.urls[i].toString())
  269. backgroundItem.hasMesh(meshName)
  270. }
  271. }
  272. }
  273. }
  274. }
  275. JobSpecs
  276. {
  277. id: jobSpecs
  278. anchors
  279. {
  280. bottom: parent.bottom;
  281. right: sidebar.left;
  282. bottomMargin: UM.Theme.sizes.default_margin.height;
  283. rightMargin: UM.Theme.sizes.default_margin.width;
  284. }
  285. }
  286. UM.MessageStack
  287. {
  288. anchors
  289. {
  290. horizontalCenter: parent.horizontalCenter
  291. horizontalCenterOffset: -(UM.Theme.sizes.sidebar.width/ 2)
  292. top: parent.verticalCenter;
  293. bottom: parent.bottom;
  294. }
  295. }
  296. Loader
  297. {
  298. id: view_panel
  299. //anchors.left: parent.left;
  300. //anchors.right: parent.right;
  301. //anchors.bottom: parent.bottom
  302. anchors.top: viewModeButton.bottom
  303. anchors.topMargin: UM.Theme.sizes.default_margin.height;
  304. anchors.left: viewModeButton.left;
  305. //anchors.bottom: buttons.top;
  306. //anchors.bottomMargin: UM.Theme.sizes.default_margin.height;
  307. height: childrenRect.height;
  308. source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
  309. }
  310. Button
  311. {
  312. id: openFileButton;
  313. //style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
  314. text: catalog.i18nc("@action:button","Open File");
  315. iconSource: UM.Theme.icons.load
  316. style: UM.Theme.styles.tool_button
  317. tooltip: '';
  318. anchors
  319. {
  320. top: parent.top;
  321. //topMargin: UM.Theme.sizes.loadfile_margin.height
  322. left: parent.left;
  323. //leftMargin: UM.Theme.sizes.loadfile_margin.width
  324. }
  325. action: actions.open;
  326. }
  327. Image
  328. {
  329. id: logo
  330. anchors
  331. {
  332. left: parent.left
  333. leftMargin: UM.Theme.sizes.default_margin.width;
  334. bottom: parent.bottom
  335. bottomMargin: UM.Theme.sizes.default_margin.height;
  336. }
  337. source: UM.Theme.images.logo;
  338. width: UM.Theme.sizes.logo.width;
  339. height: UM.Theme.sizes.logo.height;
  340. z: -1;
  341. sourceSize.width: width;
  342. sourceSize.height: height;
  343. }
  344. Button
  345. {
  346. id: viewModeButton
  347. anchors
  348. {
  349. top: toolbar.bottom;
  350. topMargin: UM.Theme.sizes.window_margin.height;
  351. left: parent.left;
  352. }
  353. text: catalog.i18nc("@action:button","View Mode");
  354. iconSource: UM.Theme.icons.viewmode;
  355. style: UM.Theme.styles.tool_button;
  356. tooltip: '';
  357. menu: Menu
  358. {
  359. id: viewMenu;
  360. Instantiator
  361. {
  362. id: viewMenuInstantiator
  363. model: UM.ViewModel { }
  364. MenuItem
  365. {
  366. text: model.name
  367. checkable: true;
  368. checked: model.active
  369. exclusiveGroup: viewMenuGroup;
  370. onTriggered: UM.Controller.setActiveView(model.id);
  371. }
  372. onObjectAdded: viewMenu.insertItem(index, object)
  373. onObjectRemoved: viewMenu.removeItem(object)
  374. }
  375. ExclusiveGroup { id: viewMenuGroup; }
  376. }
  377. }
  378. Toolbar
  379. {
  380. id: toolbar;
  381. anchors {
  382. top: openFileButton.bottom;
  383. topMargin: UM.Theme.sizes.window_margin.height;
  384. left: parent.left;
  385. }
  386. }
  387. Sidebar
  388. {
  389. id: sidebar;
  390. anchors
  391. {
  392. top: parent.top;
  393. bottom: parent.bottom;
  394. right: parent.right;
  395. }
  396. width: UM.Theme.sizes.sidebar.width;
  397. addMachineAction: actions.addMachine;
  398. configureMachinesAction: actions.configureMachines;
  399. addProfileAction: actions.addProfile;
  400. manageProfilesAction: actions.manageProfiles;
  401. }
  402. Rectangle
  403. {
  404. x: base.mouseX + UM.Theme.sizes.default_margin.width;
  405. y: base.mouseY + UM.Theme.sizes.default_margin.height;
  406. width: childrenRect.width;
  407. height: childrenRect.height;
  408. Label
  409. {
  410. text: UM.ActiveTool.properties.getValue("Rotation") != undefined ? "%1°".arg(UM.ActiveTool.properties.getValue("Rotation")) : "";
  411. }
  412. visible: UM.ActiveTool.valid && UM.ActiveTool.properties.Rotation != undefined;
  413. }
  414. }
  415. }
  416. UM.PreferencesDialog
  417. {
  418. id: preferences
  419. Component.onCompleted:
  420. {
  421. //; Remove & re-add the general page as we want to use our own instead of uranium standard.
  422. removePage(0);
  423. insertPage(0, catalog.i18nc("@title:tab","General"), generalPage);
  424. //: View preferences page title
  425. insertPage(1, catalog.i18nc("@title:tab","View"), viewPage);
  426. //Force refresh
  427. setPage(0)
  428. }
  429. Item {
  430. visible: false
  431. GeneralPage
  432. {
  433. id: generalPage
  434. }
  435. ViewPage
  436. {
  437. id: viewPage
  438. }
  439. }
  440. }
  441. Actions
  442. {
  443. id: actions;
  444. open.onTriggered: openDialog.open();
  445. quit.onTriggered: base.visible = false;
  446. undo.onTriggered: UM.OperationStack.undo();
  447. undo.enabled: UM.OperationStack.canUndo;
  448. redo.onTriggered: UM.OperationStack.redo();
  449. redo.enabled: UM.OperationStack.canRedo;
  450. deleteSelection.onTriggered:
  451. {
  452. Printer.deleteSelection()
  453. }
  454. deleteObject.onTriggered:
  455. {
  456. if(objectContextMenu.objectId != 0)
  457. {
  458. Printer.deleteObject(objectContextMenu.objectId);
  459. objectContextMenu.objectId = 0;
  460. }
  461. }
  462. multiplyObject.onTriggered:
  463. {
  464. if(objectContextMenu.objectId != 0)
  465. {
  466. Printer.multiplyObject(objectContextMenu.objectId, 1);
  467. objectContextMenu.objectId = 0;
  468. }
  469. }
  470. centerObject.onTriggered:
  471. {
  472. if(objectContextMenu.objectId != 0)
  473. {
  474. Printer.centerObject(objectContextMenu.objectId);
  475. objectContextMenu.objectId = 0;
  476. }
  477. }
  478. groupObjects.onTriggered:
  479. {
  480. Printer.groupSelected()
  481. }
  482. unGroupObjects.onTriggered:
  483. {
  484. Printer.ungroupSelected()
  485. }
  486. mergeObjects.onTriggered:
  487. {
  488. Printer.mergeSelected()
  489. }
  490. deleteAll.onTriggered: Printer.deleteAll()
  491. resetAllTranslation.onTriggered: Printer.resetAllTranslation()
  492. resetAll.onTriggered: Printer.resetAll()
  493. reloadAll.onTriggered: Printer.reloadAll()
  494. addMachine.onTriggered: addMachineWizard.visible = true;
  495. addProfile.onTriggered: { UM.MachineManager.createProfile(); preferences.visible = true; preferences.setPage(4); }
  496. preferences.onTriggered: { preferences.visible = true; preferences.setPage(0); }
  497. configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(3); }
  498. manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
  499. documentation.onTriggered: CuraActions.openDocumentation();
  500. reportBug.onTriggered: CuraActions.openBugReportPage();
  501. showEngineLog.onTriggered: engineLog.visible = true;
  502. about.onTriggered: aboutDialog.visible = true;
  503. toggleFullScreen.onTriggered: base.toggleFullscreen()
  504. }
  505. Menu
  506. {
  507. id: objectContextMenu;
  508. property variant objectId: -1;
  509. MenuItem { action: actions.centerObject; }
  510. MenuItem { action: actions.deleteObject; }
  511. MenuItem { action: actions.multiplyObject; }
  512. MenuSeparator { }
  513. MenuItem { action: actions.deleteAll; }
  514. MenuItem { action: actions.reloadAll; }
  515. MenuItem { action: actions.resetAllTranslation; }
  516. MenuItem { action: actions.resetAll; }
  517. MenuItem { action: actions.groupObjects;}
  518. MenuItem { action: actions.mergeObjects;}
  519. MenuItem { action: actions.unGroupObjects;}
  520. }
  521. Menu
  522. {
  523. id: contextMenu;
  524. MenuItem { action: actions.deleteAll; }
  525. MenuItem { action: actions.reloadAll; }
  526. MenuItem { action: actions.resetAllTranslation; }
  527. MenuItem { action: actions.resetAll; }
  528. MenuItem { action: actions.groupObjects;}
  529. MenuItem { action: actions.mergeObjects;}
  530. MenuItem { action: actions.unGroupObjects;}
  531. }
  532. Connections
  533. {
  534. target: UM.Controller
  535. onContextMenuRequested:
  536. {
  537. if(objectId == 0)
  538. {
  539. contextMenu.popup();
  540. } else
  541. {
  542. objectContextMenu.objectId = objectId;
  543. objectContextMenu.popup();
  544. }
  545. }
  546. }
  547. FileDialog
  548. {
  549. id: openDialog;
  550. //: File open dialog title
  551. title: catalog.i18nc("@title:window","Open file")
  552. modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
  553. //TODO: Support multiple file selection, workaround bug in KDE file dialog
  554. //selectMultiple: true
  555. nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
  556. onAccepted:
  557. {
  558. //Because several implementations of the file dialog only update the folder
  559. //when it is explicitly set.
  560. var f = folder;
  561. folder = f;
  562. UM.MeshFileHandler.readLocalFile(fileUrl)
  563. var meshName = backgroundItem.getMeshName(fileUrl.toString())
  564. backgroundItem.hasMesh(meshName)
  565. }
  566. }
  567. EngineLog
  568. {
  569. id: engineLog;
  570. }
  571. AddMachineWizard
  572. {
  573. id: addMachineWizard
  574. }
  575. AboutDialog
  576. {
  577. id: aboutDialog
  578. }
  579. Connections
  580. {
  581. target: Printer
  582. onRequestAddPrinter:
  583. {
  584. addMachineWizard.visible = true
  585. addMachineWizard.firstRun = false
  586. }
  587. }
  588. Component.onCompleted:
  589. {
  590. UM.Theme.load(UM.Resources.getPath(UM.Resources.Themes, "cura"))
  591. }
  592. Timer
  593. {
  594. id: startupTimer;
  595. interval: 100;
  596. repeat: false;
  597. running: true;
  598. onTriggered:
  599. {
  600. if(!base.visible)
  601. {
  602. base.visible = true;
  603. restart();
  604. }
  605. else if(UM.MachineManager.activeMachineInstance == "")
  606. {
  607. addMachineWizard.firstRun = true;
  608. addMachineWizard.open();
  609. }
  610. }
  611. }
  612. }