Revision control
Copy as Markdown
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
pragma ComponentBehavior: Bound
import QtPositioning
import QtQuick
import QtQuick.Controls.Basic as QC
import QtQuick.Layouts
import SatelliteInformation
Rectangle {
id: root
signal cleanupFocus
required property SortFilterModel sortFilterModel
required property color inViewColor
required property color inUseColor
readonly property int iconItemWidth: 50
color: Theme.darkBackgroundColor
property var satelliteSystemModel: [
{"name": "GPS", "id": GeoSatelliteInfo.GPS},
{"name": "GLONASS", "id": GeoSatelliteInfo.GLONASS},
{"name": "GALILEO", "id": GeoSatelliteInfo.GALILEO},
{"name": "BEIDOU", "id": GeoSatelliteInfo.BEIDOU},
{"name": "QZSS", "id": GeoSatelliteInfo.QZSS},
{"name": "IRNSS", "id": GeoSatelliteInfo.IRNSS},
{"name": "SBAS", "id": GeoSatelliteInfo.SBAS}
]
component RssiElement : Rectangle {
id: rssiRoot
required property int rssi
implicitHeight: rssiVal.implicitHeight
implicitWidth: rssiVal.implicitWidth + dbm.implicitWidth + rssiLayout.spacing
color: "transparent"
RowLayout {
id: rssiLayout
anchors.fill: parent
spacing: 2
Text {
id: rssiVal
text: rssiRoot.rssi >= 0 ? rssiRoot.rssi : qsTr("N/A")
color: Theme.textSecondaryColor
font.pixelSize: Theme.smallFontSize
font.weight: Theme.fontDefaultWeight
}
Text{
id: dbm
visible: rssiRoot.rssi >= 0
text: qsTr("dBm")
color: Theme.textGrayColor
font.pixelSize: Theme.smallFontSize
font.weight: Theme.fontDefaultWeight
}
}
}
component StatusElement : Rectangle {
id: statusRoot
required property bool inUse
implicitHeight: statusText.implicitHeight
implicitWidth: statusText.implicitWidth + statusIcon.implicitWidth + statusLayout.spacing
color: "transparent"
RowLayout {
id: statusLayout
anchors.fill: parent
spacing: Theme.defaultSpacing
Rectangle {
id: statusIcon
implicitHeight: statusText.font.pixelSize
implicitWidth: implicitHeight
radius: height / 2
color: statusRoot.inUse ? root.inUseColor : root.inViewColor
}
Text {
id: statusText
text: statusRoot.inUse ? qsTr("In Use") : qsTr("In View")
color: Theme.textSecondaryColor
font.pixelSize: Theme.smallFontSize
font.weight: Theme.fontLightWeight
}
}
}
RssiElement {
id: hiddenRssiElement
rssi: 999
visible: false
}
StatusElement {
id: hiddenStatusElement
inUse: false
visible: false
}
component ListHeader : Rectangle {
implicitHeight: identifierHdr.height
color: root.color
RowLayout {
anchors {
fill: parent
leftMargin: Theme.defaultSpacing * 2
rightMargin: Theme.defaultSpacing * 2
}
spacing: Theme.defaultSpacing * 2
Item {
id: blank
implicitWidth: root.iconItemWidth
}
Text {
id: identifierHdr
text: qsTr("Identifier")
color: Theme.textSecondaryColor
font.pixelSize: Theme.mediumFontSize
font.weight: Theme.fontDefaultWeight
Layout.fillWidth: true
}
Text {
id: rssiHdr
text: qsTr("RSSI")
color: Theme.textSecondaryColor
font.pixelSize: Theme.mediumFontSize
font.weight: Theme.fontDefaultWeight
Layout.preferredWidth: hiddenRssiElement.width
}
Text {
id: statusHdr
text: qsTr("Status")
color: Theme.textSecondaryColor
font.pixelSize: Theme.mediumFontSize
font.weight: Theme.fontDefaultWeight
Layout.preferredWidth: hiddenStatusElement.width
}
}
Rectangle {
anchors.bottom: parent.bottom
height: 1
width: parent.width
color: Theme.tableSeparatorColor
}
}
component ListItem : Rectangle {
id: listItem
required property int index
required property var modelData
color: "transparent"
RowLayout {
anchors {
fill: parent
leftMargin: Theme.defaultSpacing * 2
rightMargin: Theme.defaultSpacing * 2
}
spacing: Theme.defaultSpacing * 2
Rectangle {
implicitWidth: root.iconItemWidth
color: "transparent"
Image {
anchors.centerIn: parent
source: listItem.index % 2 === 0 ? "icons/satellite1.png"
: "icons/satellite2.png"
}
}
Text {
text: listItem.modelData.system + "-" + listItem.modelData.id
color: Theme.textMainColor
font.pixelSize: Theme.mediumFontSize
font.weight: Theme.fontDefaultWeight
Layout.fillWidth: true
}
RssiElement {
rssi: listItem.modelData.rssi
Layout.preferredWidth: hiddenRssiElement.width
}
StatusElement {
inUse: listItem.modelData.inUse
Layout.preferredWidth: hiddenStatusElement.width
}
}
Rectangle {
anchors.bottom: parent.bottom
height: 1
width: parent.width
color: Theme.tableSeparatorColor
}
}
component SearchInput : QC.TextField {
id: searchInput
palette {
placeholderText: Theme.grayColor
text: Theme.textMainColor
}
rightPadding: padding + searchIcon.width + searchIcon.anchors.rightMargin
font.pixelSize: Theme.smallFontSize
font.weight: Theme.fontLightWeight
background: Rectangle {
border {
width: 1
color:Theme.searchBorderColor
}
color: "transparent"
radius: 3
Image {
id: searchIcon
anchors {
right: parent.right
rightMargin: Theme.defaultSpacing
verticalCenter: parent.verticalCenter
}
source: "icons/search.svg"
sourceSize.height: searchInput.implicitHeight - searchInput.padding * 2
fillMode: Image.PreserveAspectFit
}
}
}
component IconButton : QC.ToolButton {
id: iconButton
property bool selected: false
icon.width: 0
icon.height: 0
icon.color: selected ? Theme.greenColor : Theme.grayColor
background: Rectangle {
border {
width: 1
color: iconButton.selected ? Theme.greenColor : Theme.searchBorderColor
}
color: "transparent"
radius: 3
}
}
component MenuPopup : QC.Popup {
modal: true
background: Rectangle {
radius: 8
color: Theme.backgroundColor
border {
width: 1
color: Theme.separatorColor
}
}
}
component CheckElement : QC.ItemDelegate {
id: checkElement
readonly property int iconSize: font.pixelSize * 2
checked: true
padding: 0
display: QC.AbstractButton.TextBesideIcon
font.pixelSize: Theme.smallFontSize
font.weight: Theme.fontLightWeight
palette.text: checked ? Theme.greenColor : Theme.textSecondaryColor
icon.source: checked ? "icons/checkbox.svg" : "icons/checkbox_blank.svg"
icon.height: iconSize
icon.width: iconSize
icon.color: checked ? Theme.greenColor : Theme.textSecondaryColor
LayoutMirroring.enabled: true
LayoutMirroring.childrenInherit: true
background: Rectangle {
anchors.fill: parent
color: "transparent"
}
onClicked: {
checked = !checked
}
}
Rectangle {
id: sortAndFilter
width: root.width
height: searchField.implicitHeight + sortAndFilterLayout.anchors.margins * 2
color: Theme.backgroundColor
RowLayout {
id: sortAndFilterLayout
anchors {
fill: parent
margins: Theme.defaultSpacing * 2
}
spacing: Theme.defaultSpacing * 2
SearchInput {
id: searchField
placeholderText: qsTr("Search")
Layout.fillWidth: true
onTextChanged: root.sortFilterModel.updateFilterString(text);
onVisibleChanged: {
if (!visible && activeFocus)
root.cleanupFocus()
}
}
IconButton {
selected: sortMenu.visible
icon.source: "icons/sort.svg"
rotation: 90
Layout.preferredHeight: searchField.implicitHeight
Layout.preferredWidth: Layout.preferredHeight
onClicked: sortMenu.open()
}
IconButton {
selected: filterMenu.visible
icon.source: "icons/filter.svg"
Layout.preferredHeight: searchField.implicitHeight
Layout.preferredWidth: Layout.preferredHeight
onClicked: filterMenu.open()
}
}
}
Rectangle {
id: separator
anchors.top: sortAndFilter.bottom
color: Theme.separatorColor
height: 1
width: root.width
}
ListView {
id: satellitesView
anchors {
top: separator.bottom
bottom: root.bottom
}
width: root.width
clip: true
model: root.sortFilterModel
header: ListHeader {
height: 30
width: root.width
z: 2 // to show on top of the items
}
headerPositioning: ListView.OverlayHeader
delegate: ListItem {
height: 50
width: root.width
}
}
MenuPopup {
id: sortMenu
x: root.width - sortMenu.width - Theme.defaultSpacing
y: satellitesView.y - Theme.defaultSpacing
ColumnLayout {
anchors.fill: parent
spacing: Theme.defaultSpacing
CheckElement {
checked: false
text: qsTr("By Identifier")
Layout.alignment: Qt.AlignRight
onCheckedChanged: {
root.sortFilterModel.updateSortRoles(Roles.SystemRole, checked)
}
}
CheckElement {
checked: false
text: qsTr("By Status")
Layout.alignment: Qt.AlignRight
onCheckedChanged: {
root.sortFilterModel.updateSortRoles(Roles.InUseRole, checked)
}
}
}
}
MenuPopup {
id: filterMenu
x: root.width - filterMenu.width - Theme.defaultSpacing
y: satellitesView.y - Theme.defaultSpacing
ColumnLayout {
id: filterLayout
anchors.fill: parent
spacing: Theme.defaultSpacing
Text {
text: qsTr("Satellite Identifier")
color: Theme.textMainColor
font.pixelSize: Theme.mediumFontSize
font.weight: Theme.fontDefaultWeight
Layout.alignment: Qt.AlignRight
}
//! [0]
Repeater {
model: root.satelliteSystemModel
delegate: CheckElement {
required property var modelData
text: modelData.name
Layout.alignment: Qt.AlignRight
onCheckedChanged: {
root.sortFilterModel.updateSelectedSystems(modelData.id, checked)
}
}
}
//! [0]
Text {
text: qsTr("Satellite Status")
color: Theme.textMainColor
font.pixelSize: Theme.mediumFontSize
font.weight: Theme.fontDefaultWeight
Layout.alignment: Qt.AlignRight
}
//! [1]
CheckElement {
text: qsTr("In View")
Layout.alignment: Qt.AlignRight
onCheckedChanged: root.sortFilterModel.updateShowInView(checked)
}
CheckElement {
text: qsTr("In Use")
Layout.alignment: Qt.AlignRight
onCheckedChanged: root.sortFilterModel.updateShowInUse(checked)
}
//! [1]
}
}
}