Cura.qml 22 KB

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