diff --git a/resources/AdvancedTab.qml b/resources/AdvancedTab.qml index 57bb02914..bc0529646 100644 --- a/resources/AdvancedTab.qml +++ b/resources/AdvancedTab.qml @@ -5,66 +5,34 @@ import QtQuick 2.5 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.15 -Item { +MainTab { id: advancedTab - width: parent.width - height: parent.height + subTabNames: ["System Monitor", "IMU", "Magnetometer", "Networking", "Spectrum Analyzer", "INS"] + curSubTabIndex: Globals.initialMainTabIndex == 6 ? Globals.initialSubTabIndex : 0 - TabBar { - id: advancedBar + StackLayout { + id: advancedBarLayout - z: Constants.commonChart.zAboveCharts - currentIndex: Globals.initialMainTabIndex == 6 ? Globals.initialSubTabIndex : 0 - contentHeight: Constants.tabBarHeight - - Repeater { - model: ["System Monitor", "IMU", "Magnetometer", "Networking", "Spectrum Analyzer", "INS"] - - TabButton { - text: modelData - width: implicitWidth - } + anchors.fill: parent + currentIndex: curSubTabIndex + AdvancedTabComponents.AdvancedSystemMonitorTab { } - } - - Rectangle { - id: advancedTabBackground - - width: parent.width - height: parent.height - anchors.top: advancedBar.bottom - anchors.bottom: advancedTab.bottom - Component.onCompleted: { + AdvancedTabComponents.AdvancedImuTab { } - StackLayout { - id: advancedBarLayout - - width: parent.width - height: parent.height - currentIndex: advancedBar.currentIndex - - AdvancedTabComponents.AdvancedSystemMonitorTab { - } - - AdvancedTabComponents.AdvancedImuTab { - } - - AdvancedTabComponents.AdvancedMagnetometerTab { - } - - AdvancedTabComponents.AdvancedNetworkingTab { - } + AdvancedTabComponents.AdvancedMagnetometerTab { + } - AdvancedTabComponents.AdvancedSpectrumAnalyzerTab { - } + AdvancedTabComponents.AdvancedNetworkingTab { + } - AdvancedTabComponents.AdvancedInsTab { - } + AdvancedTabComponents.AdvancedSpectrumAnalyzerTab { + } + AdvancedTabComponents.AdvancedInsTab { } } diff --git a/resources/BaselineTab.qml b/resources/BaselineTab.qml index 2741f3d69..fa0fdbe22 100644 --- a/resources/BaselineTab.qml +++ b/resources/BaselineTab.qml @@ -5,12 +5,9 @@ import QtQuick 2.5 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 -Item { +MainTab { id: baselineTab - width: parent.width - height: parent.height - SplitView { id: baselineSplitView diff --git a/resources/Constants/Constants.qml b/resources/Constants/Constants.qml index 84381e6ea..786540ca8 100644 --- a/resources/Constants/Constants.qml +++ b/resources/Constants/Constants.qml @@ -49,10 +49,11 @@ QtObject { readonly property real smallPointSize: 7 readonly property real mediumPointSize: 8 readonly property real largePointSize: 9 + readonly property string infoPath: "qrc:///images/fontawesome/info-circle-solid.svg" readonly property bool debugMode: false readonly property color swiftGrey: "#323F48" readonly property color swiftLightGrey: "#3C464F" - readonly property color swiftControlBackground: "#ECECEC" + readonly property color swiftControlBackground: "#E0E0E0" readonly property color tabButtonUnselectedTextColor: "#767676" readonly property color materialGrey: "dimgrey" readonly property color swiftOrange: "#FF8300" @@ -95,13 +96,16 @@ QtObject { readonly property string settingsPath: "qrc:///images/fontawesome/cogs-solid.svg" readonly property string updatePath: "qrc:///images/fontawesome/chevron-circle-up-solid.svg" readonly property string advancedPath: "qrc:///images/fontawesome/lock-solid.svg" - readonly property real tabBarHeight: 45 - readonly property real tabBarWidth: 50 + readonly property real tabBarHeight: 48 + readonly property real tabBarWidth: 62 readonly property int buttonPadding: 0 readonly property int buttonInset: 0 readonly property int separatorMargin: 10 readonly property int separatorHeight: 1 - readonly property color backgroundColor: "#fafafa" + readonly property color backgroundColor: swiftGrey + readonly property color statusGoodColor: "#07DD01" + readonly property color statusOkColor: "yellow" + readonly property color statusBadColor: "red" } updateTab: QtObject { @@ -572,6 +576,7 @@ QtObject { readonly property string solidCirclePath: "qrc:///images/fontawesome/circle-solid.svg" readonly property string squareSolidPath: "qrc:///images/fontawesome/square-solid.svg" readonly property string swiftLogoPath: "qrc:///images/icon.png" + readonly property string swiftLogoWidePath: "qrc:///images/swiftLogoWide.svg" } insSettingsPopup: QtObject { diff --git a/resources/MainTab.qml b/resources/MainTab.qml new file mode 100644 index 000000000..efecffc6d --- /dev/null +++ b/resources/MainTab.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 + +Item { + property var subTabNames: [] + property int curSubTabIndex: -1 +} diff --git a/resources/MainTabs.qml b/resources/MainTabs.qml index bcb9ebc44..6b8fb0cd4 100644 --- a/resources/MainTabs.qml +++ b/resources/MainTabs.qml @@ -4,7 +4,11 @@ import QtQuick.Layouts 1.15 import SwiftConsole 1.0 Item { + id: mainTabs + property alias currentIndex: stackLayout.currentIndex + property var subTabNames: mainTabs.currentIndex < 0 ? [] : stackLayout.children[stackLayout.currentIndex].subTabNames + property int curSubTabIndex: -1 StackLayout { id: stackLayout @@ -12,24 +16,31 @@ Item { anchors.fill: parent TrackingTab { + curSubTabIndex: mainTabs.curSubTabIndex } SolutionTab { + curSubTabIndex: mainTabs.curSubTabIndex } BaselineTab { + curSubTabIndex: mainTabs.curSubTabIndex } ObservationTab { + curSubTabIndex: mainTabs.curSubTabIndex } SettingsTab { + curSubTabIndex: mainTabs.curSubTabIndex } UpdateTab { + curSubTabIndex: mainTabs.curSubTabIndex } AdvancedTab { + curSubTabIndex: mainTabs.curSubTabIndex } } diff --git a/resources/ObservationTab.qml b/resources/ObservationTab.qml index 61686cfe3..e1206c555 100644 --- a/resources/ObservationTab.qml +++ b/resources/ObservationTab.qml @@ -6,12 +6,9 @@ import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import SwiftConsole 1.0 -Item { +MainTab { id: observationTab - width: parent.width - height: parent.height - SplitView { id: observationView diff --git a/resources/SettingsTab.qml b/resources/SettingsTab.qml index 2073897a1..f1794bb47 100644 --- a/resources/SettingsTab.qml +++ b/resources/SettingsTab.qml @@ -1,15 +1,13 @@ import "Constants" import Qt.labs.platform 1.1 as LabsPlatform -import QtCharts 2.2 -import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Dialogs 1.3 import QtQuick.Layouts 1.15 import "SettingsTabComponents" as SettingsTabComponents import SwiftConsole 1.0 -Item { +MainTab { id: settingsTab function selectedRow() { @@ -40,9 +38,6 @@ Item { return text; } - width: parent.width - height: parent.height - SettingsTabData { id: settingsTabData } diff --git a/resources/SideNavBar.qml b/resources/SideNavBar.qml index 0ef266782..7f380cb90 100644 --- a/resources/SideNavBar.qml +++ b/resources/SideNavBar.qml @@ -9,6 +9,7 @@ Item { id: top property alias currentIndex: navButtons.currentIndex + property string currentTabName: top.currentIndex < 0 ? "" : tabModel[top.currentIndex].tooltip property bool enabled: true property var tabModel: [{ "name": "Tracking", @@ -23,7 +24,7 @@ Item { "tooltip": "Baseline", "source": Constants.sideNavBar.baselinePath }, { - "name": "Obs ", + "name": "Observations", "tooltip": "Observations", "source": Constants.sideNavBar.observationsPath }, { @@ -40,17 +41,22 @@ Item { "source": Constants.sideNavBar.advancedPath }] + function clickButton(index) { + navButtons.itemAtIndex(index).toggle(); + } + ConnectionData { id: connectionData } ColumnLayout { anchors.fill: parent + spacing: 0 Rectangle { Layout.fillWidth: true Layout.fillHeight: true - color: Constants.swiftGrey + color: Constants.sideNavBar.backgroundColor ButtonGroup { id: navButtonGroup @@ -67,18 +73,15 @@ Item { anchors.fill: parent model: tabModel - currentIndex: Globals.initialMainTabIndex + currentIndex: -1 enabled: top.enabled highlightMoveDuration: 200 highlightResizeDuration: 0 highlightFollowsCurrentItem: true - Component.onCompleted: { - currentItem.checked = true; - } highlight: Item { // TODO: This is an odd z order which depends on the Z order of some things in the buttons, refactor. - z: 6 + z: 11 Rectangle { height: 2 @@ -90,29 +93,29 @@ Item { } delegate: SideNavButton { + text: modelData.name + icon.source: modelData.source + ToolTip.text: modelData.tooltip buttonGroup: navButtonGroup + height: Constants.sideNavBar.tabBarHeight } } } - TabButton { + SideNavButton { id: connectButton Layout.alignment: Qt.AlignBottom - Layout.preferredWidth: Constants.sideNavBar.tabBarWidth - border: false + Layout.fillWidth: true + height: Constants.sideNavBar.tabBarHeight + text: "Connection" icon.source: Constants.icons.lightningBoltPath - icon.color: !enabled ? Constants.materialGrey : Constants.swiftOrange - backgroundColor: hovered ? Qt.darker("white", 1.1) : "white" - checkable: false - padding: Constants.sideNavBar.buttonPadding - rightInset: Constants.sideNavBar.buttonInset - leftInset: Constants.sideNavBar.buttonInset - ToolTip.visible: hovered ToolTip.text: "Connection Dialog" + checkable: false enabled: Globals.connected_at_least_once + silenceButtonGroupWarning: true onClicked: { if (stack.connectionScreenVisible()) stack.mainView(); @@ -121,13 +124,81 @@ Item { } } - Timer { - interval: Utils.hzToMilliseconds(Constants.staticTimerSlowIntervalRate) - running: true - repeat: true - onTriggered: { - connectButton.checked = Globals.conn_state == Constants.connection.connected; + Rectangle { + id: connectionStatusIndicator + + property real speed: 0 + + Layout.alignment: Qt.AlignBottom + Layout.fillWidth: true + height: Constants.sideNavBar.tabBarHeight + enabled: top.enabled + color: Constants.sideNavBar.backgroundColor + state: "bad" + states: [ + State { + name: "good" + + PropertyChanges { + target: connectionStatusCircle + color: Constants.sideNavBar.statusGoodColor + } + + }, + State { + name: "ok" + + PropertyChanges { + target: connectionStatusCircle + color: Constants.sideNavBar.statusOkColor + } + + }, + State { + name: "bad" + + PropertyChanges { + target: connectionStatusCircle + color: Constants.sideNavBar.statusBadColor + } + + } + ] + + Column { + anchors.centerIn: parent + spacing: 2 + + Label { + anchors.horizontalCenter: parent.horizontalCenter + bottomPadding: 0 + bottomInset: 0 + text: connectionStatusIndicator.speed + " KB/s" + font.pointSize: Constants.smallPointSize + font.letterSpacing: -1 + color: Qt.darker("white", enabled ? 1 : 1.4) + } + + Rectangle { + id: connectionStatusCircle + + property int diameter: 15 + + anchors.horizontalCenter: parent.horizontalCenter + width: diameter + height: diameter + radius: diameter / 2 + + Behavior on color { + ColorAnimation { + } + + } + + } + } + } } diff --git a/resources/SideNavBarComponents/SideNavButton.qml b/resources/SideNavBarComponents/SideNavButton.qml index 96dd5f086..7e7335232 100644 --- a/resources/SideNavBarComponents/SideNavButton.qml +++ b/resources/SideNavBarComponents/SideNavButton.qml @@ -12,25 +12,23 @@ Button { property QtObject buttonGroup property QtObject view: ListView.view + property bool separator: true + property bool silenceButtonGroupWarning: false ButtonGroup.group: buttonGroup - width: view.width - height: implicitHeight < width ? width : implicitHeight + width: view ? view.width : 0 z: visualFocus ? 10 : control.checked || control.highlighted ? 5 : 1 display: AbstractButton.TextUnderIcon checkable: true - text: modelData.name - ToolTip.text: modelData.tooltip + icon.width: 22 + icon.height: 22 + icon.color: control.checked || control.highlighted ? Qt.darker(Constants.swiftOrange, control.enabled ? 1 : 1.4) : control.flat && !control.down ? (control.visualFocus ? Constants.swiftOrange : control.palette.windowText) : Qt.darker("white", control.enabled ? 1 : 1.4) ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: ToolTip.text.length != 0 && hovered - icon.source: modelData.source - icon.width: 22 - icon.height: 22 - icon.color: control.checked || control.highlighted ? Qt.darker(Constants.swiftOrange, control.enabled ? 1 : 1.5) : control.flat && !control.down ? (control.visualFocus ? Constants.swiftOrange : control.palette.windowText) : Qt.darker("white", control.enabled ? 1 : 1.5) font.pointSize: Constants.smallPointSize font.capitalization: Font.MixedCase - font.letterSpacing: -1 + font.letterSpacing: 0 // No idea why the insets are set, but they need to be 0 so there are no gaps between buttons. topInset: 0 bottomInset: 0 @@ -42,7 +40,9 @@ Button { // 3 to match the new style mockups. spacing: 3 Component.onCompleted: { - console.assert(buttonGroup != undefined, "No buttonGroup assigned to SideNavButton! Undesired behavior will result."); + if (!silenceButtonGroupWarning) + console.assert(buttonGroup != undefined, "No buttonGroup assigned to SideNavButton! Undesired behavior will result."); + } contentItem: IconLabel { @@ -52,14 +52,14 @@ Button { icon: control.icon text: control.text font: control.font - color: control.checked || control.highlighted ? Qt.darker(control.palette.dark, control.enabled ? 1 : 1.5) : control.flat && !control.down ? (control.visualFocus ? Constants.swiftOrange : control.palette.windowText) : Qt.darker("white", control.enabled ? 1 : 1.5) + color: control.checked || control.highlighted ? Qt.darker(control.palette.dark, control.enabled ? 1 : 1.5) : control.flat && !control.down ? (control.visualFocus ? Constants.swiftOrange : control.palette.windowText) : Qt.darker("white", control.enabled ? 1 : 1.4) } background: Rectangle { implicitWidth: 100 implicitHeight: 40 visible: !control.flat || control.down || control.checked || control.highlighted - color: Color.blend(control.checked || control.highlighted ? Qt.darker("white", control.enabled ? 1 : 1.5) : Constants.swiftGrey, control.palette.mid, control.down ? 0.5 : 0) + color: Color.blend(control.checked || control.highlighted ? Qt.darker("white", control.enabled ? 1 : 1.4) : Constants.sideNavBar.backgroundColor, control.palette.mid, control.down ? 0.5 : 0) border.color: Constants.swiftOrange border.width: control.visualFocus ? 1 : 0 @@ -68,8 +68,8 @@ Button { anchors.right: parent.right anchors.bottom: parent.bottom height: 1 - color: Qt.darker("white", control.enabled ? 1 : 1.5) - visible: !control.visualFocus && !(control.view.itemAtIndex(index + 1) != null ? control.view.itemAtIndex(index + 1).visualFocus : false) + color: Qt.darker("white", control.enabled ? 1 : 1.4) + visible: control.separator && !control.visualFocus && !(control.view && control.view.itemAtIndex(index + 1) ? control.view.itemAtIndex(index + 1).visualFocus : false) } Repeater { diff --git a/resources/SolutionTab.qml b/resources/SolutionTab.qml index bbb4e6edd..047807591 100644 --- a/resources/SolutionTab.qml +++ b/resources/SolutionTab.qml @@ -1,16 +1,15 @@ import "Constants" import QtCharts 2.2 import QtQuick 2.5 -import QtQuick.Controls 2.12 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import "SolutionTabComponents" as SolutionTabComponents -Item { +MainTab { id: solutionTab - width: parent.width - height: parent.height + subTabNames: ["Position", "Velocity"] + curSubTabIndex: Globals.initialMainTabIndex == 1 ? Globals.initialSubTabIndex : 0 SplitView { id: solutionSplitView @@ -19,56 +18,21 @@ Item { orientation: Qt.Horizontal SolutionTabComponents.SolutionTable { - width: Constants.solutionTable.width + SplitView.minimumWidth: 240 } - Rectangle { - id: solutionPlots + StackLayout { + id: solutionBarLayout - Layout.minimumWidth: 200 - Layout.fillWidth: true - - TabBar { - id: solutionBar - - currentIndex: Globals.initialMainTabIndex == 1 ? Globals.initialSubTabIndex : 0 - z: Constants.commonChart.zAboveCharts - contentHeight: Constants.tabBarHeight - - Repeater { - model: ["Position", "Velocity"] - - TabButton { - text: modelData - width: implicitWidth - } - - } + SplitView.minimumWidth: 410 + SplitView.fillWidth: true + SplitView.fillHeight: true + currentIndex: curSubTabIndex + SolutionTabComponents.SolutionPositionTab { } - Rectangle { - id: solutionTabBackground - - width: parent.width - height: parent.height - anchors.top: solutionBar.bottom - - StackLayout { - id: solutionBarLayout - - width: parent.width - height: parent.height - currentIndex: solutionBar.currentIndex - - SolutionTabComponents.SolutionPositionTab { - } - - SolutionTabComponents.SolutionVelocityTab { - } - - } - + SolutionTabComponents.SolutionVelocityTab { } } diff --git a/resources/SolutionTabComponents/SolutionTable.qml b/resources/SolutionTabComponents/SolutionTable.qml index eedd7832b..61ae30840 100644 --- a/resources/SolutionTabComponents/SolutionTable.qml +++ b/resources/SolutionTabComponents/SolutionTable.qml @@ -26,6 +26,8 @@ Item { } + implicitWidth: Constants.solutionTable.width + SolutionTableEntries { id: solutionTableEntries } diff --git a/resources/TabInfoBar.qml b/resources/TabInfoBar.qml new file mode 100644 index 000000000..31cc5bd84 --- /dev/null +++ b/resources/TabInfoBar.qml @@ -0,0 +1,184 @@ +import "Constants" +import QtQuick 2.5 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import SwiftConsole 1.0 + +Rectangle { + id: tabInfoBar + + property string tabName: "Tracking" + property var subTabNames: ["Hello World", "Foo Bar", "Quux Quuux"] + property alias curSubTabIndex: tabBar.currentIndex + property int rhsItemSpacing: 15 + + signal aboutClicked() + + implicitHeight: rowLayout.implicitHeight + implicitWidth: rowLayout.implicitWidth + + // Top grey line separating the bar from the window title area + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + height: 1 + color: "#C2C2C2" + z: 2 + } + + // Bottom grey line separating the bar from the main tab area + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: 1 + color: "#C2C2C2" + z: 2 + } + + RowLayout { + id: rowLayout + + anchors.fill: parent + spacing: 0 + + Label { + id: tabLabel + + Layout.fillWidth: false + padding: 8 + leftPadding: 13 + rightPadding: 13 + text: tabName + color: Constants.swiftOrange + font.family: "Roboto Condensed" + font.capitalization: Font.AllUppercase + font.letterSpacing: 1 + font.pointSize: 20 + font.bold: true // Could also try playing with font.weight + } + + TabBar { + id: tabBar + + visible: tabBarRepeater.count > 0 + Layout.fillWidth: false + spacing: 1 + + Repeater { + id: tabBarRepeater + + model: subTabNames + + TabButton { + width: implicitWidth + topPadding: 16 + bottomPadding: 16 + rightInset: -0.5 + text: modelData + border: false + } + + } + + } + + // Spacer item + Item { + implicitHeight: tabBar.implicitHeight + Layout.fillWidth: true + } + + Item { + implicitWidth: children[0].implicitWidth + rhsItemSpacing + Layout.fillHeight: true + + Image { + anchors.top: parent.top + anchors.topMargin: 7 + anchors.bottom: parent.bottom + anchors.bottomMargin: 7 + source: Constants.icons.swiftLogoWidePath + fillMode: Image.PreserveAspectFit + } + + } + + Rectangle { + Layout.fillHeight: true + Layout.topMargin: 7 + Layout.bottomMargin: 7 + width: 1 + color: "#C2C2C2" + Layout.alignment: Qt.AlignVCenter + } + + Label { + leftPadding: rhsItemSpacing + rightPadding: rhsItemSpacing + text: "Console" + color: Constants.swiftLightGrey + font.family: "Roboto Condensed" + font.capitalization: Font.AllUppercase + font.letterSpacing: 2 + font.pointSize: 20 + } + + Rectangle { + Layout.fillHeight: true + Layout.topMargin: 7 + Layout.bottomMargin: 7 + width: 1 + color: "#C2C2C2" + Layout.alignment: Qt.AlignVCenter + } + + Item { + implicitWidth: children[0].implicitWidth + rhsItemSpacing * 4 / 3 + Layout.fillHeight: true + + RoundButton { + anchors.centerIn: parent + flat: true + icon.source: Constants.infoPath + icon.width: 20 + icon.height: 20 + icon.color: Constants.swiftLightGrey + padding: rhsItemSpacing / 3 + onClicked: tabInfoBar.aboutClicked() + } + + } + + } + + // Add in single-line separators between the items. + Repeater { + model: tabInfoBar.tabName.length > 0 ? tabBar.count + 1 : 0 + + Rectangle { + property var tabButton: tabBar.itemAt(index) + + height: rowLayout.height + width: 1 + color: "#C2C2C2" + x: tabBar.count > 0 ? tabBar.x + (tabButton ? tabButton.x - 1 : tabBar.width) : tabLabel.x + tabLabel.width + } + + } + + gradient: Gradient { + GradientStop { + position: 0 + color: "white" + } + + GradientStop { + position: 1 + color: Constants.swiftControlBackground + } + + } + +} diff --git a/resources/Theme/Theme.qml b/resources/Theme/Theme.qml deleted file mode 100644 index 4ccd822d5..000000000 --- a/resources/Theme/Theme.qml +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of The Qt Company Ltd 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 -** OWNER 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.12 -pragma Singleton - -QtObject { - readonly property color gray: "#b2b1b1" - readonly property color lightGray: "#dddddd" - readonly property color light: "#ffffff" - readonly property color blue: "#2d548b" - property color mainColor: "#17a81a" - readonly property color dark: "#222222" - readonly property color mainColorDarker: Qt.darker(mainColor, 1.5) - property int baseSize: 10 - readonly property int smallSize: 10 - readonly property int largeSize: 16 - property font font - - font.bold: true - font.underline: false - font.pixelSize: 14 - font.family: "arial" -} diff --git a/resources/Theme/qmldir b/resources/Theme/qmldir deleted file mode 100644 index 4a58c13a9..000000000 --- a/resources/Theme/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module Theme -singleton Theme 1.0 Theme.qml diff --git a/resources/TrackingTab.qml b/resources/TrackingTab.qml index fb851c119..e3fc86850 100644 --- a/resources/TrackingTab.qml +++ b/resources/TrackingTab.qml @@ -1,64 +1,26 @@ import "Constants" import QtCharts 2.2 import QtQuick 2.5 -import QtQuick.Controls 2.12 +import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import "TrackingTabComponents" as TrackingTabComponents -Item { +MainTab { id: trackingTab - width: parent.width - height: parent.height + subTabNames: ["Signals", "Sky Plot"] + curSubTabIndex: Globals.initialMainTabIndex == 0 ? Globals.initialSubTabIndex : 0 - TabBar { - id: trackingBar + StackLayout { + id: trackingBarLayout - anchors.left: parent.left - anchors.right: parent.right - z: Constants.commonChart.zAboveCharts - currentIndex: Globals.initialMainTabIndex == 0 ? Globals.initialSubTabIndex : 0 - contentHeight: Constants.tabBarHeight - - Repeater { - model: ["Signals", "Sky Plot"] - - TabButton { - text: modelData - width: implicitWidth - } + anchors.fill: parent + currentIndex: curSubTabIndex + TrackingTabComponents.TrackingSignalsTab { } - } - - Rectangle { - id: trackingTabBackground - - width: parent.width - height: parent.height - anchors.top: trackingBar.bottom - anchors.bottom: trackingTab.bottom - Component.onCompleted: { - } - - StackLayout { - id: trackingBarLayout - - width: parent.width - height: parent.height - currentIndex: trackingBar.currentIndex - - TrackingTabComponents.TrackingSignalsTab { - Layout.fillWidth: true - Layout.fillHeight: true - } - - TrackingTabComponents.TrackingSkyPlotTab { - Layout.fillWidth: true - Layout.fillHeight: true - } - + TrackingTabComponents.TrackingSkyPlotTab { } } diff --git a/resources/UpdateTab.qml b/resources/UpdateTab.qml index c0b3d48d9..112919d63 100644 --- a/resources/UpdateTab.qml +++ b/resources/UpdateTab.qml @@ -5,7 +5,7 @@ import QtQuick.Layouts 1.15 import SwiftConsole 1.0 import "UpdateTabComponents" as UpdateTabComponents -Item { +MainTab { id: updateTab property bool consoleVersionDialogAlready: false @@ -51,9 +51,6 @@ Item { return text; } - width: parent.width - height: parent.height - UpdateTabData { id: updateTabData } diff --git a/resources/console_resources.qrc b/resources/console_resources.qrc index f503d316a..786f7e94f 100644 --- a/resources/console_resources.qrc +++ b/resources/console_resources.qrc @@ -4,6 +4,7 @@ fonts/Roboto-LICENSE.txt fonts/Roboto-Regular.ttf fonts/Roboto-Bold.ttf + fonts/RobotoCondensed-Regular.ttf view.qml MainDialogView.qml MainTabs.qml @@ -71,12 +72,14 @@ images/fontawesome/bars-solid.svg images/fontawesome/play-solid.svg images/fontawesome/power-off-solid.svg + images/fontawesome/info-circle-solid.svg images/iconic/media-pause.svg images/fontawesome/crosshairs-solid.svg images/fontawesome/eraser-solid.svg images/fontawesome/expand-solid.svg images/ConnectionIcon.svg images/LogoBackground.jpg + images/swiftLogoWide.svg images/fontawesome/folder-open-regular.svg images/fontawesome/folder-solid.svg images/fontawesome/square-solid.svg @@ -101,9 +104,10 @@ BaseComponents/SmallCheckBox.qml BaseComponents/SwiftGroupBox.qml ChartLegend.qml - Theme/qmldir - Theme/Theme.qml styles/SwiftNav/TabBar.qml styles/SwiftNav/TabButton.qml + styles/SwiftNav/RoundButton.qml + MainTab.qml + TabInfoBar.qml diff --git a/resources/fonts/RobotoCondensed-Regular.ttf b/resources/fonts/RobotoCondensed-Regular.ttf new file mode 100644 index 000000000..62dd61e5d Binary files /dev/null and b/resources/fonts/RobotoCondensed-Regular.ttf differ diff --git a/resources/images/fontawesome/info-circle-solid.svg b/resources/images/fontawesome/info-circle-solid.svg new file mode 100644 index 000000000..5cf096d17 --- /dev/null +++ b/resources/images/fontawesome/info-circle-solid.svg @@ -0,0 +1 @@ + diff --git a/resources/images/swiftLogoWide.svg b/resources/images/swiftLogoWide.svg new file mode 100644 index 000000000..0cddc1527 --- /dev/null +++ b/resources/images/swiftLogoWide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/styles/SwiftNav/RoundButton.qml b/resources/styles/SwiftNav/RoundButton.qml new file mode 100644 index 000000000..bb1421a49 --- /dev/null +++ b/resources/styles/SwiftNav/RoundButton.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Controls.impl 2.12 +import QtQuick.Templates 2.12 as T + +T.RoundButton { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding) + padding: 6 + spacing: 6 + icon.width: 24 + icon.height: 24 + icon.color: control.checked || control.highlighted ? control.palette.brightText : control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText + + contentItem: IconLabel { + spacing: control.spacing + mirrored: control.mirrored + display: control.display + icon: control.icon + text: control.text + font: control.font + color: control.checked || control.highlighted ? control.palette.brightText : control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText + } + + background: Rectangle { + implicitWidth: control.icon.width + 2 + implicitHeight: control.icon.height + 2 + radius: control.radius + opacity: enabled ? 1 : 0.3 + visible: !control.flat || control.down || control.checked || control.highlighted + color: Color.blend(control.checked || control.highlighted ? control.palette.dark : control.palette.button, control.palette.mid, control.down ? 0.5 : 0) + border.color: control.palette.highlight + border.width: control.visualFocus ? 2 : 0 + } + +} diff --git a/resources/styles/SwiftNav/TabBar.qml b/resources/styles/SwiftNav/TabBar.qml index cb258f4c2..d32125b91 100644 --- a/resources/styles/SwiftNav/TabBar.qml +++ b/resources/styles/SwiftNav/TabBar.qml @@ -10,7 +10,6 @@ T.TabBar { implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding) implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding) - spacing: -1 contentItem: ListView { model: control.contentModel @@ -31,9 +30,8 @@ T.TabBar { z: 2 Rectangle { - x: 1 height: 2 - width: parent.width - 2 + width: parent.width y: control.position === T.TabBar.Footer ? 0 : parent.height - height color: control.Material.accentColor } @@ -55,22 +53,6 @@ T.TabBar { } - Rectangle { - z: 2 - anchors.top: parent.top - width: parent.width - height: 1 - color: "#C2C2C2" - } - - Rectangle { - z: 2 - anchors.bottom: parent.bottom - width: parent.width - height: 1 - color: "#C2C2C2" - } - } } diff --git a/resources/styles/SwiftNav/TabButton.qml b/resources/styles/SwiftNav/TabButton.qml index 2d242f3fd..42cc76520 100644 --- a/resources/styles/SwiftNav/TabButton.qml +++ b/resources/styles/SwiftNav/TabButton.qml @@ -46,6 +46,7 @@ T.TabButton { id: control property color labelColor: !control.enabled ? control.Material.hintTextColor : control.down || control.checked ? "white" : Constants.tabButtonUnselectedTextColor + property color gradientStartColor: down || checked ? Qt.lighter(Constants.swiftGrey, 1.7) : hovered ? Qt.lighter(Constants.swiftControlBackground, 1.1) : "white" property color backgroundColor: down || checked ? Constants.swiftGrey : hovered ? Qt.darker(Constants.swiftControlBackground, 1.1) : Constants.swiftControlBackground property bool border: true @@ -79,6 +80,20 @@ T.TabButton { implicitHeight: control.Material.touchTarget clip: true color: backgroundColor + + gradient: Gradient { + GradientStop { + position: 0 + color: gradientStartColor + } + + GradientStop { + position: 1 + color: backgroundColor + } + + } + } } diff --git a/resources/view.qml b/resources/view.qml index 4ab5237f8..a81b3c49e 100644 --- a/resources/view.qml +++ b/resources/view.qml @@ -1,8 +1,7 @@ import "Constants" -import QtCharts 2.2 -import QtQuick 2.5 +import QtQuick 2.15 import QtQuick.Controls 2.15 -import QtQuick.Controls.Material 2.12 +import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import SwiftConsole 1.0 @@ -29,10 +28,182 @@ ApplicationWindow { anchors.fill: parent } + MouseArea { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + z: 1 + height: 30 + visible: tabInfoBar.state == "closed" + hoverEnabled: true + acceptedButtons: Qt.NoButton + onPositionChanged: tabInfoBarOpenTimer.restart() + onExited: tabInfoBarOpenTimer.stop() + + Timer { + id: tabInfoBarOpenTimer + + interval: 200 + onTriggered: tabInfoBar.open() + } + + } + + TabInfoBar { + id: tabInfoBar + + property int openDuration: 1000 + property int closeDuration: 350 + + function open() { + state = "opened"; + } + + function close() { + state = "closed"; + } + + function cancelAutoClose() { + tabInfoBarCloseTimer.stop(); + } + + function closeAfterDelaySubtabless() { + if (tabName.length > 0 && subTabNames.length == 0) + tabInfoBarCloseTimer.restart(); + else + cancelAutoClose(); + } + + // We explicitly do not anchor in the vertical, so the item can + // be slid up "under" the window. + anchors.left: parent.left + anchors.right: parent.right + z: 2 + tabName: sideNavBar.currentTabName + subTabNames: mainTabs.subTabNames + state: "opened" + onAboutClicked: logoPopup.open() + // When the tab name changes, make sure this item is shown. + // If there is no subtabs, then close it after some time. + onTabNameChanged: { + open(); + closeAfterDelaySubtabless(); + } + states: [ + // The opened state sets the y position so the item is + // positioned so it's top is right at the top of the parent + // item. + State { + name: "opened" + + PropertyChanges { + target: tabInfoBar + y: 0 + } + + }, + // The closed state sets the y position so the item is + // positioned so it's bottom is right at the top of the + // parent item, and all but one pixel height of the item is + // hidden. One pixel is still shown so there is a border + // line at the top of the view. + State { + name: "closed" + + PropertyChanges { + target: tabInfoBar + y: -height + 1 + } + + } + ] + // Make the opened/closed state transitions smooth. + transitions: [ + Transition { + from: "opened" + to: "closed" + + NumberAnimation { + target: tabInfoBar + properties: "y" + duration: tabInfoBar.closeDuration + easing.type: Easing.OutQuad + } + + }, + Transition { + from: "closed" + to: "opened" + + NumberAnimation { + target: tabInfoBar + properties: "y" + duration: tabInfoBar.openDuration + easing.type: Easing.OutQuad + } + + } + ] + + Timer { + id: tabInfoBarCloseTimer + + interval: 3000 + onTriggered: parent.close() + } + + // This captures any clicks outside of the buttons, and toggles + // the state from opened to closed or vice versa. + MouseArea { + anchors.fill: parent + z: -1 + onClicked: parent.state = parent.state == "opened" ? "closed" : "opened" + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + onEntered: parent.cancelAutoClose() + onExited: parent.closeAfterDelaySubtabless() + } + + } + + Rectangle { + anchors.right: parent.right + anchors.rightMargin: 5 + y: -3 + z: 1 + implicitHeight: tabInfoBarOpenText.implicitHeight + 9 + implicitWidth: 30 + color: Constants.swiftControlBackground + radius: 3 + + Text { + id: tabInfoBarOpenText + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 3 + text: "▼" + color: Constants.swiftLightGrey + } + + MouseArea { + anchors.fill: parent + onClicked: tabInfoBar.open() + } + + } + RowLayout { property alias stackView: dialogStack.dialogStack - anchors.fill: parent + anchors.left: parent.left + anchors.right: parent.right + anchors.top: tabInfoBar.bottom + anchors.bottom: parent.bottom spacing: 0 SideNavBar { @@ -55,6 +226,9 @@ ApplicationWindow { } function mainView() { + if (sideNavBar.currentIndex < 0) + sideNavBar.clickButton(Globals.initialMainTabIndex); + stack.currentIndex = 1; } @@ -83,6 +257,7 @@ ApplicationWindow { MainTabs { id: mainTabs + curSubTabIndex: tabInfoBar.curSubTabIndex SplitView.fillHeight: true SplitView.fillWidth: true Layout.leftMargin: Constants.margins diff --git a/swiftnav_console/main.py b/swiftnav_console/main.py index 625b40699..6255817f8 100644 --- a/swiftnav_console/main.py +++ b/swiftnav_console/main.py @@ -801,6 +801,8 @@ def main(): app.setApplicationName(ApplicationMetadata.APPLICATION_NAME) QFontDatabase.addApplicationFont(":/fonts/Roboto-Regular.ttf") QFontDatabase.addApplicationFont(":/fonts/Roboto-Bold.ttf") + QFontDatabase.addApplicationFont(":/fonts/RobotoCondensed-Regular.ttf") + # We specifically *don't* want the RobotoCondensed-Bold.ttf font so we get the right look when bolded. qmlRegisterType(LogPanelData, "SwiftConsole", 1, 0, "LogPanelData") # type: ignore qmlRegisterType(ConnectionData, "SwiftConsole", 1, 0, "ConnectionData") # type: ignore