Add save+open to notebook, allow multiple windows, add translations, add welcome window
diff --git a/ide/qml/NbWindow.qml b/ide/qml/NbWindow.qml
new file mode 100644
index 0000000..5710c9e
--- /dev/null
+++ b/ide/qml/NbWindow.qml
@@ -0,0 +1,213 @@
+import QtQuick 2.5
+import QtQuick.Controls 2.15
+import QtQuick.Controls.Material 2.0
+import QtQuick.Layouts 1.3
+
+import sh.swisschili.REFAL 1.0
+
+ApplicationWindow {
+ id: root
+ width: 800
+ height: 800
+ title: "Refal Notebook — " + notebook.savePath
+ visible: true
+
+ Material.theme: Material.Light
+ Material.accent: Material.Orange
+
+ minimumWidth: column.implicitWidth
+
+ required property ApplicationWindow welcomeWindow
+
+ function openNotebook(path) {
+ notebook.open(path);
+ }
+
+ menuBar: MenuBar {
+ Menu {
+ title: qsTr("&File")
+
+ Action {
+ text: qsTr("&New")
+
+ onTriggered: {
+ welcomeWindow.openNotebook();
+ }
+ }
+
+ Action {
+ text: qsTr("&Save")
+ shortcut: "Ctrl+s"
+
+ onTriggered: {
+ notebook.save()
+ }
+ }
+
+ Action {
+ text: qsTr("&Open")
+ shortcut: "Ctrl+o"
+
+ onTriggered: {
+ notebook.open();
+ }
+ }
+ }
+
+ Menu {
+ title: qsTr("&View")
+
+ Action {
+ text: qsTr("&Welcome Window")
+ checkable: true
+
+ checked: welcomeWindow.visible
+
+ onTriggered: {
+ welcomeWindow.toggleVisible()
+ }
+ }
+
+ Action {
+ id: varInspector
+ text: qsTr("&Variable Inspector")
+
+ checkable: true
+ }
+ }
+
+ Menu {
+ title: qsTr("&Runtime")
+
+ Action {
+ text: qsTr("Run &Selected Cell")
+ shortcut: "Ctrl+Return"
+
+ onTriggered: {
+ if (codeEditor.currentItem !== null) {
+ notebook.runCell(codeEditor.currentItem.uuid)
+ }
+ }
+ }
+
+ Action {
+ text: qsTr("Run &All")
+ }
+
+ Action {
+ text: qsTr("&Reset Runtime State")
+ }
+ }
+ }
+
+ Notebook {
+ id: notebook
+
+ onSaveError: (message) =>
+ {
+ console.error(message)
+ }
+ }
+
+ ColumnLayout {
+ id: column
+ anchors.fill: parent
+
+ SplitView {
+ id: split
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ orientation: Qt.Horizontal
+
+ ListView {
+ id: codeEditor
+ SplitView.fillWidth: true
+ SplitView.minimumWidth: 400
+ model: notebook.cellModel
+ clip: true
+
+ spacing: 5
+
+ header: ColumnLayout {
+ width: codeEditor.width
+
+ Pane {
+ Layout.bottomMargin: 0
+
+ ColumnLayout {
+ Label {
+ font.pointSize: 18
+ text: qsTr("Notebook")
+ }
+
+ Label {
+ visible: codeEditor.count === 0
+
+ text: qsTr("Looks like you haven't created any cells yet. Click the + button below to create one.")
+ }
+ }
+ }
+
+ InsertRow {
+ onInsertClicked: notebook.cellModel.insertCellBefore(0)
+ }
+
+ Item {
+ height: 5 // JANK!
+ }
+ }
+
+ delegate: NotebookCell {
+ id: notebookCell
+
+ required property var model
+ required property var index
+ required property var uuid
+
+ width: codeEditor.width
+
+ code: model.code
+ result: model.result.trim()
+ status: model.status
+ resultType: model.resultType
+ cellActive: codeEditor.currentIndex === index
+
+ onCodeEditingFinished: code => model.code = code
+
+ onInsertBelowClicked: {
+ console.info(index);
+ notebook.cellModel.insertCellBefore(index + 1);
+ }
+
+ onRunClicked: {
+ notebook.runCell(uuid)
+ }
+
+ onCellFocused: {
+ codeEditor.currentIndex = index
+ }
+
+ onDeleteClicked: {
+ notebook.cellModel.deleteCellAt(index)
+ }
+
+ onCellUnfocused: {
+ codeEditor.currentIndex = -1
+ }
+ }
+ }
+
+ Item {
+ id: variables
+ SplitView.minimumWidth: 240
+
+ visible: varInspector.checked
+
+ Label {
+ anchors.centerIn: parent
+ text: qsTr("Variables")
+ }
+ }
+ }
+ }
+}