Skip to content
QGCToolBar.cc 17.7 KiB
Newer Older
/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009 - 2011 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/>.

======================================================================*/

#include <QToolButton>
#include <QLabel>
#include "QGCToolBar.h"
#include "UASManager.h"
lm's avatar
lm committed
#include "MainWindow.h"

QGCToolBar::QGCToolBar(QWidget *parent) :
    QToolBar(parent),
    toggleLoggingAction(NULL),
    logReplayAction(NULL),
    mav(NULL),
lm's avatar
lm committed
    player(NULL),
    changed(true),
    batteryPercent(0),
    batteryVoltage(0),
    wpId(0),
    wpDistance(0),
    systemArmed(false)
{
    setObjectName("QGC_TOOLBAR");
lm's avatar
lm committed

    toggleLoggingAction = new QAction(QIcon(":"), "Logging", this);
    toggleLoggingAction->setCheckable(true);
    logReplayAction = new QAction(QIcon(":"), "Replay", this);
lm's avatar
lm committed

    addAction(toggleLoggingAction);
    addAction(logReplayAction);

    // CREATE TOOLBAR ITEMS
    // Add internal actions
    // Add MAV widget
    symbolButton = new QToolButton(this);
    symbolButton->setStyleSheet("QWidget { background-color: #050508; color: #DDDDDF; background-clip: border; } QToolButton { font-weight: bold; font-size: 12px; border: 0px solid #999999; border-radius: 5px; min-width:22px; max-width: 22px; min-height: 22px; max-height: 22px; padding: 0px; margin: 0px 0px 0px 20px; background-color: none; }");
	addWidget(symbolButton);

LM's avatar
LM committed
    toolBarNameLabel = new QLabel("------", this);
	toolBarNameLabel->setToolTip(tr("Currently controlled vehicle"));
    addWidget(toolBarNameLabel);

    toolBarTimeoutLabel = new QLabel("UNCONNECTED", this);
    toolBarTimeoutLabel->setToolTip(tr("System timed out, interval since last message"));
    toolBarTimeoutLabel->setStyleSheet(QString("QLabel { margin: 0px 2px; font: 14px; color: %1; background-color: %2; }").arg(QGC::colorDarkWhite.name()).arg(QGC::colorMagenta.name()));
    addWidget(toolBarTimeoutLabel);

    toolBarSafetyLabel = new QLabel("SAFE", this);
    toolBarSafetyLabel->setStyleSheet("QLabel { margin: 0px 2px; font: 14px; color: #14C814; }");
	toolBarSafetyLabel->setToolTip(tr("Vehicle safety state"));
    addWidget(toolBarSafetyLabel);

LM's avatar
LM committed
    toolBarModeLabel = new QLabel("------", this);
    toolBarModeLabel->setStyleSheet("QLabel { margin: 0px 2px; font: 14px; color: #3C7B9E; }");
	toolBarModeLabel->setToolTip(tr("Vehicle mode"));
    addWidget(toolBarModeLabel);

LM's avatar
LM committed
    toolBarStateLabel = new QLabel("------", this);
    toolBarStateLabel->setStyleSheet("QLabel { margin: 0px 2px; font: 14px; color: #FEC654; }");
	toolBarStateLabel->setToolTip(tr("Vehicle state"));
    addWidget(toolBarStateLabel);

LM's avatar
LM committed
    toolBarBatteryBar = new QProgressBar(this);
    toolBarBatteryBar->setStyleSheet("QProgressBar:horizontal { margin: 0px 4px 0px 0px; border: 1px solid #4A4A4F; border-radius: 4px; text-align: center; padding: 2px; color: #111111; background-color: #111118; height: 10px; } QProgressBar:horizontal QLabel { font-size: 9px; color: #111111; } QProgressBar::chunk { background-color: green; }");
LM's avatar
LM committed
    toolBarBatteryBar->setMinimum(0);
    toolBarBatteryBar->setMaximum(100);
    toolBarBatteryBar->setMinimumWidth(20);
    toolBarBatteryBar->setMaximumWidth(100);
lm's avatar
lm committed
    toolBarBatteryBar->setToolTip(tr("Battery charge level"));
    addWidget(toolBarBatteryBar);

    toolBarBatteryVoltageLabel = new QLabel("xx.x V");
    toolBarBatteryVoltageLabel->setStyleSheet(QString("QLabel { margin: 0px 0px 0px 4px; font: 14px; color: %1; }").arg(QColor(Qt::green).name()));
	toolBarBatteryVoltageLabel->setToolTip(tr("Battery voltage"));
    addWidget(toolBarBatteryVoltageLabel);

    toolBarWpLabel = new QLabel("WP--", this);
    toolBarWpLabel->setStyleSheet("QLabel { margin: 0px 2px; font: 18px; color: #3C7B9E; }");
	toolBarWpLabel->setToolTip(tr("Current mission"));
LM's avatar
LM committed
    addWidget(toolBarWpLabel);

    toolBarDistLabel = new QLabel("--- ---- m", this);
	toolBarDistLabel->setToolTip(tr("Distance to current mission"));
LM's avatar
LM committed
    addWidget(toolBarDistLabel);

    toolBarMessageLabel = new QLabel("No system messages.", this);
    toolBarMessageLabel->setStyleSheet("QLabel { margin: 0px 4px; font: 12px; font-style: italic; color: #3C7B9E; }");
	toolBarMessageLabel->setToolTip(tr("Most recent system message"));
LM's avatar
LM committed
    addWidget(toolBarMessageLabel);
lm's avatar
lm committed

    // DONE INITIALIZING BUTTONS

	// Configure the toolbar for the current default UAS
    setActiveUAS(UASManager::instance()->getActiveUAS());
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
lm's avatar
lm committed

    // Set the toolbar to be updated every 2s
lm's avatar
lm committed
    connect(&updateViewTimer, SIGNAL(timeout()), this, SLOT(updateView()));
    updateViewTimer.start(2000);
void QGCToolBar::heartbeatTimeout(bool timeout, unsigned int ms)
{
    // set timeout label visible
    if (timeout)
    {
        // Alternate colors to increase visibility
        if ((ms / 1000) % 2 == 0)
        {
            toolBarTimeoutLabel->setStyleSheet(QString("QLabel { margin: 0px 2px; font: 14px; color: %1; background-color: %2; }").arg(QGC::colorDarkWhite.name()).arg(QGC::colorMagenta.name()));
        }
        else
        {
            toolBarTimeoutLabel->setStyleSheet(QString("QLabel { margin: 0px 2px; font: 14px; color: %1; background-color: %2; }").arg(QGC::colorDarkWhite.name()).arg(QGC::colorMagenta.dark(250).name()));
        }
        toolBarTimeoutLabel->setText(tr("CONNECTION LOST: %1 s").arg((ms / 1000.0f), 2, 'f', 1, ' '));
    }
    else
    {
        // Check if loss text is present, reset once
        if (toolBarTimeoutLabel->text() != "")
        {
            toolBarTimeoutLabel->setText("");
            toolBarTimeoutLabel->setStyleSheet(QString(""));
        }
    }
}

lm's avatar
lm committed
void QGCToolBar::setLogPlayer(QGCMAVLinkLogPlayer* player)
{
    this->player = player;
Lorenz Meier's avatar
Lorenz Meier committed
    connect(toggleLoggingAction, SIGNAL(triggered(bool)), this, SLOT(logging(bool)));
    connect(logReplayAction, SIGNAL(triggered(bool)), this, SLOT(playLogFile(bool)));
lm's avatar
lm committed
}

void QGCToolBar::playLogFile(bool checked)
{
    // Check if player exists
    if (player)
    {
        // If a logfile is already replayed, stop the replay
        // and select a new logfile
        if (player->isPlayingLogFile())
        {
            player->playPause(false);
            {
                if (!player->selectLogFile()) return;
            }
        }
        // If no replaying happens already, start it
        else
        {
            if (!player->selectLogFile()) return;
        }
void QGCToolBar::logging(bool checked)
lm's avatar
lm committed
{
    // Stop logging in any case
    MainWindow::instance()->getMAVLink()->enableLogging(false);

	// If the user is enabling logging
    if (checked)
lm's avatar
lm committed
    {
		// Prompt the user for a filename/location to save to
        QString fileName = QFileDialog::getSaveFileName(this, tr("Specify MAVLink log file to save to"), QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), tr("MAVLink Logfile (*.mavlink *.log *.bin);;"));
lm's avatar
lm committed

		// Check that they didn't cancel out
		if (fileName.isNull())
		{
			toggleLoggingAction->setChecked(false);
			return;
		}

		// Make sure the file's named properly
lm's avatar
lm committed
        if (!fileName.endsWith(".mavlink"))
        {
            fileName.append(".mavlink");
        }

		// Check that we can save the logfile
lm's avatar
lm committed
        QFileInfo file(fileName);
lm's avatar
lm committed
        {
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Critical);
            msgBox.setText(tr("The selected logfile is not writable"));
            msgBox.setInformativeText(tr("Please make sure that the file %1 is writable or select a different file").arg(fileName));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
        }
lm's avatar
lm committed
        else
        {
            MainWindow::instance()->getMAVLink()->setLogfileName(fileName);
            MainWindow::instance()->getMAVLink()->enableLogging(true);
        }
    }
}

void QGCToolBar::addPerspectiveChangeAction(QAction* action)
{
lm's avatar
lm committed
    insertAction(toggleLoggingAction, action);

    // Set tab style
    QWidget* widget = widgetForAction(action);
    widget->setStyleSheet("\
                          * { font-weight: bold; min-height: 16px; min-width: 24px; \
                          border-top: 1px solid #BBBBBB; \
                          border-bottom: 0px; \
                          border-left: 1px solid #BBBBBB; \
                          border-right: 1px solid #BBBBBB; \
                          border-top-left-radius: 5px; \
                          border-top-right-radius: 5px; \
                          border-bottom-left-radius: 0px; \
                          border-bottom-right-radius: 0px; \
                          max-height: 22px; \
                          margin-top: 4px; \
                          margin-left: 2px; \
                          margin-bottom: 0px; \
                          margin-right: 2px; \
                          background-color: #222222; \
                  } \
                  *:checked { \
                          background-color: #000000; \
                          border-top: 2px solid #379AC3; \
                          border-bottom: 0px; \
                          border-left: 2px solid #379AC3; \
                          border-right: 2px solid #379AC3; \
                  } \
                  *:pressed { \
                          background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #bbbbbb, stop: 1 #b0b0b0); \
                          border-top: 2px solid #379AC3; \
                          border-bottom: 0px; \
                          border-left: 2px solid #379AC3; \
                          border-right: 2px solid #379AC3; }");
}

void QGCToolBar::setActiveUAS(UASInterface* active)
{
    // Do nothing if system is the same or NULL
    if ((active == NULL) || mav == active) return;

    if (mav)
    {
        // Disconnect old system
        disconnect(mav, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString,QString)));
        disconnect(mav, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
        disconnect(mav, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString)));
        disconnect(mav, SIGNAL(systemTypeSet(UASInterface*,uint)), this, SLOT(setSystemType(UASInterface*,uint)));
