Artemis 4 RC1

This commit is contained in:
Marco Dalla Tiezza
2024-05-28 22:40:45 +02:00
parent acc44c93b3
commit 528c816508
254 changed files with 14757 additions and 30137 deletions

48
ui/About.qml Normal file
View File

@@ -0,0 +1,48 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Window
import QtQuick.Controls.Material
Dialog {
x: (parent.width - width) / 2
y: (parent.height - height) / 2
property int currentYear: new Date().getFullYear()
modal: true
RowLayout {
Layout.fillWidth: true
spacing: 10
Image {
Layout.alignment: Qt.AlignCenter
sourceSize.height: 80
sourceSize.width: 80
source: "qrc:///images/artemis_icon.svg"
}
Label {
text: "<style>a { color: " + Material.accent + "; }</style>" +
"<p><b>Artemis</a> " + APPLICATION_VERSION + "</b></p>" +
"<p>" + "<a href=\"https://github.com/AresValley/Artemis\">ARTEMIS</a> " +
qsTr("- The Radio Signals Recognition Manual") + "<br/>" +
"Powered By Python " + PYTHON_VERSION + " & Qt " + QT_VERSION + "</p>" +
"<p>Copyright (c) 2014-" + currentYear + " <a href=\"https://aresvalley.com\">" + qsTr("AresValley") +
"</a> GPLv3 License</p>"
Layout.fillWidth: true
Layout.minimumWidth: 200
textFormat: Text.RichText
wrapMode: Text.WordWrap
onLinkActivated: (link) => {
Qt.openUrlExternally(link)
}
}
}
}

450
ui/Artemis.qml Normal file
View File

