import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import Controls 1.0 as Controls import Screens 1.0 as Screens import Cubo 1.0 import Utils 1.0 ApplicationWindow { id: window title: qsTr("Cubo Verde BMS") width: 1366 height: 768 visible: true RowLayout { anchors.fill: parent spacing: 0 Rectangle { id: pane color: Palette.alternativeBackgroundColor implicitWidth: 300 property bool minimized: false ColumnLayout { anchors.fill: parent spacing: 0 Item { Layout.preferredHeight: 40 } Image { source: "qrc:/Icons/cubo-logo.svg" sourceSize.width: pane.minimized ? 70 : 115 sourceSize.height: pane.minimized ? 70 : 115 Layout.alignment: Qt.AlignCenter } Item { Layout.preferredHeight: pane.minimized ? 85 : 40 } Controls.MenuItemDelegate { text: qsTr("Hide menu") font.weight: Font.Normal icon.source: "qrc:/Icons/hide-menu.svg" minimized: pane.minimized mirroredIcon: pane.minimized onClicked: if (pane.implicitWidth === 300) { animation.from = 300 animation.to = 100 animation.running = true pane.minimized = true } else { animation.from = 100 animation.to = 300 animation.running = true pane.minimized = false } Layout.fillWidth: true } Item { Layout.preferredHeight: 70 } ListView { id: menuView clip: true boundsBehavior: Flickable.StopAtBounds property var menuModel: [ {"text": qsTr("AKB monitor"), "icon": "qrc:/Icons/akb-monitor.svg"}, {"text": qsTr("Cell monitor"), "icon": "qrc:/Icons/cell-monitor.svg"}, {"text": qsTr("Configuration"), "icon": "qrc:/Icons/bms-configuration.svg"}, {"text": qsTr("Visualization"), "icon": "qrc:/Icons/visualization.svg"}, {"text": qsTr("History"), "icon": "qrc:/Icons/history.svg"}, {"text": qsTr("BMS service"), "icon": "qrc:/Icons/bms-service.svg"} ] model: menuModel.length delegate: Controls.MenuItemDelegate { width: ListView.view.width text: menuView.menuModel[modelData].text icon.source: menuView.menuModel[modelData].icon highlighted: ListView.isCurrentItem minimized: pane.minimized onClicked: menuView.currentIndex = index } Layout.fillHeight: true Layout.fillWidth: true } Controls.MenuItemDelegate { text: qsTr("Connection") icon.source: "qrc:/Icons/connection.svg" icon.color: "#FFFFFF" minimized: pane.minimized onClicked: connectionDialog.open() Layout.fillWidth: true } Item { Layout.preferredHeight: 40 } } PropertyAnimation { id: animation target: pane property: "implicitWidth" duration: 200 easing.type: Easing.InQuad } Layout.preferredWidth: implicitWidth Layout.fillHeight: true } ColumnLayout { spacing: 0 RowLayout { id: topBar Label { text: stack.itemAt(stack.currentIndex).title font.pixelSize: 38 font.weight: Font.Bold color: Palette.textColor } Item { Layout.fillWidth: true } RowLayout { spacing: 20 ColumnLayout { spacing: 5 RowLayout { spacing: 7 Controls.ContentLabel { id: connectionStatusLabel text: qsTr("Disconnected") Layout.alignment: Qt.AlignRight } Controls.AvailabilityIndicator { id: connectionStatusIndicator enabled: false neutral: false Layout.alignment: Qt.AlignCenter } Controls.ContentLabel { id: firmwareLabel text: "-" Layout.alignment: Qt.AlignRight } Layout.alignment: Qt.AlignRight } RowLayout { spacing: 5 Controls.ContentLabel { text: qsTr("Serial number") + ":" Layout.alignment: Qt.AlignRight } Controls.SubtitleLabel { id: serialLabel text: "-" Layout.alignment: Qt.AlignRight } Layout.alignment: Qt.AlignRight } Layout.topMargin: 15 Layout.bottomMargin: 15 Layout.fillHeight: true } Controls.LineSeparator { horizontal: false Layout.fillHeight: true Layout.topMargin: 15 Layout.bottomMargin: 15 } Item { RowLayout { id: languagesLayout anchors.fill: parent spacing: 10 Controls.ContentLabel { text: Translator.currentLanguageName } Image { source: Translator.currentLanguageIcon sourceSize.width: 30 sourceSize.height: 26 } } MouseArea { anchors.fill: parent onClicked: languagesPopup.open() } Popup { id: languagesPopup width: 90 contentHeight: languagesList.contentHeight padding: 1 x: -(width - languagesLayout.width) / 2 y: languagesLayout.height + 2 background: Rectangle { color: Palette.backgroundColor radius: 6 border.width: 1 border.color: Palette.borderColor } contentItem: ListView { id: languagesList model: [Translator.Russian, Translator.English, Translator.Italian] width: languagesPopup.width height: 120 clip: true spacing: 0 delegate: Rectangle { width: ListView.view.width height: 40 color: Palette.backgroundColor RowLayout { anchors.fill: parent spacing: 10 Controls.ContentLabel { text: Translator.languageName(modelData) Layout.fillWidth: true Layout.leftMargin: 10 } Image { source: Translator.languageIcon(modelData) sourceSize.width: 30 sourceSize.height: 26 Layout.rightMargin: 10 } } MouseArea { anchors.fill: parent hoverEnabled: true onPressed: parent.color = Palette.selectedBackgroundColor onReleased: parent.color = Palette.backgroundColor onEntered: parent.color = Palette.hoveredBackgroundColor onExited: parent.color = Palette.backgroundColor onClicked: { languagesPopup.close() Translator.currentLanguage = modelData } } } } } Layout.preferredWidth: languagesLayout.implicitWidth Layout.preferredHeight: languagesLayout.implicitHeight } } Layout.leftMargin: 45 Layout.rightMargin: 45 Layout.maximumHeight: 90 } StackLayout { id: stack currentIndex: menuView.currentIndex Layout.fillWidth: true Layout.fillHeight: true Layout.leftMargin: 45 Layout.rightMargin: 45 Layout.bottomMargin: 30 Screens.AkbMonitorScreen { property string title: qsTr("AKB monitor") } Screens.CellMonitorScreen { property string title: qsTr("Cell monitor") } Screens.BmsSettingsScreen { property string title: qsTr("BMS settings") onNeedWait: { if (active) { busyPopup.text = text busyPopup.open() } else { busyPopup.close() } } } Screens.VisualizationScreen { property string title: qsTr("Visualization") } Screens.DebugInformationScreen { id: debugScreen property string title: qsTr("Information output") } Screens.BmsServiceScreen { } } } } Connections { target: BmsInterface onPortConnectedChanged: { connectionStatusLabel.text = Qt.binding(function(){ return BmsInterface.isPortConnected() ? qsTr("Connected") : qsTr("Disconnected") }) connectionStatusIndicator.enabled = BmsInterface.isPortConnected() if (BmsInterface.isPortConnected()) { BmsInterface.commands().getBMSconf() } else { serialLabel.text = "-" firmwareLabel.text = "-" } } onMessageDialog: { if (!messageDialog.visible) { messageDialog.title = title messageDialog.description = msg messageDialog.good = isGood messageDialog.open() } else { messageDialog.queue.push({"title": title, "description": msg, "good": isGood}) } } onStatusMessage: { for (var i = 0; i < statusPopup.filteredStatuses.length; ++i) { if (msg === statusPopup.filteredStatuses[i]) { return } } if (!statusPopup.visible) { statusPopup.text = msg statusPopup.good = isGood statusPopup.open() } else { if (statusPopup.text !== msg) { statusPopup.queue.push({"text": msg, "good": isGood}) } } } onFwUploadStatus: { if (isOngoing) { if (!progressPopup.opened) { progressPopup.open() } progressPopup.text = status progressPopup.progress = progress } else { progressPopup.close() BmsInterface.emitMessageDialog(qsTr("Firmware update"), status, true) } } onBmsConfigurationStored: busyPopup.close() } Connections { target: BmsInterface.bmsConfig() onUpdated: { serialLabel.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed() } } Connections { target: BmsInterface.commands() onFwVersionReceived: { firmwareLabel.text = major + "." + minor } } Screens.ConnectionDialog { id: connectionDialog } Screens.MessageDialog { id: messageDialog property var queue: [] onClosed: { if (queue.length > 0) { var message = queue.pop() messageDialog.title = message.title messageDialog.description = message.description messageDialog.good = message.good messageDialog.open() } } } Screens.StatusPopup { id: statusPopup property var filteredStatuses: [] property var queue: [] onClosed: { if (queue.length > 0) { var message = queue.pop() statusPopup.text = message.text statusPopup.good = message.good statusPopup.open() } } onOpened: { hideStatusTimer.start() } } Timer { id: hideStatusTimer interval: 3000 onTriggered: statusPopup.close() } Popup { id: busyPopup x: (parent.width - width) / 2 y: (parent.height - height) / 2 modal: true closePolicy: Popup.NoAutoClose property string text: "" background: Rectangle { color: "transparent" } ColumnLayout { Controls.BusyIndicator { running: true Layout.alignment: Qt.AlignCenter } Controls.SubtitleLabel { text: busyPopup.text color: Palette.alternativeTextColor maximumLineCount: 3 wrapMode: Text.Wrap font.pixelSize: 20 Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter leftPadding: 10 rightPadding: 10 background: Rectangle { color: Palette.textColor opacity: 0.3 radius: 6 } } } onOpened: hideBusyTimer.start() onClosed: hideBusyTimer.stop() } Popup { id: progressPopup x: (parent.width - width) / 2 y: (parent.height - height) / 2 modal: true closePolicy: Popup.NoAutoClose property alias text: progressText.text property alias progress: progressBar.value background: Rectangle { color: "transparent" } ColumnLayout { Controls.ProgressBar { id: progressBar Layout.alignment: Qt.AlignCenter Layout.preferredWidth: 500 } Controls.SubtitleLabel { text: "asdfzasdf" id: progressText color: Palette.alternativeTextColor maximumLineCount: 3 wrapMode: Text.Wrap font.pixelSize: 20 Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter leftPadding: 10 rightPadding: 10 background: Rectangle { color: Palette.textColor opacity: 0.3 radius: 6 } } } } Timer { id: hideBusyTimer interval: 30000 onTriggered: busyPopup.close() } background: Rectangle { color: Palette.screenBackgroundColor } Component.onCompleted: { connectionDialog.open() Qt.callLater(debugScreen.printMessage, qsTr("Tool started"), true) } }