LM's avatar
LM committed
        disconnect(mav, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(receiveTextMessage(int,int,int,QString)));
LM's avatar
LM committed
        disconnect(mav, SIGNAL(batteryChanged(UASInterface*,double,double,int)), this, SLOT(updateBatteryRemaining(UASInterface*,double,double,int)));
        disconnect(mav, SIGNAL(armingChanged(bool)), this, SLOT(updateArmingState(bool)));
        disconnect(mav, SIGNAL(heartbeatTimeout(bool, unsigned int)), this, SLOT(heartbeatTimeout(bool,unsigned int)));
        if (mav->getWaypointManager())
        {
            disconnect(mav->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)), this, SLOT(updateCurrentWaypoint(quint16)));
            disconnect(mav->getWaypointManager(), SIGNAL(waypointDistanceChanged(double)), this, SLOT(updateWaypointDistance(double)));
        }
    }

    // Connect new system
    mav = active;
    connect(active, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*, QString,QString)));
    connect(active, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString)));
    connect(active, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString)));
    connect(active, SIGNAL(systemTypeSet(UASInterface*,uint)), this, SLOT(setSystemType(UASInterface*,uint)));
LM's avatar
LM committed
    connect(active, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(receiveTextMessage(int,int,int,QString)));
LM's avatar
LM committed
    connect(active, SIGNAL(batteryChanged(UASInterface*,double,double,int)), this, SLOT(updateBatteryRemaining(UASInterface*,double,double,int)));
    connect(active, SIGNAL(armingChanged(bool)), this, SLOT(updateArmingState(bool)));
    connect(active, SIGNAL(heartbeatTimeout(bool, unsigned int)), this, SLOT(heartbeatTimeout(bool,unsigned int)));
    if (active->getWaypointManager())
    {
        connect(active->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)), this, SLOT(updateCurrentWaypoint(quint16)));
        connect(active->getWaypointManager(), SIGNAL(waypointDistanceChanged(double)), this, SLOT(updateWaypointDistance(double)));
    }

    // Update all values once
    systemName = mav->getUASName();
    systemArmed = mav->isArmed();