@@ -0,0 +1,450 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
import QtQuick.Dialogs
Window {
id: window
width: 1100
height: 800
Component.onCompleted: {
x = Screen.width/2 - width/2
y = Screen.height/2 - height/2
}
title: qsTr("Artemis")
visible: true
modality: Qt.ApplicationModal
flags: Qt.Window
// Windows without upper bar
//flags: Qt.FramelessWindowHint
signal loadSignal(int signalId)
signal showPref()
signal showDBmanager()
signal showCatManager()
signal openSigEditor(string type, var sig_param, bool is_new)
signal showSpaceWeather()
signal checkDbUpdates()
signal startDownloader()
signal openDbDirectory()
signal newDb(string name)
signal exportDb(string path)
signal importDb(string path)
property var loadedList
function populateList(signalsList) {
loadedList = signalsList
textFieldSearch.enabled = true
var currentIndex = listView.currentIndex
refreshList()
// Set the currentIndex back after refreshing the list
if (currentIndex >= 0 && currentIndex < listModel.count) {
listView.currentIndex = currentIndex
}
}
function refreshList() {
listModel.clear()
for (var i = 0; i < loadedList.length; i++) {
var name = loadedList[i].name.toLowerCase()
var search = textFieldSearch.text.toLowerCase()
if (name.includes(search)) {
listModel.append(loadedList[i])
}
}
itemChangedList()
}
function itemChangedList() {
var selected_sig = listModel.get(listView.currentIndex)
if (selected_sig !== undefined) {
loadSignal(listModel.get(listView.currentIndex).SIG_ID)
editSignalMenu.enabled = true
} else {
editSignalMenu.enabled = false
}
}
function clearList() {
listModel.clear()
loadedList = []
textFieldSearch.clear()
textFieldSearch.enabled = false
}
function lockMenu(toggle) {
if (toggle) {
openFileMenu.enabled = false
exportFileMenu.enabled = false
newSignalMenu.enabled = false
editCategoryMenu.enabled = false
} else {
openFileMenu.enabled = true
exportFileMenu.enabled = true
newSignalMenu.enabled = true
editCategoryMenu.enabled = true
}
}
function bottomInfoBar(message, messageType) {
bottomInfoLabel.text = message
switch (messageType) {
case "warning":
bottomInfoLabel.color = Material.color(Material.Red)
break
case "info":
bottomInfoLabel.color = Material.foreground
break
}
}
function openGeneralDialog(messageType, title, message) {
dialogGeneral.messageType = messageType
dialogGeneral.title = title
dialogGeneral.message = message
dialogGeneral.open()
}
function openDialogDownloadDb(messageType, title, message) {
dialogDownloadDb.messageType = messageType
dialogDownloadDb.title = title
dialogDownloadDb.message = message
dialogDownloadDb.open()
}
function openDialogDownloadArtemis(messageType, title, message) {
dialogDownloadArtemis.messageType = messageType
dialogDownloadArtemis.title = title
dialogDownloadArtemis.message = message
dialogDownloadArtemis.open()
}
DialogMessage {
id: dialogDownloadDb
modal: true
standardButtons: Dialog.Cancel | Dialog.Yes
onAccepted: {
startDownloader()
}
}
DialogMessage {
id: dialogDownloadArtemis
modal: true
standardButtons: Dialog.Cancel | Dialog.Yes
onAccepted: {
Qt.openUrlExternally("https://github.com/AresValley/Artemis")
}
}
DialogMessage {
id: dialogGeneral
modal: true
standardButtons: Dialog.Ok
}
Dialog {
id: dialogNewDb
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
standardButtons: Dialog.Ok | Dialog.Cancel
ColumnLayout {
anchors.fill: parent
TextField {
id: newDbName
Layout.fillWidth: true
placeholderText: qsTr("New DB Name")
}
}
onAccepted: {
newDb(newDbName.text)
}
}
FileDialog {
id: exportDialog
title: "Please choose a save folder..."
fileMode: FileDialog.SaveFile
nameFilters: ["Archive (.tar)"]
onAccepted: {
exportDb(selectedFile)
}
}
FileDialog {
id: importDialog
title: "Please choose a valid tar.gz archive..."
fileMode: FileDialog.OpenFile
nameFilters: ["Archive (*.tar)"]
onAccepted: {
importDb(selectedFile)
}
}
About {
id: aboutDialog
}
Page {
anchors.fill: parent
leftPadding: 5
rightPadding: 5
bottomPadding: 5
header: MenuBar {
id: topBar
Menu {
title: qsTr("File")
MenuItem {
text: "New Database..."
onClicked: {dialogNewDb.open()}
}
MenuItem {
text: "Load Database..."
onClicked: {showDBmanager()}
}
MenuSeparator {}
MenuItem {
id: importFileMenu
text: "Import Database"
onClicked: {importDialog.open()}
}
MenuItem {
id: exportFileMenu
text: "Export Database"
onClicked: {exportDialog.open()}
enabled: false
}
MenuSeparator {}
MenuItem {
id: editCategoryMenu
text: "Edit Tags"
onClicked: {showCatManager()}
enabled: false
}
MenuSeparator {}
MenuItem {
id: openFileMenu
text: "Open Database Folder"
onClicked: {openDbDirectory()}
enabled: false
}
MenuItem {
text: "Preferences"
onClicked: {showPref()}
}
MenuItem {
text: "Exit"
onClicked: {window.close()}
}
}
Menu {
id: signalMenu
title: qsTr("Signal")
MenuItem {
id: newSignalMenu
enabled: false
text: "New.."
onClicked: {openSigEditor('Signal', [], true)}
}
MenuItem {
id: editSignalMenu
enabled: false
text: "Edit..."
onClicked: {openSigEditor('Signal', [], false)}
}
}
Menu {
title: qsTr("Space Weather")
MenuItem {
text: "Check Report"
onClicked: {
showSpaceWeather()
}
}
}
Menu {
id: aboutMenu
title: qsTr("Help")
MenuItem {
text: "Check for Updates"
onClicked: {checkDbUpdates()}
}
MenuSeparator {}
MenuItem {
text: "Documentation"
onClicked: {Qt.openUrlExternally('https://AresValley.github.io/Artemis')}
}
MenuItem {
text: "Show Release Notes"
onClicked: {Qt.openUrlExternally('https://github.com/AresValley/Artemis/blob/master/CHANGELOG.md')}
}
MenuSeparator {}
MenuItem {
text: "Report Issue"
onClicked: {Qt.openUrlExternally('https://github.com/AresValley/Artemis/issues')}
}
MenuSeparator {}
MenuItem {
text: "About"
onClicked: {
aboutDialog.open()
}
}
}
}
footer: Label {
id: bottomInfoLabel
font.pixelSize: 12
leftPadding: 5
rightPadding: 5
bottomPadding: 5
}
RowLayout {
anchors.fill: parent
spacing: 20
ColumnLayout {
Layout.maximumWidth: 250
TextField {
id: textFieldSearch
enabled: false
Layout.fillWidth: true
Layout.topMargin: 10
placeholderText: qsTr("Search")
onTextChanged: {
refreshList()
}
}
RowLayout {
ListView {
id: listView
Layout.fillWidth: true
Layout.fillHeight: true
highlightMoveDuration: 0
clip: true
focus: true
ScrollBar.vertical: bar
highlight: Rectangle { color: Material.accent; radius: 5 }
onCurrentIndexChanged: { itemChangedList() }
delegate: Item {
id: listDelegate
width: ListView.view.width
height: 20
Label {text: name}
MouseArea {
anchors.fill: parent
onClicked: listView.currentIndex = index
}
}
model: ListModel {
id: listModel
}
}
ScrollBar {
id: bar
Layout.fillHeight: true
active: true
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
Layout.fillWidth: true
TabBar {
id: tabBar
width: parent.width
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
TabButton {
text: qsTr("Signal")
}
TabButton {
text: qsTr("Filter")
}
}
StackLayout {
currentIndex: tabBar.currentIndex
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillHeight: true
Layout.fillWidth: true
Item {
SignalPage {
id: signalPage
}
}
Item {
FilterPage {
id: filterPage
}
}
}
}
}
}
}

214
ui/CategoryEditor.qml Normal file
View File

@@ -0,0 +1,214 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Window {
id: windowCategoryEditor
title: 'Artemis - Category Manager'
width: 450
height: 400
Component.onCompleted: {
x = Screen.width/2 - width/2
y = Screen.height/2 - height/2
}
modality: Qt.ApplicationModal
flags: Qt.Window
signal saveParam(var data, bool isNew)
signal deleteParam(int clbId)
function loadList(dict) {
clearAll()
for (var i = 0; i < dict.length; i++) {
myModel.append(dict[i])
}
}
function itemChanged() {
var selected_cat = myModel.get(listView.currentIndex)
if (selected_cat !== undefined) {
renameButton.enabled = true
deleteButton.enabled = true
} else {
renameButton.enabled = false
deleteButton.enabled = false
}
}
function getModel() {
var modelList = []
for (var i = 0; i < myModel.count; i++) {
modelList.push(myModel.get(i).value)
}
return modelList
}
function clearAll() {
myModel.clear()
}
DialogMessage {
id: dialogDeleteConfirmation
modal: true
title: "Are you sure?"
message: "You are about to delete the selected category tag. The process cannot be undone."
messageType: "warn"
standardButtons: Dialog.Cancel | Dialog.Yes
onAccepted: {
deleteParam(myModel.get(listView.currentIndex).clb_id)
}
}
Dialog {
id: dialogNewCat
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
standardButtons: Dialog.Ok | Dialog.Cancel
ColumnLayout {
anchors.fill: parent
TextField {
id: newCatName
Layout.fillWidth: true
placeholderText: qsTr("Tag")
}
}
onAccepted: {
saveParam([newCatName.text], true)
}
}
Dialog {
id: dialogRenameCat
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
standardButtons: Dialog.Ok | Dialog.Cancel
ColumnLayout {
anchors.fill: parent
TextField {
id: renameCatName
Layout.fillWidth: true
placeholderText: qsTr("Tag")
}
}
onAccepted: {
saveParam(
[
renameCatName.text,
myModel.get(listView.currentIndex).clb_id
],
false
)
}
}
Page {
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 10
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
ListView {
id: listView
Layout.fillWidth: true
Layout.fillHeight: true
highlightMoveDuration: 0
highlight: Rectangle { color: Material.accent; radius: 5 }
onCurrentIndexChanged: { itemChanged() }
delegate: Item {
id: listDelegate
width: ListView.view.width
height: 20
Label { text: value }
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
}
model: ListModel {
id: myModel
}
}
}
RowLayout {
Layout.fillWidth: true
Button {
id: addButton
text: qsTr("Add")
onClicked: {
dialogNewCat.open()
}
icon.source: "qrc:/images/icons/add.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Item {
Layout.fillWidth: true
}
Button {
id: renameButton
text: qsTr("Rename")
onClicked: {
dialogRenameCat.open()
}
icon.source: "qrc:/images/icons/rename.svg"
enabled: false
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
Item {
Layout.fillWidth: true
}
Button {
id: deleteButton
text: qsTr("Delete")
onClicked: {
dialogDeleteConfirmation.open()
}
icon.source: "qrc:/images/icons/delete.svg"
enabled: false
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
}
}
}
}

293
ui/DbManager.qml Normal file
View File

@@ -0,0 +1,293 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Window {
id: windowDBmanager
width: 500
height: 400
modality: Qt.ApplicationModal
flags: Qt.Dialog
title: qsTr("Artemis - Load Database")
signal loadDB (string dbName)
signal deleteDB (string dbName)
signal renameDB (string dbName, string newDbName)
function loadList(dict) {
clearAll()
for (var i = 0; i < dict.length; i++) {
myModel.append(dict[i])
}
itemChanged()
}
function itemChanged() {
var selected_db = myModel.get(listView.currentIndex)
if (selected_db !== undefined) {
lockMenu(false)
titleLabel.text = myModel.get(listView.currentIndex).name
totDocsLabel.text = myModel.get(listView.currentIndex).documents_n
totSignalsLabel.text = myModel.get(listView.currentIndex).signals_n
totImagesLabel.text = myModel.get(listView.currentIndex).images_n
totAudioLabel.text = myModel.get(listView.currentIndex).audio_n
} else {
lockMenu(true)
}
}
function getModel() {
var modelList = []
for (var i = 0; i < myModel.count; i++) {
modelList.push(myModel.get(i).name)
}
return modelList
}
function clearAll() {
titleLabel.text = 'N/A'
totDocsLabel.text = ''
totSignalsLabel.text = ''
totImagesLabel.text = ''
totAudioLabel.text = ''
myModel.clear()
}
function loadDBButton() {
loadDB(myModel.get(listView.currentIndex).db_dir_name)
}
function renameDb() {
if (textDBName.readOnly) {
textDBName.focus = true
textDBName.readOnly = false
renameButton.highlighted = true
createDbButton.enabled = false
deleteDbButton.enabled = false
}
else {
renameDB(myModel.get(listView.currentIndex).db_dir_name, textDBName.text)
textDBName.focus = false
textDBName.readOnly = true
renameButton.highlighted = false
createDbButton.enabled = true
deleteDbButton.enabled = true
}
}
function lockMenu(toggle) {
if (toggle) {
deleteButton.enabled = false
renameButton.enabled = false
loadButton.enabled = false
} else {
deleteButton.enabled = true
renameButton.enabled = true
loadButton.enabled = true
}
}
DialogMessage {
id: dialogDeleteConfirmation
modal: true
title: "Are you sure?"
message: "You are about to delete the database and all its contents permanently. The process cannot be undone."
messageType: "warn"
standardButtons: Dialog.Cancel | Dialog.Yes
onAccepted: {
deleteDB(myModel.get(listView.currentIndex).db_dir_name)
}
}
Dialog {
id: renameDb
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
standardButtons: Dialog.Ok | Dialog.Cancel
ColumnLayout {
anchors.fill: parent
TextField {
id: newDbName
Layout.fillWidth: true
placeholderText: qsTr("New DB Name")
}
}
onAccepted: {
renameDB(myModel.get(listView.currentIndex).db_dir_name, newDbName.text)
}
}
Page {
anchors.fill: parent
RowLayout {
anchors.fill: parent
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 10
ListView {
id: listView
width: 150
Layout.fillHeight: true
highlight: Rectangle { color: Material.accent; radius: 5 }
onCurrentIndexChanged: { itemChanged() }
delegate: Item {
id: listDelegate
width: ListView.view.width
height: 20
Label { text: name }
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
}
model: ListModel {
id: myModel
}
}
ToolSeparator {
rightPadding: 10
leftPadding: 10
Layout.fillHeight: true
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Label {
id: titleLabel
Layout.bottomMargin: 20
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.pointSize: 15
font.bold: true
}
GridLayout {
columnSpacing: 25
columns: 2
Label {
text: qsTr("Total Signals:")
font.pointSize: 12
font.bold: true
}
Label {
id: totSignalsLabel
text: qsTr("0")
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("Total Documents:")
font.pointSize: 12
}
Label {
id: totDocsLabel
text: qsTr("0")
font.pointSize: 12
}
Label {
text: qsTr("Images:")
Layout.leftMargin: 15
font.pointSize: 12
}
Label {
id: totImagesLabel
text: qsTr("0")
font.pointSize: 12
}
Label {
text: qsTr("Audio:")
Layout.leftMargin: 15
font.pointSize: 12
}
Label {
id: totAudioLabel
text: qsTr("0")
font.pointSize: 12
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
RowLayout {
Button {
id: deleteButton
text: qsTr("Delete")
icon.source: "qrc:/images/icons/delete.svg"
display: AbstractButton.TextBesideIcon
enabled: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
dialogDeleteConfirmation.open()
}
}
Item {
Layout.fillWidth: true
}
Button {
id: renameButton
text: qsTr("Rename")
icon.source: "qrc:/images/icons/rename.svg"
display: AbstractButton.TextBesideIcon
enabled: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
renameDb.open()
}
}
Item {
Layout.fillWidth: true
}
Button {
id: loadButton
text: qsTr("Load")
icon.source: "qrc:/images/icons/load.svg"
display: AbstractButton.TextBesideIcon
enabled: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
loadDBButton()
}
}
}
}
}
}
}

55
ui/DialogMessage.qml Normal file
View File

@@ -0,0 +1,55 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Window
Dialog {
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
property string message
property string messageType
RowLayout {
Layout.fillWidth: true
spacing: 10
Image {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
sourceSize.height: 60
sourceSize.width: 60
source: {
switch (messageType.toLowerCase()) {
case "question":
return "qrc:///images/icons/dialog_quest.svg"
case "warn":
return "qrc:///images/icons/dialog_warn.svg"
case "error":
return "qrc:///images/icons/dialog_error.svg"
case "info":
return "qrc:///images/icons/dialog_info.svg"
default:
return "qrc:///images/icons/dialog_info.svg"
}
}
}
Label {
text: message
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
Layout.minimumWidth: 200
Layout.maximumWidth: 300
textFormat: Text.RichText
wrapMode: Text.WordWrap
}
}
}

538
ui/DocumentsManager.qml Normal file
View File

@@ -0,0 +1,538 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
import QtQuick.Dialogs
Window {
id: documentsManageranager
width: 800
height: 500
Component.onCompleted: {
x = Screen.width/2 - width/2
y = Screen.height/2 - height/2
}
modality: Qt.ApplicationModal
flags: Qt.Window
title: qsTr("Artemis - Documents Manager")
signal saveNewDoc (variant docParamLst)
signal updateDoc (variant docParamLst)
signal deleteDoc (string docId, string extension, string type, bool preview)
signal openDoc (string docId, string extension)
function loadList(dict) {
clearAll()
for (var i = 0; i < dict.length; i++) {
myModel.append(dict[i])
}
itemChanged()
}
function getModel() {
var dictionaryList = []
for (var i = 0; i < myModel.count; i++) {
var dictionary = [
myModel.get(i).doc_id,
myModel.get(i).name,
myModel.get(i).description,
myModel.get(i).type,
myModel.get(i).preview,
myModel.get(i).extension
]
dictionaryList.push(dictionary)
}
return dictionaryList
}
function itemChanged() {
var selected_doc = myModel.get(listView.currentIndex)
if (selected_doc !== undefined) {
var docId = selected_doc.doc_id
var extension = selected_doc.extension
var name = selected_doc.name
var description = selected_doc.description
var type = selected_doc.type
var preview = selected_doc.preview
nameField.text = name
fileNameField.text = docId + '.' + extension
descriptionField.text = description
lockMenu(false)
if (type === 'Image' || type === 'Audio') {
switchPreview.visible = true
if (preview === 1) {
switchPreview.checked = true
} else {
switchPreview.checked = false
}
} else {
switchPreview.visible = false
}
} else {
lockMenu(true)
}
}
function contentChanged() {
if (listView.currentIndex !== -1) {
myModel.set(
listView.currentIndex,
{
'name': nameField.text,
'description': descriptionField.text,
}
)
}
}
function lockMenu(toggle) {
if (toggle) {
openButton.enabled = false
switchPreview.visible = false
deleteButton.enabled = false
editButton.enabled = false
} else {
openButton.enabled = true
deleteButton.enabled = true
editButton.enabled = true
}
}
function clearAll() {
nameField.clear()
fileNameField.clear()
descriptionField.clear()
myModel.clear()
}
function previewChanged(is_preview) {
var previewItem = myModel.get(listView.currentIndex)
if (previewItem.preview !== is_preview) {
if (is_preview) {
for (var i = 0; i < myModel.count; i++) {
if (myModel.get(i).type === previewItem.type) {
myModel.get(i).preview = 0
}
}
previewItem.preview = 1
} else {
previewItem.preview = 0
}
updateDoc(getModel())
itemChanged()
changeSavedDialog.open()
}
}
function validateFields() {
if (newPathField.text === '' || newNameField.text === '') {
// message file or name not selected
return false
} else {
return true
}
}
function setEditFileTypeComboBox(type) {
for (var idx = 0; idx < editFileTypeComboBox.count; idx ++) {
if (type === editFileTypeComboBox.valueAt(idx)) {
editFileTypeComboBox.currentIndex = idx
break
}
}
}
function editCurrentDoc(name, description, type) {
var selected_doc = myModel.get(listView.currentIndex)
var doc_param = [
selected_doc.doc_id,
name,
description,
type,
selected_doc.preview,
]
updateDoc([doc_param])
}
FileDialog {
id: fileDialog
title: "Please choose a file"
nameFilters: [
"Image (*.jpg *.png)",
"Audio (*.mp3 *.m4a *.ogg)",
"Document (*.txt *.pdf)",
"All files (*)"
]
onAccepted: {
newPathField.text = selectedFile
if (selectedNameFilter.name === 'Image') {
newFileTypeComboBox.currentIndex = 0
} else if (selectedNameFilter.name === 'Audio') {
newFileTypeComboBox.currentIndex = 1
} else if (selectedNameFilter.name === 'Document') {
newFileTypeComboBox.currentIndex = 2
} else {
newFileTypeComboBox.currentIndex = 3
}
}
}
Dialog {
id: dialogAddNew
height: 400
width: 400
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
standardButtons: Dialog.Save | Dialog.Close
ColumnLayout {
anchors.fill: parent
RowLayout {
Layout.fillWidth: true
TextField {
id: newPathField
Layout.fillWidth: true
placeholderText: qsTr("Path")
readOnly: true
}
Button {
text: qsTr("Browse")
onClicked: {
fileDialog.open()
}
}
}
RowLayout {
Layout.fillWidth: true
ComboBox {
id: newFileTypeComboBox
model: ["Image", "Audio", "Document", "Other"]
}
TextField {
id: newNameField
Layout.fillWidth: true
placeholderText: qsTr("Name")
}
}
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
ScrollBar.vertical.interactive: true
TextArea {
id: newDescriptionField
placeholderText: qsTr("Description")
wrapMode: TextEdit.WordWrap
}
}
}
onAccepted: {
if (validateFields()) {
saveNewDoc(
[
newPathField.text,
newNameField.text,
newDescriptionField.text,
newFileTypeComboBox.currentText
]
)
}
}
}
Dialog {
id: dialogEdit
height: 400
width: 400
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.NoAutoClose
standardButtons: Dialog.Save | Dialog.Close
ColumnLayout {
anchors.fill: parent
RowLayout {
Layout.fillWidth: true
ComboBox {
id: editFileTypeComboBox
model: ["Image", "Audio", "Document", "Other"]
}
TextField {
id: editNameField
Layout.fillWidth: true
placeholderText: qsTr("Name")
}
}
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
ScrollBar.vertical.interactive: true
TextArea {
id: editDescriptionField
placeholderText: qsTr("Description")
wrapMode: TextEdit.WordWrap
}
}
}
onAccepted: {
editCurrentDoc(
editNameField.text,
editDescriptionField.text,
editFileTypeComboBox.currentText
)
}
}
DialogMessage {
id: dialogDeleteConfirmation
modal: true
title: "Are you sure?"
message: "You are about to delete the selected document. The process cannot be undone."
messageType: "warn"
standardButtons: Dialog.Cancel | Dialog.Yes
onAccepted: {
deleteDoc(
myModel.get(listView.currentIndex).doc_id,
myModel.get(listView.currentIndex).extension,
myModel.get(listView.currentIndex).type,
myModel.get(listView.currentIndex).preview
)
}
}
DialogMessage {
id: changeSavedDialog
title: 'Change Saved!'
message: 'Your changes have been successfully saved!'
standardButtons: Dialog.Ok
}
Page {
anchors.fill: parent
RowLayout {
anchors.fill: parent
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
spacing: 0
anchors.topMargin: 10
ColumnLayout {
Layout.minimumWidth: 150
RowLayout {
Component {
id: sectionHeading
Rectangle {
width: ListView.view.width
height: 30
color: "#00000000"
Label {
text: section
font.capitalization: Font.AllUppercase
font.bold: true
font.pixelSize: 16
color: Material.accent
font.letterSpacing: 0.5
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
ListView {
id: listView
Layout.fillWidth: true
Layout.fillHeight: true
highlightMoveDuration: 0
clip: true
focus: true
ScrollBar.vertical: bar
highlight: Rectangle { color: Material.accent; radius: 5 }
onCurrentIndexChanged: { itemChanged() }
delegate: Item {
id: listDelegate
width: ListView.view.width
height: 20
Label { text: name }
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
}
model: ListModel {
id: myModel
}
section.property: "type"
section.criteria: ViewSection.FullString
section.delegate: sectionHeading
}
ScrollBar {
id: bar
Layout.fillHeight: true
active: true
}
}
Button {
id: addButton
text: qsTr("Add")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
icon.source: "qrc:/images/icons/add.svg"
display: AbstractButton.TextBesideIcon
onClicked: {
dialogAddNew.open()
}
}
}
ToolSeparator {
id: toolSeparator
rightPadding: 10
leftPadding: 10
Layout.fillHeight: true
}
ColumnLayout {
Layout.preferredWidth: 300
Label {
text: qsTr("FILE DETAILS")
font.letterSpacing: 0.5
color: Material.accent
font.pixelSize: 18
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
TextField {
id: nameField
Layout.fillWidth: true
placeholderText: qsTr("Name")
onTextChanged: {
contentChanged()
}
}
TextField {
id: fileNameField
Layout.fillWidth: true
placeholderText: qsTr("File")
readOnly: true
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.vertical.interactive: true
TextArea {
id: descriptionField
wrapMode: TextEdit.WordWrap
font.pointSize: 10
onTextChanged: {
contentChanged()
}
}
}
RowLayout {
Button {
id: deleteButton
text: qsTr("Delete")
icon.source: "qrc:/images/icons/delete.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
dialogDeleteConfirmation.open()
}
}
Item {
Layout.fillWidth: true
}
Switch {
id: switchPreview
text: qsTr("Main")
onCheckedChanged: {
if (checked) {
previewChanged(1)
} else {
previewChanged(0)
}
}
}
Button {
id: editButton
text: qsTr("Edit")
enabled: false
icon.source: "qrc:/images/icons/rename.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
editNameField.text = myModel.get(listView.currentIndex).name
setEditFileTypeComboBox(myModel.get(listView.currentIndex).type)
editDescriptionField.text = myModel.get(listView.currentIndex).description
dialogEdit.open()
}
}
Button {
id: openButton
text: qsTr("Open")
enabled: false
icon.source: "qrc:/images/icons/open.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
openDoc(
myModel.get(listView.currentIndex).doc_id,
myModel.get(listView.currentIndex).extension
)
}
}
}
}
}
}
}

