diff --git a/src_qt6/EasyReflectometryApp.pyproject b/src_qt6/EasyReflectometryApp.pyproject new file mode 100644 index 00000000..f9db2944 --- /dev/null +++ b/src_qt6/EasyReflectometryApp.pyproject @@ -0,0 +1,43 @@ +{ + "files": [ + "EasyReflectometryApp.qmlproject", + "EasyReflectometryApp/main.py", + "EasyReflectometryApp/main.qml", + "EasyReflectometryApp/Gui/qmldir", + "EasyReflectometryApp/Gui/ApplicationWindow.qml", + "EasyReflectometryApp/Gui/StatusBar.qml", + "EasyReflectometryApp/Gui/Globals/qmldir", + "EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml", + "EasyReflectometryApp/Gui/Globals/BackendProxy.qml", + "EasyReflectometryApp/Gui/Globals/References.qml", + "EasyReflectometryApp/Gui/Pages/Home/Content.qml", + "EasyReflectometryApp/Gui/Pages/Home/Popups/About.qml", + "EasyReflectometryApp/Gui/Pages/Project/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Project/MainAreaTabs/Description.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Basic/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Basic/Groups/Examples.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Basic/Groups/GetStarted.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Basic/Groups/Recent.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Basic/Popups/OpenCifFile.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Basic/Popups/ProjectDescription.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Extra/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Extra/Groups/Scrolling.qml", + "EasyReflectometryApp/Gui/Pages/Project/SidebarTabs/Text/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Report/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Report/MainAreaTabs/Summary.qml", + "EasyReflectometryApp/Gui/Pages/Report/SidebarTabs/Basic/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Report/SidebarTabs/Basic/Groups/Export.qml", + "EasyReflectometryApp/Gui/Pages/Report/SidebarTabs/Extra/Layout.qml", + "EasyReflectometryApp/Gui/Pages/Report/SidebarTabs/Extra/Groups/Empty.qml", + "EasyReflectometryApp/Logic/Mock/qmldir", + "EasyReflectometryApp/Logic/Mock/BackendProxy.qml", + "EasyReflectometryApp/Logic/Mock/Project.qml", + "EasyReflectometryApp/Logic/Mock/Report.qml", + "EasyReflectometryApp/Logic/Mock/Status.qml", + "EasyReflectometryApp/Logic/Py/backend_proxy.py", + "EasyReflectometryApp/Logic/Py/helpers.py", + "EasyReflectometryApp/Logic/Py/project.py", + "EasyReflectometryApp/Logic/Py/report.py", + "EasyReflectometryApp/Logic/Py/status.py" + ] +} diff --git a/src_qt6/EasyReflectometryApp.qmlproject b/src_qt6/EasyReflectometryApp.qmlproject new file mode 100644 index 00000000..a1b04936 --- /dev/null +++ b/src_qt6/EasyReflectometryApp.qmlproject @@ -0,0 +1,41 @@ +import QmlProject 1.1 + +Project { + mainFile: "EasyReflectometryApp/main.qml" + + // List of module and plugin directories passed to QML runtime + importPaths: [ + "EasyReflectometryApp", + "../../EasyApp/src", + ] + + // Include .qml files from specified directory and its subdirectories + QmlFiles { + directory: "EasyReflectometryApp" + } + QmlFiles { + directory: "../../EasyApp/src/EasyApp" + } + + // Include .js files from specified directory and its subdirectories + JavaScriptFiles { + directory: "EasyReflectometryApp" + } + JavaScriptFiles { + directory: "../../EasyApp/src/EasyApp" + } + + // Include Module Definition Files (qmldir), as well as .ts and .qrc + // from specified directory and its subdirectories + Files { + directory: "EasyReflectometryApp" + filter: "qmldir;*.ts;*.qrc;*.html" + recursive: true + } + Files { + directory: "../../EasyApp/src/EasyApp" + filter: "qmldir;*.ts;*.qrc;*.html" + recursive: true + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml new file mode 100644 index 00000000..99fa368e --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml @@ -0,0 +1,115 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui as Gui +import Gui.Globals as Globals + +EaComponents.ApplicationWindow { + + /////////////////// + // APPLICATION BAR + /////////////////// + + // Left group of application bar tool buttons + appBarLeftButtons: [ + + EaElements.ToolButton { + enabled: Globals.BackendProxy.project.created + highlighted: true + fontIcon: 'save' + ToolTip.text: qsTr('Save current state of the project') + onClicked: Globals.BackendProxy.project.save() + } + + ] + + // Right group of application bar tool buttons + appBarRightButtons: [ + + EaElements.ToolButton { + fontIcon: 'cog' + ToolTip.text: qsTr('Application preferences') + onClicked: EaGlobals.Vars.showAppPreferencesDialog = true + } + + ] + + // Central group of application bar page buttons (workflow tabs) + // Page buttons for the pages described below + appBarCentralTabs.contentData: [ + + // Home page + EaElements.AppBarTabButton { + id: homeButton + objectName: 'applicationWindow.appBarCentralTabs.homeButton' + fontIcon: 'home' + text: qsTr('Home') + ToolTip.text: qsTr('Home') + //Component.onCompleted: { + // Globals.References.applicationWindow.appBarCentralTabs.homeButton = homeButton + //} + }, + // Home page + + // Project page + EaElements.AppBarTabButton { + id: projectButton + enabled: false + fontIcon: 'archive' + text: qsTr('Project') + ToolTip.text: qsTr('Project description page') + Component.onCompleted: { + Globals.References.applicationWindow.appBarCentralTabs.projectButton = projectButton + } + }, + // Project page + + // Summary page + EaElements.AppBarTabButton { + id: summaryButton + enabled: false + fontIcon: 'clipboard-list' + text: qsTr('Summary') + ToolTip.text: qsTr('Summary of the work done') + Component.onCompleted: { + Globals.References.applicationWindow.appBarCentralTabs.summaryButton = summaryButton + } + } + // Summary page + ] + + ////////////////////////////////// + // APP PAGES (MAIN AREA + SIDEBAR) + ////////////////////////////////// + + // Pages for the tab buttons described above + contentArea: [ + Loader { source: 'Pages/Home/Content.qml' }, + Loader { source: 'Pages/Project/Layout.qml' }, + Loader { source: 'Pages/Report/Layout.qml' } + ] + + ///////////// + // STATUS BAR + ///////////// + + statusBar: Gui.StatusBar {} + + /////// + // MISC + /////// + + onClosing: Qt.quit() + + Component.onCompleted: console.debug(`Application window loaded ::: ${this}`) + Component.onDestruction: console.debug(`Application window destroyed ::: ${this}`) + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml new file mode 100644 index 00000000..39729643 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2024 EasyReflectometryApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyReflectometryApp project + +pragma Singleton + +import QtQuick + +QtObject { + + readonly property var about: { + 'name': 'EasyReflectometry', + 'namePrefix': 'Easy', + 'nameSuffix': 'Reflectometry', + 'namePrefixForLogo': 'easy', + 'nameSuffixForLogo': 'reflectometry', + 'homePageUrl': 'from ApplicationInfo.qml', + 'issuesUrl': 'from ApplicationInfo.qml', + 'licenseUrl': 'from ApplicationInfo.qml', + 'dependenciesUrl': 'from ApplicationInfo.qml', + 'version': 'from ApplicationInfo.qml', + 'icon': Qt.resolvedUrl('../Resources/Logos/App.svg'), + 'date': new Date().toISOString().slice(0,10), + 'developerYearsFrom': '2019', + 'developerYearsTo': '2024', + 'description': 'Making reflectometry data analysis and modelling easy.', + 'developerIcons': [ + { + 'url': 'https://ess.eu', + 'icon': Qt.resolvedUrl('../Resources/Logos/ESS.png'), + 'heightScale': 3.0 + } + ] + } + +} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendProxy.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendProxy.qml new file mode 100644 index 00000000..09ee509e --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendProxy.qml @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +pragma Singleton + +import QtQuick + +import Logic.Mock as MockLogic + + +// If the backend_proxy_py object is created in main.py and exposed to qml, it is used as +// realBackendProxyPy to access the necessary backend properties and methods. Otherwise, the mock +// proxy defined in MockLogic/BackendProxy.qml with hardcoded data is used. +// The assumption here is that the real backend proxy and the mock proxy have the same API. + +QtObject { + + /////////////// + // Backend proxy + /////////////// + + readonly property var mockBackendProxyQml: MockLogic.BackendProxy + + readonly property var realBackendProxyPy: typeof backend_proxy_py !== 'undefined' && + backend_proxy_py !== null ? + backend_proxy_py : + undefined + + // This property is used to access the backend proxy object from GUI components. + // Sets backendProxy to realBackendProxyPy if this property is defined, otherwise sets it to + // mockBackendProxyQml + readonly property var backendProxy: realBackendProxyPy ?? mockBackendProxyQml + + ///////////// + // Status bar + ///////////// + + readonly property var status: QtObject { + readonly property string project: backendProxy.status.project + readonly property string phaseCount: backendProxy.status.phaseCount + readonly property string experimentsCount: backendProxy.status.experimentsCount + readonly property string calculator: backendProxy.status.calculator + readonly property string minimizer: backendProxy.status.minimizer + readonly property string variables: backendProxy.status.variables + } + + /////////////// + // Project page + /////////////// + + readonly property var project: QtObject { + readonly property bool created: backendProxy.project.created + readonly property var info: backendProxy.project.info + readonly property var examples: backendProxy.project.examples + + function create() { backendProxy.project.create() } + function save() { backendProxy.project.save() } + } + + /////////////// + // Summary page + /////////////// + + readonly property var summary: QtObject { + readonly property bool created: backendProxy.report.created + readonly property string asHtml: backendProxy.report.asHtml + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml new file mode 100644 index 00000000..2ccace10 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +pragma Singleton + +import QtQuick + + +// Initialisation of the reference dictionary. It is filled in later, when the required object is +// created and its unique id is assigned and added here instead of 'null'. After that, any object +// whose id is stored here can be accessed from any other qml file. + +QtObject { + + // Populated in ApplicationWindows.qml + readonly property var applicationWindow: { + 'appBarCentralTabs': { + 'homeButton': null, + 'projectButton': null, + 'summaryButton': null, + } + } + + // Populated in Pages/... + readonly property var pages: { + 'project': { + 'sidebar': { + 'basic': { + 'popups': { + 'openCifFile': null + } + } + } + } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/qmldir b/src_qt6/EasyReflectometryApp/Gui/Globals/qmldir new file mode 100644 index 00000000..de4dd47a --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/qmldir @@ -0,0 +1,5 @@ +module Globals + +singleton ApplicationInfo ApplicationInfo.qml +singleton BackendProxy BackendProxy.qml +singleton References References.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Home/Content.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Home/Content.qml new file mode 100644 index 00000000..285eb923 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Home/Content.qml @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + + +Item { + + Column { + anchors.centerIn: parent + + // Application logo + Image { + id: appLogo + + source: Globals.ApplicationInfo.about.icon + anchors.horizontalCenter: parent.horizontalCenter + width: EaStyle.Sizes.fontPixelSize * 5 + fillMode: Image.PreserveAspectFit + antialiasing: true + } + // Application logo + + // Application name + Row { + id: appName + + property string fontFamily: EaStyle.Fonts.thirdFontFamily + property string fontPixelSize: EaStyle.Sizes.fontPixelSize * 4 + + anchors.horizontalCenter: parent.horizontalCenter + + EaElements.Label { + font.family: parent.fontFamily + font.pixelSize: parent.fontPixelSize + font.weight: Font.Light + text: Globals.ApplicationInfo.about.namePrefixForLogo + } + EaElements.Label { + font.family: parent.fontFamily + font.pixelSize: parent.fontPixelSize + font.weight: Font.DemiBold + text: Globals.ApplicationInfo.about.nameSuffixForLogo + } + } + // Application name + + // Application version + EaElements.Label { + id: appVersion + + anchors.horizontalCenter: parent.horizontalCenter + + text: { + return qsTr('Version') + ` ${Globals.ApplicationInfo.about.version} (${Globals.ApplicationInfo.about.date})` + } + } + // Application version + + // Vertical spacer + Item { width: 1; height: EaStyle.Sizes.fontPixelSize * 2.5 } + + // Start button + EaElements.SideBarButton { + id: startButton + + anchors.horizontalCenter: parent.horizontalCenter + + fontIcon: 'rocket' + text: qsTr('Start') + onClicked: { + console.debug(`Clicking '${text}' button ::: ${this}`) + Globals.References.applicationWindow.appBarCentralTabs.projectButton.enabled = true + Globals.References.applicationWindow.appBarCentralTabs.projectButton.toggle() + } + } + + // Vertical spacer + Item { width: 1; height: EaStyle.Sizes.fontPixelSize * 2.5 } + + // Links + Row { + id: links + + anchors.horizontalCenter: parent.horizontalCenter + spacing: EaStyle.Sizes.fontPixelSize * 3 + + // Left links + Column { + spacing: EaStyle.Sizes.fontPixelSize + + EaElements.Button { + text: qsTr('About %1'.arg(Globals.ApplicationInfo.about.name)) + onClicked: EaGlobals.Vars.showAppAboutDialog = true + Loader { source: 'Popups/About.qml' } + } + EaElements.Button { + text: qsTr('Online documentation') + onClicked: Qt.openUrlExternally('https://github.com/EasyScience/EasyApp') + } + EaElements.Button { + text: qsTr('Get in touch online') + onClicked: console.debug(`Button clicked: ${text}`) + } + } + // Left links + + // Right links + Column { + spacing: EaStyle.Sizes.fontPixelSize + + EaElements.Button { + text: qsTr('Tutorial') + ' 1: ' + qsTr('App interface') + onClicked: console.debug(`Button clicked: ${text}`) + } + EaElements.Button { + text: qsTr('Tutorial') + ' 3: ' + qsTr('Basic usage') + onClicked: console.debug(`Button clicked: ${text}`) + } + EaElements.Button { + text: qsTr('Tutorial') + ' 3: ' + qsTr('Advanced usage') + onClicked: console.debug(`Button clicked: ${text}`) + } + } + // Right links + } + // Links + } + + Component.onCompleted: console.debug(`Home page loaded ::: ${this}`) + Component.onDestruction: console.debug(`Home page destroyed ::: ${this}`) + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Home/Popups/About.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Home/Popups/About.qml new file mode 100644 index 00000000..11815fdd --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Home/Popups/About.qml @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.AboutDialog { + + visible: EaGlobals.Vars.showAppAboutDialog + onClosed: EaGlobals.Vars.showAppAboutDialog = false + + appIconPath: Globals.ApplicationInfo.about.icon + appUrl: Globals.ApplicationInfo.about.homePageUrl + + appPrefixName: Globals.ApplicationInfo.about.namePrefixForLogo + appSuffixName: Globals.ApplicationInfo.about.nameSuffixForLogo + appVersion: Globals.ApplicationInfo.about.version + appDate: Globals.ApplicationInfo.about.date + + eulaUrl: Globals.ApplicationInfo.about.licenseUrl + oslUrl: Globals.ApplicationInfo.about.dependenciesUrl + + description: Globals.ApplicationInfo.about.description + developerIcons: Globals.ApplicationInfo.about.developerIcons + developerYearsFrom: Globals.ApplicationInfo.about.developerYearsFrom + developerYearsTo: Globals.ApplicationInfo.about.developerYearsTo + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml new file mode 100644 index 00000000..b0483f97 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.ContentPage { + + defaultInfo: Globals.BackendProxy.project.created ? + '' : + qsTr('No project defined') + + mainView: EaComponents.MainContent { + tabs: [ + EaElements.TabButton { text: qsTr('Description') } + ] + + items: [ + Loader { source: 'MainArea/Description.qml' } + ] + } + + sideBar: EaComponents.SideBar { + tabs: [ + EaElements.TabButton { text: qsTr('Basic controls') }, + EaElements.TabButton { text: qsTr('Extra controls') }, + EaElements.TabButton { text: qsTr('Text mode controls'); enabled: false } + ] + + items: [ + Loader { source: 'Sidebar/Basic/Layout.qml' }, + Loader { source: 'Sidebar/Extra/Layout.qml' }, + Loader { source: 'Sidebar/Text/Layout.qml' } + ] + + continueButton.text: Globals.BackendProxy.project.created ? + qsTr('Continue') : + qsTr('Continue without project') + + continueButton.onClicked: { + console.debug(`Clicking '${continueButton.text}' button ::: ${this}`) + Globals.References.applicationWindow.appBarCentralTabs.summaryButton.enabled = true + Globals.References.applicationWindow.appBarCentralTabs.summaryButton.toggle() + } + } + + Component.onCompleted: console.debug(`Project page loaded ::: ${this}`) + Component.onDestruction: console.debug(`Project page destroyed ::: ${this}`) + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/MainArea/Description.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/MainArea/Description.qml new file mode 100644 index 00000000..d7ad4cfd --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/MainArea/Description.qml @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + + +Rectangle { + + readonly property int commonSpacing: EaStyle.Sizes.fontPixelSize * 1.5 + + color: EaStyle.Colors.mainContentBackground + + Column { + + anchors.top: parent.top + anchors.left: parent.left + + anchors.topMargin: commonSpacing + anchors.leftMargin: commonSpacing * 1.5 + + spacing: commonSpacing + + // Project title + EaElements.TextInput { + font.family: EaStyle.Fonts.secondFontFamily + font.pixelSize: EaStyle.Sizes.fontPixelSize * 3 + font.weight: Font.ExtraLight + text: Globals.BackendProxy.project.info.name + onEditingFinished: Globals.BackendProxy.project.editData('name', text) + } + // Project title + + // Project info + Grid { + columns: 2 + rowSpacing: 0 + columnSpacing: commonSpacing + + EaElements.Label { + font.bold: true + text: qsTr('Description:') + } + EaElements.TextInput { + text: Globals.BackendProxy.project.info.description + onEditingFinished: Globals.BackendProxy.project.editData('description', text) + } + + EaElements.Label { + font.bold: true + text: qsTr('Location:') + } + EaElements.Label { + text: Globals.BackendProxy.project.info.location + } + + EaElements.Label { + font.bold: true + text: qsTr('Created:') + } + EaElements.Label { + text: Globals.BackendProxy.project.info.creationDate + } + } + // Project info + + // Project image + Image { + width: EaStyle.Sizes.fontPixelSize * 25 + fillMode: Image.PreserveAspectFit + } + // Project image + + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/Examples.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/Examples.qml new file mode 100644 index 00000000..af7062e6 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/Examples.qml @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents +import EasyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + + +EaComponents.TableView { + + id: tableView + + showHeader: false + tallRows: true + maxRowCountShow: 6 + + defaultInfoText: qsTr('No examples available') + + model: Globals.BackendProxy.project.examples + + // header + header: EaComponents.TableViewHeader { + EaComponents.TableViewLabel { + enabled: false + width: EaStyle.Sizes.fontPixelSize * 2.5 + } + + EaComponents.TableViewLabel { + flexibleWidth: true + horizontalAlignment: Text.AlignLeft + text: qsTr('name / description') + } + } + // header + + // delegate + delegate: EaComponents.TableViewDelegate { + mouseArea.onPressed: { + const filePath = tableView.model[index].path + console.debug(`Loading example: ${filePath}`) + } + + EaComponents.TableViewLabel { + text: index + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewTwoRowsAdvancedLabel { + fontIcon: 'archive' + text: tableView.model[index].name + minorText: tableView.model[index].description + ToolTip.text: tableView.model[index].description + } + } + // delegate + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/GetStarted.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/GetStarted.qml new file mode 100644 index 00000000..cb1ab180 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/GetStarted.qml @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls +//import QtQuick.Dialogs + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents +import EasyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + + +Grid { + + columns: 2 + spacing: EaStyle.Sizes.fontPixelSize + + // button 1 + EaElements.SideBarButton { + fontIcon: 'plus-circle' + text: qsTr('Create a new project') + + onClicked: { + console.debug(`Clicking '${text}' button ::: ${this}`) + EaGlobals.Vars.showProjectDescriptionDialog = true + } + + Loader { + source: '../Popups/ProjectDescription.qml' + } + } + // button 1 + + // button 2 + EaElements.SideBarButton { + fontIcon: 'upload' + text: qsTr('Open an existing project') + + onClicked: { + console.debug(`Clicking '${text}' button ::: ${this}`) + Globals.References.pages.project.sidebar.basic.popups.openCifFile.open() + } + + Loader { + source: '../Popups/OpenCifFile.qml' + } + } + // button 2 + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/Recent.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/Recent.qml new file mode 100644 index 00000000..8357f95a --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Groups/Recent.qml @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls +import QtCore + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents +import EasyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + + +EaComponents.TableView { + + id: tableView + + showHeader: false + tallRows: true + maxRowCountShow: 6 + + defaultInfoText: qsTr('No recent projects found') + + // Header row + header: EaComponents.TableViewHeader { + + EaComponents.TableViewLabel { + enabled: false + width: EaStyle.Sizes.fontPixelSize * 2.5 + } + + } + // Header row + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Layout.qml new file mode 100644 index 00000000..23952b4b --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Layout.qml @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.SideBarColumn { + + EaElements.GroupBox { + title: qsTr('Get started') + icon: 'rocket' + collapsed: false + + Loader { source: 'Groups/GetStarted.qml' } + } + + EaElements.GroupBox { + title: qsTr('Examples') + icon: 'database' + + Loader { source: 'Groups/Examples.qml' } + } + + EaElements.GroupBox { + title: qsTr('Recent projects') + icon: 'archive' + + Loader { source: 'Groups/Recent.qml' } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Popups/OpenCifFile.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Popups/OpenCifFile.qml new file mode 100644 index 00000000..649bb8a8 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Popups/OpenCifFile.qml @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls +import QtQuick.Dialogs + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +FileDialog{ + + id: openCifFileDialog + + fileMode: FileDialog.OpenFile + nameFilters: [ 'CIF files (*.cif)'] + + onAccepted: { + Globals.References.applicationWindow.appBarCentralTabs.summaryButton.enabled = true + } + + Component.onCompleted: { + Globals.References.pages.project.sidebar.basic.popups.openCifFile = openCifFileDialog + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Popups/ProjectDescription.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Popups/ProjectDescription.qml new file mode 100644 index 00000000..b63c66a6 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Basic/Popups/ProjectDescription.qml @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.ProjectDescriptionDialog { + + visible: EaGlobals.Vars.showProjectDescriptionDialog + onClosed: EaGlobals.Vars.showProjectDescriptionDialog = false + + onAccepted: { + Globals.BackendProxy.project.create() + Globals.References.applicationWindow.appBarCentralTabs.summaryButton.enabled = true + } + + Component.onCompleted: { + projectName = Globals.BackendProxy.project.info.name + projectDescription = Globals.BackendProxy.project.info.description + projectLocation = Globals.BackendProxy.project.info.location + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Extra/Groups/Scrolling.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Extra/Groups/Scrolling.qml new file mode 100644 index 00000000..4bc89207 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Extra/Groups/Scrolling.qml @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + + +Column { + + property int labelsCount: 50 + + spacing: EaStyle.Sizes.fontPixelSize + + Repeater { + model: labelsCount + EaElements.Label { + text: `Label ${index+1} of ${labelsCount}` + } + } + +} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Extra/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Extra/Layout.qml new file mode 100644 index 00000000..273d95a0 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Extra/Layout.qml @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.SideBarColumn { + + EaElements.GroupBox { + title: qsTr('Scrolling') + icon: 'rocket' + collapsed: false + + Loader { source: 'Groups/Scrolling.qml' } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Text/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Text/Layout.qml new file mode 100644 index 00000000..3c9c9d63 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Sidebar/Text/Layout.qml @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + + +EaComponents.SideBarColumn {} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Layout.qml new file mode 100644 index 00000000..0cb37f89 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Layout.qml @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.ContentPage { + + defaultInfo: Globals.BackendProxy.summary.created ? + '' : + qsTr('No Summary Generated') + + mainView: EaComponents.MainContent { + tabs: [ + EaElements.TabButton { text: qsTr('Summary') } + ] + + items: [ + Loader { source: 'MainArea/Summary.qml' } + ] + } + + sideBar: EaComponents.SideBar { + tabs: [ + EaElements.TabButton { text: qsTr('Basic controls') }, + EaElements.TabButton { text: qsTr('Extra controls') } + ] + + items: [ + Loader { source: 'Sidebar/Basic/Layout.qml' }, + Loader { source: 'Sidebar/Extra/Layout.qml' } + ] + + continueButton.visible: false + } + + Component.onCompleted: console.debug(`Summary page loaded ::: ${this}`) + Component.onDestruction: console.debug(`Summary page destroyed ::: ${this}`) + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/MainArea/Summary.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/MainArea/Summary.qml new file mode 100644 index 00000000..32225792 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/MainArea/Summary.qml @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Animations as EaAnimations +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + + +Rectangle { + + color: EaStyle.Colors.textViewBackground + Behavior on color { EaAnimations.ThemeChange {} } + + // Flickable + Flickable { + id: flick + + anchors.fill: parent + + contentWidth: textArea.contentWidth + contentHeight: textArea.contentHeight + + clip: true + flickableDirection: Flickable.VerticalFlick + + ScrollBar.vertical: EaElements.ScrollBar { + policy: ScrollBar.AsNeeded + interactive: false + } + + // Main text area + EaElements.TextArea { + id: textArea + + readOnly: true + + width: flick.width + topPadding: 0 + bottomPadding: 0 + padding: 2.5 * EaStyle.Sizes.fontPixelSize + + textFormat: TextEdit.RichText + text: Globals.BackendProxy.summary.asHtml + } + // Main text area + + } + // Flickable + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Groups/Export.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Groups/Export.qml new file mode 100644 index 00000000..01adcdd6 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Groups/Export.qml @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls +import QtQuick.Dialogs +import QtCore + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + + +Column { + + property string projectLocation: Globals.BackendProxy.project.info.location + + EaLogic.Utils.osPathSep() + + 'summary' + + spacing: EaStyle.Sizes.fontPixelSize + + // Name field + format selector + Row { + spacing: EaStyle.Sizes.fontPixelSize + + // Name field + EaElements.TextField { + id: nameField + width: saveButton.width - formatField.width - parent.spacing + topInset: nameLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + placeholderText: qsTr('Enter summary file name here') + Component.onCompleted: text = 'summary' + EaElements.Label { + id: nameLabel + text: qsTr('Name') + } + } + // Name field + + // Format selector + EaElements.ComboBox { + id: formatField + topInset: formatLabel.height + topPadding: topInset + padding + width: EaStyle.Sizes.fontPixelSize * 10 + textRole: 'text' + valueRole: 'value' + model: [ + { value: 'html', text: qsTr('HTML') } + ] + EaElements.Label { + id: formatLabel + text: qsTr('Format') + } + } + // Format selector + } + // Name field + format selector + + // Location field + EaElements.TextField { + id: reportLocationField + width: saveButton.width + topInset: locationLabel.height + topPadding: topInset + padding + rightPadding: chooseButton.width + horizontalAlignment: TextInput.AlignLeft + placeholderText: qsTr('Enter report location here') + Component.onCompleted: text = projectLocation + + EaElements.Label { + id: locationLabel + text: qsTr('Location') + } + + EaElements.ToolButton { + id: chooseButton + anchors.right: parent.right + topPadding: parent.topPadding + showBackground: false + fontIcon: 'folder-open' + ToolTip.text: qsTr('Choose report parent directory') + onClicked: reportParentDirDialog.open() + } + } + // Location field + + // Save button + EaElements.SideBarButton { + id: saveButton + wide: true + fontIcon: 'download' + text: qsTr('Save') + } + // Save button + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Layout.qml new file mode 100644 index 00000000..472d957a --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Layout.qml @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.SideBarColumn { + + EaElements.GroupBox { + enabled: false + title: qsTr('Export summary') + icon: 'download' + collapsed: false + + Loader { source: 'Groups/Export.qml' } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Groups/Empty.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Groups/Empty.qml new file mode 100644 index 00000000..9f478042 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Groups/Empty.qml @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + + +Column {} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Layout.qml new file mode 100644 index 00000000..ef2a2edc --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Layout.qml @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.SideBarColumn { + + EaElements.GroupBox { + title: qsTr('Empty') + icon: 'rocket' + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.icns b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.icns new file mode 100644 index 00000000..5a9224a3 Binary files /dev/null and b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.icns differ diff --git a/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.ico b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.ico new file mode 100644 index 00000000..babea15f Binary files /dev/null and b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.ico differ diff --git a/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.png b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.png new file mode 100644 index 00000000..354ddc25 Binary files /dev/null and b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.png differ diff --git a/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.svg b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.svg new file mode 100644 index 00000000..e6dd3e01 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/App.svg @@ -0,0 +1,101 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/ESS.png b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/ESS.png new file mode 100644 index 00000000..22c09d2e Binary files /dev/null and b/src_qt6/EasyReflectometryApp/Gui/Resources/Logos/ESS.png differ diff --git a/src_qt6/EasyReflectometryApp/Gui/StatusBar.qml b/src_qt6/EasyReflectometryApp/Gui/StatusBar.qml new file mode 100644 index 00000000..ff29bd69 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/StatusBar.qml @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaElements.StatusBar { + + visible: EaGlobals.Vars.appBarCurrentIndex !== 0 + + EaElements.StatusBarItem { + keyIcon: 'archive' + keyText: qsTr('Project') + valueText: Globals.BackendProxy.status.project ?? '' + ToolTip.text: qsTr('Current project') + } + + EaElements.StatusBarItem { + keyIcon: 'layer-group' + keyText: qsTr('Models') + valueText: Globals.BackendProxy.status.phaseCount ?? '' + ToolTip.text: qsTr('Number of models added') + } + + EaElements.StatusBarItem { + keyIcon: 'microscope' + keyText: qsTr('Experiments') + valueText: Globals.BackendProxy.status.experimentsCount ?? '' + ToolTip.text: qsTr('Number of experiments added') + } + + EaElements.StatusBarItem { + keyIcon: 'calculator' + keyText: qsTr('Calculator') + valueText: Globals.BackendProxy.status.calculator ?? '' + ToolTip.text: qsTr('Current calculation engine') + } + + EaElements.StatusBarItem { + keyIcon: 'level-down-alt' + keyText: qsTr('Minimizer') + valueText: Globals.BackendProxy.status.minimizer ?? '' + ToolTip.text: qsTr('Current minimization engine and method') + } + + EaElements.StatusBarItem { + keyIcon: 'th-list' + keyText: qsTr('Parameters') + valueText: Globals.BackendProxy.status.variables ?? '' + ToolTip.text: qsTr('Number of parameters: total, free and fixed') + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/qmldir b/src_qt6/EasyReflectometryApp/Gui/qmldir new file mode 100644 index 00000000..d3151d58 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/qmldir @@ -0,0 +1,4 @@ +module Gui + +ApplicationWindow ApplicationWindow.qml +StatusBar StatusBar.qml diff --git a/src_qt6/EasyReflectometryApp/Logic/Mock/BackendProxy.qml b/src_qt6/EasyReflectometryApp/Logic/Mock/BackendProxy.qml new file mode 100644 index 00000000..c8f64a82 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Mock/BackendProxy.qml @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +pragma Singleton + +import QtQuick + +import Logic.Mock as MockLogic + +QtObject { + + property var application: MockLogic.Application + property var project: MockLogic.Project + property var status: MockLogic.Status + property var report: MockLogic.Report + +} + + diff --git a/src_qt6/EasyReflectometryApp/Logic/Mock/Project.qml b/src_qt6/EasyReflectometryApp/Logic/Mock/Project.qml new file mode 100644 index 00000000..f3a275fa --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Mock/Project.qml @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +pragma Singleton + +import QtQuick + +QtObject { + + property bool created: false + + readonly property var info: { + 'name': 'Super duper project', + 'description': 'Default project description from Mock proxy', + 'location': '/path to the project', + 'creationDate': '' + } + + readonly property var examples: [ + { + 'description': 'neutrons, powder, constant wavelength, HRPT@PSI', + 'name': 'La0.5Ba0.5CoO3 (HRPT)', + 'path': ':/Examples/La0.5Ba0.5CoO3_HRPT@PSI/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, HRPT@PSI', + 'name': 'La0.5Ba0.5CoO3-Raw (HRPT)', + 'path': ':/Examples/La0.5Ba0.5CoO3-Raw_HRPT@PSI/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, HRPT@PSI, 2 phases', + 'name': 'La0.5Ba0.5CoO3-Mult-Phases (HRPT)', + 'path': ':/Examples/La0.5Ba0.5CoO3-Mult-Phases_HRPT@PSI/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, D20@ILL', + 'name': 'Co2SiO4 (D20)', + 'path': ':/Examples/Co2SiO4_D20@ILL/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, G41@LLB', + 'name': 'Dy3Al5O12 (G41)', + 'path': ':/Examples/Dy3Al5O12_G41@LLB/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, D1A@ILL', + 'name': 'PbSO4 (D1A)', + 'path': ':/Examples/PbSO4_D1A@ILL/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, 3T2@LLB', + 'name': 'LaMnO3 (3T2)', + 'path': ':/Examples/LaMnO3_3T2@LLB/project.cif' + } + ] + + function create() { + console.debug(`Creating project ${info.name}`) + info.creationDate = `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}` + infoChanged() // this signal is not emitted automatically when only part of the object is changed + created = true + } + + function save() { + console.debug(`Saving project ${info.name}`) + } + +} diff --git a/src_qt6/EasyReflectometryApp/Logic/Mock/Report.qml b/src_qt6/EasyReflectometryApp/Logic/Mock/Report.qml new file mode 100644 index 00000000..5a6db305 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Mock/Report.qml @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +pragma Singleton + +import QtQuick + +QtObject { + property bool created: true + + readonly property string asHtml: ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Summary

Project information

TitleLa0.5Ba0.5CoO3
Descriptionneutrons, powder, constant wavelength
No. of phases1
No. of experiments1

Crystal data

Phase datablocklbco
Crystal system, space groupcubic,  P m -3 m

Data collection

Experiment datablockhrpt
Radiation probeneutron
Measured range: min, max, inc (°)10.0,  164.85,  0.05
+ + +' + +} diff --git a/src_qt6/EasyReflectometryApp/Logic/Mock/Status.qml b/src_qt6/EasyReflectometryApp/Logic/Mock/Status.qml new file mode 100644 index 00000000..6eec0bd4 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Mock/Status.qml @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +pragma Singleton + +import QtQuick + +QtObject { + + readonly property string project: 'Undefined' + readonly property string phaseCount: '1' + readonly property string experimentsCount: '1' + readonly property string calculator: 'CrysPy' + readonly property string minimizer: 'Lmfit (leastsq)' + readonly property string variables: '31 (3 free, 28 fixed)' + +} diff --git a/src_qt6/EasyReflectometryApp/Logic/Mock/qmldir b/src_qt6/EasyReflectometryApp/Logic/Mock/qmldir new file mode 100644 index 00000000..f1830657 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Mock/qmldir @@ -0,0 +1,6 @@ +module MockLogic + +singleton BackendProxy BackendProxy.qml +singleton Project Project.qml +singleton Report Report.qml +singleton Status Status.qml diff --git a/src_qt6/EasyReflectometryApp/Logic/Py/backend_proxy.py b/src_qt6/EasyReflectometryApp/Logic/Py/backend_proxy.py new file mode 100644 index 00000000..2ec51610 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Py/backend_proxy.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: 2024 EasyApp contributors +# SPDX-License-Identifier: BSD-3-Clause +# © 2024 Contributors to the EasyApp project + +from PySide6.QtCore import QObject, Property + +from EasyApp.Logic.Logging import LoggerLevelHandler + +from .project import Project +from .status import Status +from .report import Report + + +class BackendProxy(QObject): + def __init__(self, parent=None): + super().__init__(parent) + self._logger = LoggerLevelHandler(self) + self._project = Project(self) + self._status = Status(self) + self._report = Report(self) + + @Property('QVariant', constant=True) + def logger(self): + return self._logger + + @Property('QVariant', constant=True) + def project(self): + return self._project + + @Property('QVariant', constant=True) + def status(self): + return self._status + + @Property('QVariant', constant=True) + def report(self): + return self._report diff --git a/src_qt6/EasyReflectometryApp/Logic/Py/helpers.py b/src_qt6/EasyReflectometryApp/Logic/Py/helpers.py new file mode 100644 index 00000000..a97866d4 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Py/helpers.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2024 EasyApp contributors +# SPDX-License-Identifier: BSD-3-Clause +# © 2024 Contributors to the EasyApp project + +class IO: + + @staticmethod + def formatMsg(type, *args): + types = {'main': '*', 'sub': ' -'} + mark = types[type] + widths = [22,21,20,10] + widths[0] -= len(mark) + msgs = [] + for idx, arg in enumerate(args): + msgs.append(f'{arg:<{widths[idx]}}') + msg = ' ▌ '.join(msgs) + msg = f'{mark} {msg}' + return msg diff --git a/src_qt6/EasyReflectometryApp/Logic/Py/project.py b/src_qt6/EasyReflectometryApp/Logic/Py/project.py new file mode 100644 index 00000000..33e65ee0 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Py/project.py @@ -0,0 +1,105 @@ +# SPDX-FileCopyrightText: 2024 EasyApp contributors +# SPDX-License-Identifier: BSD-3-Clause +# © 2024 Contributors to the EasyApp project + +import time +from PySide6.QtCore import QObject, Signal, Slot, Property + +from EasyApp.Logic.Logging import console +from .helpers import IO + + +_PY_INFO = { + 'name': 'Super duper project', + 'description': 'Default project description from Py proxy', + 'location': '/path to the project', + 'creationDate': '' +} + +_PY_EXAMPLES = [ + { + 'description': 'neutrons, powder, constant wavelength, HRPT@PSI', + 'name': 'La0.5Ba0.5CoO3 (HRPT)', + 'path': ':/Examples/La0.5Ba0.5CoO3_HRPT@PSI/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, HRPT@PSI', + 'name': 'La0.5Ba0.5CoO3-Raw (HRPT)', + 'path': ':/Examples/La0.5Ba0.5CoO3-Raw_HRPT@PSI/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, HRPT@PSI, 2 phases', + 'name': 'La0.5Ba0.5CoO3-Mult-Phases (HRPT)', + 'path': ':/Examples/La0.5Ba0.5CoO3-Mult-Phases_HRPT@PSI/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, D20@ILL', + 'name': 'Co2SiO4 (D20)', + 'path': ':/Examples/Co2SiO4_D20@ILL/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, G41@LLB', + 'name': 'Dy3Al5O12 (G41)', + 'path': ':/Examples/Dy3Al5O12_G41@LLB/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, D1A@ILL', + 'name': 'PbSO4 (D1A)', + 'path': ':/Examples/PbSO4_D1A@ILL/project.cif' + }, + { + 'description': 'neutrons, powder, constant wavelength, 3T2@LLB', + 'name': 'LaMnO3 (3T2)', + 'path': ':/Examples/LaMnO3_3T2@LLB/project.cif' + } +] + + +class Project(QObject): + createdChanged = Signal() + infoChanged = Signal() + examplesChanged = Signal() + + def __init__(self, parent=None): + super().__init__(parent) + self._proxy = parent + self._created = False + self._info = _PY_INFO + self._examples = _PY_EXAMPLES + + @Property(bool, notify=createdChanged) + def created(self): + return self._created + + @created.setter + def created(self, newValue): + if self._created == newValue: + return + self._created = newValue + self.createdChanged.emit() + + @Property('QVariant', notify=infoChanged) + def info(self): + return self._info + + @info.setter + def info(self, newValue): + if self._info == newValue: + return + self._info = newValue + self.infoChanged.emit() + + @Property('QVariant', constant=True) + def examples(self): + return self._examples + + @Slot() + def create(self): + console.debug(IO.formatMsg('main', f'Creating project {self.info["name"]}')) + self.info['creationDate'] = time.strftime("%d %b %Y %H:%M", time.localtime()) + self.infoChanged.emit() + self.created = True + + @Slot() + def save(self): + console.debug(IO.formatMsg('main', f'Saving project {self.info["name"]}')) diff --git a/src_qt6/EasyReflectometryApp/Logic/Py/report.py b/src_qt6/EasyReflectometryApp/Logic/Py/report.py new file mode 100644 index 00000000..fe80babf --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Py/report.py @@ -0,0 +1,108 @@ +# SPDX-FileCopyrightText: 2024 EasyApp contributors +# SPDX-License-Identifier: BSD-3-Clause +# © 2024 Contributors to the EasyApp project + +from PySide6.QtCore import QObject, Signal, Property + + +_PY_HTML = """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Py Summary

Project information

TitleLa0.5Ba0.5CoO3
Descriptionneutrons, powder, constant wavelength
No. of phases1
No. of experiments1

Crystal data

Phase datablocklbco
Crystal system, space groupcubic,  P m -3 m

Data collection

Experiment datablockhrpt
Radiation probeneutron
Measured range: min, max, inc (°)10.0,  164.85,  0.05
+ + +""" + + +class Report(QObject): + createdChanged = Signal() + asHtmlChanged = Signal() + + def __init__(self, parent): + super().__init__(parent) + self._proxy = parent + self._created = True + self._asHtml = _PY_HTML + + @Property(bool, notify=createdChanged) + def created(self): + return self._created + + @created.setter + def created(self, newValue): + if self._created == newValue: + return + self._created = newValue + self.createdChanged.emit() + + @Property(str, notify=asHtmlChanged) + def asHtml(self): + return self._asHtml + + @asHtml.setter + def asHtml(self, newValue): + if self._asHtml == newValue: + return + self._asHtml = newValue + self.asHtmlChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Logic/Py/status.py b/src_qt6/EasyReflectometryApp/Logic/Py/status.py new file mode 100644 index 00000000..b223b055 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Logic/Py/status.py @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: 2024 EasyApp contributors +# SPDX-License-Identifier: BSD-3-Clause +# © 2024 Contributors to the EasyApp project + +from PySide6.QtCore import QObject, Signal, Property + + +class Status(QObject): + projectChanged = Signal() + phaseCountChanged = Signal() + experimentsCountChanged = Signal() + calculatorChanged = Signal() + minimizerChanged = Signal() + variablesChanged = Signal() + + def __init__(self, parent): + super().__init__(parent) + self._proxy = parent + self._project = 'Py backend' + self._phaseCount = '1' + self._experimentsCount = '1' + self._calculator = 'CrysPy' + self._minimizer = 'Lmfit (leastsq)' + self._variables = '31 (3 free, 28 fixed)' + + @Property(str, notify=projectChanged) + def project(self): + return self._project + + @project.setter + def project(self, newValue): + if self._project == newValue: + return + self._project = newValue + self.projectChanged.emit() + + @Property(str, notify=phaseCountChanged) + def phaseCount(self): + return self._phaseCount + + @phaseCount.setter + def phaseCount(self, newValue): + if self._phaseCount == newValue: + return + self._phaseCount = newValue + self.phaseCountChanged.emit() + + @Property(str, notify=experimentsCountChanged) + def experimentsCount(self): + return self._experimentsCount + + @experimentsCount.setter + def experimentsCount(self, newValue): + if self._experimentsCount == newValue: + return + self._experimentsCount = newValue + self.experimentsCountChanged.emit() + + @Property(str, notify=calculatorChanged) + def calculator(self): + return self._calculator + + @calculator.setter + def calculator(self, newValue): + if self._calculator == newValue: + return + self._calculator = newValue + self.calculatorChanged.emit() + + @Property(str, notify=minimizerChanged) + def minimizer(self): + return self._minimizer + + @minimizer.setter + def minimizer(self, newValue): + if self._minimizer == newValue: + return + self._minimizer = newValue + self.minimizerChanged.emit() + + @Property(str, notify=variablesChanged) + def variables(self): + return self._variables + + @variables.setter + def variables(self, newValue): + if self._variables == newValue: + return + self._variables = newValue + self.variablesChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/__init__.py b/src_qt6/EasyReflectometryApp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src_qt6/EasyReflectometryApp/__version__.py b/src_qt6/EasyReflectometryApp/__version__.py new file mode 100644 index 00000000..1f356cc5 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/__version__.py @@ -0,0 +1 @@ +__version__ = '1.0.0' diff --git a/src_qt6/EasyReflectometryApp/main.py b/src_qt6/EasyReflectometryApp/main.py new file mode 100644 index 00000000..ad159867 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/main.py @@ -0,0 +1,46 @@ +# SPDX-FileCopyrightText: 2024 EasyReflectometryApp contributors +# SPDX-License-Identifier: BSD-3-Clause +# © 2024 Contributors to the EasyReflectometryApp project + +import sys + +from pathlib import Path + +from PySide6.QtGui import QGuiApplication +from PySide6.QtQml import QQmlApplicationEngine +from PySide6.QtCore import qInstallMessageHandler + +from EasyApp.Logic.Logging import console + +from Logic.Py.backend_proxy import BackendProxy + +CURRENT_DIR = Path(__file__).parent # path to qml components of the current project +EASYAPP_DIR = CURRENT_DIR / '..' / '..' / '..' / 'EasyApp' / 'src' # path to qml components of the easyapp module +MAIN_QML = CURRENT_DIR / 'main.qml' # path to the root qml file + + +if __name__ == '__main__': + qInstallMessageHandler(console.qmlMessageHandler) + console.debug('Custom Qt message handler defined') + + app = QGuiApplication(sys.argv) + console.debug(f'Qt Application created {app}') + + engine = QQmlApplicationEngine() + console.debug(f'QML application engine created {engine}') + + backend_proxy = BackendProxy() + engine.rootContext().setContextProperty('backend_proxy_py', backend_proxy) + console.debug('backend_proxy object exposed to QML as backend_proxy_py') + + engine.addImportPath(EASYAPP_DIR) + engine.addImportPath(CURRENT_DIR) + console.debug('Paths added where QML searches for components') + + engine.load(MAIN_QML) + console.debug('Main QML component loaded') + + console.debug('Application event loop is about to start') + if not engine.rootObjects(): + sys.exit(-1) + sys.exit(app.exec()) diff --git a/src_qt6/EasyReflectometryApp/main.qml b/src_qt6/EasyReflectometryApp/main.qml new file mode 100644 index 00000000..f5d56832 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/main.qml @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2024 EasyApp contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2024 Contributors to the EasyApp project + +import QtQuick +import QtQuick.Controls + +import Gui as Gui + + +Gui.ApplicationWindow { + + id: applicationWindow // Global access + +} diff --git a/src_qt6/LICENSE b/src_qt6/LICENSE new file mode 100644 index 00000000..7304d4d1 --- /dev/null +++ b/src_qt6/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2021-2023, European Spallation Source +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/src_qt6/pyproject.toml b/src_qt6/pyproject.toml new file mode 100644 index 00000000..f92bb4cb --- /dev/null +++ b/src_qt6/pyproject.toml @@ -0,0 +1,45 @@ +[build-system] +requires = ['hatchling'] +build-backend = 'hatchling.build' + +[project] +name = 'EasyReflectometryApp' +version = '1.0.0' +description = "Making reflectometry data analysis and modelling easy." +authors = [ + {name = "Andrew R. McCluskey", email = "andrew.mccluskey@ess.eu"}, + {name = "Andrew Sazonov"}, + {name = "Simon Ward"}, + {name = "Andreas Pedersen", email = "andreas.pedersen@ess.eu"} +] +maintainers = [ + {name = "Andrew R. McCluskey", email = "andrew.mccluskey@ess.eu"}, + {name = "Andreas Pedersen", email = "andreas.pedersen@ess.eu"} +] +license = {file = 'LICENSE'} +classifiers = [ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python :: 3', + 'Operating System :: MacOS', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux' +] + +requires-python = '>=3.10' +dependencies = [ + 'PySide6>=6.6,<6.8', + 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@examples', +] + +[project.urls] +homepage = 'https://easyreflectometry.org' +documentation = 'https://easyreflectometry.org' +changelog = 'https://github.com/easyScience/EasyReflectometryApp/blob/main/CHANGELOG.md' + +[tool.hatch.build.targets.wheel] +packages = ['src/EasyReflectometryApp'] + +# To allow dependencies residing in git +[tool.hatch.metadata] +allow-direct-references = true \ No newline at end of file