LM's avatar
LM committed
    toolBarNameLabel->setText(mav->getUASName());
    toolBarNameLabel->setStyleSheet(QString("QLabel { font: bold 16px; color: %1; }").arg(mav->getColor().name()));
    symbolButton->setStyleSheet(QString("QWidget { background-color: %1; color: #DDDDDF; background-clip: border; } QToolButton { font-weight: bold; font-size: 12px; border: 0px solid #999999; border-radius: 5px; min-width:22px; max-width: 22px; min-height: 22px; max-height: 22px; padding: 0px; margin: 0px 4px 0px 20px; background-color: none; }").arg(mav->getColor().name()));
    toolBarModeLabel->setText(mav->getShortMode());
    toolBarStateLabel->setText(mav->getShortState());
    toolBarTimeoutLabel->setStyleSheet(QString(""));
    toolBarTimeoutLabel->setText("");
    setSystemType(mav, mav->getSystemType());
}

void QGCToolBar::createCustomWidgets()
{

}

void QGCToolBar::updateArmingState(bool armed)
{
    systemArmed = armed;
    changed = true;
}

lm's avatar
lm committed
void QGCToolBar::updateView()
{
    if (!changed) return;
    toolBarDistLabel->setText(tr("%1 m").arg(wpDistance, 6, 'f', 2, '0'));
    toolBarWpLabel->setText(tr("WP%1").arg(wpId));
    toolBarBatteryBar->setValue(batteryPercent);
    toolBarBatteryVoltageLabel->setText(tr("%1 V").arg(batteryVoltage, 4, 'f', 1, ' '));
    toolBarStateLabel->setText(tr("%1").arg(state));
    toolBarModeLabel->setText(tr("%1").arg(mode));
    toolBarNameLabel->setText(systemName);
    toolBarMessageLabel->setText(lastSystemMessage);

    if (systemArmed)
    {
        toolBarSafetyLabel->setStyleSheet(QString("QLabel { margin: 0px 2px; font: 14px; color: %1; background-color: %2; }").arg(QGC::colorRed.name()).arg(QGC::colorYellow.name()));
        toolBarSafetyLabel->setText(tr("ARMED"));
    }
    else
    {
        toolBarSafetyLabel->setStyleSheet("QLabel { margin: 0px 2px; font: 14px; color: #14C814; }");
        toolBarSafetyLabel->setText(tr("SAFE"));
    }

lm's avatar
lm committed
    changed = false;
lm's avatar
lm committed
}