60
ui/Downloader.qml Normal file
View File

@@ -0,0 +1,60 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Window {
id: windowDownloader
width: 400
height: 130
maximumHeight: height
maximumWidth: width
minimumHeight: height
minimumWidth: width
modality: Qt.ApplicationModal
flags: Qt.Dialog
title: qsTr("Artemis - Downloader")
signal onAbort()
Page {
id: page
anchors.fill: parent
ColumnLayout {
id: columnLayout
anchors.fill: parent
Label {
text: qsTr("Downloading in progress...")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
ProgressBar {
objectName: "progressBar"
Layout.rightMargin: 20
Layout.leftMargin: 20
Layout.fillWidth: true
value: 0
}
Label {
objectName: "labelProgress"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Button {
text: qsTr("Abort")
icon.source: "qrc:/images/icons/abort.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
onClicked: { onAbort() }
}
}
}
}

632
ui/FilterPage.qml Normal file
View File

@@ -0,0 +1,632 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Page {
id: filterPage
anchors.fill: parent
objectName: "filterPageObj"
signal applyFilter(var filterDict)
signal sendBottomAlert(string message, string messagType)
property var filterDict: {}
function updateFilterDict() {
filterDict = {}
if (switchFreq.checked) {
var unitFreqValue = comboBoxFreq.currentValue.value
var lower_band = parseFloat(textFieldFreq.text) * unitFreqValue * (1 - tolFreq.value)
var upper_band = parseFloat(textFieldFreq.text) * unitFreqValue * (1 + tolFreq.value)
filterDict['frequency'] = {
'lower_band': lower_band,
'upper_band': upper_band
}
}
if (switchBand.checked) {
var unitBandValue = comboBoxBand.currentValue.value
var lower_band = parseFloat(textFieldBand.text) * unitBandValue * (1 - tolBand.value)
var upper_band = parseFloat(textFieldBand.text) * unitBandValue * (1 + tolBand.value)
filterDict['bandwidth'] = {
'lower_band': lower_band,
'upper_band': upper_band
}
}
if (switchACF.checked) {
var lower_band = parseFloat(textFieldACF.text) * (1 - tolACF.value)
var upper_band = parseFloat(textFieldACF.text) * (1 + tolACF.value)
filterDict['acf'] = {
'lower_band': lower_band,
'upper_band': upper_band
}
}
if (switchModulation.checked) {
var modulationList = []
for (var i = 0; i < modelModulation.count; i++) {
if (modelModulation.get(i).checked) {
modulationList.push(
modelModulation.get(i).value
)
}
}
filterDict['modulation'] = modulationList
}
if (switchLocation.checked) {
var locationList = []
for (var i = 0; i < modelLocation.count; i++) {
if (modelLocation.get(i).checked) {
locationList.push(
modelLocation.get(i).value
)
}
}
filterDict['location'] = locationList
}
if (switchCategory.checked) {
var categoryList = []
for (var i = 0; i < modelCategory.count; i++) {
if (modelCategory.get(i).checked) {
categoryList.push(
modelCategory.get(i).clb_id
)
}
}
filterDict['category'] = categoryList
}
applyFilter(filterDict)
}
function resetAll() {
switchFreq.checked = false
switchBand.checked = false
switchACF.checked = false
switchModulation.checked = false
switchLocation.checked = false
switchCategory.checked = false
lockFreq(true)
lockBand(true)
lockACF(true)
}
function lockFreq(toggle) {
if(toggle) {
textFieldFreq.enabled = false
comboBoxFreq.enabled = false
tolFreq.enabled = false
summaryFreq.text = ''
}
else {
textFieldFreq.enabled = true
comboBoxFreq.enabled = true
tolFreq.enabled = true
if (textFieldFreq.text !== '') {
updateSummaryFreq()
updateFilterDict()
}
}
}
function lockBand(toggle) {
if(toggle) {
textFieldBand.enabled = false
comboBoxBand.enabled = false
tolBand.enabled = false
summaryBand.text = ''
}
else {
textFieldBand.enabled = true
comboBoxBand.enabled = true
tolBand.enabled = true
if (textFieldBand.text !== '') {
updateSummaryBand()
updateFilterDict()
}
}
}
function lockACF(toggle) {
if(toggle) {
textFieldACF.enabled = false
tolACF.enabled = false
summaryACF.text = ''
}
else {
textFieldACF.enabled = true
tolACF.enabled = true
if (textFieldACF.text !== '') {
updateSummaryACF()
updateFilterDict()
}
}
}
function updateSummaryFreq() {
if (textFieldFreq.text !== "") {
var unitFreqText = comboBoxFreq.currentValue.text
var lowFreq = (parseFloat(textFieldFreq.text) * (1 - tolFreq.value)).toFixed(1)
var uppFreq = (parseFloat(textFieldFreq.text) * (1 + tolFreq.value)).toFixed(1)
if (tolFreq.value === 0) {
summaryFreq.text = lowFreq + " " + unitFreqText
}
else {
summaryFreq.text = lowFreq + " " + unitFreqText + " - " + uppFreq + " " + unitFreqText
}
}
}
function updateSummaryBand() {
if (textFieldBand.text !== "") {
var unitBandText = comboBoxBand.currentValue.text
var lowBand = (parseFloat(textFieldBand.text) * (1 - tolBand.value)).toFixed(1)
var uppBand = (parseFloat(textFieldBand.text) * (1 + tolBand.value)).toFixed(1)
if (tolBand.value === 0) {
summaryBand.text = lowBand + " " + unitBandText
}
else {
summaryBand.text = lowBand + " " + unitBandText + " - " + uppBand + " " + unitBandText
}
}
}
function updateSummaryACF() {
if (textFieldACF.text !== "") {
var lowBand = (parseFloat(textFieldACF.text) * (1 - tolACF.value)).toFixed(1)
var uppBand = (parseFloat(textFieldACF.text) * (1 + tolACF.value)).toFixed(1)
if (tolACF.value === 0) {
summaryACF.text = lowBand + " ms"
}
else {
summaryACF.text = lowBand + " ms" + " - " + uppBand + " ms"
}
}
}
function loadLists(filterList) {
modelModulation.clear()
var modulationDict = filterList[0].modulation
for (var i = 0; i < modulationDict.length; i++) {
modelModulation.append(modulationDict[i])
}
modelLocation.clear()
var locationDict = filterList[0].location
for (var i = 0; i < locationDict.length; i++) {
modelLocation.append(locationDict[i])
}
modelCategory.clear()
var categoryDict = filterList[0].category
for (var i = 0; i < categoryDict.length; i++) {
modelCategory.append(categoryDict[i])
}
}
ColumnLayout {
anchors.fill: parent
GridLayout {
rows: 2
columns: 3
rowSpacing: 10
columnSpacing: 10
GroupBox {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
RowLayout {
Label {
text: qsTr("Frequency")
Layout.fillWidth: true
font.bold: true
font.pointSize: 12
font.capitalization: Font.SmallCaps
}
Switch {
id: switchFreq
onToggled: {
if(switchFreq.checked) {
lockFreq(false)
}
else {
lockFreq(true)
updateFilterDict()
}
}
}
}
RowLayout {
TextField {
id: textFieldFreq
Layout.fillWidth: true
placeholderText: qsTr("Frequency")
validator: DoubleValidator{bottom: 0}
enabled: false
onTextChanged: {
if(switchFreq.checked && textFieldFreq.text !== '') {
updateSummaryFreq()
updateFilterDict()
}
}
}
ComboBox {
id: comboBoxFreq
enabled: false
textRole: 'text'
model: ListModel {
ListElement { text: "Hz"; value: 1 }
ListElement { text: "kHz"; value: 1e3 }
ListElement { text: "MHz"; value: 1e6 }
ListElement { text: "GHz"; value: 1e9 }
}
onActivated: {
if(switchFreq.checked && textFieldFreq.text !== '') {
updateSummaryFreq()
updateFilterDict()
}
}
}
}
Slider {
id: tolFreq
Layout.fillWidth: true
enabled: false
value: 0
onValueChanged: {
if(switchFreq.checked && textFieldFreq.text !== '') {
updateSummaryFreq()
updateFilterDict()
}
}
}
Label {
id: summaryFreq
color: Material.color(Material.Green)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
GroupBox {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
RowLayout {
Label {
text: qsTr("Bandwidth")
Layout.fillWidth: true
font.bold: true
font.pointSize: 12
font.capitalization: Font.SmallCaps
}
Switch {
id: switchBand
onToggled: {
if(switchBand.checked) {
lockBand(false)
}
else {
lockBand(true)
updateFilterDict()
}
}
}
}
RowLayout {
TextField {
id: textFieldBand
validator: DoubleValidator {
bottom: 0
}
onTextChanged: {
if(switchBand.checked && textFieldBand.text !== '') {
updateSummaryBand()
updateFilterDict()
}
}
Layout.fillWidth: true
placeholderText: qsTr("Bandwidth")
enabled: false
}
ComboBox {
id: comboBoxBand
enabled: false
textRole: 'text'
model: ListModel {
ListElement { text: "Hz"; value: 1 }
ListElement { text: "kHz"; value: 1e3 }
ListElement { text: "MHz"; value: 1e6 }
ListElement { text: "GHz"; value: 1e9 }
}
onActivated: {
if(switchBand.checked && textFieldBand.text !== '') {
updateSummaryBand()
updateFilterDict()
}
}
}
}
Slider {
id: tolBand
Layout.fillWidth: true
enabled: false
value: 0
onValueChanged: {
if(switchBand.checked && textFieldBand.text !== '') {
updateSummaryBand()
updateFilterDict()
}
}
}
Label {
id: summaryBand
color: Material.color(Material.Green)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
GroupBox {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
RowLayout {
Label {
text: qsTr("ACF")
Layout.fillWidth: true
font.bold: true
font.pointSize: 12
font.capitalization: Font.SmallCaps
}
Switch {
id: switchACF
onToggled: {
if(switchACF.checked) {
lockACF(false)
} else {
lockACF(true)
updateFilterDict()
}
}
}
}
RowLayout {
TextField {
id: textFieldACF
validator: DoubleValidator {
bottom: 0
}
onTextChanged: {
if(switchACF.checked && textFieldACF.text !== '') {
updateSummaryACF()
updateFilterDict()
}
}
Layout.fillWidth: true
placeholderText: qsTr("ACF")
enabled: false
}
ComboBox {
enabled: false
model: ['ms']
}
}
Slider {
id: tolACF
Layout.fillWidth: true
enabled: false
value: 0
onValueChanged: {
if(switchACF.checked && textFieldACF.text !== '') {
updateSummaryACF()
updateFilterDict()
}
}
}
Label {
id: summaryACF
color: Material.color(Material.Green)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
GroupBox {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
RowLayout {
Label {
text: qsTr("Modulation")
Layout.fillWidth: true
font.bold: true
font.pointSize: 12
font.capitalization: Font.SmallCaps
}
Switch {
id: switchModulation
onToggled: {
updateFilterDict()
}
}
}
ListView {
Layout.minimumHeight: 200
Layout.fillWidth: true
Layout.fillHeight: true
highlightMoveDuration: 0
clip: true
focus: true
ScrollBar.vertical: ScrollBar {
active: true
}
delegate: Item {
width: ListView.view.width
height: 30
CheckBox {
enabled: switchModulation.checked
text: value
onCheckedChanged: {
modelModulation.setProperty(index, "checked", checked)
updateFilterDict()
}
}
}
model: ListModel {
id: modelModulation
}
}
}
}
GroupBox {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
RowLayout {
Label {
text: qsTr("Location")
Layout.fillWidth: true
font.bold: true
font.pointSize: 12
font.capitalization: Font.SmallCaps
}
Switch {
id: switchLocation
onToggled: {
updateFilterDict()
}
}
}
ListView {
Layout.minimumHeight: 200
Layout.fillHeight: true
Layout.fillWidth: true
highlightMoveDuration: 0
clip: true
focus: true
ScrollBar.vertical: ScrollBar {
active: true
}
delegate: Item {
width: ListView.view.width
height: 30
CheckBox {
enabled: switchLocation.checked
text: value
onCheckedChanged: {
modelLocation.setProperty(index, "checked", checked)
updateFilterDict()
}
}
}
model: ListModel {
id: modelLocation
}
}
}
}
GroupBox {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
RowLayout {
Label {
text: qsTr("Category")
Layout.fillWidth: true
font.bold: true
font.pointSize: 12
font.capitalization: Font.SmallCaps
}
Switch {
id: switchCategory
onToggled: {
updateFilterDict()
}
}
}
ListView {
Layout.minimumHeight: 200
Layout.fillHeight: true
Layout.fillWidth: true
highlightMoveDuration: 0
clip: true
focus: true
ScrollBar.vertical: ScrollBar {
active: true
}
delegate: Item {
width: ListView.view.width
height: 30
CheckBox {
enabled: switchCategory.checked
text: value
onCheckedChanged: {
modelCategory.setProperty(index, "checked", checked)
updateFilterDict()
}
}
}
model: ListModel {
id: modelCategory
}
}
}
}
}
}
}

151
ui/Preferences.qml Normal file
View File

@@ -0,0 +1,151 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Window {
id: windowPreferences
width: 450
height: 400
Component.onCompleted: {
x = Screen.width/2 - width/2
y = Screen.height/2 - height/2
}
modality: Qt.ApplicationModal
flags: Qt.Window
title: qsTr("Artemis - Preferences")
signal saveMaterialAccent(string arg)
signal saveMaterialTheme(string arg)
function saveAll() {
saveMaterialAccent(comboBoxAccent.currentText)
saveMaterialTheme(comboBoxTheme.currentText)
}
function loadMaterialAccent(accent) {
for (var idx = 0; idx < comboBoxAccent.count; idx ++) {
if (accent === comboBoxAccent.valueAt(idx)) {
comboBoxAccent.currentIndex = idx
break
}
}
}
function loadMaterialTheme(theme) {
for (var idx = 0; idx < comboBoxTheme.count; idx ++) {
if (theme === comboBoxTheme.valueAt(idx)) {
comboBoxTheme.currentIndex = idx
break
}
}
}
DialogMessage {
id: dialogPreferencesSaved
modal: true
title: "Preferences saved!"
message: "User preferences has been saved succesfully! Artemis restart is require for changes to take effect."
standardButtons: Dialog.Ok
onAccepted: {
windowPreferences.close()
}
}
Pane {
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
anchors.rightMargin: 15
anchors.leftMargin: 15
anchors.bottomMargin: 15
anchors.topMargin: 15
RowLayout {
Layout.fillWidth: true
Label {
text: "Material Theme"
font.pixelSize: 12
clip: true
Layout.fillWidth: true
}
ComboBox {
id: comboBoxTheme
width: 137
height: 48
model: [
"System",
"Light",
"Dark"
]
}
}
RowLayout {
Layout.fillWidth: true
Label {
text: "Material Accent"
font.pixelSize: 12
clip: true
Layout.fillWidth: true
}
ComboBox {
id: comboBoxAccent
width: 137
height: 48
model: [
"Red",
"Pink",
"Purple",
"DeepPurple",
"Indigo",
"Blue",
"LightBlue",
"Cyan",
"Teal",
"Green",
"LightGreen",
"Lime",
"Yellow",
"Amber",
"Orange",
"DeepOrange",
"Brown",
"Grey",
"BlueGrey"
]
}
}
Item {
Layout.fillHeight: true
}
Button {
text: qsTr("Save")
icon.source: "qrc:/images/icons/save.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
onClicked: {
saveAll()
dialogPreferencesSaved.open()
}
}
}
}
}

204
ui/SignalEditor.qml Normal file
View File

@@ -0,0 +1,204 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Window {
id: windowSignalEditor
width: 500
height: 400
Component.onCompleted: {
x = Screen.width/2 - width/2
y = Screen.height/2 - height/2
}
modality: Qt.ApplicationModal
flags: Qt.Window
signal saveParam(string type, var data, bool isNew)
signal deleteParam(string type, int ID)
property string paramType
property int paramID
property bool isNew
property var validator_freq: /^\d+(\.\d+)?$/
property var validator_all: /.*/
function load(type, sig_param, is_new) {
clearAll()
isNew = is_new
paramType = type
paramValue.placeholderText = paramType
if (isNew) {
paramID = 0
windowSignalEditor.title = 'Artemis - New ' + paramType
} else {
paramID = sig_param[0]
windowSignalEditor.title = 'Artemis - Edit ' + paramType
if (paramType === 'Frequency' || paramType === 'Bandwidth') {
var freq = changeUnit(sig_param[1])
paramValue.text = sig_param[1] / freq.scale
loadUnitComboBox(freq.unit)
} else {
paramValue.text = sig_param[1]
}
paramDescription.text = sig_param[2]
}
}
function save() {
if (paramType === 'Frequency' || paramType === 'Bandwidth') {
var scaleFactor = unitComboBox.currentValue.value
var mainValue = paramValue.text * scaleFactor
} else {
var mainValue = paramValue.text
}
var param = [paramID, mainValue, paramDescription.text]
saveParam(paramType, param, isNew)
changeSavedDialog.open()
}
function clearAll() {
paramValue.clear()
paramDescription.clear()
loadUnitComboBox('Hz')
}
function changeUnit(frequency) {
var digits = frequency.toString().length
if (digits < 4)
return { scale: 1, unit: "Hz" }
else if (digits < 7)
return { scale: Math.pow(10, 3), unit: "kHz" }
else if (digits < 10)
return { scale: Math.pow(10, 6), unit: "MHz" }
else
return { scale: Math.pow(10, 9), unit: "GHz" }
}
function loadUnitComboBox(unit) {
for (var idx = 0; idx < unitComboBox.count; idx ++) {
if (unit === unitComboBox.valueAt(idx).text) {
unitComboBox.currentIndex = idx
break
}
}
}
DialogMessage {
id: changeSavedDialog
title: 'Change Saved!'
message: 'Your changes have been successfully saved!'
standardButtons: Dialog.Ok
onAccepted: {
windowSignalEditor.close()
}
}
DialogMessage {
id: dialogDeleteConfirmation
modal: true
title: "Are you sure?"
message: "You are about to delete the selected " + paramType + ". The process cannot be undone."
messageType: "warn"
standardButtons: Dialog.Cancel | Dialog.Yes
onAccepted: {
deleteParam(paramType, paramID)
windowSignalEditor.close()
}
}
Page {
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.topMargin: 10
anchors.bottomMargin: 10
RowLayout {
TextField {
id: paramValue
visible: paramType !== 'Description' ? true : false
Layout.fillWidth: true
placeholderText: qsTr("Frequency")
validator: RegularExpressionValidator {
regularExpression: paramType === 'Frequency' || paramType === 'Bandwidth' ? validator_freq : validator_all
}
}
ComboBox {
id: unitComboBox
visible: paramType === 'Frequency' || paramType === 'Bandwidth' ? true : false
textRole: 'text'
model: ListModel {
ListElement { text: 'Hz'; value: 1 }
ListElement { text: 'kHz'; value: 1e3 }
ListElement { text: 'MHz'; value: 1e6 }
ListElement { text: 'GHz'; value: 1e9 }
}
}
}
ScrollView {
Layout.fillWidth: true
Layout.topMargin: 5
Layout.fillHeight: true
ScrollBar.vertical.interactive: true
TextArea {
id: paramDescription
placeholderText: qsTr("Description")
wrapMode: TextEdit.WordWrap
font.pointSize: 10
}
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
Button {
id: deleteButton
visible: isNew ? false : true
text: qsTr("Delete")
icon.source: "qrc:/images/icons/delete.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
dialogDeleteConfirmation.open()
}
}
Item {
Layout.fillWidth: true
}
Button {
id: saveButton
text: qsTr("Save")
icon.source: "qrc:/images/icons/save.svg"
display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
save()
}
}
}
}
}
}

644
ui/SignalPage.qml Normal file
View File

@@ -0,0 +1,644 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
import './components' as UIComponents
Page {
id: signalPage
anchors.fill: parent
objectName: "signalPageObj"
signal openDocManager()
signal openSigEditor(string type, var sig_param, bool is_new)
signal addCatTag(int clbId)
signal deleteCatTag(int catId)
property string urlSigidwiki
property var frequencyList
property var bandwidthList
property var categoryList
property var allCategoryList
property var modulationList
property var modeList
property var acfList
property var locationList
function populateSignalParam(sig) {
var sig = sig[0]
signalName.text = sig.name
frequencyList = sig.frequency
bandwidthList = sig.bandwidth
var freq_lo = sig.frequency[0]
var freq_up = sig.frequency.slice(-1)[0]
var band_lo = sig.bandwidth[0]
var band_up = sig.bandwidth.slice(-1)[0]
freqValue.text = format_range(freq_lo, freq_up)
bandValue.text = format_range(band_lo, band_up)
categoryList = sig.category
allCategoryList = sig.all_category
modeList = sig.mode
modulationList = sig.modulation
locationList = sig.location
acfList = sig.acf
descriptionTextArea.text = sig.description
if (freq_lo !== undefined) {
bandBar.setBandBar(freq_lo[1], freq_up[1])
}
if (sig.url !== undefined) {
urlButton.visible = true
urlSigidwiki = sig.url
}
else {
urlButton.visible = false
}
image.source = sig.spectrum_path
if (sig.audio_path !== '') {
loadPlayer(sig.audio_path)
} else {
lockPlayer()
}
lockMenu(false)
}
function format_range(lower_freq, upper_freq) {
try {
if (lower_freq[1] !== upper_freq[1]) {
return lower_freq[3] + ' - ' + upper_freq[3]
} else {
return lower_freq[3]
}
} catch (error) {
return 'UNKNOWN'
}
}
function loadPlayer(audio_path) {
audioPlayer.resetPlayer()
audioPlayer.loadSound(audio_path)
}
function lockPlayer() {
audioPlayer.resetPlayer()
}
function resetAll() {
signalName.text = ""
freqValue.text = "-"
bandValue.text = "-"
frequencyList = []
bandwidthList = []
categoryList = []
modeList = []
modulationList = []
locationList = []
acfList = []
descriptionTextArea.text = ""
bandBar.resetBandBar()
audioPlayer.resetPlayer()
image.source = "qrc:///images/spectrum_not_available.svg"
lockMenu(true)
}
function lockMenu(toggle) {
if (toggle) {
urlButton.visible = false
docManagerButton.visible = false
freqButton.enabled = false
bandButton.enabled = false
modulationButton.enabled = false
modeButton.enabled = false
acfButton.enabled = false
locationButton.enabled = false
addTagButton.enabled = false
} else {
docManagerButton.visible = true
freqButton.enabled = true
bandButton.enabled = true
modulationButton.enabled = true
modeButton.enabled = true
acfButton.enabled = true
locationButton.enabled = true
addTagButton.enabled = true
}
}
Dialog {
id: dialogAddCategory
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
closePolicy: Popup.CloseOnPressOutside
ColumnLayout {
anchors.fill: parent
Repeater {
model: allCategoryList
delegate: Button {
text: modelData.value
Layout.fillWidth: true
Layout.preferredHeight: 25
highlighted: true
bottomInset: 3
topInset: 3
flat: false
onClicked: {
addCatTag(modelData.clb_id)
dialogAddCategory.close()
}
}
}
}
}
ColumnLayout {
anchors.fill: parent
Label {
id: signalName
color: Material.accent
font.pixelSize: 25
horizontalAlignment: Text.AlignHCenter
Layout.topMargin: 10
Layout.fillHeight: false
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
clip: true
Layout.fillWidth: true
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Repeater {
model: categoryList
delegate: Button {
text: modelData[1]
Layout.preferredHeight: 25
highlighted: true
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: hovered
text: 'Click to remove'
}
onClicked: {
deleteCatTag(modelData[0])
}
}
}
Button {
id: addTagButton
enabled: false
Layout.preferredHeight: 25
Layout.preferredWidth: 25
bottomInset: 3
topInset: 3
text: '+'
onClicked: {
dialogAddCategory.open()
}
}
}
RowLayout {
Layout.fillWidth: true
ColumnLayout {
Label {
color: Material.accent
text: qsTr("FREQUENCY RANGE")
font.pixelSize: 12
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Label {
id: freqValue
color: Material.accent
text: qsTr("-")
font.pixelSize: 18
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Item {
Layout.fillWidth: true
}
ColumnLayout {
Label {
color: Material.accent
text: qsTr("BANDWIDTH RANGE")
font.pixelSize: 12
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
Label {
id: bandValue
color: Material.accent
text: qsTr("-")
font.pixelSize: 18
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
}
}
UIComponents.BandBar {
id: bandBar
Layout.fillWidth: true
}
RowLayout {
width: 100
height: 100
Layout.topMargin: 5
spacing: 15
ColumnLayout {
width: 100
height: 100
RowLayout {
Button {
id: freqButton
enabled: false
contentItem: Label {
text: "FREQUENCY"
horizontalAlignment : Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
font.bold: true
}
Layout.minimumWidth: 120
height: 25
flat: true
bottomInset: 0
topInset: 0
rightPadding: 10
leftPadding: 10
bottomPadding: 0
topPadding: 0
onClicked: {
openSigEditor('Frequency', [], true)
}
}
ListView {
height: 25
Layout.fillWidth: true
spacing: 5
orientation: ListView.Horizontal
clip: true
model: frequencyList
delegate: Button {
text: modelData[3]
height: 25
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: modelData[2] !== '' ? hovered : false
text: modelData[2]
}
onClicked: {
openSigEditor('Frequency', modelData, false)
}
}
}
}
RowLayout {
Button {
id: bandButton
enabled: false
contentItem: Label {
text: "BANDWIDTH"
horizontalAlignment : Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
font.bold: true
}
Layout.minimumWidth: 120
height: 25
flat: true
bottomInset: 0
topInset: 0
rightPadding: 10
leftPadding: 10
bottomPadding: 0
topPadding: 0
onClicked: {
openSigEditor('Bandwidth', [], true)
}
}
ListView {
height: 25
Layout.fillWidth: true
spacing: 5
orientation: ListView.Horizontal
clip: true
model: bandwidthList
delegate: Button {
text: modelData[3]
height: 25
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: modelData[2] !== '' ? hovered : false
text: modelData[2]
}
onClicked: {
openSigEditor('Bandwidth', modelData, false)
}
}
}
}
RowLayout {
Button {
id: modulationButton
enabled: false
contentItem: Label {
text: "MODULATION"
horizontalAlignment : Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
font.bold: true
}
Layout.minimumWidth: 120
height: 25
flat: true
bottomInset: 0
topInset: 0
rightPadding: 10
leftPadding: 10
bottomPadding: 0
topPadding: 0
onClicked: {
openSigEditor('Modulation', [], true)
}
}
ListView {
height: 25
Layout.fillWidth: true
spacing: 5
orientation: ListView.Horizontal
clip: true
model: modulationList
delegate: Button {
text: modelData[1]
height: 25
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: modelData[2] !== '' ? hovered : false
text: modelData[2]
}
onClicked: {
openSigEditor('Modulation', modelData, false)
}
}
}
}
RowLayout {
Button {
id: modeButton
enabled: false
contentItem: Label {
text: "MODE"
horizontalAlignment : Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
font.bold: true
}
Layout.minimumWidth: 120
height: 25
flat: true
bottomInset: 0
topInset: 0
rightPadding: 10
leftPadding: 10
bottomPadding: 0
topPadding: 0
onClicked: {
openSigEditor('Mode', [], true)
}
}
ListView {
height: 25
Layout.fillWidth: true
spacing: 5
orientation: ListView.Horizontal
clip: true
model: modeList
delegate: Button {
text: modelData[1]
height: 25
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: modelData[2] !== '' ? hovered : false
text: modelData[2]
}
onClicked: {
openSigEditor('Mode', modelData, false)
}
}
}
}
RowLayout {
Button {
id: acfButton
enabled: false
contentItem: Label {
text: "ACF"
horizontalAlignment : Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
font.bold: true
}
height: 25
Layout.minimumWidth: 120
flat: true
bottomInset: 0
topInset: 0
rightPadding: 10
leftPadding: 10
bottomPadding: 0
topPadding: 0
onClicked: {
openSigEditor('ACF', [], true)
}
}
ListView {
height: 25
Layout.fillWidth: true
spacing: 5
orientation: ListView.Horizontal
clip: true
model: acfList
delegate: Button {
text: modelData[1]
height: 25
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: modelData[2] !== '' ? hovered : false
text: modelData[2]
}
onClicked: {
openSigEditor('ACF', modelData, false)
}
}
}
}
RowLayout {
Button {
id: locationButton
enabled: false
contentItem: Label {
text: "LOCATION"
horizontalAlignment : Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 14
font.bold: true
}
Layout.minimumWidth: 120
height: 25
flat: true
bottomInset: 0
topInset: 0
rightPadding: 10
leftPadding: 10
bottomPadding: 0
topPadding: 0
onClicked: {
openSigEditor('Location', [], true)
}
}
ListView {
height: 25
Layout.fillWidth: true
spacing: 5
orientation: ListView.Horizontal
clip: true
model: locationList
delegate: Button {
text: modelData[1]
height: 25
bottomInset: 3
topInset: 3
flat: false
ToolTip {
visible: modelData[2] !== '' ? hovered : false
text: modelData[2]
}
onClicked: {
openSigEditor('Location', modelData, false)
}
}
}
}
ScrollView {
Layout.fillWidth: true
Layout.topMargin: 5
Layout.fillHeight: true
ScrollBar.vertical.interactive: true
TextArea {
id: descriptionTextArea
wrapMode: TextEdit.WordWrap
textFormat: Text.MarkdownText
font.pointSize: 10
readOnly: true
}
}
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: false
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
UIComponents.AudioPlayer {
id: audioPlayer
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
}
Image {
id: image
source: ""
Layout.preferredHeight: 300
Layout.preferredWidth: 180
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
fillMode: Image.Stretch
}
Item {
Layout.fillHeight: true
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
RoundButton {
id: urlButton
icon.source: "qrc:/images/icons/browser.svg"
display: AbstractButton.IconOnly
visible: false
text: "U"
onClicked: {
Qt.openUrlExternally(urlSigidwiki)
}
}
RoundButton {
id: docManagerButton
icon.source: "qrc:/images/icons/documents.svg"
display: AbstractButton.IconOnly
visible: false
text: "D"
onClicked: {
openDocManager()
}
}
}
}
}
}
}

