Ref T731, moved QML map in dialog

* initial structure
* embedded a QQuickWidget in dialog
This commit is contained in:
Klaus Basan
2019-09-21 01:52:55 +02:00
committed by Mat Sutcliffe
parent cf6d60348e
commit 329b1e8c9a
14 changed files with 741 additions and 10 deletions

View File

@@ -1,6 +1,6 @@
load(common_pre)
QT += core dbus gui network svg widgets
QT += core dbus gui network svg widgets quickwidgets
TARGET = blackgui
TEMPLATE = lib
@@ -61,6 +61,7 @@ HEADERS += $$PWD/graphs/*.h
SOURCES += $$PWD/graphs/*.cpp
FORMS += $$PWD/*.ui
RESOURCES += qml/qml.qrc
win32 {
HEADERS += $$PWD/win/*.h

View File

@@ -0,0 +1,27 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
//! \file
#include "afvmapdialog.h"
#include "ui_afvmapdialog.h"
namespace BlackGui
{
namespace Components
{
CAfvMapDialog::CAfvMapDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::CAfvMapDialog)
{
ui->setupUi(this);
}
CAfvMapDialog::~CAfvMapDialog() { }
} // ns
} // ns

View File

@@ -0,0 +1,41 @@
/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
//! \file
#ifndef BLACKGUI_COMPONENTS_AFVMAPDIALOG_H
#define BLACKGUI_COMPONENTS_AFVMAPDIALOG_H
#include "blackgui/blackguiexport.h"
#include <QDialog>
#include <QScopedPointer>
namespace Ui { class CAfvMapDialog; }
namespace BlackGui
{
namespace Components
{
//! QML map to display ATC stations
class BLACKGUI_EXPORT CAfvMapDialog : public QDialog
{
Q_OBJECT
public:
//! Ctor
explicit CAfvMapDialog(QWidget *parent = nullptr);
//! Dtor
virtual ~CAfvMapDialog() override;
private:
QScopedPointer<Ui::CAfvMapDialog> ui;
};
} // ns
} // ns
#endif // guard

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CAfvMapDialog</class>
<widget class="QDialog" name="CAfvMapDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>640</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QQuickWidget" name="qw_AfvMap">
<property name="resizeMode">
<enum>QQuickWidget::SizeRootObjectToView</enum>
</property>
<property name="source">
<url>
<string>qrc:/blackgui/qml/AFVMap.qml</string>
</url>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="bb_AfvMap">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QQuickWidget</class>
<extends>QWidget</extends>
<header location="global">QtQuickWidgets/QQuickWidget</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>bb_AfvMap</sender>
<signal>accepted()</signal>
<receiver>CAfvMapDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>bb_AfvMap</sender>
<signal>rejected()</signal>
<receiver>CAfvMapDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

399
src/blackgui/qml/AFVMap.qml Normal file
View File

@@ -0,0 +1,399 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtLocation 5.12
import QtPositioning 5.12
Rectangle {
id: window
width: 1200
height: 800
visible: true
// title: "Audio For Vatsim"
Plugin {
id: mapPlugin
name: "osm"
}
Grid {
id: leftGrid
columns: 2
rows: 6
spacing: 10
padding: 10
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 5
anchors.leftMargin: 10
Label {
id: lblUsername
width: 100
text: qsTr("Username")
verticalAlignment: Text.AlignVCenter
Layout.fillHeight: true
Layout.fillWidth: false
}
TextField {
id: tfUsername
width: 350
height: 25
text: qsTr("1234567")
selectByMouse: true
enabled: voiceClient.connectionStatus == 0 // Disconnected
horizontalAlignment: Text.AlignLeft
renderType: Text.NativeRendering
}
Label {
id: lblPassword
width: 100
text: qsTr("Password")
Layout.fillWidth: false
Layout.fillHeight: false
verticalAlignment: Text.AlignVCenter
}
TextField {
id: tfPassword
width: 350
height: 25
text: qsTr("123456")
selectByMouse: true
enabled: voiceClient.connectionStatus == 0 // Disconnected
echoMode: TextInput.PasswordEchoOnEdit
horizontalAlignment: Text.AlignLeft
renderType: Text.NativeRendering
}
Label {
id: lblCallsign
width: 100
text: qsTr("Callsign")
Layout.fillWidth: false
Layout.fillHeight: false
verticalAlignment: Text.AlignVCenter
}
TextField {
id: tfCallsign
width: 350
height: 25
text: qsTr("DECHK")
selectByMouse: true
enabled: voiceClient.connectionStatus == 0 // Disconnected
horizontalAlignment: Text.AlignLeft
renderType: Text.NativeRendering
}
Label {
id: lblInputDevice
width: 100
text: qsTr("Input Device")
verticalAlignment: Text.AlignVCenter
Layout.fillHeight: false
Layout.fillWidth: false
}
ComboBox {
id: cbInputDevices
width: 350
height: 25
model: voiceClient.availableInputDevices()
}
Label {
id: lblOutputDevice
width: 100
text: qsTr("Output Device")
verticalAlignment: Text.AlignVCenter
Layout.fillHeight: false
Layout.fillWidth: false
}
ComboBox {
id: cbOutputDevices
width: 350
height: 25
model: voiceClient.availableOutputDevices()
}
Frame {
background: Rectangle {
color: "transparent"
border.color: "transparent"
}
}
Row {
spacing: 10
Button {
id: btConnect
width: 170
height: 25
text: voiceClient.connectionStatus == 0 ? "Connect" : "Disconnect"
onClicked: {
if (voiceClient.connectionStatus == 0) {
voiceClient.connectTo(tfUsername.text, tfPassword.text, tfCallsign.text)
afvMapReader.setOwnCallsign(tfCallsign.text)
} else if (voiceClient.connectionStatus == 1) {
voiceClient.disconnectFrom()
}
}
}
Button {
id: btStartAudio
property bool started: false
width: 170
height: 25
text: qsTr("Start Audio")
onClicked: {
btStartAudio.enabled = false
cbInputDevices.enabled = false
cbOutputDevices.enabled = false
voiceClient.start(cbInputDevices.currentText, cbOutputDevices.currentText)
}
}
}
}
Grid {
id: rightGrid
padding: 10
anchors.top: parent.top
anchors.left: leftGrid.right
anchors.right: parent.right
spacing: 10
rows: 3
columns: 3
Transceiver {
id: transceiver1
transceiverId: 0
onRxOnChanged: {
voiceClient.enableTransceiver(transceiverId, rxOn)
}
}
SpinBox {
id: sbAltitude
width: 150
height: 40
stepSize: 500
to: 50000
from: 0
value: 1000
}
Label {
id: lblReceivingCom1
height: 40
text: qsTr("Receiving: ") + voiceClient.receivingCallsignsCom1
verticalAlignment: Text.AlignVCenter
}
Transceiver {
id: transceiver2
transceiverId: 1
txOn: false
onRxOnChanged: {
voiceClient.enableTransceiver(transceiverId, rxOn)
}
}
Button {
id: btUpdateStack
width: 150
height: 40
text: qsTr("Update Stack")
onClicked: {
voiceClient.updateComFrequency(0, transceiver1.frequency * 1000)
voiceClient.updateComFrequency(1, transceiver2.frequency * 1000)
voiceClient.updatePosition(map.center.latitude, map.center.longitude, sbAltitude.value)
}
}
Label {
id: lblReceivingCom2
height: 40
text: qsTr("Receiving: ") + voiceClient.receivingCallsignsCom2
verticalAlignment: Text.AlignVCenter
// anchors.verticalCenter: parent.verticalCenter
}
}
Column {
id: column
spacing: 10
anchors.top: rightGrid.bottom
anchors.left: leftGrid.right
anchors.right: parent.right
ProgressBar {
id: pbAudioInput
width: 500
height: 25
anchors.left: parent.left
anchors.leftMargin: 10
value: voiceClient.inputVolumePeakVU
}
ProgressBar {
id: pbAudioOutput
width: 500
height: 25
anchors.left: parent.left
anchors.leftMargin: 10
value: voiceClient.outputVolumePeakVU
}
}
Row {
padding: 0
spacing: 10
anchors.top: column.bottom
anchors.left: leftGrid.right
anchors.right: parent.right
CheckBox {
id: cbVhfEffects
text: qsTr("VHF Effects")
checked: true
anchors.verticalCenter: parent.verticalCenter
onClicked: voiceClient.setBypassEffects(!checked)
}
CheckBox {
id: cbLoopback
text: qsTr("Loopback")
checked: false
anchors.verticalCenter: parent.verticalCenter
onClicked: voiceClient.setLoopBack(checked)
}
Button {
id: btPtt
width: 150
height: 40
text: qsTr("PTT")
onPressed: voiceClient.setPtt(true)
onReleased: voiceClient.setPtt(false)
background: Rectangle {
implicitWidth: btPtt.width
implicitHeight: btPtt.height
color: btPtt.down ? "lightgreen" : "lightgrey"
border.width: 1
radius: 2
}
}
Label {
function translateStatus(status) {
switch(status) {
case 0: return "Disconnected"
case 1: return "Connected"
default: return "Unknown"
}
}
id: lblStatus
text: "Status: " + translateStatus(voiceClient.connectionStatus)
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
}
Map {
id: map
anchors.topMargin: 5
anchors.top: leftGrid.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
plugin: mapPlugin
center: QtPositioning.coordinate(48.50, 11.50) // Oslo
zoomLevel: 3
MapItemView {
id: mapItemView
model: afvMapReader.atcStationModel
delegate: atcDelegate
}
Component {
id: atcDelegate
AtcRing {
position {
latitude: latitude
longitude: longitude
}
radius: radioDistanceM
cs: callsign
freqAsString: frequencyAsString
freqKhz: frequencyKhz
onSelected: {
map.center = QtPositioning.coordinate(latitude, longitude)
transceiver1.frequency = frequency
voiceClient.updateComFrequency(0, transceiver1.frequency * 1000)
voiceClient.updateComFrequency(1, transceiver2.frequency * 1000)
voiceClient.updatePosition(map.center.latitude, map.center.longitude, sbAltitude.value)
}
}
}
Rectangle {
width: 3
height: 15
color: "blue"
anchors.verticalCenter: map.verticalCenter
anchors.horizontalCenter: map.horizontalCenter
}
Rectangle {
width: 15
height: 3
color: "blue"
anchors.verticalCenter: map.verticalCenter
anchors.horizontalCenter: map.horizontalCenter
}
Button {
id: btZoomIn
width: 30
height: 30
text: "+"
anchors.right: parent.right
anchors.rightMargin: 20
anchors.bottom: btZoomOut.top
anchors.bottomMargin: 5
onClicked: map.zoomLevel = map.zoomLevel + 1
}
Button {
id: btZoomOut
width: 30
height: 30
text: "-"
anchors.right: parent.right
anchors.rightMargin: 20
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
onClicked: map.zoomLevel = map.zoomLevel - 1
}
}
Timer {
interval: 5000; running: true; repeat: true
onTriggered: {
voiceClient.updateComFrequency(0, transceiver1.frequency * 1000)
voiceClient.updateComFrequency(1, transceiver2.frequency * 1000)
voiceClient.updatePosition(map.center.latitude, map.center.longitude, sbAltitude.value)
}
}
}

View File

@@ -0,0 +1,74 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtLocation 5.12
import QtPositioning 5.12
MapItemGroup {
id: atcRing
signal selected(real latitude, real longitude, string frequency)
property alias position: mainCircle.center
property alias radius: mainCircle.radius
property alias cs: idCallsignText.text
property alias freqAsString: idFrequency.text
property int freqKhz: 122800
MapCircle {
id: mainCircle
color: 'green'
border.width: 3
border.color: 'green'
opacity: 0.3
MouseArea {
anchors.fill: parent
onClicked: {
idCallsign.visible = !idCallsign.visible
}
onDoubleClicked: {
atcRing.selected(mainCircle.center.latitude, mainCircle.center.longitude, atcRing.freqKhz)
}
}
}
MapQuickItem {
id: circleCenter
sourceItem: Rectangle { width: 6; height: 6; color: "#000000"; border.width: 2; border.color: "#000000"; smooth: true; radius: 3 }
coordinate: mainCircle.center
opacity:1.0
anchorPoint: Qt.point(sourceItem.width/2, sourceItem.height/2)
}
MapQuickItem {
id: idCallsign
visible: false
coordinate: mainCircle.center
anchorPoint: Qt.point(-circleCenter.sourceItem.width * 0.5, circleCenter.sourceItem.height * -1.5)
sourceItem: Item {
Rectangle {
color: "#FFFFFF"
width: idCallsignText.width * 1.3
height: (idCallsignText.height + idFrequency.height) * 1.3
border.width: 2
border.color: "#000000"
radius: 5
}
Text {
id: idCallsignText
color:"#000000"
font.bold: true
}
Text {
id: idFrequency
color:"#000000"
anchors.top: idCallsignText.bottom
}
}
}
}

View File

@@ -0,0 +1,79 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
Row {
id: idTransceiver
property int transceiverId: 0
property alias frequency: sbFrequency.value
property alias rxOn: cbEnabled.checked
property alias txOn: cbTxOn.checked
spacing: 10
Label {
id: lblRadio
text: 'Radio ' + transceiverId
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
SpinBox {
id: sbFrequency
width: 150
height: 40
editable: true
stepSize: 25
to: 140000
from: 110000
value: 122800
property int decimals: 3
property real realValue: value / 1000
validator: DoubleValidator {
bottom: Math.min(sbFrequency.from, sbFrequency.to)
top: Math.max(sbFrequency.from, sbFrequency.to)
}
textFromValue: function(value, locale) {
return Number(value / 1000).toLocaleString(locale, 'f', sbFrequency.decimals)
}
valueFromText: function(text, locale) {
return Number.fromLocaleString(locale, text) * 1000
}
MouseArea {
anchors.fill: parent
onWheel: {
if (wheel.angleDelta.y > 0)
{
sbFrequency.value += sbFrequency.stepSize
}
else
{
sbFrequency.value -= sbFrequency.stepSize
}
wheel.accepted=true
}
}
}
CheckBox {
id: cbTxOn
height: 25
text: qsTr("TX")
checked: true
anchors.verticalCenter: parent.verticalCenter
onClicked: idTransceiver.txOnChanged(checked)
}
CheckBox {
id: cbEnabled
height: 25
text: qsTr("Enabled")
checked: true
anchors.verticalCenter: parent.verticalCenter
onClicked: idTransceiver.rxOnChanged(checked)
}
}

7
src/blackgui/qml/qml.qrc Normal file
View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/blackgui/qml">
<file>AFVMap.qml</file>
<file>AtcRing.qml</file>
<file>Transceiver.qml</file>
</qresource>
</RCC>

View File

@@ -1,6 +1,6 @@
load(common_pre)
QT += core dbus network widgets
QT += core dbus network widgets quickwidgets
TARGET = swiftguistd
TEMPLATE = app

View File

@@ -12,6 +12,7 @@
#include "blackgui/components/logcomponent.h"
#include "blackgui/components/dbloaddatadialog.h"
#include "blackgui/components/autopublishdialog.h"
#include "blackgui/components/afvmapdialog.h"
#include "blackgui/components/logindialog.h"
#include "blackgui/components/modelbrowserdialog.h"
#include "blackgui/components/settingscomponent.h"
@@ -305,7 +306,7 @@ void SwiftGuiStd::onKickedFromNetwork(const QString &kickMessage)
void SwiftGuiStd::onConnectionStatusChanged(const CConnectionStatus &from, const CConnectionStatus &to)
{
Q_UNUSED(from);
Q_UNUSED(from)
this->updateGuiStatusInformation();
// sounds
@@ -424,13 +425,13 @@ void SwiftGuiStd::onToggledWindowsOnTop(bool onTop)
void SwiftGuiStd::onCurrentMainWidgetChanged(int currentIndex)
{
emit this->currentMainInfoAreaChanged(ui->sw_MainMiddle->currentWidget());
Q_UNUSED(currentIndex);
Q_UNUSED(currentIndex)
}
void SwiftGuiStd::onChangedMainInfoAreaFloating(bool floating)
{
// code for whole floating area goes here
Q_UNUSED(floating);
Q_UNUSED(floating)
}
void SwiftGuiStd::onRequestedConsoleMessage(const QString &logMsg, bool clear)
@@ -632,3 +633,12 @@ bool SwiftGuiStd::startModelBrowser()
return true;
}
bool SwiftGuiStd::startAFVMap()
{
if (!m_mapDialog)
{
m_mapDialog.reset(new CAfvMapDialog(this));
}
m_mapDialog->exec();
return true;
}

View File

@@ -56,6 +56,7 @@ namespace BlackGui
class CAutoPublishDialog;
class CLoginDialog;
class CModelBrowserDialog;
class CAfvMapDialog;
}
}
namespace Ui { class SwiftGuiStd; }
@@ -118,6 +119,7 @@ private:
QScopedPointer<BlackGui::Components::CAutoPublishDialog> m_autoPublishDialog; //!< auto publish dialog
QScopedPointer<BlackGui::Components::CLoginDialog> m_loginDialog; //!< login dialog
QScopedPointer<BlackGui::Components::CModelBrowserDialog> m_modelBrower; //!< model browser
QScopedPointer<BlackGui::Components::CAfvMapDialog> m_mapDialog; //!< map dialog
QScopedPointer<BlackGui::Components::CAircraftModelSetValidationDialog> m_validationDialog; //!< aircraft model validation dialog
BlackMisc::CData<BlackMisc::Simulation::Data::TLastAutoPublish> m_lastAutoPublish { this };
BlackCore::CActionBind m_actionPtt { BlackMisc::Input::pttHotkeyAction(), BlackMisc::CIcons::radio16(), this, &SwiftGuiStd::onPttChanged };
@@ -310,6 +312,9 @@ private:
//! Start the model browser
bool startModelBrowser();
//! Start AFV map
bool startAFVMap();
//! Request overlay inline text message @{
void onShowOverlayVariant(const BlackMisc::CVariant &variant, int durationMs);
void onShowOverlayInlineTextMessageTab(BlackGui::Components::TextMessageTab tab);

View File

@@ -282,6 +282,7 @@
<addaction name="menu_AutoPublish"/>
<addaction name="menu_ToggleIncognito"/>
<addaction name="menu_ModelBrowser"/>
<addaction name="menu_AfvMap"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Window"/>
@@ -505,7 +506,7 @@
</action>
<action name="menu_AutoPublish">
<property name="icon">
<iconset resource="../blackmisc/blackmisc.qrc">
<iconset>
<normaloff>:/diagona/icons/diagona/icons/paper-plane--plus.png</normaloff>:/diagona/icons/diagona/icons/paper-plane--plus.png</iconset>
</property>
<property name="text">
@@ -522,6 +523,11 @@
<string>Model brower</string>
</property>
</action>
<action name="menu_AfvMap">
<property name="text">
<string>AFV map</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
@@ -568,9 +574,7 @@
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../blackmisc/blackmisc.qrc"/>
</resources>
<resources/>
<connections/>
<slots>
<slot>setMainPage()</slot>

View File

@@ -226,6 +226,7 @@ void SwiftGuiStd::initGuiSignals()
connect(ui->menu_MovingMap, &QAction::triggered, this, &SwiftGuiStd::onMenuClicked);
connect(ui->menu_ToggleIncognito, &QAction::triggered, this, &SwiftGuiStd::onMenuClicked);
connect(ui->menu_ModelBrowser, &QAction::triggered, this, &SwiftGuiStd::startModelBrowser, Qt::QueuedConnection);
connect(ui->menu_AfvMap, &QAction::triggered, this, &SwiftGuiStd::startAFVMap, Qt::QueuedConnection);
connect(m_navigator.data(), &CNavigatorDialog::navigatorClosed, this, &SwiftGuiStd::onNavigatorClosed, Qt::QueuedConnection);
m_navigator->setMainWindow(this);

View File

@@ -168,7 +168,7 @@ void SwiftGuiStd::initMenus()
// for hotkeys
const QString swift(CGuiActionBindHandler::pathSwiftPilotClient());
static const CActionBind swiftRoot(swift, CIcons::swift16()); // inserts action for root folder
Q_UNUSED(swiftRoot);
Q_UNUSED(swiftRoot)
m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_InfoAreas, swift + "Info areas"));
m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_File, swift + "File"));
m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_Window, swift + "Window"));