void QGCToolBar::updateWaypointDistance(double distance)
{
lm's avatar
lm committed
    if (wpDistance != distance) changed = true;
    wpDistance = distance;
}

void QGCToolBar::updateCurrentWaypoint(quint16 id)
{
lm's avatar
lm committed
    if (wpId != id) changed = true;
lm's avatar
lm committed
    wpId = id;
LM's avatar
LM committed
void QGCToolBar::updateBatteryRemaining(UASInterface* uas, double voltage, double percent, int seconds)
{
    Q_UNUSED(uas);
    Q_UNUSED(seconds);
lm's avatar
lm committed
    if (batteryPercent != percent || batteryVoltage != voltage) changed = true;
lm's avatar
lm committed
    batteryPercent = percent;
    batteryVoltage = voltage;
LM's avatar
LM committed
}

void QGCToolBar::updateState(UASInterface* system, QString name, QString description)
{
    Q_UNUSED(system);
    Q_UNUSED(description);
lm's avatar
lm committed
    if (state != name) changed = true;
lm's avatar
lm committed
    state = name;
}

void QGCToolBar::updateMode(int system, QString name, QString description)
{
    Q_UNUSED(system);
    Q_UNUSED(description);
lm's avatar
lm committed
    if (mode != name) changed = true;
    mode = name;
}

void QGCToolBar::updateName(const QString& name)
{
lm's avatar
lm committed
    if (systemName != name) changed = true;
lm's avatar
lm committed
    systemName = name;
}

/**
 * The current system type is represented through the system icon.
 *
 * @param uas Source system, has to be the same as this->uas
 * @param systemType type ID, following the MAVLink system type conventions
 * @see http://pixhawk.ethz.ch/software/mavlink
 */
void QGCToolBar::setSystemType(UASInterface* uas, unsigned int systemType)
{
    Q_UNUSED(uas);
        // Set matching icon
        switch (systemType) {
        case 0:
            symbolButton->setIcon(QIcon(":/files/images/mavs/generic.svg"));
            symbolButton->setIcon(QIcon(":/files/images/mavs/fixed-wing.svg"));
            symbolButton->setIcon(QIcon(":/files/images/mavs/quadrotor.svg"));
            symbolButton->setIcon(QIcon(":/files/images/mavs/coaxial.svg"));
            symbolButton->setIcon(QIcon(":/files/images/mavs/helicopter.svg"));
            symbolButton->setIcon(QIcon(":/files/images/mavs/unknown.svg"));
            symbolButton->setIcon(QIcon(":/files/images/mavs/unknown.svg"));
LM's avatar
LM committed
void QGCToolBar::receiveTextMessage(int uasid, int componentid, int severity, QString text)
{
    Q_UNUSED(uasid);
    Q_UNUSED(componentid);
    Q_UNUSED(severity);
lm's avatar
lm committed
    if (lastSystemMessage != text) changed = true;
lm's avatar
lm committed
    lastSystemMessage = text;
QGCToolBar::~QGCToolBar()
{
    if (toggleLoggingAction) toggleLoggingAction->deleteLater();
    if (logReplayAction) logReplayAction->deleteLater();