diff --git a/buttleofx/MainWindow.qml b/buttleofx/MainWindow.qml index df988b6d..028b10e7 100644 --- a/buttleofx/MainWindow.qml +++ b/buttleofx/MainWindow.qml @@ -1,10 +1,10 @@ -import QtQuick 2.0 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 import QtQml 2.1 +import QtQuick 2.0 import QuickMamba 1.0 -import QtQuick.Dialogs 1.1 import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 import QtQuick.LocalStorage 2.0 import "gui/graph/qml" @@ -13,6 +13,7 @@ import "gui/paramEditor/qml" import "gui/browser/qml" import "gui/plugin/qml" import "gui/shortcut/qml" +import "gui/dialogs" ApplicationWindow { property var settingsDatabase: getInitializedDatabase() @@ -69,20 +70,18 @@ ApplicationWindow { width: 1200 height: 800 id: mainWindowQML - title:"ButtleOFX" + title: "ButtleOFX" // TopFocusHandler { // anchors.fill: parent // } Keys.onPressed: { - // Viewer if ((event.key == Qt.Key_1) && (event.modifiers & Qt.KeypadModifier)) { player.changeViewer(1) } if ((event.key == Qt.Key_2) && (event.modifiers & Qt.KeypadModifier)) { - player.changeViewer(2) } if ((event.key == Qt.Key_3) && (event.modifiers & Qt.KeypadModifier)) { @@ -117,15 +116,15 @@ ApplicationWindow { } } - property bool aNodeIsSelected:true + property bool aNodeIsSelected: true // Window of hint for plugins PluginWindow { id: doc title: "Plugin's Documentation" - selectedNodeLabel: _buttleData.currentSelectedNodeWrappers.count!=0 ? _buttleData.currentSelectedNodeWrappers.get(0).name : "" - selectedNodeDoc: _buttleData.currentSelectedNodeWrappers.count!=0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginDoc : "" - selectedNodeGroup: _buttleData.currentSelectedNodeWrappers.count!=0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginGroup : "" + selectedNodeLabel: _buttleData.currentSelectedNodeWrappers.count != 0 ? _buttleData.currentSelectedNodeWrappers.get(0).name : "" + selectedNodeDoc: _buttleData.currentSelectedNodeWrappers.count != 0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginDoc : "" + selectedNodeGroup: _buttleData.currentSelectedNodeWrappers.count != 0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginGroup : "" } // Window of shortcuts @@ -134,103 +133,102 @@ ApplicationWindow { title: "Shortcuts" } - FileDialog { + FileViewerDialog { id: finderLoadGraph + visible: false title: "Open a graph" - nameFilters: [ "All files (*)" ] - selectedNameFilter: "All files (*)" + buttonText: "Open" + folderModelFolder: _buttleData.homeDir - onAccepted: { - if (finderLoadGraph.fileUrl) { - _buttleData.loadData(finderLoadGraph.fileUrl) + onButtonClicked: { + if (finderLoadGraph.entryBarText != "") { + _buttleData.newData() + _buttleData.loadData(currentFile) + finderLoadGraph.visible = false } } } - FileDialog { + FileViewerDialog { id: finderSaveGraph + visible: false title: "Save the graph" - nameFilters: [ "All files (*)" ] - selectedNameFilter: "All files (*)" + buttonText: "Save" + folderModelFolder: _buttleData.homeDir - onAccepted: { - if (finderSaveGraph.fileUrl) { - _buttleData.saveData(finderSaveGraph.fileUrl) - } + // Acceptable values are the verb parts of the callers ID's, i.e. 'open', + // 'new', and 'close' + property string action + + // This initializer function takes in the action being done by the user so we know + // what to do when called. + function show(doAction) { + action = doAction + finderSaveGraph.visible = true } - selectExisting: false + onButtonClicked: { + if (finderSaveGraph.entryBarText != "") { + _buttleData.urlOfFileToSave = currentFile + _buttleData.saveData(_buttleData.urlOfFileToSave) + + finderSaveGraph.visible = false + + if (action == "open") { + finderLoadGraph.visible = true + } else if (action == "new") { + _buttleData.newData() + } else if (action == "close") { + Qt.quit() + } + } + } } - MessageDialog { + ExitDialog { id: openGraph - title:"Save the graph?" - icon: StandardIcon.Warning - modality: Qt.WindowStaysOnTopHint && Qt.WindowModal - text: urlOfFileToSave == "" ? "Save graph changes before closing ?" : "Save " + _buttleData.getFileName(urlOfFileToSave) + " changes before closing ?" - detailedText: "If you don't save the graph, unsaved modifications will be lost. " - standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Abort - Component.onCompleted: visible = false - - onYes: { - if(urlOfFileToSave!="") { + visible: false + dialogText: "Do you want to save before closing this file?
If you don't, all unsaved changes will be lost" + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) - } else{ - finderSaveGraph.open() + } else { + finderSaveGraph.show("open") } } - onNo: { - finderLoadGraph.open() + onDiscardButtonClicked: { + finderLoadGraph.visible = true } - onRejected: {} } - MessageDialog { + ExitDialog { id: newGraph - title: "Save the graph?" - icon: StandardIcon.Warning - modality: Qt.WindowStaysOnTopHint && Qt.WindowModal - text: urlOfFileToSave == "" ? "Save graph changes before closing ?" : "Save " + _buttleData.getFileName(urlOfFileToSave) + " changes before closing ?" - detailedText: "If you don't save the graph, unsaved modifications will be lost. " - standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Abort - Component.onCompleted: visible = false - - onYes: { - if (urlOfFileToSave!="") { + visible: false + dialogText: "Do you want to save before closing this file?
If you don't, all unsaved changes will be lost" + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) - _buttleData.newData() } else { - finderSaveGraph.open() - _buttleData.newData() + finderSaveGraph.show("new") } } - onNo: { - _buttleData.newData() - } + onDiscardButtonClicked: _buttleData.newData() } - MessageDialog { + ExitDialog { id: closeButtle - title: "Save the graph?" - icon: StandardIcon.Warning - modality: Qt.WindowStaysOnTopHint && Qt.WindowModal - text: urlOfFileToSave == "" ? "Save graph changes before closing ?" : "Save " + _buttleData.getFileName(urlOfFileToSave) + " changes before closing ?" - detailedText: "If you don't save the graph, unsaved modifications will be lost. " - standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Abort - Component.onCompleted: visible = false - - onYes: { - if(urlOfFileToSave!="") { + visible: false + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) } else { - finderSaveGraph.open() - finderSaveGraph.close() - finderSaveGraph.open() + finderSaveGraph.show("close") } } - onNo: { - Qt.quit() - } + onDiscardButtonClicked: Qt.quit() } menuBar: MenuBar { @@ -245,7 +243,7 @@ ApplicationWindow { if (!_buttleData.graphCanBeSaved) { _buttleData.newData() } else { - newGraph.open() + newGraph.visible = true } } } @@ -256,11 +254,9 @@ ApplicationWindow { onTriggered: { if (!_buttleData.graphCanBeSaved) { - finderLoadGraph.open() + finderLoadGraph.visible = true } else { - openGraph.open() - openGraph.close() - openGraph.open() + openGraph.visible = true } } } @@ -275,7 +271,7 @@ ApplicationWindow { MenuItem { text: "Save As" shortcut: "Ctrl+Shift+S" - onTriggered: finderSaveGraph.open() + onTriggered: finderSaveGraph.visible = true } MenuSeparator { } @@ -288,7 +284,7 @@ ApplicationWindow { if (!_buttleData.graphCanBeSaved) { Qt.quit() } else { - closeButtle.open() + closeButtle.visible = true } } } @@ -301,7 +297,7 @@ ApplicationWindow { id: undoRedoStack title: "Undo/Redo stack" - property variant undoRedoList:_buttleData.graphCanBeSaved ? _buttleManager.undoRedoStack:_buttleManager.undoRedoStack + property variant undoRedoList: _buttleData.graphCanBeSaved ? _buttleManager.undoRedoStack : _buttleManager.undoRedoStack Instantiator { model: undoRedoStack.undoRedoList @@ -412,10 +408,11 @@ ApplicationWindow { title: "Nodes" Instantiator { - model: _buttleData.getMenu(1,"") + model: _buttleData.getMenu(1, "") + Menu { id: firstMenu - title:object + title: object __parentContentItem: nodesMenu.__contentItem // To remove warning Instantiator { @@ -445,11 +442,11 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(2,firstMenu.title) + model: _buttleData.getMenu(2, firstMenu.title) Menu { id: secondMenu - title:object + title: object __parentContentItem: nodesMenu.__contentItem // To remove warning Instantiator { @@ -479,11 +476,11 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(3,secondMenu.title) + model: _buttleData.getMenu(3, secondMenu.title) Menu { id: thirdMenu - title:object + title: object __parentContentItem: nodesMenu.__contentItem // To remove warning Instantiator { @@ -513,10 +510,10 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(4,thirdMenu.title) + model: _buttleData.getMenu(4, thirdMenu.title) Menu { - id:fourthMenu + id: fourthMenu title: object __parentContentItem: nodesMenu.__contentItem // To remove warning @@ -547,7 +544,7 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(5,fourthMenu.title) + model: _buttleData.getMenu(5, fourthMenu.title) Menu { id: fifthMenu @@ -620,7 +617,6 @@ ApplicationWindow { } } - Menu { title: "View" @@ -635,7 +631,7 @@ ApplicationWindow { browserView.checked = false advancedView.checked = false selectedView = 1 - saveSetting("view",selectedView) + saveSetting("view", selectedView) lastSelectedDefaultView = view1 topLeftView.visible = true bottomLeftView.visible = true @@ -656,7 +652,7 @@ ApplicationWindow { defaultView.checked = false advancedView.checked = false selectedView = 2 - saveSetting("view",selectedView) + saveSetting("view", selectedView) lastSelectedDefaultView = view2 topLeftView.visible = true bottomLeftView.visible = true @@ -677,9 +673,9 @@ ApplicationWindow { defaultView.checked = false browserView.checked = false selectedView = 3 - saveSetting("view",selectedView) + saveSetting("view", selectedView) lastSelectedDefaultView = view3 - topLeftView.visible=true + topLeftView.visible = true bottomLeftView.visible = true topRightView.visible = true bottomRightView.visible = false @@ -693,29 +689,41 @@ ApplicationWindow { MenuItem { text: "Browser" checkable: true - checked: browser.parent.visible==true ? true : false - onTriggered: browser.parent.visible == false ? browser.parent.visible=true : browser.parent.visible=false + checked: browser.parent.visible + + onTriggered: { + browser.parent.visible = !browser.parent.visible + } } MenuItem { text: "Viewer" checkable: true - checked: player.parent.visible==true ? true : false - onTriggered: player.parent.visible == false ? player.parent.visible=true : player.parent.visible=false + checked: player.parent.visible + + onTriggered: { + player.parent.visible = !player.parent.visible + } } MenuItem { text: "Graph" checkable: true - checked: graphEditor.parent.visible==true ? true : false - onTriggered: graphEditor.parent.visible == false ? graphEditor.parent.visible=true : graphEditor.parent.visible=false + checked: graphEditor.parent.visible + + onTriggered: { + graphEditor.parent.visible = !graphEditor.parent.visible + } } MenuItem { text: "Parameters" checkable: true - checked: paramEditor.parent.visible==true ? true : false - onTriggered: paramEditor.parent.visible == false ? paramEditor.parent.visible=true : paramEditor.parent.visible=false + checked: paramEditor.parent.visible + + onTriggered: { + paramEditor.parent.visible = !paramEditor.parent.visible + } } */ } @@ -732,7 +740,6 @@ ApplicationWindow { } */ - // This rectangle represents the zone under the menu, it allows to define the anchors.fill and margins for the SplitterRow Rectangle { id: modulsContainer @@ -796,7 +803,7 @@ ApplicationWindow { view2[1] break case 3: - if(advancedParamEditor.displayGraph) + if (advancedParamEditor.displayGraph) view3[3] else view3[1] @@ -850,7 +857,7 @@ ApplicationWindow { implicitWidth: parent.width implicitHeight: topRightView.visible ? 0.5 * parent.height : parent.height z: -1 - visible: selectedView ==3 ? false : true + visible: selectedView != 3 children: switch (selectedView) { @@ -876,7 +883,7 @@ ApplicationWindow { id: subviews visible: false - property variant parentBeforeFullscreen : null + property variant parentBeforeFullscreen: null Player { id: player @@ -893,7 +900,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = player @@ -905,8 +912,8 @@ ApplicationWindow { anchors.fill: parent onButtonCloseClicked: { - if (parent!=fullscreenContent) { - selectedView=-1 + if (parent != fullscreenContent) { + selectedView = -1 parent.visible = false } else { fullscreenWindow.visibility = Window.Hidden @@ -914,7 +921,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = graphEditor @@ -928,7 +935,7 @@ ApplicationWindow { currentParamNode: _buttleData.currentParamNodeWrapper ? _buttleData.currentParamNodeWrapper : null onButtonCloseClicked: { - if (parent!=fullscreenContent) { + if (parent != fullscreenContent) { selectedView =- 1 parent.visible = false } else { @@ -937,7 +944,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = paramEditor @@ -958,7 +965,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = advancedParamEditor @@ -979,7 +986,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = browser diff --git a/buttleofx/data/buttleData.py b/buttleofx/data/buttleData.py index 1cb7af8d..43b68acc 100644 --- a/buttleofx/data/buttleData.py +++ b/buttleofx/data/buttleData.py @@ -524,9 +524,7 @@ def loadData(self, url='buttleofx/backup/data.bofx'): """ Loads all data from a Json file (the default Json file if no url is given) """ - filepath = QtCore.QUrl(url).toLocalFile() - self.newData() with open(filepath, 'r') as f: @@ -649,11 +647,11 @@ def saveData(self, url): """ Saves all data in a json file """ + # If called from Python, it could be a str or a QUrl if isinstance(url, str): - # If called from Python, it could be a str or a QUrl. - filepath = QtCore.QUrl.fromLocalFile(url).toLocalFile() + filepath = url else: - filepath = QtCore.QUrl(url).toLocalFile() + filepath = url.toLocalFile() if not filepath.lower().endswith(".bofx"): filepath = filepath + ".bofx" @@ -739,6 +737,9 @@ def zoom(self, width, height, nodeWidth, zoomCoeff, graphPreviousWidth, graphPre def getButtlePath(self): return self._buttlePath + def getHomeDir(self): + return os.path.expanduser("~") + def getCurrentConnectionWrapper(self): """ Returns the current currentConnectionWrapper. @@ -1039,6 +1040,7 @@ def graphCanBeSaved(self): # filePath buttlePath = QtCore.pyqtProperty(str, getButtlePath, constant=True) + homeDir = QtCore.pyqtProperty(str, getHomeDir, constant=True) # Current param, view, and selected node currentParamNodeChanged = QtCore.pyqtSignal() diff --git a/buttleofx/gui/dialogs/ExitDialog.qml b/buttleofx/gui/dialogs/ExitDialog.qml new file mode 100644 index 00000000..9f8e9aa3 --- /dev/null +++ b/buttleofx/gui/dialogs/ExitDialog.qml @@ -0,0 +1,90 @@ +import QtQuick 2.1 +import QtQuick.Window 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + +Window { + id: exitDialog + width: 425 + height: 100 + title: "Save Changes?" + color: "#141414" + flags: Qt.Dialog + + property string dialogText: "Do you want to save before exiting?
If you don't, all unsaved changes will be lost." + + signal saveButtonClicked + signal discardButtonClicked + + Component { + id: buttonStyle + + ButtonStyle { + background: Rectangle { + radius: 6 + implicitWidth: 100 + implicitHeight: 25 + + border.color: control.hovered ? "#00B2A1" : "#9F9C99" + border.width: control.hovered ? 3 : 2 + + gradient: Gradient { + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + GradientStop { position: .5; color: control.pressed ? "#D9D9D9" : "#EFEBE7" } + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + } + } + } + } + + ColumnLayout { + anchors.centerIn: parent + spacing: 15 + + RowLayout { + spacing: 20 + + Image { source: "../img/icons/logo_icon.png" } + + Text { + text: dialogText + color: "#FEFEFE" + } + } + + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + spacing: 6 + + Button { + id: saveButton + text: "Save" + style: buttonStyle + + onClicked: { + exitDialog.saveButtonClicked() + exitDialog.visible = false + } + } + + Button { + id: discardButton + text: "Discard" + style: buttonStyle + + onClicked: { + exitDialog.discardButtonClicked() + exitDialog.visible = false + } + } + + Button { + id: abortButton + text: "Abort" + style: buttonStyle + onClicked: exitDialog.visible = false + } + } + } +} diff --git a/buttleofx/gui/dialogs/FileViewerDialog.qml b/buttleofx/gui/dialogs/FileViewerDialog.qml new file mode 100644 index 00000000..0f1088b1 --- /dev/null +++ b/buttleofx/gui/dialogs/FileViewerDialog.qml @@ -0,0 +1,206 @@ +import QtQuick 2.1 +import QtQuick.Window 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import Qt.labs.folderlistmodel 2.1 + +Window { + id: fileViewerWindow + width: 630 + height: 380 + color: "#141414" + flags: Qt.Dialog + + property string buttonText + property string folderModelFolder + property string entryBarText: entryBar.text + + signal buttonClicked(string currentFile) + + FolderListModel { + id: folderModel + showDirsFirst: true + folder: folderModelFolder + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + + RowLayout { + id: headerBar + anchors.top: parent.top + anchors.leftMargin: parent.spacing + anchors.rightMargin: parent.spacing + + Button { + id: parentFolderButton + width: 15 + height: 15 + + iconSource: + if (hovered) { + "../img/buttons/browser/parent_hover.png" + } else { + "../img/buttons/browser/parent.png" + } + + style: + ButtonStyle { + background: Rectangle { + anchors.fill: parent + color: "transparent" + } + } + + onClicked: { + folderModel.folder = folderModel.parentFolder + } + } + + Rectangle { + Layout.fillWidth: true + height: 24 + color: "black" + radius: 5 + border.color: "grey" + + TextInput { + id: urlBar + x: 5 + y: 4 + + text: folderModel.folder.toString().substring(7) + readOnly: true + selectByMouse: true + Layout.fillWidth: true + + color: "white" + selectionColor: "#00b2a1" + } + } + } + + ScrollView { + anchors.top: headerBar.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: bottomRow.top + anchors.bottomMargin: 4 + + GridView { + id: folderView + model: folderModel + cellWidth: 100 + cellHeight: 100 + highlightFollowsCurrentItem: false + + highlight: Rectangle { + width: folderView.cellWidth + height: folderView.cellHeight + color: "#00b2a1" + radius: 4 + + x: folderView.currentItem.x + y: folderView.currentItem.y + Behavior on x { SmoothedAnimation { duration: -1; velocity: -1 } } + Behavior on y { SmoothedAnimation { duration: -1; velocity: -1 } } + } + + delegate: Rectangle { + width: folderView.cellWidth + height: folderView.cellHeight + color: "transparent" + + Column { + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + Image { + anchors.horizontalCenter: parent.horizontalCenter + width: 55 + height: 55 + asynchronous: true + fillMode: Image.PreserveAspectFit + sourceSize.width: width + sourceSize.height: height + property variant supportedFormats: ["bmp", "gif", "jpg", "jpeg", "png", "pbm", "pgm", "ppm", "xbm", "xpm"] + + source: { + if (folderModel.isFolder(index)) { + "../img/buttons/browser/folder-icon.png" + } else if (supportedFormats.indexOf(folderModel.get(index, "fileSuffix").toLowerCase()) != -1) { + folderModel.get(index, "filePath") + } else { + "../img/buttons/browser/file-icon.png" + } + } + } + + Text { + text: fileName + color: "white" + width: folderView.cellWidth - 10 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAnywhere + } + } + + MouseArea { + anchors.fill: parent + + onClicked: { + folderView.currentIndex = index + if (!folderModel.isFolder(index)) { + entryBar.text = folderModel.get(index, "fileName") + } else { + entryBar.text = "" + } + } + onDoubleClicked: { + if (folderModel.isFolder(index)) { + folderModel.folder = folderModel.get(index, "filePath") + } + } + } + } + } + } + + RowLayout { + id: bottomRow + Layout.fillWidth: true + Layout.fillHeight: true + anchors.bottom: parent.bottom + + TextField { + id: entryBar + Layout.fillWidth: true + } + + Button { + text: buttonText + + style: + ButtonStyle { + background: Rectangle { + radius: 6 + implicitWidth: 100 + implicitHeight: 25 + + border.color: control.hovered ? "#00B2A1" : "#9F9C99" + border.width: control.hovered ? 3 : 2 + + gradient: Gradient { + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + GradientStop { position: .5; color: control.pressed ? "#D9D9D9" : "#EFEBE7" } + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + } + } + } + onClicked: fileViewerWindow.buttonClicked(folderModel.folder + "/" + entryBarText) + } + } + } +} diff --git a/buttleofx/gui/graph/qml/FinderLoadGraph.qml b/buttleofx/gui/graph/qml/FinderLoadGraph.qml deleted file mode 100644 index 5462f2f6..00000000 --- a/buttleofx/gui/graph/qml/FinderLoadGraph.qml +++ /dev/null @@ -1,18 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Dialogs 1.0 - -FileDialog { - signal getFileUrl(string fileurl) - - id: finderLoadGraph - title: "Open a graph" - folder: _buttleData.buttlePath - nameFilters: ["ButtleOFX Graph files (*.bofx)", "All files (*)"] - selectedNameFilter: "All files (*)" - - onAccepted: { - console.log(finderLoadGraph.fileUrl) - _buttleData.loadData(finderLoadGraph.fileUrl) - getFileUrl(finderLoadGraph.fileUrl) - } -} diff --git a/buttleofx/gui/graph/qml/FinderSaveGraph.qml b/buttleofx/gui/graph/qml/FinderSaveGraph.qml deleted file mode 100644 index 34a964f7..00000000 --- a/buttleofx/gui/graph/qml/FinderSaveGraph.qml +++ /dev/null @@ -1,19 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Dialogs 1.0 - -FileDialog { - signal getFileUrl(string fileurl) - - id: finderSaveGraph - title: "Save the graph" - folder: _buttleData.buttlePath - nameFilters: ["ButtleOFX Graph files (*.bofx)", "All files (*)"] - selectedNameFilter: "All files (*)" - - onAccepted: { - _buttleData.saveData(finderSaveGraph.fileUrl) - getFileUrl(finderSaveGraph.fileUrl) - } - - selectExisting: false -} diff --git a/buttleofx/gui/graph/qml/Tools.qml b/buttleofx/gui/graph/qml/Tools.qml index 857a4c63..2b541b6d 100644 --- a/buttleofx/gui/graph/qml/Tools.qml +++ b/buttleofx/gui/graph/qml/Tools.qml @@ -1,7 +1,7 @@ import QtQuick 2.0 -import QtQuick.Dialogs 1.0 import "../../plugin/qml" +import "../../dialogs" Rectangle { id: tools @@ -13,6 +13,72 @@ Rectangle { signal clickCreationNode(string nodeType) + FileViewerDialog { + id: finderLoadGraph + visible: false + title: "Open a graph" + buttonText: "Open" + folderModelFolder: _buttleData.homeDir + + onButtonClicked: { + if (finderLoadGraph.entryBarText != "") { + _buttleData.newData() + _buttleData.loadData(currentFile) + finderLoadGraph.visible = false + } + } + } + + FileViewerDialog { + id: finderSaveGraph + visible: false + title: "Save the graph" + buttonText: "Save" + folderModelFolder: _buttleData.homeDir + + // Acceptable values are the verb parts of the callers ID's, i.e. 'open' + // and 'save' (in which case we do no additional work). + property string action + + // This initializer function takes in the action being done by the user so we know + // what to do when called. + function show(doAction) { + action = doAction + finderSaveGraph.visible = true + } + + onButtonClicked: { + if (finderSaveGraph.entryBarText != "") { + _buttleData.urlOfFileToSave = currentFile + _buttleData.saveData(_buttleData.urlOfFileToSave) + + finderSaveGraph.visible = false + + if (action == "open") { + finderLoadGraph.visible = true + } + } + } + } + + ExitDialog { + id: openGraph + visible: false + dialogText: "Do you want to save before closing this file?
If you don't, all unsaved changes will be lost" + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { + _buttleData.saveData(urlOfFileToSave) + finderLoadGraph.visible = true + } else { + finderSaveGraph.show("open") + } + } + onDiscardButtonClicked: { + finderLoadGraph.visible = true + } + } + gradient: Gradient { GradientStop { position: 0.0; color: gradian2 } GradientStop { position: 0.85; color: gradian2 } @@ -39,13 +105,13 @@ Rectangle { locked: false onClicked: { - if (pluginVisible==true){ - pluginVisible=false + if (pluginVisible == true){ + pluginVisible = false } else { - pluginVisible=true + pluginVisible = true } - editNode=false + editNode = false } } @@ -62,11 +128,9 @@ Rectangle { editNode = false if (!_buttleData.graphCanBeSaved) { - finderLoadGraph.open() + finderLoadGraph.visible = true } else { - openGraph.open() - openGraph.close() - openGraph.open() + openGraph.visible = true } } } @@ -82,10 +146,11 @@ Rectangle { onClicked: { pluginVisible = false editNode = false + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) } else { - finderSaveGraph.open() + finderSaveGraph.show("save") } } } diff --git a/buttleofx/main.py b/buttleofx/main.py index 3275d763..c8d81dec 100644 --- a/buttleofx/main.py +++ b/buttleofx/main.py @@ -74,51 +74,57 @@ class EventFilter(QtCore.QObject): - def eventFilter(self, receiver, event): - buttleData = ButtleDataSingleton().get() - browser = FileModelBrowserSingleton().get() + def __init__(self, app, engine): + self.mainApp = app + self.mainEngine = engine + self.buttleData = ButtleDataSingleton().get() + super(EventFilter, self).__init__() + + def onSaveDialogButtonClicked(self, fileToSave): + self.buttleData.urlOfFileToSave = fileToSave + self.buttleData.saveData(QtCore.QUrl(self.buttleData.urlOfFileToSave)) + QtCore.QCoreApplication.quit() + + def onExitDialogDiscardButtonClicked(self): + QtCore.QCoreApplication.quit() + + def onExitDialogSaveButtonClicked(self): + if self.buttleData.urlOfFileToSave: + self.buttleData.saveData(self.buttleData.urlOfFileToSave) + QtCore.QCoreApplication.quit() + else: + saveDialogComponent = QtQml.QQmlComponent(self.mainEngine) + saveDialogComponent.loadUrl(QtCore.QUrl("ButtleOFX/buttleofx/gui/dialogs/FileViewerDialog.qml")) + + saveDialog = saveDialogComponent.create() + QtQml.QQmlProperty.write(saveDialog, "title", "Save the graph") + QtQml.QQmlProperty.write(saveDialog, "buttonText", "Save") + QtQml.QQmlProperty.write(saveDialog, "folderModelFolder", self.buttleData.getHomeDir()) + + saveDialog.buttonClicked.connect(self.onSaveDialogButtonClicked) + saveDialog.show() + def eventFilter(self, receiver, event): if event.type() == QtCore.QEvent.KeyPress: - # If alt f4 event ignored + # If Alt F4 event ignored if event.modifiers() == QtCore.Qt.AltModifier and event.key() == QtCore.Qt.Key_F4: event.ignore() if event.type() != QtCore.QEvent.Close: return super(EventFilter, self).eventFilter(receiver, event) if not isinstance(receiver, QtQuick.QQuickWindow) or not receiver.title() == "ButtleOFX": return False - if not buttleData.graphCanBeSaved: + if not self.buttleData.graphCanBeSaved: return False - msgBox = QtWidgets.QMessageBox() - msgBox.setText("Save graph changes before closing ?") - msgBox.setModal(True) - msgBox.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) - msgBox.setInformativeText("If you don't save the graph, unsaved modifications will be lost.") - msgBox.setStandardButtons( - QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard | QtWidgets.QMessageBox.Abort) - msgBox.setDefaultButton(QtWidgets.QMessageBox.Save) - ret = msgBox.exec_() - - if ret == QtWidgets.QMessageBox.Save: - if buttleData.urlOfFileToSave: - # Save on the already existing file - buttleData.saveData(buttleData.urlOfFileToSave) - # Close the application - return super(EventFilter, self).eventFilter(receiver, event) - - # This project has never been saved, so ask the user on which file to save. - dialog = QtWidgets.QFileDialog() - fileToSave = dialog.getSaveFileName(None, "Save the graph", browser.getFirstFolder())[0] - if not (fileToSave.endswith(".bofx")): - fileToSave += ".bofx" - buttleData.urlOfFileToSave = fileToSave - buttleData.saveData(fileToSave) - # Close the application - return super(EventFilter, self).eventFilter(receiver, event) + exitDialogComponent = QtQml.QQmlComponent(self.mainEngine) + # Note that we give the path relative to run_buttleofx.sh, because that becomes the PWD when this is run. + # We also do this for the saveDialogComponent in self.onExitDialogSaveButtonClicked(). + exitDialogComponent.loadUrl(QtCore.QUrl("ButtleOFX/buttleofx/gui/dialogs/ExitDialog.qml")) - if ret == QtWidgets.QMessageBox.Discard: - # Close the application - return super(EventFilter, self).eventFilter(receiver, event) + exitDialog = exitDialogComponent.create() + exitDialog.saveButtonClicked.connect(self.onExitDialogSaveButtonClicked) + exitDialog.discardButtonClicked.connect(self.onExitDialogDiscardButtonClicked) + exitDialog.show() # Don't call the parent class, so we don't close the application return True @@ -288,7 +294,7 @@ def main(argv, app): print("Watch directory:", parentDir) qic.addFilesFromDirectory(parentDir, recursive=True) - aFilter = EventFilter() + aFilter = EventFilter(app, engine) app.installEventFilter(aFilter) topLevelItem.show()