Newer
Older
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief QGC Main Tool Bar
* @author Gus Grubba <mavlink@grubba.com>
*/
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.MultiVehicleManager 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controllers 1.0
Item {
id: toolBarHolder
height: toolBarHeight
property var qgcPal: QGCPalette { id: palette; colorGroupEnabled: true }
property var activeVehicle: multiVehicleManager.activeVehicle
readonly property real toolBarHeight: ScreenTools.defaultFontPixelHeight * 3
property int cellSpacerSize: ScreenTools.isMobile ? getProportionalDimmension(6) : getProportionalDimmension(4)
readonly property int cellHeight: toolBarHeight * 0.75
readonly property real horizontalMargins: ScreenTools.defaultFontPixelWidth / 2
readonly property real verticalMargins: ScreenTools.defaultFontPixelHeight / 4
readonly property var colorBlue: "#1a6eaa"
readonly property var colorGreen: "#329147"
readonly property var colorRed: "#942324"
readonly property var colorOrange: "#a76f26"
readonly property var colorWhite: "#f0f0f0"
property var colorOrangeText: (qgcPal.globalTheme === QGCPalette.Light) ? "#b75711" : "#ea8225"
property var colorRedText: (qgcPal.globalTheme === QGCPalette.Light) ? "#ee1112" : "#ef2526"
property var colorGreenText: (qgcPal.globalTheme === QGCPalette.Light) ? "#046b1b" : "#00d930"
property var colorWhiteText: (qgcPal.globalTheme === QGCPalette.Light) ? "#343333" : "#f0f0f0"
MainToolBarController { id: _controller }
function showToolbarMessage(message) {
toolBarMessage.text = message
if (toolBarMessage.contentHeight > toolBarMessageCloseButton.height) {
toolBarHolder.height = toolBarHeight + toolBarMessage.contentHeight + (verticalMargins * 2)
toolBarHolder.height = toolBarHeight + toolBarMessageCloseButton.height + (verticalMargins * 2)
if (activeVehicle.messageTypeNone)
if (activeVehicle.messageTypeNorma)
if (activeVehicle.messageTypeWarning)
if (activeVehicle.messageTypeError)
return colorRed;
// Cannot be so make make it obnoxious to show error
return "purple";
}
function getMessageIcon() {
if (activeVehicle.messageTypeNormal || activeVehicle.messageTypeNone)
if(activeVehicle.batteryPercent < 20.0)
else if(activeVehicle.batteryPercent < 40.0)
else if(activeVehicle.batteryPercent < 60.0)
else if(activeVehicle.batteryPercent < 80.0)
else if(activeVehicle.batteryPercent < 90.0)
if (activeVehicle.batteryPercent > 40.0)
if(activeVehicle.batteryPercent > 0.01)
return colorRed;
// This means there is no battery level data
return colorBlue;
}
function getSatelliteColor() {
// No GPS data
if (activeVehicle.satelliteCount < 0)
if(activeVehicle.satelliteLock < 2)
if(activeVehicle.satelliteLock === 2)
return colorBlue;
// Lock is 3D or more
return colorGreen;
}
function getRSSIColor(value) {
if(value < 10)
return colorRed;
if(value < 50)
return colorOrange;
return colorGreen;
return (multiVehicleManager.activeVehicleAvailable && activeVehicle.heartbeatTimeout === 0 && _controller.connectionCount > 0);
//-------------------------------------------------------------------------
//-- Main menu for Mobile Devices
Menu {
id: maintMenu
id: flyViewShowing
text: "Fly"
checkable: true
checked: true
onTriggered: {
checked = true
_controller.onFlyView();
id: setupViewShowing
text: "Setup"
checkable: true
onTriggered: {
checked = true
_controller.onSetupView();
id: planViewShowing
text: "Plan"
checkable: true
onTriggered: {
checked = true
_controller.onPlanView();
MenuSeparator { }
MenuItem {
text: "QGroundControl Settings"
onTriggered: controller.showSettings()
}
Component {
id: activeVehicleComponent
height: cellHeight
spacing: cellSpacerSize
width: (activeVehicle.messageCount > 99) ? getProportionalDimmension(65) : getProportionalDimmension(60)
color: getMessageColor()
border.color: "#00000000"
border.width: 0
property bool showTriangle: false
Image {
id: messageIcon
source: getMessageIcon();
anchors.leftMargin: getProportionalDimmension(8)
id: messageTextRect
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
width: messages.width - messageIcon.width
text: (activeVehicle.messageCount > 0) ? activeVehicle.messageCount : ''
font.weight: Font.DemiBold
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
color: colorWhite
}
}
source: "/qmlimages/arrow-down.png"
visible: (messages.showTriangle) && (activeVehicle.messageCount > 0)
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.bottomMargin: getProportionalDimmension(3)
anchors.rightMargin: getProportionalDimmension(3)
Timer {
id: mouseOffTimer
interval: 2000;
running: false;
repeat: false
onTriggered: {
messages.showTriangle = false;
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
messages.showTriangle = true;
mouseOffTimer.start();
}
onClicked: {
_controller.onEnterMessageArea(p.x, p.y);
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 12
height: cellHeight
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
text: "Vehicle " + activeVehicle.id
menu: vehicleMenu
Menu {
id: vehicleMenu
}
Component {
id: vehicleMenuItemComponent
MenuItem {
checkable: true
checked: vehicle.active
onTriggered: multiVehicleManager.activeVehicle = vehicle
property int vehicleId: Number(text.split(" ")[1])
property var vehicle: multiVehicleManager.getVehicleById(vehicleId)
}
}
property var vehicleMenuItems: []
function updateVehicleMenu() {
// Remove old menu items
for (var i=0; i<vehicleMenuItems.length; i++) {
vehicleMenu.removeItem(vehicleMenuItems[i])
}
vehicleMenuItems.length = 0
// Add new items
for (var i=0; i<multiVehicleManager.vehicles.count; i++) {
var vehicle = multiVehicleManager.vehicles.get(i)
var menuItem = vehicleMenuItemComponent.createObject(null, { "text": "Vehicle " + vehicle.id })
vehicleMenuItems.push(menuItem)
vehicleMenu.insertItem(i, menuItem)
}
}
Component.onCompleted: updateVehicleMenu()
Connections {
target: multiVehicleManager.vehicles
onCountChanged: parent.updateVehicleMenu
color: getSatelliteColor();
border.color: "#00000000"
border.width: 0
Image {
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: getProportionalDimmension(6)
text: activeVehicle.satelliteCount >= 0 ? activeVehicle.satelliteCount : 'NA'
font.pixelSize: activeVehicle.satelliteCount >= 0 ? ScreenTools.defaultFontPixelSize : ScreenTools.smallFontPixelSize
font.weight: Font.DemiBold
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: getProportionalDimmension(6)
horizontalAlignment: Text.AlignRight
color: colorWhite
}
id: rssiRC
width: getProportionalDimmension(55)
visible: _controller.remoteRSSI <= 100
anchors.verticalCenter: parent.verticalCenter
color: getRSSIColor(_controller.remoteRSSI);
border.color: "#00000000"
border.width: 0
Image {
source: "qrc:/res/AntennaRC";
width: cellHeight * 0.7
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: getProportionalDimmension(6)
mipmap: true
smooth: true
}
anchors.right: parent.right
anchors.rightMargin: getProportionalDimmension(6)
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignRight
font.weight: Font.DemiBold
color: colorWhite
}
}
Rectangle {
id: rssiTelemetry
width: getProportionalDimmension(80)
height: cellHeight
visible: (_controller.telemetryRRSSI > 0) && (_controller.telemetryLRSSI > 0)
anchors.verticalCenter: parent.verticalCenter
color: getRSSIColor(Math.min(_controller.telemetryRRSSI,_controller.telemetryLRSSI));
border.color: "#00000000"
border.width: 0
Image {
source: "qrc:/res/AntennaT";
width: cellHeight * 0.7
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: getProportionalDimmension(6)
mipmap: true
smooth: true
}
Column {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: getProportionalDimmension(6)
Row {
anchors.right: parent.right
QGCLabel {
text: 'R '
font.weight: Font.DemiBold
color: colorWhite
}
QGCLabel {
text: _controller.telemetryRRSSI + 'dB'
font.weight: Font.DemiBold
color: colorWhite
}
}
Row {
anchors.right: parent.right
QGCLabel {
font.weight: Font.DemiBold
color: colorWhite
}
QGCLabel {
text: _controller.telemetryLRSSI + 'dB'
font.weight: Font.DemiBold
color: colorWhite
}
}
}
}
width: activeVehicle.batteryConsumed < 0.0 ? getProportionalDimmension(60) : getProportionalDimmension(80)
border.color: "#00000000"
border.width: 0
Image {
source: getBatteryIcon();
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
visible: batteryStatus.visible && activeVehicle.batteryConsumed < 0.0
Lorenz Meier
committed
text: (activeVehicle.batteryVoltage > 0) ? activeVehicle.batteryVoltage.toFixed(1) + 'V' : '---';
font.weight: Font.DemiBold
anchors.right: parent.right
anchors.rightMargin: getProportionalDimmension(6)
horizontalAlignment: Text.AlignRight
color: colorWhite
}
Column {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: getProportionalDimmension(6)
visible: batteryStatus.visible && activeVehicle.batteryConsumed >= 0.0
Lorenz Meier
committed
text: (activeVehicle.batteryVoltage > 0) ? activeVehicle.batteryVoltage.toFixed(1) + 'V' : '---';
width: getProportionalDimmension(30)
horizontalAlignment: Text.AlignRight
font.weight: Font.DemiBold
color: colorWhite
}
QGCLabel {
Lorenz Meier
committed
text: (activeVehicle.batteryConsumed > 0) ? activeVehicle.batteryConsumed.toFixed(0) + 'mAh' : '---';
width: getProportionalDimmension(30)
horizontalAlignment: Text.AlignRight
font.weight: Font.DemiBold
color: colorWhite
}
}
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 11
height: cellHeight
text: activeVehicle.armed ? "Armed" : "Disarmed"
menu: Menu {
MenuItem {
enabled: !activeVehicle.armed
text: "Arm"
onTriggered: activeVehicle.armed = true
}
MenuItem {
enabled: activeVehicle.armed
text: "Disarm"
onTriggered: activeVehicle.armed = false
QGCButton {
width: ScreenTools.defaultFontPixelWidth * 15
height: cellHeight
anchors.verticalCenter: parent.verticalCenter
text: activeVehicle.flightMode
menu: activeVehicle.flightModeSetAvailable ? flightModesMenu : null
Menu {
id: flightModesMenu
}
Component {
id: flightModeMenuItemComponent
MenuItem {
checkable: true
checked: activeVehicle.flightMode == text
onTriggered: activeVehicle.flightMode = text
property var flightModesMenuItems: []
function updateFlightModesMenu() {
if (activeVehicle.flightModeSetAvailable) {
// Remove old menu items
for (var i=0; i<flightModesMenuItems.length; i++) {
flightModesMenu.removeItem(flightModesMenuItems[i])
}
flightModesMenuItems.length = 0
// Add new items
for (var i=0; i<activeVehicle.flightModes.length; i++) {
var menuItem = flightModeMenuItemComponent.createObject(null, { "text": activeVehicle.flightModes[i] })
flightModesMenuItems.push(menuItem)
flightModesMenu.insertItem(i, menuItem)
}
}
}
Component.onCompleted: updateFlightModesMenu()
Connections {
target: multiVehicleManager
onActiveVehicleChanged: parent.updateFlightModesMenu
}
width: ScreenTools.defaultFontPixelWidth * 4
height: cellHeight
anchors.verticalCenter: parent.verticalCenter
color: colorBlue
border.width: 0
visible: activeVehicle.hilMode
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "HIL"
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
} // Row
} // Component - activeVehicleComponent
Row {
id: toolRow
x: horizontalMargins
y: (toolBarHeight - cellHeight) / 2
height: cellHeight
spacing: getProportionalDimmension(4)
//---------------------------------------------------------------------
//-- Main menu for Non Mobile Devices (Chevron Buttons)
Row {
id: row11
height: cellHeight
spacing: -getProportionalDimmension(12)
anchors.top: parent.top
visible: !ScreenTools.isMobile
Connections {
target: ScreenTools
onRepaintRequested: {
setupButton.repaintChevron = true;
planButton.repaintChevron = true;
flyButton.repaintChevron = true;
}
}
ExclusiveGroup { id: mainActionGroup }
QGCToolBarButton {
id: setupButton
width: getProportionalDimmension(90)
height: cellHeight
checked = true
_controller.onSetupView();
}
z: 1000
}
QGCToolBarButton {
id: planButton
width: getProportionalDimmension(90)
height: cellHeight
checked = true
_controller.onPlanView();
}
z: 900
}
QGCToolBarButton {
id: flyButton
width: getProportionalDimmension(90)
height: cellHeight
checked = true
_controller.onFlyView();
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
}
z: 800
}
} // Row
//---------------------------------------------------------------------
//-- Indicators
Row {
id: row12
height: cellHeight
spacing: cellSpacerSize
anchors.verticalCenter: parent.verticalCenter
//-- "Hamburger" menu for Mobile Devices
Item {
id: actionButton
visible: ScreenTools.isMobile
height: cellHeight
width: cellHeight
Image {
id: buttomImg
anchors.fill: parent
source: "/qmlimages/buttonMore.svg"
mipmap: true
smooth: true
antialiasing: true
fillMode: Image.PreserveAspectFit
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
if (mouse.button == Qt.LeftButton)
{
maintMenu.popup();
}
}
}
}
//-- Separator if Hamburger menu is visible
Rectangle {
visible: actionButton.visible
height: cellHeight
width: cellHeight
color: "#00000000"
anchors.verticalCenter: parent.verticalCenter
}
Loader {
id: activeVehicleLoader
visible: showMavStatus()
sourceComponent: multiVehicleManager.activeVehicleAvailable ? activeVehicleComponent : undefined
property real cellHeight: toolBarHolder.cellHeight
property real cellSpacerSize: toolBarHolder.cellSpacerSize
}
visible: (_controller.connectionCount > 0 && multiVehicleManager.activeVehicleAvailable && activeVehicle.heartbeatTimeout != 0)
anchors.verticalCenter: parent.verticalCenter
color: "#00000000"
border.color: "#00000000"
border.width: 0
id: connectionStatusText
text: qsTr("CONNECTION LOST")
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
id: connectRow
anchors.rightMargin: verticalMargins
anchors.right: parent.right
anchors.top: toolRow.top
anchors.verticalCenter: toolRow.verticalCenter
height: toolRow.height
spacing: cellSpacerSize
_controller.configListChanged.connect(connectMenu.updateConnectionList);
function addMenuEntry(name) {
var label = "Add Connection"
if(name !== "")
label = name;
var mItem = connectMenu.addItem(label);
var menuSlot = function() {_controller.onConnect(name)};
mItem.triggered.connect(menuSlot);
}
function updateConnectionList() {
connectMenu.clear();
for(var i = 0; i < _controller.configList.length; i++) {
connectMenu.addMenuEntry(_controller.configList[i]);
if(_controller.configList.length > 0) {
connectMenu.addSeparator();
}
// Add "Add Connection" to the list
connectMenu.addMenuEntry("");
visible: _controller.connectionCount === 0
text: qsTr("Connect")
menu: connectMenu
}
QGCButton {
id: disconnectButton
visible: _controller.connectionCount === 1
}
}
Menu {
id: disconnectMenu
Component.onCompleted: {
_controller.connectedListChanged.connect(disconnectMenu.onConnectedListChanged)
function addMenuEntry(name) {
var mItem = disconnectMenu.addItem(name);
var menuSlot = function() {_controller.onDisconnect(name)};
function onConnectedListChanged(conList) {
disconnectMenu.clear();
for(var i = 0; i < conList.length; i++) {
visible: _controller.connectionCount > 1
id: progressBar
anchors.top: toolRow.bottom
height: getProportionalDimmension(3)
width: parent.width * _controller.progressBarValue
id: toolBarMessageArea
anchors.leftMargin: horizontalMargins
anchors.rightMargin: horizontalMargins
anchors.topMargin: verticalMargins
anchors.bottomMargin: verticalMargins
anchors.top: progressBar.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: qgcPal.windowShadeDark
visible: false
QGCLabel {
id: toolBarMessage
anchors.fill: parent
wrapMode: Text.WordWrap
}
QGCButton {
id: toolBarMessageCloseButton
anchors.rightMargin: horizontalMargins
anchors.top: parent.top
anchors.right: parent.right
text: "Close Message"
onClicked: {
parent.visible = false
_controller.onToolBarMessageClosed()