74
ui/SpaceWeather.qml Normal file
View File

@@ -0,0 +1,74 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Window {
id: windowSpaceWeather
width: 1000
height: 700
Component.onCompleted: {
x = Screen.width/2 - width/2
y = Screen.height/2 - height/2
}
modality: Qt.ApplicationModal
flags: Qt.Window
title: qsTr("Artemis - Space Weather")
function updateBottomBar(message) {
spaceBottomBar.text = message
}
Page {
anchors.fill: parent
footer: Label {
id: spaceBottomBar
font.pixelSize: 12
leftPadding: 5
rightPadding: 5
bottomPadding: 5
}
ColumnLayout {
anchors.fill: parent
TabBar {
id: tabBar
width: parent.width
Layout.fillWidth: true
TabButton {
text: qsTr("Current")
}
TabButton {
text: qsTr("Forecasts")
}
}
StackLayout {
currentIndex: tabBar.currentIndex
Layout.fillHeight: true
Layout.fillWidth: true
Item {
SpaceWeatherCurrentPage {
id: spaceWeatherCurrentPage
}
}
Item {
SpaceWeatherForecastPage {
id: spaceWeatherForecastPage
}
}
}
}
}
}

View File

@@ -0,0 +1,400 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
import './components' as UIComponents
Page {
id: spaceWeatherCurrent
anchors.fill: parent
objectName: "spaceWeatherCurrentObj"
property string g_now_text
property string s_now_text
property string r_now_text
function loadReport(poseidon_data) {
setLight(lightG_now, 'G', poseidon_data['GSR_SCALES']['G_now'])
setLight(lightS_now, 'S', poseidon_data['GSR_SCALES']['S_now'])
setLight(lightR_now, 'R', poseidon_data['GSR_SCALES']['R_now'])
setLight(lightG_24h, 'G', poseidon_data['GSR_SCALES']['G_max24h'])
setLight(lightS_24h, 'S', poseidon_data['GSR_SCALES']['S_max24h'])
setLight(lightR_24h, 'R', poseidon_data['GSR_SCALES']['R_max24h'])
g_now_text = poseidon_data['GSR_SCALES']['G_now_text']
s_now_text = poseidon_data['GSR_SCALES']['S_now_text']
r_now_text = poseidon_data['GSR_SCALES']['R_now_text']
kIndexLightPanel.setLights(poseidon_data['AK']['k_index_round'])
labelKIndex.text = 'Kp Index: ' + poseidon_data['AK']['k_index']
aIndexLightPanel.setLights(poseidon_data['AK']['a_index'])
labelAIndex.text = 'A Index: ' + poseidon_data['AK']['a_index']
labelMux.text = poseidon_data['PROPAGATION']['MUX']
labelEME.text = poseidon_data['PROPAGATION']['EME']
labelMS.text = poseidon_data['PROPAGATION']['MS']
labelHfNoise.text = poseidon_data['AK']['exp_noise']
labelPeakFluxClass.text = poseidon_data['XRAY']['peak_flux_class']
labelPeakFluxClass3h.text = poseidon_data['XRAY']['peak_flux_class_3h']
labelPeakFluxClass24h.text = poseidon_data['XRAY']['peak_flux_class_24h']
}
function setLight(lightId, type, level) {
lightId.text = type + level
if (level === 0) {
} else if (level === 1) {
lightId.Material.background = Material.Green
} else if (level === 2) {
lightId.Material.background = Material.Amber
} else if (level === 3) {
lightId.Material.background = Material.Orange
} else if (level === 4) {
lightId.Material.background = Material.DeepOrange
} else if (level === 5) {
lightId.Material.background = Material.Red
}
}
DialogMessage {
id: gsrDialog
standardButtons: Dialog.Ok
}
Page {
anchors.fill: parent
RowLayout {
anchors.fill: parent
anchors.rightMargin: 20
anchors.leftMargin: 20
anchors.bottomMargin: 20
anchors.topMargin: 20
ColumnLayout {
Layout.fillHeight: true
Label {
id: labelKIndex
text: qsTr("Kp Index:")
font.pointSize: 11
font.capitalization: Font.SmallCaps
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
UIComponents.KIndexLight {
id: kIndexLightPanel
width: 250
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
ColumnLayout {
Label {
text: qsTr("NOAA SPACE WEATHER SCALE")
font.letterSpacing: 0.5
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Frame {
clip: true
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
rows: 5
columns: 3
Label {
width: parent.width /3
text: qsTr("Geomagnetic Storm")
font.capitalization: Font.SmallCaps
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Solar Radiation Storms")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.capitalization: Font.SmallCaps
}
Label {
text: qsTr("Radio Blackout")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.capitalization: Font.SmallCaps
}
Item {
}
Label {
text: qsTr("Current")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.pointSize: 8
}
Item {
}
Button {
id: lightG_now
text: qsTr("G")
font.pixelSize: 15
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.bold: true
display: AbstractButton.TextOnly
ToolTip.visible: hovered
ToolTip.text: qsTr("Click for details")
onClicked: {
gsrDialog.title = "Geomagnetic Storms"
gsrDialog.message = g_now_text
gsrDialog.open()
}
}
Button {
id: lightS_now
text: qsTr("S")
font.pixelSize: 15
display: AbstractButton.TextOnly
onClicked: {
gsrDialog.title = "Solar Radiation Storms"
gsrDialog.message = s_now_text
gsrDialog.open()
}
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.bold: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Click for details")
}
Button {
id: lightR_now
text: qsTr("R")
font.pixelSize: 15
display: AbstractButton.TextOnly
onClicked: {
gsrDialog.title = "Radio Blackout"
gsrDialog.message = r_now_text
gsrDialog.open()
}
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.bold: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Click for details")
}
Item {
}
Label {
text: qsTr("24h Maximums")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.pointSize: 8
}
Item {
}
Button {
id: lightG_24h
text: qsTr("G")
font.pixelSize: 15
display: AbstractButton.TextOnly
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.bold: true
}
Button {
id: lightS_24h
text: qsTr("S")
font.pixelSize: 15
display: AbstractButton.TextOnly
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.bold: true
}
Button {
id: lightR_24h
text: qsTr("R")
font.pixelSize: 15
display: AbstractButton.TextOnly
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.bold: true
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Label {
text: qsTr("X-RAY SOLAR ACTIVITY")
font.letterSpacing: 0.5
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Frame {
clip: true
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
columnSpacing: 15
columns: 2
rows: 2
Label {
text: qsTr("Current Flux Class:")
font.capitalization: Font.SmallCaps
}
Label {
id: labelPeakFluxClass
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.capitalization: Font.SmallCaps
font.bold: true
font.pointSize: 12
}
Label {
text: qsTr("Peak 3h Flux Class:")
font.capitalization: Font.SmallCaps
}
Label {
id: labelPeakFluxClass3h
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.capitalization: Font.SmallCaps
font.bold: true
font.pointSize: 12
}
Label {
text: qsTr("Peak 24h Flux Class:")
font.capitalization: Font.SmallCaps
}
Label {
id: labelPeakFluxClass24h
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.capitalization: Font.SmallCaps
font.bold: true
font.pointSize: 12
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Label {
text: qsTr("RF PROPAGATION")
font.letterSpacing: 0.5
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Frame {
clip: true
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
columnSpacing: 15
rows: 2
columns: 2
Label {
text: qsTr("MUX (MHz):")
}
Label {
id: labelMux
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.capitalization: Font.SmallCaps
font.bold: true
font.pointSize: 12
}
Label {
text: qsTr("Earth-Moon-Earth:")
font.capitalization: Font.SmallCaps
}
Label {
id: labelEME
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.pointSize: 12
font.bold: true
font.capitalization: Font.SmallCaps
}
Label {
text: qsTr("Meteor Scatter:")
font.capitalization: Font.SmallCaps
}
Label {
id: labelMS
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.pointSize: 12
font.capitalization: Font.SmallCaps
font.bold: true
}
Label {
text: qsTr("Expected HF Noise:")
font.capitalization: Font.SmallCaps
}
Label {
id: labelHfNoise
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
font.pointSize: 12
font.capitalization: Font.SmallCaps
font.bold: true
}
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
}
ColumnLayout {
Label {
id: labelAIndex
text: qsTr("A Index:")
font.pointSize: 11
font.capitalization: Font.SmallCaps
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
UIComponents.AIndexLight {
id: aIndexLightPanel
width: 250
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
}
}
}

View File

@@ -0,0 +1,758 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Page {
id: spaceWeatherCurrent
anchors.fill: parent
objectName: "spaceWeatherForecastObj"
function loadForecastReport(poseidon_data) {
if (poseidon_data['FORCST']['SUMMARY']['G_REPORT'][0] === 1) {
imageAttentionGReport.source = "qrc:/images/icons/dialog_warn.svg"
} else {
imageAttentionGReport.source = "qrc:/images/icons/dialog_info.svg"
}
labelGReport.text = poseidon_data['FORCST']['SUMMARY']['G_REPORT'][1]
if (poseidon_data['FORCST']['SUMMARY']['S_REPORT'][0] === 1) {
imageAttentionSReport.source = "qrc:/images/icons/dialog_warn.svg"
} else {
imageAttentionSReport.source = "qrc:/images/icons/dialog_info.svg"
}
labelSReport.text = poseidon_data['FORCST']['SUMMARY']['S_REPORT'][1]
if (poseidon_data['FORCST']['SUMMARY']['R_REPORT'][0] === 1) {
imageAttentionRReport.source = "qrc:/images/icons/dialog_warn.svg"
} else {
imageAttentionRReport.source = "qrc:/images/icons/dialog_info.svg"
}
labelRReport.text = poseidon_data['FORCST']['SUMMARY']['R_REPORT'][1]
labelDay1kp.text = poseidon_data['FORCST']['SUMMARY']['PRE_DATES'][0]
labelDay2kp.text = poseidon_data['FORCST']['SUMMARY']['PRE_DATES'][1]
labelDay3kp.text = poseidon_data['FORCST']['SUMMARY']['PRE_DATES'][2]
var timeRanges = ['00-03UT', '03-06UT', '06-09UT', '09-12UT', '12-15UT', '15-18UT', '18-21UT', '21-00UT']
for (var i = 0; i < timeRanges.length; i++) {
var timeRange = timeRanges[i]
for (var j = 0; j < 3; j++) {
var index = j.toString()
var labelName = 'labelKp' + (i).toString() + (j+1).toString()
var labelText = poseidon_data['FORCST']['SUMMARY']['kp'][timeRange][j]['textual']
var colorText = poseidon_data['FORCST']['SUMMARY']['kp'][timeRange][j]['color']
eval(labelName + '.text = labelText')
if (colorText !== '') {
eval(labelName + '.color = colorText')
}
}
}
labelDay1Event.text = poseidon_data['FORCST']['PRE_DATES'][0]
labelDay2Event.text = poseidon_data['FORCST']['PRE_DATES'][1]
labelDay3Event.text = poseidon_data['FORCST']['PRE_DATES'][2]
labelEventS10.text = poseidon_data['FORCST']['SUMMARY']['S_PROB']['probS1'][0] + ' %'
labelEventS11.text = poseidon_data['FORCST']['SUMMARY']['S_PROB']['probS1'][1] + ' %'
labelEventS12.text = poseidon_data['FORCST']['SUMMARY']['S_PROB']['probS1'][2] + ' %'
labelEventMFlare0.text = poseidon_data['FORCST']['CLASS_M'][0] + ' %'
labelEventMFlare1.text = poseidon_data['FORCST']['CLASS_M'][1] + ' %'
labelEventMFlare2.text = poseidon_data['FORCST']['CLASS_M'][2] + ' %'
labelEventXFlare0.text = poseidon_data['FORCST']['CLASS_X'][0] + ' %'
labelEventXFlare1.text = poseidon_data['FORCST']['CLASS_X'][1] + ' %'
labelEventXFlare2.text = poseidon_data['FORCST']['CLASS_X'][2] + ' %'
labelEventPFlare0.text = poseidon_data['FORCST']['CLASS_PROTON'][0] + ' %'
labelEventPFlare1.text = poseidon_data['FORCST']['CLASS_PROTON'][1] + ' %'
labelEventPFlare2.text = poseidon_data['FORCST']['CLASS_PROTON'][2] + ' %'
labelEventR1R20.text = poseidon_data['FORCST']['SUMMARY']['R_PROB']['probR1'][0] + ' %'
labelEventR1R21.text = poseidon_data['FORCST']['SUMMARY']['R_PROB']['probR1'][1] + ' %'
labelEventR1R22.text = poseidon_data['FORCST']['SUMMARY']['R_PROB']['probR1'][2] + ' %'
labelEventR30.text = poseidon_data['FORCST']['SUMMARY']['R_PROB']['probR3'][0] + ' %'
labelEventR31.text = poseidon_data['FORCST']['SUMMARY']['R_PROB']['probR3'][1] + ' %'
labelEventR32.text = poseidon_data['FORCST']['SUMMARY']['R_PROB']['probR3'][2] + ' %'
var geoActiveM0 = poseidon_data['FORCST']['GEO_MID_ACTIVE'][0] + ' %'
var geoActiveM1 = poseidon_data['FORCST']['GEO_MID_ACTIVE'][1] + ' %'
var geoActiveM2 = poseidon_data['FORCST']['GEO_MID_ACTIVE'][2] + ' %'
var geoActiveH0 = poseidon_data['FORCST']['GEO_HIG_ACTIVE'][0] + ' %'
var geoActiveH1 = poseidon_data['FORCST']['GEO_HIG_ACTIVE'][1] + ' %'
var geoActiveH2 = poseidon_data['FORCST']['GEO_HIG_ACTIVE'][2] + ' %'
var geoMinorM0 = poseidon_data['FORCST']['GEO_MID_MINOR'][0] + ' %'
var geoMinorM1 = poseidon_data['FORCST']['GEO_MID_MINOR'][1] + ' %'
var geoMinorM2 = poseidon_data['FORCST']['GEO_MID_MINOR'][2] + ' %'
var geoMinorH0 = poseidon_data['FORCST']['GEO_HIG_MINOR'][0] + ' %'
var geoMinorH1 = poseidon_data['FORCST']['GEO_HIG_MINOR'][1] + ' %'
var geoMinorH2 = poseidon_data['FORCST']['GEO_HIG_MINOR'][2] + ' %'
var geoMajorM0 = poseidon_data['FORCST']['GEO_MID_MAJOR'][0] + ' %'
var geoMajorM1 = poseidon_data['FORCST']['GEO_MID_MAJOR'][1] + ' %'
var geoMajorM2 = poseidon_data['FORCST']['GEO_MID_MAJOR'][2] + ' %'
var geoMajorH0 = poseidon_data['FORCST']['GEO_HIG_MAJOR'][0] + ' %'
var geoMajorH1 = poseidon_data['FORCST']['GEO_HIG_MAJOR'][1] + ' %'
var geoMajorH2 = poseidon_data['FORCST']['GEO_HIG_MAJOR'][2] + ' %'
labelEventActive0.text = geoActiveM0 + ' / ' + geoActiveH0
labelEventActive1.text = geoActiveM1 + ' / ' + geoActiveH1
labelEventActive2.text = geoActiveM2 + ' / ' + geoActiveH2
labelEventMinor0.text = geoMinorM0 + ' / ' + geoMinorH0
labelEventMinor1.text = geoMinorM1 + ' / ' + geoMinorH1
labelEventMinor2.text = geoMinorM2 + ' / ' + geoMinorH2
labelEventMajor0.text = geoMajorM0 + ' / ' + geoMajorH0
labelEventMajor1.text = geoMajorM1 + ' / ' + geoMajorH1
labelEventMajor2.text = geoMajorM2 + ' / ' + geoMajorH2
}
ColumnLayout {
anchors.fill: parent
anchors.rightMargin: 20
anchors.leftMargin: 20
anchors.bottomMargin: 20
anchors.topMargin: 20
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Label {
text: qsTr("FORECAST SUMMARY")
font.capitalization: Font.SmallCaps
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Frame {
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
spacing: 15
RowLayout {
spacing: 20
Image {
id: imageAttentionGReport
sourceSize.height: 40
sourceSize.width: 40
fillMode: Image.PreserveAspectFit
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Label {
font.capitalization: Font.SmallCaps
text: qsTr("Geomagnetic Activity")
font.pointSize: 11
Layout.fillWidth: true
}
Label {
id: labelGReport
wrapMode: Label.WordWrap
Layout.fillWidth: true
}
}
}
RowLayout {
spacing: 20
Image {
id: imageAttentionSReport
fillMode: Image.PreserveAspectFit
sourceSize.height: 40
sourceSize.width: 40
}
ColumnLayout {
Layout.fillHeight: true
Label {
text: qsTr("Solar Radiation Storms")
font.pointSize: 11
font.capitalization: Font.SmallCaps
Layout.fillWidth: true
}
Label {
id: labelSReport
wrapMode: Label.WordWrap
Layout.fillWidth: true
}
Layout.fillWidth: true
}
}
RowLayout {
spacing: 20
Image {
id: imageAttentionRReport
fillMode: Image.PreserveAspectFit
sourceSize.height: 40
sourceSize.width: 40
}
ColumnLayout {
Layout.fillHeight: true
Label {
text: qsTr("Radio Blackouts")
font.pointSize: 11
font.capitalization: Font.SmallCaps
Layout.fillWidth: true
}
Label {
id: labelRReport
wrapMode: Label.WordWrap
Layout.fillWidth: true
}
Layout.fillWidth: true
}
}
}
}
}
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Label {
text: qsTr("3-DAY Kp INDEX")
font.capitalization: Font.SmallCaps
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Frame {
clip: true
Layout.fillHeight: true
GridLayout {
anchors.fill: parent
columnSpacing: 15
rows: 9
columns: 4
Label {
text: qsTr("Time (UTC)")
}
Label {
id: labelDay1kp
text: qsTr("Day 1")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelDay2kp
text: qsTr("Day 2")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelDay3kp
text: qsTr("Day 3")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("00-03")
}
Label {
id: labelKp01
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp02
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp03
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("03-06")
}
Label {
id: labelKp11
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp12
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp13
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("06-09")
}
Label {
id: labelKp21
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp22
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp23
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("09-12")
}
Label {
id: labelKp31
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp32
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp33
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("12-15")
}
Label {
id: labelKp41
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp42
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp43
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("15-18")
}
Label {
id: labelKp51
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp52
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp53
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("18-21")
}
Label {
id: labelKp61
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp62
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp63
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
text: qsTr("21-00")
}
Label {
id: labelKp71
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp72
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
Label {
id: labelKp73
Layout.leftMargin: labelDay1kp.width * 0.3
font.pointSize: 12
font.bold: true
}
}
}
}
ColumnLayout {
Label {
text: qsTr("EVENTS PROBABILITY")
font.capitalization: Font.SmallCaps
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Frame {
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
rows: 9
columnSpacing: 15
columns: 4
Label {
}
Label {
id: labelDay1Event
text: qsTr("Day 1")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelDay2Event
text: qsTr("Day 2")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelDay3Event
text: qsTr("Day 3")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Solar Radiation Storm")
font.capitalization: Font.SmallCaps
font.bold: true
Layout.columnSpan: 4
}
Label {
text: qsTr("S1 or greater")
}
Label {
id: labelEventS10
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventS11
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventS12
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Solar Flares")
font.capitalization: Font.SmallCaps
font.bold: true
Layout.columnSpan: 4
}
Label {
text: qsTr("Class M flare")
}
Label {
id: labelEventMFlare0
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventMFlare1
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventMFlare2
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Class X flare")
}
Label {
id: labelEventXFlare0
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventXFlare1
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventXFlare2
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Proton flare")
}
Label {
id: labelEventPFlare0
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventPFlare1
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventPFlare2
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Radio Blackout")
font.capitalization: Font.SmallCaps
font.bold: true
Layout.columnSpan: 4
}
Label {
text: qsTr("R1 - R2")
}
Label {
id: labelEventR1R20
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventR1R21
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventR1R22
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("R3 or greater")
}
Label {
id: labelEventR30
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventR31
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventR32
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Geomagnetic Activity")
font.capitalization: Font.SmallCaps
font.bold: true
Layout.columnSpan: 4
}
Label {
text: qsTr("Active")
}
Label {
id: labelEventActive0
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventActive1
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventActive2
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Minor")
}
Label {
id: labelEventMinor0
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventMinor1
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventMinor2
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: qsTr("Major")
}
Label {
id: labelEventMajor0
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventMajor1
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
id: labelEventMajor2
font.bold: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
Layout.fillHeight: true
clip: true
}
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
}

View File

@@ -0,0 +1,140 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Item {
function setLights(aIndex) {
resetLights()
if (aIndex >= 0 && aIndex < 8) {
rect0.color = "#539bff"
} else if (aIndex >= 8 && aIndex < 16) {
rect1.color = "#0ccf43"
} else if (aIndex >= 16 && aIndex < 30) {
rect2.color = "#f0e000"
} else if (aIndex >= 30 && aIndex < 50) {
rect3.color = "#ffb700"
} else if (aIndex >= 50 && aIndex < 100) {
rect4.color = "#ff7b00"
} else if (aIndex >= 100) {
rect5.color = "#e80000"
}
}
function resetLights() {
rect0.color = "#2b4d7f"
rect1.color = "#076823"
rect2.color = "#797200"
rect3.color = "#815f00"
rect4.color = "#814100"
rect5.color = "#750300"
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Rectangle {
id: rect5
color: "#750300"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
topLeftRadius: 10
topRightRadius: 10
Label {
text: qsTr("SEVERE STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.2
}
}
Rectangle {
id: rect4
color: "#814100"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("MAJOR STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.2
}
}
Rectangle {
id: rect3
color: "#815f00"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("MINOR STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.2
}
}
Rectangle {
id: rect2
color: "#797200"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("ACTIVE")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.2
}
}
Rectangle {
id: rect1
color: "#076823"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("UNSETTLED")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.2
}
}
Rectangle {
id: rect0
color: "#2b4d7f"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
bottomLeftRadius: 10
bottomRightRadius: 10
Label {
text: qsTr("QUIET")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.2
}
}
}
}

View File

@@ -0,0 +1,156 @@
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import QtMultimedia
Item {
width: 200
height: 80
property bool loop: false
function loadSound(audio_path) {
player.stop()
player.source = audio_path
buttonPlay.icon.color = Material.accent
buttonPlay.enabled = true
buttonLoop.enabled = true
}
function playSound() {
buttonPlay.icon.color = Material.foreground
buttonPause.icon.color = Material.accent
buttonStop.icon.color = Material.accent
buttonPlay.enabled = false
buttonPause.enabled = true
buttonStop.enabled = true
buttonLoop.enabled = true
playerPosition.enabled = player.seekable
player.play()
}
function pauseSound() {
buttonPlay.icon.color = Material.accent
buttonPause.icon.color = Material.foreground
buttonPlay.enabled = true
buttonPause.enabled = false
player.pause()
}
function stopSound() {
buttonPlay.icon.color = Material.accent
buttonPause.icon.color = Material.foreground
buttonStop.icon.color = Material.foreground
buttonLoop.icon.color = Material.foreground
buttonPlay.enabled = true
buttonPause.enabled = false
buttonStop.enabled = false
buttonLoop.enabled = false
loop = false
player.stop()
}
function resetPlayer() {
player.stop()
player.source = ''
loop = false
buttonPlay.icon.color = Material.foreground
buttonPause.icon.color = Material.foreground
buttonStop.icon.color = Material.foreground
buttonLoop.icon.color = Material.foreground
buttonPlay.enabled = false
buttonPause.enabled = false
buttonStop.enabled = false
buttonLoop.enabled = false
playerPosition.enabled = false
}
ColumnLayout {
RowLayout {
spacing: 0
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
RoundButton {
id: buttonPlay
icon.color: Material.foreground
icon.source: "qrc:/images/icons/player_play.svg"
display: AbstractButton.IconOnly
enabled: false
flat: true
onClicked: playSound()
}
RoundButton {
id: buttonPause
icon.color: Material.foreground
icon.source: "qrc:/images/icons/player_pause.svg"
display: AbstractButton.IconOnly
enabled: false
flat: true
onClicked: pauseSound()
}
RoundButton {
id: buttonStop
icon.color: Material.foreground
icon.source: "qrc:/images/icons/player_stop.svg"
display: AbstractButton.IconOnly
enabled: false
flat: true
onClicked: stopSound()
}
RoundButton {
id: buttonLoop
icon.color: Material.foreground
icon.source: "qrc:/images/icons/player_loop.svg"
display: AbstractButton.IconOnly
enabled: false
flat: true
onClicked: {
if (loop) {
loop = false
icon.color = Material.foreground
} else {
loop = true
icon.color = Material.accent
}
}
}
}
Slider {
id: playerPosition
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.preferredHeight: 20
enabled: player.seekable
value: player.duration > 0 ? player.position / player.duration : 0
onMoved: {
player.position = player.duration * playerPosition.position
}
}
MediaPlayer {
id: player
audioOutput: audioOutput
onPlaybackStateChanged: {
if (player.playbackState === MediaPlayer.StoppedState) {
if (loop) {
playSound()
} else {
stopSound()
}
}
}
}
AudioOutput {
id: audioOutput
//volume: volumeSlider.value
}
}
}

261
ui/components/BandBar.qml Normal file
View File

@@ -0,0 +1,261 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
Item {
width: 400
height: 20
function setBandBar(lof, upf) {
resetBandBar()
if (lof < 30) {
selector.anchors.left = rectangleELF.left
} else if (lof >= 30 && lof < 300) {
selector.anchors.left = rectangleSLF.left
} else if (lof >= 300 && lof < 3000) {
selector.anchors.left = rectangleULF.left
} else if (lof >= 3000 && lof < 30000) {
selector.anchors.left = rectangleVLF.left
} else if (lof >= 30000 && lof < 300000) {
selector.anchors.left = rectangleLF.left
} else if (lof >= 300000 && lof < 3000000) {
selector.anchors.left = rectangleMF.left
} else if (lof >= 3000000 && lof < 30000000) {
selector.anchors.left = rectangleHF.left
} else if (lof >= 30000000 && lof < 300000000) {
selector.anchors.left = rectangleVHF.left
} else if (lof >= 300000000 && lof < 3000000000) {
selector.anchors.left = rectangleUHF.left
} else if (lof >= 3000000000 && lof < 30000000000) {
selector.anchors.left = rectangleSHF.left
} else if (lof >= 30000000000 && lof < 300000000000) {
selector.anchors.left = rectangleEHF.left
}
if (upf < 30) {
selector.anchors.right = rectangleELF.right
} else if (upf >= 30 && upf < 300) {
selector.anchors.right = rectangleSLF.right
} else if (upf >= 300 && upf < 3000) {
selector.anchors.right = rectangleULF.right
} else if (upf >= 3000 && upf < 30000) {
selector.anchors.right = rectangleVLF.right
} else if (upf >= 30000 && upf < 300000) {
selector.anchors.right = rectangleLF.right
} else if (upf >= 300000 && upf < 3000000) {
selector.anchors.right = rectangleMF.right
} else if (upf >= 3000000 && upf < 30000000) {
selector.anchors.right = rectangleHF.right
} else if (upf >= 30000000 && upf < 300000000) {
selector.anchors.right = rectangleVHF.right
} else if (upf >= 300000000 && upf < 3000000000) {
selector.anchors.right = rectangleUHF.right
} else if (upf >= 3000000000 && upf < 30000000000) {
selector.anchors.right = rectangleSHF.right
} else if (upf >= 30000000000 && upf < 300000000000) {
selector.anchors.right = rectangleEHF.right
}
}
function resetBandBar() {
selector.anchors.left = container.left
selector.anchors.right = container.left
}
Rectangle {
id: container
radius: 13
anchors.fill: parent
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop {
position: 0
color: "#1a000000"
}
GradientStop {
position: 0.5
color: "#26000000"
}
GradientStop {
position: 1
color: "#1a000000"
}
}
Rectangle {
id: rectangleELF
width: parent.width/11
anchors.left: parent.left
anchors.right: rectangleSLF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("ELF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleSLF
width: parent.width/11
anchors.right: rectangleULF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("SLF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleULF
width: parent.width/11
anchors.right: rectangleVLF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("ULF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleVLF
width: parent.width/11
anchors.right: rectangleLF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("VLF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleLF
width: parent.width/11
anchors.right: rectangleMF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("LF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleMF
width: parent.width/11
anchors.right: rectangleHF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("MF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleHF
width: parent.width/11
anchors.right: rectangleVHF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("HF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleVHF
width: parent.width/11
anchors.right: rectangleUHF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("VHF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleUHF
width: parent.width/11
anchors.right: rectangleSHF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("UHF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleSHF
width: parent.width/11
anchors.right: rectangleEHF.left
height: 20
color: "#00ffffff"
Label {
text: qsTr("SHF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: rectangleEHF
width: parent.width/11
anchors.right: parent.right
height: 20
color: "#00ffffff"
Label {
text: qsTr("EHF")
font.bold: true
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: selector
height: 20
color: Material.accent
radius: 10
z: -1
}
}
}

View File

@@ -0,0 +1,216 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Item {
function setLights(kIndex) {
resetLights()
if (kIndex === 0) {
rect0.color = "#539bff"
} else if (kIndex === 1) {
rect1.color = "#0ccf43"
} else if (kIndex === 2) {
rect2.color = "#0ccf43"
} else if (kIndex === 3) {
rect3.color = "#f0e000"
} else if (kIndex === 4) {
rect4.color = "#f0e000"
} else if (kIndex === 5) {
rect5.color = "#ffb700"
} else if (kIndex === 6) {
rect6.color = "#ff7b00"
} else if (kIndex === 7) {
rect7.color = "#e80000"
} else if (kIndex === 8) {
rect8.color = "#e80000"
} else if (kIndex === 9) {
rect9.color = "#e80000"
}
}
function resetLights() {
rect0.color = "#2b4d7f"
rect1.color = "#076823"
rect2.color = "#076823"
rect3.color = "#797200"
rect4.color = "#797200"
rect5.color = "#815f00"
rect6.color = "#814100"
rect7.color = "#750300"
rect8.color = "#750300"
rect9.color = "#750300"
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Rectangle {
id: rect9
color: "#750300"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
topLeftRadius: 10
topRightRadius: 10
Label {
text: qsTr("SUPER STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect8
color: "#750300"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("EXTREME STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect7
color: "#750300"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("SEVERE STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect6
color: "#814100"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("MAJOR STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect5
color: "#815f00"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("MINOR STORM")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect4
color: "#797200"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("ACTIVE")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect3
color: "#797200"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("UNSETTLED")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect2
color: "#076823"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("QUIET")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect1
color: "#076823"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Label {
text: qsTr("VERY QUIET")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
Rectangle {
id: rect0
color: "#2b4d7f"
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
bottomLeftRadius: 10
bottomRightRadius: 10
Label {
text: qsTr("INACTIVE")
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: parent.height*0.3
}
}
}
}