diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ed2a9aca0141dbc2ae2234616cb363921d646d9..8e049063b542d5e1d30477ed7f67bba257eb1cb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,7 @@ set(QGC_RESOURCES HackFileDialog.qrc qgcresources.qrc qgroundcontrol.qrc + qgcimages.qrc src/FirmwarePlugin/APM/APMResources.qrc src/FirmwarePlugin/PX4/PX4Resources.qrc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f27db15ca06a8d4ae9438a5b66e91a6a6a4c075d..7a425a67ce1642ec84b9208565a3b08e8fc39e42 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,8 +72,8 @@ add_library(qgc KMLFileHelper.cc LogCompressor.cc main.cc - QGC.cc QGCApplication.cc + QGC.cc QGCComboBox.cc QGCDockWidget.cc QGCFileDownload.cc @@ -81,21 +81,15 @@ add_library(qgc QGCLoggingCategory.cc QGCMapPalette.cc QGCPalette.cc - QGCQFileDialog.cc QGCQGeoCoordinate.cc - QGCQmlWidgetHolder.cpp - QGCQuickWidget.cc QGCTemporaryFile.cc QGCToolbox.cc RunGuard.cc ShapeFileHelper.cc SHPFileHelper.cc TerrainTile.cc - UTM.cpp - # UI - QGCQmlWidgetHolder.ui - QGCQmlWidgetHolder.h + UTM.cpp ) set_source_files_properties(QGCApplication.cc PROPERTIES COMPILE_DEFINITIONS GIT_VERSION="${git_tag}") @@ -176,3 +170,4 @@ target_include_directories(qgc ${CMAKE_CURRENT_BINARY_DIR}/qgc_autogen/include # HACK: AUTOUIC paths not inheriting? ${CMAKE_CURRENT_BINARY_DIR}/qgc_autogen/include_Debug ) + diff --git a/src/QmlControls/CMakeLists.txt b/src/QmlControls/CMakeLists.txt index 7c5b170d3b19fac3f68f927ab9892083a9430454..ff7d06189514074691d824ca24ace84bbd6099cb 100644 --- a/src/QmlControls/CMakeLists.txt +++ b/src/QmlControls/CMakeLists.txt @@ -9,7 +9,6 @@ add_library(QmlControls QGCImageProvider.cc QGroundControlQmlGlobal.cc QmlObjectListModel.cc - QmlTestWidget.cc RCChannelMonitorController.cc ScreenToolsController.cc ) diff --git a/src/QmlControls/QmlTestWidget.cc b/src/QmlControls/QmlTestWidget.cc deleted file mode 100644 index 6710f7e73998486b8795d22eb216d21f7cf2bb4b..0000000000000000000000000000000000000000 --- a/src/QmlControls/QmlTestWidget.cc +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/// @file -/// @author Don Gagne - -#include "QmlTestWidget.h" - -#include - -QmlTestWidget::QmlTestWidget(void) - : QGCQmlWidgetHolder(QString(), NULL, NULL) -{ - setAttribute(Qt::WA_DeleteOnClose); - resize(900, 500); - setVisible(true); - - setContextPropertyObject("controller", this); - - setSource(QUrl::fromUserInput("qrc:qml/QmlTest.qml")); -} - -void QmlTestWidget::showColorDialog(QQuickItem* item) -{ - Q_UNUSED(item) - QColorDialog colorDialog(this); - connect(&colorDialog, &QColorDialog::colorSelected, this, &QmlTestWidget::_colorSelected); - colorDialog.open(); -} - -void QmlTestWidget::_colorSelected(const QColor & color) -{ - Q_UNUSED(color); -} - diff --git a/src/QmlControls/QmlTestWidget.h b/src/QmlControls/QmlTestWidget.h deleted file mode 100644 index acb2bc69fcb6321af113b7116a82d36f2a7233d1..0000000000000000000000000000000000000000 --- a/src/QmlControls/QmlTestWidget.h +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#ifndef QmlTestWidget_h -#define QmlTestWidget_h - -/// @file -/// @author Don Gagne - -#include "QGCQmlWidgetHolder.h" - -/// This is used to create widgets which are implemented in QML. - -class QmlTestWidget : public QGCQmlWidgetHolder -{ - Q_OBJECT - -public: - QmlTestWidget(void); - - Q_INVOKABLE void showColorDialog(QQuickItem* item); - -private slots: - void _colorSelected(const QColor & color); - -}; - -#endif diff --git a/src/Settings/CMakeLists.txt b/src/Settings/CMakeLists.txt index 05ed4c8211b83f0a7402d252679aa410b3f5d770..36b765f61ff19b2e87b526c173387842af9e9684 100644 --- a/src/Settings/CMakeLists.txt +++ b/src/Settings/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(Settings AppSettings.cc AutoConnectSettings.cc BrandImageSettings.cc + FirmwareUpgradeSettings.cc FlightMapSettings.cc FlyViewSettings.cc OfflineMapsSettings.cc diff --git a/src/ViewWidgets/CMakeLists.txt b/src/ViewWidgets/CMakeLists.txt index d48b0f9bca6c91326fcd0a14cb2adbce972cddb2..9c631c1026d920dba6a29ca87fe1cab5bc3ef765 100644 --- a/src/ViewWidgets/CMakeLists.txt +++ b/src/ViewWidgets/CMakeLists.txt @@ -1,7 +1,5 @@ add_library(ViewWidgets - CustomCommandWidget.cc - CustomCommandWidgetController.cc ViewWidgetController.cc ) diff --git a/src/ViewWidgets/CustomCommandWidget.cc b/src/ViewWidgets/CustomCommandWidget.cc deleted file mode 100644 index 720e4ec6e3f7da22bea83f2b64e76b06a4dc83c3..0000000000000000000000000000000000000000 --- a/src/ViewWidgets/CustomCommandWidget.cc +++ /dev/null @@ -1,21 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include "CustomCommandWidget.h" - -CustomCommandWidget::CustomCommandWidget(const QString& title, QAction* action, QWidget *parent) : - QGCQmlWidgetHolder(title, action, parent) -{ - Q_UNUSED(title); - Q_UNUSED(action); - setSource(QUrl::fromUserInput("qrc:/qml/CustomCommandWidget.qml")); - - loadSettings(); -} diff --git a/src/ViewWidgets/CustomCommandWidget.h b/src/ViewWidgets/CustomCommandWidget.h deleted file mode 100644 index 27626ad67788bb0c6a80bd2e444d64e1fe238347..0000000000000000000000000000000000000000 --- a/src/ViewWidgets/CustomCommandWidget.h +++ /dev/null @@ -1,25 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/// @file -/// @author Don Gagne - -#pragma once - -#include "QGCQmlWidgetHolder.h" - -class CustomCommandWidget : public QGCQmlWidgetHolder -{ - Q_OBJECT - -public: - CustomCommandWidget(const QString& title, QAction* action, QWidget *parent = 0); -}; - diff --git a/src/ViewWidgets/CustomCommandWidgetController.cc b/src/ViewWidgets/CustomCommandWidgetController.cc deleted file mode 100644 index 70d329938d173f7d538c4687f752abb79ba87800..0000000000000000000000000000000000000000 --- a/src/ViewWidgets/CustomCommandWidgetController.cc +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include "CustomCommandWidgetController.h" -#include "MultiVehicleManager.h" -#include "QGCMAVLink.h" -#include "QGCQFileDialog.h" -#include "UAS.h" -#include "QGCApplication.h" - -#include -#include - -const char* CustomCommandWidgetController::_settingsKey = "CustomCommand.QmlFile"; - -CustomCommandWidgetController::CustomCommandWidgetController(void) : - _vehicle(NULL) -{ - if(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()) { - _vehicle = qgcApp()->toolbox()->multiVehicleManager()->activeVehicle(); - } - QSettings settings; - _customQmlFile = settings.value(_settingsKey).toString(); -} - -void CustomCommandWidgetController::sendCommand(int commandId, QVariant componentId, QVariant confirm, QVariant param1, QVariant param2, QVariant param3, QVariant param4, QVariant param5, QVariant param6, QVariant param7) -{ - Q_UNUSED(confirm); - - if(_vehicle) { - _vehicle->sendMavCommand(componentId.toInt(), - (MAV_CMD)commandId, - true, // show error if fails - param1.toFloat(), param2.toFloat(), param3.toFloat(), param4.toFloat(), param5.toFloat(), param6.toFloat(), param7.toFloat()); - } -} - -void CustomCommandWidgetController::selectQmlFile(void) -{ - QSettings settings; - QString qmlFile = QGCQFileDialog::getOpenFileName(NULL, tr("Select custom Qml file"), QString(), tr("Qml files (*.qml)")); - if (qmlFile.isEmpty()) { - _customQmlFile.clear(); - settings.remove(_settingsKey); - } else { - QUrl url = QUrl::fromLocalFile(qmlFile); - _customQmlFile = url.toString(); - settings.setValue(_settingsKey, _customQmlFile); - } - emit customQmlFileChanged(_customQmlFile); -} - -void CustomCommandWidgetController::clearQmlFile(void) -{ - _customQmlFile.clear(); - QSettings settings; - settings.remove(_settingsKey); - emit customQmlFileChanged(_customQmlFile); -} diff --git a/src/comm/CMakeLists.txt b/src/comm/CMakeLists.txt index 4a5fa752f30a0f68dd47e66d6cf98c94ba46d60c..b9f421cf68a5ffa89521a14452ed0011b5384ea6 100644 --- a/src/comm/CMakeLists.txt +++ b/src/comm/CMakeLists.txt @@ -16,7 +16,6 @@ add_library(comm LogReplayLink.cc MavlinkMessagesTimer.cc MAVLinkProtocol.cc - QGCFlightGearLink.cc QGCJSBSimLink.cc QGCMAVLink.cc QGCSerialPortInfo.cc @@ -30,7 +29,6 @@ add_library(comm # HEADERS # shouldn't be listed here, but aren't named properly for AUTOMOC - QGCFlightGearLink.h QGCHilLink.h QGCJSBSimLink.h ) diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc deleted file mode 100644 index 5b25c96ae6d3ce1bbd6c79d19bf169bfe6c530a7..0000000000000000000000000000000000000000 --- a/src/comm/QGCFlightGearLink.cc +++ /dev/null @@ -1,1017 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Definition of UDP connection (server) for unmanned vehicles - * @see Flightgear Manual http://mapserver.flightgear.org/getstart.pdf - * @author Lorenz Meier - * @author Thomas Gubler - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "QGCFlightGearLink.h" -#include "QGC.h" -//-- TODO: #include "QGCQFileDialog.h" -#include "QGCMessageBox.h" -#include "QGCApplication.h" -#include "Vehicle.h" -#include "UAS.h" -#include "QGroundControlQmlGlobal.h" - -// FlightGear _fgProcess start and connection is quite fragile. Uncomment the define below to get higher level of debug output -// for tracking down problems. -//#define DEBUG_FLIGHTGEAR_CONNECT - -QGCFlightGearLink::QGCFlightGearLink(Vehicle* vehicle, QString startupArguments, QString remoteHost, QHostAddress host, quint16 port) - : _vehicle(vehicle) - , _udpCommSocket(NULL) - , _fgProcess(NULL) - , flightGearVersion(3) - , startupArguments(startupArguments) - , _sensorHilEnabled(true) - , barometerOffsetkPa(0.0f) -{ - // We're doing it wrong - because the Qt folks got the API wrong: - // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/ - moveToThread(this); - - this->host = host; - this->port = port + _vehicle->id(); - this->connectState = false; - this->currentPort = 49000 + _vehicle->id(); - this->name = tr("FlightGear 3.0+ Link (port:%1)").arg(port); - setRemoteHost(remoteHost); - - // We need a mechanism so show error message from our FGLink thread on the UI thread. This signal connection will do that for us. - connect(this, &QGCFlightGearLink::showCriticalMessageFromThread, qgcApp(), &QGCApplication::criticalMessageBoxOnMainThread); - connect(this, &QGCFlightGearLink::disconnectSim, this, &QGCFlightGearLink::disconnectSimulation); -} - -QGCFlightGearLink::~QGCFlightGearLink() -{ //do not disconnect unless it is connected. - //disconnectSimulation will delete the memory that was allocated for process, terraSync and _udpCommSocket - if(connectState){ - disconnectSimulation(); - } -} - -/// @brief Runs the simulation thread. We do setup work here which needs to happen in the separate thread. -void QGCFlightGearLink::run() -{ - Q_ASSERT(_vehicle); - Q_ASSERT(!_fgProcessName.isEmpty()); - - // We communicate with FlightGear over a UDP _udpCommSocket - _udpCommSocket = new QUdpSocket(this); - Q_CHECK_PTR(_udpCommSocket); - _udpCommSocket->moveToThread(this); - _udpCommSocket->bind(host, port, QAbstractSocket::ReuseAddressHint); - QObject::connect(_udpCommSocket, &QUdpSocket::readyRead, this, &QGCFlightGearLink::readBytes); - - - // Connect to the various HIL signals that we use to then send information across the UDP protocol to FlightGear. - connect(_vehicle->uas(), &UAS::hilControlsChanged, this, &QGCFlightGearLink::updateControls); - - connect(this, &QGCFlightGearLink::hilStateChanged, _vehicle->uas(), &UAS::sendHilState); - connect(this, &QGCFlightGearLink::sensorHilGpsChanged, _vehicle->uas(), &UAS::sendHilGps); - connect(this, &QGCFlightGearLink::sensorHilRawImuChanged, _vehicle->uas(), &UAS::sendHilSensors); - connect(this, &QGCFlightGearLink::sensorHilOpticalFlowChanged, _vehicle->uas(), &UAS::sendHilOpticalFlow); - - // Start a new QProcess to run FlightGear in - _fgProcess = new QProcess(this); - Q_CHECK_PTR(_fgProcess); - _fgProcess->moveToThread(this); - - connect(_fgProcess, static_cast(&QProcess::error), - this, &QGCFlightGearLink::processError); - -//#ifdef DEBUG_FLIGHTGEAR_CONNECT - connect(_fgProcess, &QProcess::readyReadStandardOutput, this, &QGCFlightGearLink::_printFgfsOutput); - connect(_fgProcess, &QProcess::readyReadStandardError, this, &QGCFlightGearLink::_printFgfsError); -//#endif - - if (!_fgProcessWorkingDirPath.isEmpty()) { - _fgProcess->setWorkingDirectory(_fgProcessWorkingDirPath); - qDebug() << "Working directory" << _fgProcess->workingDirectory(); - } - -#ifdef Q_OS_WIN32 - // On Windows we need to full qualify the location of the excecutable. The call to setWorkingDirectory only - // sets the QProcess context, not the QProcess::start context. For some strange reason this is not the case on - // OSX. - QDir fgProcessFullyQualified(_fgProcessWorkingDirPath); - _fgProcessName = fgProcessFullyQualified.absoluteFilePath(_fgProcessName); -#endif - -#ifdef DEBUG_FLIGHTGEAR_CONNECT - qDebug() << "\nStarting FlightGear" << _fgProcessWorkingDirPath << _fgProcessName << _fgArgList << "\n"; -#endif - - _fgProcess->start(_fgProcessName, _fgArgList); - connectState = true; - - emit simulationConnected(connectState); - emit simulationConnected(); - - exec(); -} - -void QGCFlightGearLink::setPort(int port) -{ - this->port = port; - disconnectSimulation(); - connectSimulation(); -} - -void QGCFlightGearLink::processError(QProcess::ProcessError err) -{ - switch(err) - { - case QProcess::FailedToStart: - emit showCriticalMessageFromThread(tr("FlightGear Failed to Start"), _fgProcess->errorString()); - break; - case QProcess::Crashed: - emit showCriticalMessageFromThread(tr("FlightGear Crashed"), tr("This is a FlightGear-related problem. Please upgrade FlightGear")); - break; - case QProcess::Timedout: - emit showCriticalMessageFromThread(tr("FlightGear Start Timed Out"), tr("Please check if the path and command is correct")); - break; - case QProcess::WriteError: - emit showCriticalMessageFromThread(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); - break; - case QProcess::ReadError: - emit showCriticalMessageFromThread(tr("Could not Communicate with FlightGear"), tr("Please check if the path and command is correct")); - break; - case QProcess::UnknownError: - default: - emit showCriticalMessageFromThread(tr("FlightGear Error"), tr("Please check if the path and command is correct.")); - break; - } -} - -/** - * @param host Hostname in standard formatting, e.g. localhost:14551 or 192.168.1.1:14551 - */ -void QGCFlightGearLink::setRemoteHost(const QString& host) -{ - if (host.contains(":")) - { - //qDebug() << "HOST: " << host.split(":").first(); - QHostInfo info = QHostInfo::fromName(host.split(":").first()); - if (info.error() == QHostInfo::NoError) - { - // Add host - QList hostAddresses = info.addresses(); - QHostAddress address; - for (int i = 0; i < hostAddresses.size(); i++) - { - // Exclude loopback IPv4 and all IPv6 addresses - if (!hostAddresses.at(i).toString().contains(":")) - { - address = hostAddresses.at(i); - } - } - currentHost = address; - //qDebug() << "Address:" << address.toString(); - // Set port according to user input - currentPort = host.split(":").last().toInt(); - } - } - else - { - QHostInfo info = QHostInfo::fromName(host); - if (info.error() == QHostInfo::NoError) - { - // Add host - currentHost = info.addresses().first(); - } - } - -} - -void QGCFlightGearLink::updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode) -{ - // magnetos,aileron,elevator,rudder,throttle\n - - //float magnetos = 3.0f; - Q_UNUSED(time); - Q_UNUSED(systemMode); - Q_UNUSED(navMode); - - if(!qIsNaN(rollAilerons) && !qIsNaN(pitchElevator) && !qIsNaN(yawRudder) && !qIsNaN(throttle)) - { - QString state("%1\t%2\t%3\t%4\t%5\n"); - state = state.arg(rollAilerons).arg(pitchElevator).arg(yawRudder).arg(true).arg(throttle); - emit _invokeWriteBytes(state.toLatin1()); - //qDebug() << "Updated controls" << rollAilerons << pitchElevator << yawRudder << throttle; - //qDebug() << "Updated controls" << state; - } - else - { - qDebug() << "HIL: Got NaN values from the hardware: isnan output: roll: " << qIsNaN(rollAilerons) << ", pitch: " << qIsNaN(pitchElevator) << ", yaw: " << qIsNaN(yawRudder) << ", throttle: " << qIsNaN(throttle); - } -} - -void QGCFlightGearLink::_writeBytes(const QByteArray data) -{ - //#define QGCFlightGearLink_DEBUG -#ifdef QGCFlightGearLink_DEBUG - QString bytes; - QString ascii; - for (int i=0, size = data.size(); i 31 && data[i] < 127) - { - ascii.append(data[i]); - } - else - { - ascii.append(219); - } - } - qDebug() << "Sent" << size << "bytes to" << currentHost.toString() << ":" << currentPort << "data:"; - qDebug() << bytes; - qDebug() << "ASCII:" << ascii; -#endif - if (connectState && _udpCommSocket) _udpCommSocket->writeDatagram(data, currentHost, currentPort); -} - -/** - * @brief Read a number of bytes from the interface. - * - * @param data Pointer to the data byte array to write the bytes to - * @param maxLength The maximum number of bytes to write - **/ -void QGCFlightGearLink::readBytes() -{ - const qint64 maxLength = 65536; - char data[maxLength]; - QHostAddress sender; - quint16 senderPort; - - unsigned int s = _udpCommSocket->pendingDatagramSize(); - if (s > maxLength) std::cerr << __FILE__ << __LINE__ << " UDP datagram overflow, allowed to read less bytes than datagram size" << std::endl; - _udpCommSocket->readDatagram(data, maxLength, &sender, &senderPort); - - QByteArray b(data, s); - - // Print string - QString state(b); - //qDebug() << "FG LINK GOT:" << state; - - QStringList values = state.split("\t"); - - // Check length - const int nValues = 22; - if (values.size() != nValues) - { - qDebug() << "RETURN LENGTH MISMATCHING EXPECTED" << nValues << "BUT GOT" << values.size(); - qDebug() << state; - emit showCriticalMessageFromThread(tr("FlightGear HIL"), - tr("Flight Gear protocol file '%1' is out of date. Quit %2. Delete the file and restart %2 to fix.").arg(_fgProtocolFileFullyQualified).arg(qgcApp()->applicationName())); - disconnectSimulation(); - return; - } - - // Parse string - float roll, pitch, yaw, rollspeed, pitchspeed, yawspeed; - double lat, lon, alt; - float ind_airspeed; - float true_airspeed; - float vx, vy, vz, xacc, yacc, zacc; - float diff_pressure; - float temperature; - float abs_pressure; - float mag_variation, mag_dip, xmag_ned, ymag_ned, zmag_ned, xmag_body, ymag_body, zmag_body; - float alt_agl; - - - lat = values.at(1).toDouble(); - lon = values.at(2).toDouble(); - alt = values.at(3).toDouble(); - roll = values.at(4).toFloat(); - pitch = values.at(5).toFloat(); - yaw = values.at(6).toFloat(); - rollspeed = values.at(7).toFloat(); - pitchspeed = values.at(8).toFloat(); - yawspeed = values.at(9).toFloat(); - - xacc = values.at(10).toFloat(); - yacc = values.at(11).toFloat(); - zacc = values.at(12).toFloat(); - - vx = values.at(13).toFloat(); - vy = values.at(14).toFloat(); - vz = values.at(15).toFloat(); - - true_airspeed = values.at(16).toFloat(); - - mag_variation = values.at(17).toFloat(); - mag_dip = values.at(18).toFloat(); - - temperature = values.at(19).toFloat(); - abs_pressure = values.at(20).toFloat() * 1e2f; //convert to Pa from hPa - abs_pressure += barometerOffsetkPa * 1e3f; //add offset, convert from kPa to Pa - - alt_agl = values.at(21).toFloat(); - - //calculate differential pressure - const float air_gas_constant = 287.1f; // J/(kg * K) - const float absolute_null_celsius = -273.15f; // °C - float density = abs_pressure / (air_gas_constant * (temperature - absolute_null_celsius)); - diff_pressure = true_airspeed * true_airspeed * density / 2.0f; - //qDebug() << "diff_pressure: " << diff_pressure << "abs_pressure: " << abs_pressure; - - /* Calculate indicated airspeed */ - const float air_density_sea_level_15C = 1.225f; //kg/m^3 - if (diff_pressure > 0) - { - ind_airspeed = sqrtf((2.0f*diff_pressure) / air_density_sea_level_15C); - } else - { - ind_airspeed = -sqrtf((2.0f*fabsf(diff_pressure)) / air_density_sea_level_15C); - } - - //qDebug() << "ind_airspeed: " << ind_airspeed << "true_airspeed: " << true_airspeed; - - // Send updated state - //qDebug() << "sensorHilEnabled: " << sensorHilEnabled; - if (_sensorHilEnabled) - { - quint16 fields_changed = 0xFFF; //set all 12 used bits - - float pressure_alt = alt; - - xmag_ned = cosf(mag_variation); - ymag_ned = sinf(mag_variation); - zmag_ned = sinf(mag_dip); - float tempMagLength = sqrtf(xmag_ned*xmag_ned + ymag_ned*ymag_ned + zmag_ned*zmag_ned); - xmag_ned = xmag_ned / tempMagLength; - ymag_ned = ymag_ned / tempMagLength; - zmag_ned = zmag_ned / tempMagLength; - - //transform magnetic measurement to body frame coordinates - double cosPhi = cos(roll); - double sinPhi = sin(roll); - double cosThe = cos(pitch); - double sinThe = sin(pitch); - double cosPsi = cos(yaw); - double sinPsi = sin(yaw); - - float R_B_N[3][3]; - - R_B_N[0][0] = cosThe * cosPsi; - R_B_N[0][1] = -cosPhi * sinPsi + sinPhi * sinThe * cosPsi; - R_B_N[0][2] = sinPhi * sinPsi + cosPhi * sinThe * cosPsi; - - R_B_N[1][0] = cosThe * sinPsi; - R_B_N[1][1] = cosPhi * cosPsi + sinPhi * sinThe * sinPsi; - R_B_N[1][2] = -sinPhi * cosPsi + cosPhi * sinThe * sinPsi; - - R_B_N[2][0] = -sinThe; - R_B_N[2][1] = sinPhi * cosThe; - R_B_N[2][2] = cosPhi * cosThe; - - Eigen::Matrix3f R_B_N_M = Eigen::Map((float*)R_B_N).eval(); - - Eigen::Vector3f mag_ned(xmag_ned, ymag_ned, zmag_ned); - - Eigen::Vector3f mag_body = R_B_N_M * mag_ned; - - xmag_body = mag_body(0); - ymag_body = mag_body(1); - zmag_body = mag_body(2); - - emit sensorHilRawImuChanged(QGC::groundTimeUsecs(), xacc, yacc, zacc, rollspeed, pitchspeed, yawspeed, - xmag_body, ymag_body, zmag_body, abs_pressure*1e-2f, diff_pressure*1e-2f, pressure_alt, temperature, fields_changed); //Pressure in hPa for _vehicle->uas()link - -// qDebug() << "sensorHilRawImuChanged " << xacc << yacc << zacc << rollspeed << pitchspeed << yawspeed << xmag << ymag << zmag << abs_pressure << diff_pressure << pressure_alt << temperature; - int gps_fix_type = 3; - float eph = 0.3f; - float epv = 0.6f; - float vel = sqrt(vx*vx + vy*vy + vz*vz); - float cog = yaw; - int satellites = 8; - - emit sensorHilGpsChanged(QGC::groundTimeUsecs(), lat, lon, alt, gps_fix_type, eph, epv, vel, vx, vy, vz, cog, satellites); -// qDebug() << "sensorHilGpsChanged " << lat << lon << alt << vel; - - // Send Optical Flow message. For now we set the flow quality to 0 and just write the ground_distance field - float distanceMeasurement = -1.0; // -1 means invalid value - if (fabsf(roll) < 0.87 && fabsf(pitch) < 0.87) // return a valid value only for decent angles - { - distanceMeasurement = fabsf((float)(1.0/cosPhi * 1.0/cosThe * alt_agl)); // assuming planar ground - } - emit sensorHilOpticalFlowChanged(QGC::groundTimeUsecs(), 0, 0, 0.0f, - 0.0f, 0.0f, distanceMeasurement); - } else { - emit hilStateChanged(QGC::groundTimeUsecs(), roll, pitch, yaw, rollspeed, - pitchspeed, yawspeed, lat, lon, alt, - vx, vy, vz, - ind_airspeed, true_airspeed, - xacc, yacc, zacc); - //qDebug() << "hilStateChanged " << (qint32)lat << (qint32)lon << (qint32)alt; - } - - // // Echo data for debugging purposes - // std::cerr << __FILE__ << __LINE__ << "Received datagram:" << std::endl; - // int i; - // for (i=0; ipendingDatagramSize(); -} - -/** - * @brief Disconnect the connection. - * - * @return True if connection has been disconnected, false if connection couldn't be disconnected. - **/ -bool QGCFlightGearLink::disconnectSimulation() -{ - disconnect(_fgProcess, static_cast(&QProcess::error), - this, &QGCFlightGearLink::processError); - - disconnect(_vehicle->uas(), &UAS::hilControlsChanged, this, &QGCFlightGearLink::updateControls); - - disconnect(this, &QGCFlightGearLink::hilStateChanged, _vehicle->uas(), &UAS::sendHilState); - disconnect(this, &QGCFlightGearLink::sensorHilGpsChanged, _vehicle->uas(), &UAS::sendHilGps); - disconnect(this, &QGCFlightGearLink::sensorHilRawImuChanged, _vehicle->uas(), &UAS::sendHilSensors); - disconnect(this, &QGCFlightGearLink::sensorHilOpticalFlowChanged, _vehicle->uas(), &UAS::sendHilOpticalFlow); - - if (_fgProcess) - { - _fgProcess->close(); - _fgProcess->deleteLater(); - _fgProcess = NULL; - } - if (_udpCommSocket) - { - _udpCommSocket->close(); - _udpCommSocket->deleteLater(); - _udpCommSocket = NULL; - } - - connectState = false; - - emit simulationDisconnected(); - emit simulationConnected(false); - - // Exit the thread - quit(); - - return !connectState; -} - -/// @brief Splits a space separated set of command line arguments into a QStringList. -/// Quoted strings are allowed and handled correctly. -/// @param uiArgs Arguments to parse -/// @param argList Returned argument list -/// @return Returns false if the argument list has mistmatced quotes within in. - -bool QGCFlightGearLink::parseUIArguments(QString uiArgs, QStringList& argList) -{ - // FYI: The only reason this routine is public is so that we can reference it from a unit test. - - // This is not as easy as it seams since some options can be quoted to preserve spaces within things like - // directories. There is likely some crazed regular expression which can do this. But after trying that - // route I gave up and instead here is the code which does it the hard way. Another thing to be aware of - // is that the QStringList passed to QProces::start is similar to what you would get in argv after the - // command line is processed. This means that quoted strings have the quotes removed before making it to argv. - - bool inQuotedString = false; - bool previousSpace = false; - QString currentArg; - for (int i=0; iuas()) { - return false; - } - - QString fgAppName; - QString fgRootPath; // FlightGear root data directory as specified by --fg-root - QStringList fgRootPathProposedList; // Directories we will attempt to search for --fg-root - bool fgRootDirOverride = false; // true: User has specified --fg-root from ui options - QString fgSceneryPath; // FlightGear scenery path as specified by --fg-scenery - bool fgSceneryDirOverride = false; // true: User has specified --fg-scenery from ui options - QDir fgAppDir; // Location of main FlightGear application - - // Reset the list of arguments which will be provided to FG to the arguments set by the user via the UI - // First split the space separated command line arguments coming in from the ui into a QStringList since - // that is what QProcess::start needs. - QStringList uiArgList; - bool mismatchedQuotes = parseUIArguments(startupArguments, uiArgList); - if (!mismatchedQuotes) { - QGCMessageBox::critical(tr("FlightGear HIL"), tr("FlightGear failed to start. There are mismatched quotes in specified command line options")); - return false; - } -#ifdef DEBUG_FLIGHTGEAR_CONNECT - qDebug() << "\nSplit arguments" << uiArgList << "\n"; -#endif - // Now set the FG arguments to the arguments from the UI - _fgArgList = uiArgList; - -#if defined Q_OS_MAC - // Mac installs will default to the /Applications folder 99% of the time. Anything other than - // that is pretty non-standard so we don't try to get fancy beyond hardcoding that path. - fgAppDir.setPath("/Applications"); - fgAppName = "FlightGear.app"; - // new path - _fgProcessName = "./fgfs"; - _fgProcessWorkingDirPath = "/Applications/FlightGear.app/Contents/MacOS/"; - if(!QFileInfo(_fgProcessWorkingDirPath + _fgProcessName).exists()){ - // old path - _fgProcessName = "./fgfs.sh"; - _fgProcessWorkingDirPath = "/Applications/FlightGear.app/Contents/Resources/"; - } - fgRootPathProposedList += "/Applications/FlightGear.app/Contents/Resources/data/"; -#elif defined Q_OS_WIN32 - _fgProcessName = "fgfs.exe"; - - // Windows installs are not as easy to determine. Default installation is to - // C:\Program Files\FlightGear, but that can be easily changed. That also doesn't - // tell us whether the user is running 32 or 64 bit which will both be installed there. - // The preferences for the fgrun app will tell us which version they are using - // and where it is. That is stored in the $APPDATA\fliggear.org\fgrun.prefs file. This - // looks to be a more stable location and way to determine app location so we use that. - fgAppName = "fgfs.exe"; - const char* appdataEnv = "APPDATA"; - if (!qgetenv(appdataEnv).isEmpty()) { - QString fgrunPrefsFile = QDir(qgetenv(appdataEnv).constData()).absoluteFilePath("flightgear.org/fgrun.prefs"); - qDebug() << fgrunPrefsFile; - QFile file(fgrunPrefsFile); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&file); - QString lookahead; // lookahead for continuation lines - while (!in.atEnd() || !lookahead.isEmpty()) { - QString line; - QRegExp regExp; - - // Prefs file has strange format where a line prepended with "+" is a continuation of the previous line. - // So do a lookahead to determine if we have a continuation or not. - - if (!lookahead.isEmpty()) { - line = lookahead; - lookahead.clear(); - } else { - line = in.readLine(); - } - - if (!in.atEnd()) { - lookahead = in.readLine(); - regExp.setPattern("^\\+(.*)"); - if (regExp.indexIn(lookahead) == 0) { - Q_ASSERT(regExp.captureCount() == 1); - line += regExp.cap(1); - lookahead.clear(); - } - } - - regExp.setPattern("^fg_exe:(.*)"); - if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { - QString fgExeLocationFullQualified = regExp.cap(1); - qDebug() << fgExeLocationFullQualified; - regExp.setPattern("(.*)\\\\fgfs.exe"); - if (regExp.indexIn(fgExeLocationFullQualified) == 0 && regExp.captureCount() == 1) { - fgAppDir.setPath(regExp.cap(1)); - _fgProcessWorkingDirPath = fgAppDir.absolutePath(); - qDebug() << "fg_exe" << fgAppDir.absolutePath(); - } - continue; - } - - regExp.setPattern("^fg_root:(.*)"); - if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { - fgRootPathProposedList += QDir(regExp.cap(1)).absolutePath(); - qDebug() << "fg_root" << fgRootPathProposedList[0]; - continue; - } - - regExp.setPattern("^fg_scenery:(.*)"); - if (regExp.indexIn(line) == 0 && regExp.captureCount() == 1) { - // Scenery can contain multiple paths separated by ';' so don't do QDir::absolutePath on it - fgSceneryPath = regExp.cap(1); - qDebug() << "fg_scenery" << fgSceneryPath; - continue; - } - } - } - } -#elif defined Q_OS_LINUX - // Linux installs to a location on the path so we don't need a directory to run the executable - fgAppName = "fgfs"; - _fgProcessName = "fgfs"; - fgRootPathProposedList += "/usr/share/flightgear/data/"; // Default Archlinux location - fgRootPathProposedList += "/usr/share/games/flightgear/"; // Default Ubuntu location -#else -#error Unknown OS build flavor -#endif - -#ifndef Q_OS_LINUX - // Validate the FlightGear application directory location. Linux runs from path so we don't validate on that OS. - Q_ASSERT(!fgAppName.isEmpty()); - QString fgAppFullyQualified = fgAppDir.absoluteFilePath(fgAppName); - //-- TODO: - /* - while (!QFileInfo(fgAppFullyQualified).exists()) { - QMessageBox msgBox(QMessageBox::Critical, - tr("FlightGear application not found"), - tr("FlightGear application not found at: %1").arg(fgAppFullyQualified), - QMessageBox::Cancel, - MainWindow::instance()); - msgBox.setWindowModality(Qt::ApplicationModal); - msgBox.addButton(tr("I'll specify directory"), QMessageBox::ActionRole); - if (msgBox.exec() == QMessageBox::Cancel) { - return false; - } - - // Let the user pick the right directory - QString dirPath = QString(); //-- TODO: QGCQFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName); - if (dirPath.isEmpty()) { - return false; - } - fgAppDir.setPath(dirPath); - fgAppFullyQualified = fgAppDir.absoluteFilePath(fgAppName); - } - */ -#endif - - // If we have an --fg-root coming in from the ui options, that setting overrides any internal searching of - // proposed locations. - QString argValue; - fgRootDirOverride = _findUIArgument(_fgArgList, "--fg-root", argValue); - if (fgRootDirOverride) { - fgRootPathProposedList.clear(); - fgRootPathProposedList += argValue; - qDebug() << "--fg-root override" << argValue; - } - - // See if we can find an --fg-root directory from the proposed list. - Q_ASSERT(fgRootPath.isEmpty()); - for (int i=0; i as an additional command line parameter from ui."); - } - QGCMessageBox::critical(tr("FlightGear HIL"), errMsg); - return false; - } - - if (!fgRootDirOverride) { - _fgArgList += "--fg-root=" + fgRootPath; - } - - // Add --fg-scenery command line arg. If --fg-scenery is specified from the ui we use that instead. - // On Windows --fg-scenery is required on the command line otherwise FlightGear won't boot. - fgSceneryDirOverride = _findUIArgument(_fgArgList, "--fg-scenery", argValue); - if (fgSceneryDirOverride) { - fgSceneryPath = argValue; - qDebug() << "--fg-scenery override" << argValue; - } else if (!fgSceneryPath.isEmpty()) { - _fgArgList += "--fg-scenery=" + fgSceneryPath; - } - -#ifdef Q_OS_WIN32 - // Windows won't start without an --fg-scenery set. We don't validate the directory in the path since - // it can be multiple paths. - if (fgSceneryPath.isEmpty()) { - QString errMsg; - if (fgSceneryDirOverride) { - errMsg = tr("--fg-scenery directory specified from ui option not found: %1").arg(fgSceneryPath); - } else { - errMsg = tr("Unable to automatically determine --fg-scenery directory location. You will need to specify --fg-scenery=directory as an additional command line parameter from ui."); - } - QGCMessageBox::critical(tr("FlightGear HIL"), errMsg); - return false; - } -#else - Q_UNUSED(fgSceneryDirOverride); -#endif - - // Setup and verify directory which contains QGC provided aircraft files - QString qgcAircraftDir(QApplication::applicationDirPath() + "/flightgear/Aircraft"); - if (!QFileInfo(qgcAircraftDir).isDir()) { - QGCMessageBox::critical(tr("FlightGear HIL"), tr("Incorrect %1 installation. Aircraft directory is missing: '%2'.").arg(qgcApp()->applicationName()).arg(qgcAircraftDir)); - return false; - } - _fgArgList += "--fg-aircraft=" + qgcAircraftDir; - - // Setup protocol we will be using to communicate with FlightGear - QString fgProtocol(_vehicle->vehicleType() == MAV_TYPE_QUADROTOR ? "qgroundcontrol-quadrotor" : "qgroundcontrol-fixed-wing"); - QString fgProtocolArg("--generic=socket,%1,300,127.0.0.1,%2,udp,%3"); - _fgArgList << fgProtocolArg.arg("out").arg(port).arg(fgProtocol); - _fgArgList << fgProtocolArg.arg("in").arg(currentPort).arg(fgProtocol); - - // Verify directory where FlightGear stores communicaton protocols. - QDir fgProtocolDir(fgRootPath); - if (!fgProtocolDir.cd("Protocol")) { - QGCMessageBox::critical(tr("FlightGear HIL"), tr("Incorrect FlightGear setup. Protocol directory is missing: '%1'. Command line parameter for --fg-root may be set incorrectly.").arg(fgProtocolDir.path())); - return false; - } - - // Verify directory which contains QGC provided FlightGear communication protocol files - QDir qgcProtocolDir(QApplication::applicationDirPath() + "/flightgear/Protocol/"); - if (!qgcProtocolDir.isReadable()) { - QGCMessageBox::critical(tr("FlightGear HIL"), tr("Incorrect installation. Protocol directory is missing (%1).").arg(qgcProtocolDir.path())); - return false; - } - - // Make sure we can find the communication protocol file in QGC install - QString fgProtocolXmlFile = fgProtocol + ".xml"; - QString qgcProtocolFileFullyQualified = qgcProtocolDir.absoluteFilePath(fgProtocolXmlFile); - if (!QFileInfo(qgcProtocolFileFullyQualified).exists()) { - QGCMessageBox::critical(tr("FlightGear HIL"), tr("Incorrect installation. FlightGear protocol file missing: %1").arg(qgcProtocolFileFullyQualified)); - return false; - } - - // Communication protocol must be in FlightGear protocol directory. There does not appear to be any way - // around this by specifying something on the FlightGear command line. FG code does direct append - // of protocol xml file to $FG_ROOT and $FG_ROOT only allows a single directory to be specified. - _fgProtocolFileFullyQualified = fgProtocolDir.absoluteFilePath(fgProtocolXmlFile); - - if (QFileInfo(_fgProtocolFileFullyQualified).exists()) { - // Verify that the file is current by comparing it against the one in QGC - - QFile fgFile(_fgProtocolFileFullyQualified); - QFile qgcFile(qgcProtocolFileFullyQualified); - - if (!fgFile.open(QIODevice::ReadOnly) || - !qgcFile.open(QIODevice::ReadOnly)) { - QGCMessageBox::warning(tr("FlightGear HIL"), tr("Unable to verify that protocol file %1 is current. " - "If file is out of date, you may experience problems. " - "Safest approach is to delete the file manually and allow %2 install the latest file.").arg(qgcApp()->applicationName()).arg(_fgProtocolFileFullyQualified)); - } - - QByteArray fgBytes = fgFile.readAll(); - QByteArray qgcBytes = qgcFile.readAll(); - - fgFile.close(); - qgcFile.close(); - - if (fgBytes != qgcBytes) { - QGCMessageBox::warning(tr("FlightGear HIL"), tr("FlightGear protocol file %1 is out of date. It will be deleted, which will cause %2 to install the latest version of the file.").arg(_fgProtocolFileFullyQualified).arg(qgcApp()->applicationName())); - if (!QFile::remove(_fgProtocolFileFullyQualified)) { - QGCMessageBox::warning(tr("FlightGear HIL"), tr("Delete of protocol file failed. You will have to manually delete the file.")); - return false; - } - } - } - - if (!QFileInfo(_fgProtocolFileFullyQualified).exists()) { - QMessageBox msgBox(QMessageBox::Critical, - tr("FlightGear Failed to Start"), - tr("FlightGear Failed to Start. %1 protocol (%2) not installed to FlightGear Protocol directory (%3)").arg(qgcApp()->applicationName()).arg(fgProtocolXmlFile).arg(fgProtocolDir.path()), - QMessageBox::Cancel, - MainWindow::instance()); - msgBox.setWindowModality(Qt::ApplicationModal); - msgBox.addButton(tr("Fix it for me"), QMessageBox::ActionRole); - if (msgBox.exec() == QMessageBox::Cancel) { - return false; - } - - // Now that we made it this far, we should be able to try to copy the protocol file to FlightGear. - bool succeeded = QFile::copy(qgcProtocolFileFullyQualified, _fgProtocolFileFullyQualified); - if (!succeeded) { -#ifdef Q_OS_WIN32 - QString copyCmd = QString("copy \"%1\" \"%2\"").arg(qgcProtocolFileFullyQualified).arg(_fgProtocolFileFullyQualified); - copyCmd.replace("/", "\\"); -#else - QString copyCmd = QString("sudo cp %1 %2").arg(qgcProtocolFileFullyQualified).arg(_fgProtocolFileFullyQualified); -#endif - - QMessageBox msgBox(QMessageBox::Critical, - tr("Copy failed"), -#ifdef Q_OS_WIN32 - tr("Copy from (%1) to (%2) failed, possibly due to permissions issue. You will need to perform manually. Try pasting the following command into a Command Prompt which was started with Run as Administrator:\n\n").arg(qgcProtocolFileFullyQualified).arg(_fgProtocolFileFullyQualified) + copyCmd, -#else - tr("Copy from (%1) to (%2) failed, possibly due to permissions issue. You will need to perform manually. Try pasting the following command into a shell:\n\n").arg(qgcProtocolFileFullyQualified).arg(_fgProtocolFileFullyQualified) + copyCmd, -#endif - QMessageBox::Cancel, - MainWindow::instance()); - msgBox.setWindowModality(Qt::ApplicationModal); - msgBox.addButton(tr("Copy to Clipboard"), QMessageBox::ActionRole); - if (msgBox.exec() != QMessageBox::Cancel) { - QApplication::clipboard()->setText(copyCmd); - } - return false; - } - } - - // Start the engines to save a startup step - if (_vehicle->vehicleType() == MAV_TYPE_QUADROTOR) { - // Start all engines of the quad - _fgArgList << "--prop:/engines/engine[0]/running=true"; - _fgArgList << "--prop:/engines/engine[1]/running=true"; - _fgArgList << "--prop:/engines/engine[2]/running=true"; - _fgArgList << "--prop:/engines/engine[3]/running=true"; - } else { - _fgArgList << "--prop:/engines/engine/running=true"; - } - - // We start out at our home position - QGeoCoordinate homePosition = QGroundControlQmlGlobal::flightMapPosition(); - _fgArgList << QString("--lat=%1").arg(homePosition.latitude()); - _fgArgList << QString("--lon=%1").arg(homePosition.longitude()); - // The altitude is not set because an altitude not equal to the ground altitude leads to a non-zero default throttle in flightgear - // Without the altitude-setting the aircraft is positioned on the ground - //_fgArgList << QString("--altitude=%1").arg(homePosition.altitude()); - -#ifdef DEBUG_FLIGHTGEAR_CONNECT - // This tell FlightGear to output highest debug level of log output. Handy for debuggin failures by looking at the FG - // log files. - _fgArgList << "--log-level=debug"; -#endif - - start(HighPriority); - return true; -} - -void QGCFlightGearLink::_printFgfsOutput(void) -{ - qDebug() << "fgfs stdout:"; - QByteArray byteArray = _fgProcess->readAllStandardOutput(); - QStringList strLines = QString(byteArray).split("\n"); - - for (const QString &line: strLines){ - qDebug() << line; - } -} - -void QGCFlightGearLink::_printFgfsError(void) -{ - qDebug() << "fgfs stderr:"; - - QByteArray byteArray = _fgProcess->readAllStandardError(); - QStringList strLines = QString(byteArray).split("\n"); - - for (const QString &line: strLines){ - qDebug() << line; - } -} - -/** - * @brief Set the startup arguments used to start flightgear - * - **/ -void QGCFlightGearLink::setStartupArguments(QString startupArguments) -{ - this->startupArguments = startupArguments; -} - -/** - * @brief Check if connection is active. - * - * @return True if link is connected, false otherwise. - **/ -bool QGCFlightGearLink::isConnected() -{ - return connectState; -} - -QString QGCFlightGearLink::getName() -{ - return name; -} - -QString QGCFlightGearLink::getRemoteHost() -{ - return QString("%1:%2").arg(currentHost.toString(), currentPort); -} - -void QGCFlightGearLink::setName(QString name) -{ - this->name = name; - // emit nameChanged(this->name); -} - -void QGCFlightGearLink::setBarometerOffset(float barometerOffsetkPa) -{ - this->barometerOffsetkPa = barometerOffsetkPa; -} diff --git a/src/comm/QGCFlightGearLink.h b/src/comm/QGCFlightGearLink.h deleted file mode 100644 index e9c94aa1bdd2340657689be2181fdbe8b7c763cb..0000000000000000000000000000000000000000 --- a/src/comm/QGCFlightGearLink.h +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief UDP connection (server) for unmanned vehicles - * @author Lorenz Meier - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "LinkInterface.h" -#include "QGCConfig.h" -#include "UASInterface.h" -#include "QGCHilLink.h" -#include "QGCHilFlightGearConfiguration.h" -#include "Vehicle.h" - -class QGCFlightGearLink : public QGCHilLink -{ - Q_OBJECT - -public: - QGCFlightGearLink(Vehicle* vehicle, QString startupArguments, QString remoteHost=QString("127.0.0.1:49000"), QHostAddress host = QHostAddress::Any, quint16 port = 49005); - ~QGCFlightGearLink(); - - bool isConnected(); - qint64 bytesAvailable(); - int getPort() const { - return port; - } - - /** - * @brief The human readable port name - */ - QString getName(); - - /** - * @brief Get remote host and port - * @return string in format : - */ - QString getRemoteHost(); - - QString getVersion() - { - return QString("FlightGear %1").arg(flightGearVersion); - } - - int getAirFrameIndex() - { - return -1; - } - - bool sensorHilEnabled() { - return _sensorHilEnabled; - } - - void sensorHilEnabled(bool sensorHilEnabled) { - _sensorHilEnabled = sensorHilEnabled; - } - - static bool parseUIArguments(QString uiArgs, QStringList& argList); - - void run(); - -signals: - void showCriticalMessageFromThread(const QString& title, const QString& message); - -public slots: -// void setAddress(QString address); - void setPort(int port); - /** @brief Add a new host to broadcast messages to */ - void setRemoteHost(const QString& host); - /** @brief Send new control states to the simulation */ - void updateControls(quint64 time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, quint8 systemMode, quint8 navMode); - /** @brief Set the simulator version as text string */ - void setVersion(const QString& version) - { - Q_UNUSED(version); - } - - void selectAirframe(const QString& airframe) - { - Q_UNUSED(airframe); - } - - void enableSensorHIL(bool enable) { - if (enable != _sensorHilEnabled) - _sensorHilEnabled = enable; - emit sensorHilChanged(enable); - } - - void readBytes(); - -private slots: - /** - * @brief Write a number of bytes to the interface. - * - * @param data Pointer to the data byte array - * @param size The size of the bytes array - **/ - void _writeBytes(const QByteArray data); - -public slots: - bool connectSimulation(); - bool disconnectSimulation(); - - void setStartupArguments(QString startupArguments); - void setBarometerOffset(float barometerOffsetkPa); - void processError(QProcess::ProcessError err); - -protected: - void setName(QString name); - -private slots: - void _printFgfsOutput(void); - void _printFgfsError(void); - -private: - static bool _findUIArgument(const QStringList& uiArgList, const QString& argLabel, QString& argValue); - - Vehicle* _vehicle; - QString _fgProcessName; ///< FlightGear process to start - QString _fgProcessWorkingDirPath; ///< Working directory to start FG process in, empty for none - QStringList _fgArgList; ///< Arguments passed to FlightGear process - - QUdpSocket* _udpCommSocket; ///< UDP communication sockect between FG and QGC - QProcess* _fgProcess; ///< FlightGear process - - QString _fgProtocolFileFullyQualified; ///< Fully qualified file name for protocol file - - QString name; - QHostAddress host; - QHostAddress currentHost; - quint16 currentPort; - quint16 port; - int id; - bool connectState; - - unsigned int flightGearVersion; - QString startupArguments; - bool _sensorHilEnabled; - float barometerOffsetkPa; -}; - diff --git a/src/qgcunittest/CMakeLists.txt b/src/qgcunittest/CMakeLists.txt index b9066a6ca4c9539c09df18633ea3acbfd5b880b5..35bcdd175d944788c8db026f6552bb0f3b157426 100644 --- a/src/qgcunittest/CMakeLists.txt +++ b/src/qgcunittest/CMakeLists.txt @@ -1,15 +1,15 @@ add_library(qgcunittest - FileDialogTest.cc - FileManagerTest.cc - FlightGearTest.cc + #FileDialogTest.cc + #FileManagerTest.cc + #FlightGearTest.cc GeoTest.cc LinkManagerTest.cc - MainWindowTest.cc + #MainWindowTest.cc MavlinkLogTest.cc - MessageBoxTest.cc + #MessageBoxTest.cc MultiSignalSpy.cc - RadioConfigTest.cc + #RadioConfigTest.cc TCPLinkTest.cc TCPLoopBackServer.cc UnitTest.cc diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 22a5ebb75d8c721c06df4736c628eeaaff4d5f6a..edef4d5187f9320942133bf5e893ab18e10ee4b6 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,57 +1,27 @@ add_library(ui - HILDockWidget.cc - linechart/ChartPlot.cc - linechart/IncrementalPlot.cc - linechart/LinechartPlot.cc - linechart/Linecharts.cc - linechart/LinechartWidget.cc - linechart/Scrollbar.cc - linechart/ScrollZoomer.cc - - MainWindow.cc MAVLinkDecoder.cc MultiVehicleDockWidget.cc - QGCHilConfiguration.cc - QGCHilFlightGearConfiguration.cc - QGCHilJSBSimConfiguration.cc - QGCHilXPlaneConfiguration.cc - QGCMapRCToParamDialog.cpp - QGCMAVLinkLogPlayer.cc QGCPluginHost.cc - QGCUASFileView.cc - QGCUASFileViewMulti.cc - - uas/QGCUnconnectedInfoWidget.cc # HEADERS # shouldn't be listed here, but aren't named properly for AUTOMOC - QGCHilFlightGearConfiguration.h - QGCHilJSBSimConfiguration.h + MAVLinkDecoder.h + MultiVehicleDockWidget.h + QGCMapRCToParamDialog.h + QGCPluginHost.h # UI - MainWindow.ui MultiVehicleDockWidget.ui - QGCHilConfiguration.ui - QGCHilFlightGearConfiguration.ui - QGCHilJSBSimConfiguration.ui - QGCHilXPlaneConfiguration.ui QGCMapRCToParamDialog.ui - QGCMAVLinkLogPlayer.ui QGCPluginHost.ui - QGCUASFileView.ui - QGCUASFileViewMulti.ui QMap3D.ui - - uas/QGCUnconnectedInfoWidget.ui ) target_link_libraries(ui PUBLIC qgc - PRIVATE - qwt ) target_include_directories(ui diff --git a/src/ui/HILDockWidget.cc b/src/ui/HILDockWidget.cc deleted file mode 100644 index 593fe9b59dbd04e7b5e10070b56bddb6614c773b..0000000000000000000000000000000000000000 --- a/src/ui/HILDockWidget.cc +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include "HILDockWidget.h" -#include "QGCHilConfiguration.h" - -HILDockWidget::HILDockWidget(const QString& title, QAction* action, QWidget *parent) - : MultiVehicleDockWidget(title, action, parent) -{ - init(); - - loadSettings(); -} - -HILDockWidget::~HILDockWidget() -{ - -} - -QWidget* HILDockWidget::_newVehicleWidget(Vehicle* vehicle, QWidget* parent) -{ - return new QGCHilConfiguration(vehicle, parent); -} diff --git a/src/ui/HILDockWidget.h b/src/ui/HILDockWidget.h deleted file mode 100644 index 5e75bb3c5f970fecbf836af5380d95c3c5b20b16..0000000000000000000000000000000000000000 --- a/src/ui/HILDockWidget.h +++ /dev/null @@ -1,27 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#pragma once - -#include "MultiVehicleDockWidget.h" - -class HILDockWidget : public MultiVehicleDockWidget -{ - Q_OBJECT - -public: - explicit HILDockWidget(const QString& title, QAction* action, QWidget *parent = 0); - ~HILDockWidget(); - -protected: - // Override from MultiVehicleDockWidget - virtual QWidget* _newVehicleWidget(Vehicle* vehicle, QWidget* parent); -}; - diff --git a/src/ui/QGCHilConfiguration.cc b/src/ui/QGCHilConfiguration.cc deleted file mode 100644 index c52aff35c3c610ab72f20581caf736caddd86cf8..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilConfiguration.cc +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include - -#include "QGCHilConfiguration.h" -#include "ui_QGCHilConfiguration.h" - -#include "QGCHilFlightGearConfiguration.h" -#include "QGCHilJSBSimConfiguration.h" -#include "QGCHilXPlaneConfiguration.h" -#include "UAS.h" - -QGCHilConfiguration::QGCHilConfiguration(Vehicle* vehicle, QWidget *parent) - : QWidget(parent) - , _vehicle(vehicle) - , ui(new Ui::QGCHilConfiguration) -{ - ui->setupUi(this); - - // XXX its quite wrong that this is implicitely a factory - // class, but this is something to clean up for later. - - QSettings settings; - settings.beginGroup("QGC_HILCONFIG"); - int i = settings.value("SIMULATOR_INDEX", -1).toInt(); - - if (i > 0) { -// ui->simComboBox->blockSignals(true); - ui->simComboBox->setCurrentIndex(i); -// ui->simComboBox->blockSignals(false); - on_simComboBox_currentIndexChanged(i); - } - - settings.endGroup(); -} - -void QGCHilConfiguration::receiveStatusMessage(const QString& message) -{ - ui->statusLabel->setText(message); -} - -QGCHilConfiguration::~QGCHilConfiguration() -{ - QSettings settings; - settings.beginGroup("QGC_HILCONFIG"); - settings.setValue("SIMULATOR_INDEX", ui->simComboBox->currentIndex()); - settings.endGroup(); - delete ui; -} - -void QGCHilConfiguration::setVersion(QString version) -{ - Q_UNUSED(version); -} - -void QGCHilConfiguration::on_simComboBox_currentIndexChanged(int index) -{ - //clean up - QLayoutItem *child; - while ((child = ui->simulatorConfigurationLayout->takeAt(0)) != 0) - { - delete child->widget(); - delete child; - } - - if(1 == index) - { - // Ensure the sim exists and is disabled - _vehicle->uas()->enableHilFlightGear(false, "", true, this); - QGCHilFlightGearConfiguration* hfgconf = new QGCHilFlightGearConfiguration(_vehicle, this); - hfgconf->show(); - ui->simulatorConfigurationLayout->addWidget(hfgconf); - QGCFlightGearLink* fg = dynamic_cast(_vehicle->uas()->getHILSimulation()); - if (fg) - { - connect(fg, &QGCFlightGearLink::statusMessage, ui->statusLabel, &QLabel::setText); - } - - } - else if (2 == index || 3 == index) - { - // Ensure the sim exists and is disabled - _vehicle->uas()->enableHilXPlane(false); - QGCHilXPlaneConfiguration* hxpconf = new QGCHilXPlaneConfiguration(_vehicle->uas()->getHILSimulation(), this); - hxpconf->show(); - ui->simulatorConfigurationLayout->addWidget(hxpconf); - - // Select correct version of XPlane - QGCXPlaneLink* xplane = dynamic_cast(_vehicle->uas()->getHILSimulation()); - if (xplane) - { - xplane->setVersion((index == 2) ? 10 : 9); - connect(xplane, &QGCXPlaneLink::statusMessage, ui->statusLabel, &QLabel::setText); - } - } -// Disabling JSB Sim since its not well maintained, -// but as refactoring is pending we're not ditching the code yet -// else if (4) -// { -// // Ensure the sim exists and is disabled -// _vehicle->uas()->enableHilJSBSim(false, ""); -// QGCHilJSBSimConfiguration* hfgconf = new QGCHilJSBSimConfiguration(_vehicle, this); -// hfgconf->show(); -// ui->simulatorConfigurationLayout->addWidget(hfgconf); -// QGCJSBSimLink* jsb = dynamic_cast(_vehicle->uas()->getHILSimulation()); -// if (jsb) -// { -// connect(jsb, SIGNAL(statusMessage(QString)), ui->statusLabel, SLOT(setText(QString))); -// } -// } -} diff --git a/src/ui/QGCHilConfiguration.h b/src/ui/QGCHilConfiguration.h deleted file mode 100644 index 331fef97d1b22b5c1b641fa1f3bec5a3bf927f1b..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilConfiguration.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#pragma once - -#include - -#include "Vehicle.h" - -namespace Ui { -class QGCHilConfiguration; -} - -class QGCHilConfiguration : public QWidget -{ - Q_OBJECT - -public: - QGCHilConfiguration(Vehicle* vehicle, QWidget *parent = 0); - ~QGCHilConfiguration(); - -public slots: - /** @brief Receive status message */ - void receiveStatusMessage(const QString& message); - void setVersion(QString version); - -private slots: - void on_simComboBox_currentIndexChanged(int index); - -private: - Vehicle* _vehicle; - - Ui::QGCHilConfiguration *ui; -}; - diff --git a/src/ui/QGCHilConfiguration.ui b/src/ui/QGCHilConfiguration.ui deleted file mode 100644 index 82e9cc10f947856056ae5f5bf8673f5b5fe0b416..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilConfiguration.ui +++ /dev/null @@ -1,75 +0,0 @@ - - - QGCHilConfiguration - - - - 0 - 0 - 366 - 301 - - - - - 0 - 0 - - - - HIL Config - - - - - - Simulator - - - - - - - true - - - - - - - - - FlightGear 3.0+ - - - - - X-Plane 10 - - - - - X-Plane 9 - - - - - - - - 0 - - - - - - - - - - - - - - - diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc deleted file mode 100644 index fabee9d009c16ec9b6b9e59cb22e569c4fa14c9b..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ /dev/null @@ -1,146 +0,0 @@ -#include "QGCHilFlightGearConfiguration.h" -#include "MainWindow.h" -#include "UAS.h" - -#include - -// Various settings groups and keys -const char* QGCHilFlightGearConfiguration::_settingsGroup = "QGC_HILCONFIG_FLIGHTGEAR"; -const char* QGCHilFlightGearConfiguration::_mavSettingsSubGroupFixedWing = "FIXED_WING"; -const char* QGCHilFlightGearConfiguration::_mavSettingsSubGroupQuadRotor = "QUADROTOR"; -const char* QGCHilFlightGearConfiguration::_aircraftKey = "AIRCRAFT"; -const char* QGCHilFlightGearConfiguration::_optionsKey = "OPTIONS"; -const char* QGCHilFlightGearConfiguration::_barometerOffsetKey = "BARO_OFFSET"; -const char* QGCHilFlightGearConfiguration::_sensorHilKey = "SENSOR_HIL"; - -// Default set of optional command line parameters. If FlightGear won't run HIL without it it should go into -// the QGCFlightGearLink code instead. -const char* QGCHilFlightGearConfiguration::_defaultOptions = "--roll=0 --pitch=0 --vc=0 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --disable-sound --disable-random-objects --disable-ai-traffic --shading-flat --fog-disable --disable-specular-highlight --disable-panel --disable-clouds --fdm=jsb --units-meters --enable-terrasync"; - -QGCHilFlightGearConfiguration::QGCHilFlightGearConfiguration(Vehicle* vehicle, QWidget *parent) - : QWidget(parent) - , _vehicle(vehicle) - , _mavSettingsSubGroup(NULL) - , _resetOptionsAction(tr("Reset to default options"), this) - -{ - _ui.setupUi(this); - - QStringList items; - if (_vehicle->vehicleType() == MAV_TYPE_FIXED_WING) - { - /*items << "EasyStar";*/ - items << "Rascal110-JSBSim"; - /*items << "c172p"; - items << "YardStik"; - items << "Malolo1";*/ - _mavSettingsSubGroup = _mavSettingsSubGroupFixedWing; - } - /*else if (_vehicle->vehicleType() == MAV_TYPE_QUADROTOR) - { - items << "arducopter"; - _mavSettingsSubGroup = _mavSettingsSubGroupQuadRotor; - }*/ - else - { - // FIXME: Should disable all input, won't work. Show error message in the status label thing. - items << ""; - } - _ui.aircraftComboBox->addItems(items); - - QSettings settings; - settings.beginGroup(_settingsGroup); - settings.beginGroup(_mavSettingsSubGroup); - QString aircraft = settings.value(_aircraftKey).toString(); - QString options = settings.value(_optionsKey).toString(); - QString baroOffset = settings.value(_barometerOffsetKey).toString(); - bool sensorHil = settings.value(_sensorHilKey, QVariant(true)).toBool(); - settings.endGroup(); - settings.endGroup(); - - if (!aircraft.isEmpty()) { - int index = _ui.aircraftComboBox->findText(aircraft); - if (index != -1) { - _ui.aircraftComboBox->setCurrentIndex(index); - } - } - if (options.isEmpty()) { - options = _defaultOptions; - } - _ui.optionsPlainTextEdit->setPlainText(options); - _ui.barometerOffsetLineEdit->setText(baroOffset); - _ui.sensorHilCheckBox->setChecked(sensorHil); - - // Provide an option on the context menu to reset the option back to default - _ui.optionsPlainTextEdit->setContextMenuPolicy(Qt::CustomContextMenu); - bool success = connect(&_resetOptionsAction, &QAction::triggered, this, &QGCHilFlightGearConfiguration::_setDefaultOptions); - Q_ASSERT(success); - success = connect(_ui.optionsPlainTextEdit, &QPlainTextEdit::customContextMenuRequested, - this, &QGCHilFlightGearConfiguration::_showContextMenu); - Q_ASSERT(success); - Q_UNUSED(success); // Silence release build unused variable warning -} - -QGCHilFlightGearConfiguration::~QGCHilFlightGearConfiguration() -{ - QString aircraft = _ui.aircraftComboBox->currentText(); - QString options = _ui.optionsPlainTextEdit->toPlainText(); - QString baroOffset = _ui.barometerOffsetLineEdit->text(); - bool sensorHil = _ui.sensorHilCheckBox->isChecked(); - - QSettings settings; - settings.beginGroup(_settingsGroup); - settings.beginGroup(_mavSettingsSubGroup); - - if (aircraft.isEmpty()) { - settings.remove(_aircraftKey); - } else { - settings.setValue(_aircraftKey, aircraft); - } - - if (options.isEmpty() || options == _defaultOptions) { - settings.remove(_optionsKey); - } else { - settings.setValue(_optionsKey, options); - } - - // Double QVariant is to convert from string to float. It will change to 0.0 if invalid. - settings.setValue(_barometerOffsetKey, QVariant(QVariant(baroOffset).toFloat())); - - settings.setValue(_sensorHilKey, QVariant(sensorHil)); - - settings.endGroup(); - settings.endGroup(); -} - -void QGCHilFlightGearConfiguration::on_startButton_clicked() -{ - //XXX check validity of inputs - QString options = _ui.optionsPlainTextEdit->toPlainText(); - options.append(" --aircraft=" + _ui.aircraftComboBox->currentText()); - _vehicle->uas()->enableHilFlightGear(true, options, _ui.sensorHilCheckBox->isChecked(), this); -} - -void QGCHilFlightGearConfiguration::on_stopButton_clicked() -{ - _vehicle->uas()->stopHil(); -} - -void QGCHilFlightGearConfiguration::on_barometerOffsetLineEdit_textChanged(const QString& baroOffset) -{ - emit barometerOffsetChanged(baroOffset.toFloat()); -} - -void QGCHilFlightGearConfiguration::_showContextMenu(const QPoint &pt) -{ - QMenu* menu = _ui.optionsPlainTextEdit->createStandardContextMenu(); - menu->addAction(&_resetOptionsAction); - menu->exec(_ui.optionsPlainTextEdit->mapToGlobal(pt)); - delete menu; -} - -void QGCHilFlightGearConfiguration::_setDefaultOptions(void) -{ - _ui.optionsPlainTextEdit->setPlainText(_defaultOptions); -} - diff --git a/src/ui/QGCHilFlightGearConfiguration.h b/src/ui/QGCHilFlightGearConfiguration.h deleted file mode 100644 index e69176fe7242c811ce1865bd3b946102f4af1387..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilFlightGearConfiguration.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -#include "QGCHilLink.h" -#include "QGCFlightGearLink.h" -#include "Vehicle.h" - -#include "ui_QGCHilFlightGearConfiguration.h" - -namespace Ui { -class QGCHilFlightGearConfiguration; -} - -class QGCHilFlightGearConfiguration : public QWidget -{ - Q_OBJECT - -public: - explicit QGCHilFlightGearConfiguration(Vehicle* vehicle, QWidget *parent = 0); - ~QGCHilFlightGearConfiguration(); - -protected: - -private slots: - void on_startButton_clicked(); - void on_stopButton_clicked(); - void on_barometerOffsetLineEdit_textChanged(const QString& baroOffset); - void _setDefaultOptions(void); - void _showContextMenu(const QPoint& pt); - -private: - Vehicle* _vehicle; - Ui::QGCHilFlightGearConfiguration _ui; - - static const char* _settingsGroup; /// Top level settings group - const char* _mavSettingsSubGroup; /// We maintain a settings sub group per mav type - - static const char* _mavSettingsSubGroupFixedWing; /// Subgroup if mav type is MAV_TYPE_FIXED_WING - static const char* _mavSettingsSubGroupQuadRotor; /// Subgroup is mav type is MAV_TYPE_QUADROTOR - - static const char* _aircraftKey; /// Settings key for aircraft selection - static const char* _optionsKey; /// Settings key for FlightGear cmd line options - static const char* _barometerOffsetKey; /// Settings key for barometer offset - static const char* _sensorHilKey; /// Settings key for Sensor Hil checkbox - - static const char* _defaultOptions; /// Default set of FlightGEar command line options - - QAction _resetOptionsAction; /// Context menu item to reset options to default - -signals: - void barometerOffsetChanged(float barometerOffsetkPa); -}; - diff --git a/src/ui/QGCHilFlightGearConfiguration.ui b/src/ui/QGCHilFlightGearConfiguration.ui deleted file mode 100644 index 96bb40fcafc88f7a9642027e787c7e1121f5d009..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilFlightGearConfiguration.ui +++ /dev/null @@ -1,123 +0,0 @@ - - - QGCHilFlightGearConfiguration - - - - 0 - 0 - 237 - 209 - - - - - 0 - 0 - - - - Form - - - Qt::LeftToRight - - - false - - - - 0 - - - 6 - - - - - - 0 - 0 - - - - true - - - - - - - <html><head/><body><p>Additional Options:</p></body></html> - - - - - - - Airframe: - - - - - - - - 0 - 0 - - - - - - - - - - - - 0 - 0 - - - - Start - - - - - - - Stop - - - - - - - Sensor HIL - - - true - - - - - - - Barometer Offset [kPa]: - - - - - - - 0 - - - - - - - - diff --git a/src/ui/QGCHilJSBSimConfiguration.cc b/src/ui/QGCHilJSBSimConfiguration.cc deleted file mode 100644 index 4e958ae0bf3d4606a056237a9affe6bc1c0ca48f..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilJSBSimConfiguration.cc +++ /dev/null @@ -1,50 +0,0 @@ -#include "QGCHilJSBSimConfiguration.h" -#include "ui_QGCHilJSBSimConfiguration.h" - -#include "MainWindow.h" -#include "UAS.h" - -QGCHilJSBSimConfiguration::QGCHilJSBSimConfiguration(Vehicle* vehicle, QWidget *parent) - : QWidget(parent) - , _vehicle(vehicle) - , ui(new Ui::QGCHilJSBSimConfiguration) -{ - ui->setupUi(this); - - QStringList items = QStringList(); - if (_vehicle->vehicleType() == MAV_TYPE_FIXED_WING) - { - items << "EasyStar"; - items << "Rascal110-JSBSim"; - items << "c172p"; - items << "YardStik"; - items << "Malolo1"; - } - else if (_vehicle->vehicleType() == MAV_TYPE_QUADROTOR) - { - items << "arducopter"; - } - else - { - items << ""; - } - ui->aircraftComboBox->addItems(items); -} - -QGCHilJSBSimConfiguration::~QGCHilJSBSimConfiguration() -{ - delete ui; -} - -void QGCHilJSBSimConfiguration::on_startButton_clicked() -{ - //XXX check validity of inputs - QString options = ui->optionsPlainTextEdit->toPlainText(); - options.append(" --script=" + ui->aircraftComboBox->currentText()); - _vehicle->uas()->enableHilJSBSim(true, options); -} - -void QGCHilJSBSimConfiguration::on_stopButton_clicked() -{ - _vehicle->uas()->stopHil(); -} diff --git a/src/ui/QGCHilJSBSimConfiguration.h b/src/ui/QGCHilJSBSimConfiguration.h deleted file mode 100644 index 99ce61b261b32df914f6579ecb8adc944f4ea7b3..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilJSBSimConfiguration.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -#include "QGCHilLink.h" -#include "QGCFlightGearLink.h" -#include "Vehicle.h" - -namespace Ui { -class QGCHilJSBSimConfiguration; -} - -class QGCHilJSBSimConfiguration : public QWidget -{ - Q_OBJECT - -public: - explicit QGCHilJSBSimConfiguration(Vehicle* vehicle, QWidget *parent = 0); - ~QGCHilJSBSimConfiguration(); - -private slots: - void on_startButton_clicked(); - void on_stopButton_clicked(); - -private: - Vehicle* _vehicle; - - Ui::QGCHilJSBSimConfiguration *ui; -}; - diff --git a/src/ui/QGCHilJSBSimConfiguration.ui b/src/ui/QGCHilJSBSimConfiguration.ui deleted file mode 100644 index 438be8947d5e68fa855b0ee7151c61355c17e735..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilJSBSimConfiguration.ui +++ /dev/null @@ -1,99 +0,0 @@ - - - QGCHilJSBSimConfiguration - - - - 0 - 0 - 237 - 204 - - - - - 0 - 0 - - - - Form - - - Qt::LeftToRight - - - false - - - - 0 - - - 6 - - - - - Airframe: - - - - - - - - 0 - 0 - - - - true - - - - - - - <html><head/><body><p>Additional Options:</p></body></html> - - - - - - - - 0 - 0 - - - - --in-air --roll=0 --pitch=0 --vc=90 --heading=300 --timeofday=noon --disable-hud-3d --disable-fullscreen --geometry=400x300 --disable-anti-alias-hud --wind=0@0 --turbulence=0.0 --prop:/sim/frame-rate-throttle-hz=30 --control=mouse --disable-intro-music --disable-sound --disable-random-objects --disable-ai-models --shading-flat --fog-disable --disable-specular-highlight --disable-random-objects --disable-panel --disable-clouds --fdm=jsb --units-meters --prop:/engines/engine/running=true - - - - - - - - 0 - 0 - - - - Start - - - - - - - Stop - - - - - - - - diff --git a/src/ui/QGCHilXPlaneConfiguration.cc b/src/ui/QGCHilXPlaneConfiguration.cc deleted file mode 100644 index bc0bd438566fe239d28621dc4c081dbb2abd3c63..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilXPlaneConfiguration.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "QGCHilXPlaneConfiguration.h" -#include "ui_QGCHilXPlaneConfiguration.h" -#include "QGCXPlaneLink.h" -#include "QGCHilConfiguration.h" - -QGCHilXPlaneConfiguration::QGCHilXPlaneConfiguration(QGCHilLink* link, QGCHilConfiguration *parent) : - QWidget(parent), - ui(new Ui::QGCHilXPlaneConfiguration) -{ - ui->setupUi(this); - this->link = link; - - connect(ui->startButton, &QPushButton::clicked, this, &QGCHilXPlaneConfiguration::toggleSimulation); - - connect(ui->hostComboBox, static_cast(&QComboBox::activated), - link, &QGCHilLink::setRemoteHost); - - connect(link, &QGCHilLink::remoteChanged, ui->hostComboBox, &QComboBox::setEditText); - connect(link, &QGCHilLink::statusMessage, parent, &QGCHilConfiguration::receiveStatusMessage); - -// connect(mav->getHILSimulation(), SIGNAL(statusMessage(QString)), this, SLOT(receiveStatusMessage(QString))); -// connect(ui->simComboBox, SIGNAL(activated(QString)), mav->getHILSimulation(), SLOT(setVersion(QString))); - - ui->startButton->setText(tr("Connect")); - - QGCXPlaneLink* xplane = dynamic_cast(link); - - if (xplane) - { -// connect(ui->randomAttitudeButton, SIGNAL(clicked()), link, SLOT(setRandomAttitude())); -// connect(ui->randomPositionButton, SIGNAL(clicked()), link, SLOT(setRandomPosition())); - - //ui->airframeComboBox->setCurrentIndex(link->getAirFrameIndex()); - //connect(ui->airframeComboBox, SIGNAL(activated(QString)), link, SLOT(selectAirframe(QString))); - // XXX not implemented yet - //ui->airframeComboBox->hide(); - ui->sensorHilCheckBox->setChecked(xplane->sensorHilEnabled()); - ui->useHilActuatorControlsCheckBox->setChecked(true); - connect(xplane, &QGCXPlaneLink::sensorHilChanged, ui->sensorHilCheckBox, &QCheckBox::setChecked); - connect(ui->sensorHilCheckBox, &QCheckBox::clicked, xplane, &QGCXPlaneLink::enableSensorHIL); - connect(xplane, &QGCXPlaneLink::useHilActuatorControlsChanged, ui->useHilActuatorControlsCheckBox, &QCheckBox::setChecked); - connect(ui->useHilActuatorControlsCheckBox, &QCheckBox::clicked, xplane, &QGCXPlaneLink::enableHilActuatorControls); - - connect(link, static_cast(&QGCHilLink::versionChanged), - this, &QGCHilXPlaneConfiguration::setVersion); - } - - ui->hostComboBox->clear(); - ui->hostComboBox->addItem(link->getRemoteHost()); - - -} - -void QGCHilXPlaneConfiguration::setVersion(int version) -{ - Q_UNUSED(version); -} - -void QGCHilXPlaneConfiguration::toggleSimulation(bool connect) -{ - if (!link) { - return; - } - - Q_UNUSED(connect); - if (!link->isConnected()) - { - link->setRemoteHost(ui->hostComboBox->currentText()); - link->connectSimulation(); - ui->startButton->setText(tr("Disconnect")); - } - else - { - link->disconnectSimulation(); - ui->startButton->setText(tr("Connect")); - } -} - -QGCHilXPlaneConfiguration::~QGCHilXPlaneConfiguration() -{ - delete ui; -} diff --git a/src/ui/QGCHilXPlaneConfiguration.h b/src/ui/QGCHilXPlaneConfiguration.h deleted file mode 100644 index 082625188fb3f934aefb6c224ac9c24be08d5f5d..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilXPlaneConfiguration.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "QGCHilLink.h" - -class QGCHilConfiguration; -namespace Ui { -class QGCHilXPlaneConfiguration; -} - -class QGCHilXPlaneConfiguration : public QWidget -{ - Q_OBJECT - -public: - explicit QGCHilXPlaneConfiguration(QGCHilLink* link, QGCHilConfiguration *parent = 0); - ~QGCHilXPlaneConfiguration(); - -public slots: - /** @brief Start / stop simulation */ - void toggleSimulation(bool connect); - /** @brief Set X-Plane version */ - void setVersion(int version); - -protected: - QGCHilLink* link; - -private: - Ui::QGCHilXPlaneConfiguration *ui; -}; - diff --git a/src/ui/QGCHilXPlaneConfiguration.ui b/src/ui/QGCHilXPlaneConfiguration.ui deleted file mode 100644 index 89b1d852301e04a99bf01dc0a65bb66f70e67669..0000000000000000000000000000000000000000 --- a/src/ui/QGCHilXPlaneConfiguration.ui +++ /dev/null @@ -1,92 +0,0 @@ - - - QGCHilXPlaneConfiguration - - - - 0 - 0 - 269 - 150 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Start - - - - - - - Host - - - - - - - Qt::Vertical - - - - 20 - 1 - - - - - - - - Enable sensor level HIL - - - - - - - true - - - - 127.0.0.1:49000 - - - - - - - - - 0 - 0 - - - - Use newer actuator format - - - - - - - - diff --git a/src/ui/QGCMAVLinkLogPlayer.cc b/src/ui/QGCMAVLinkLogPlayer.cc deleted file mode 100644 index e28824f361dd0d6d2ee9a7331383829e2bda27c2..0000000000000000000000000000000000000000 --- a/src/ui/QGCMAVLinkLogPlayer.cc +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include - -#include "MainWindow.h" -#ifndef NO_SERIAL_LINK -#include "SerialLink.h" -#endif -#include "QGCMAVLinkLogPlayer.h" -#include "QGC.h" -#include "ui_QGCMAVLinkLogPlayer.h" -#include "QGCApplication.h" -#include "SettingsManager.h" -#include "AppSettings.h" -#include "LinkManager.h" -#include "QGCQFileDialog.h" -#include "QGCMessageBox.h" - -QGCMAVLinkLogPlayer::QGCMAVLinkLogPlayer(QWidget *parent) - : QWidget (parent) - , _replayLink (NULL) - , _lastCurrentTime (0) - , _ui (new Ui::QGCMAVLinkLogPlayer) -{ - _ui->setupUi(this); - _ui->horizontalLayout->setAlignment(Qt::AlignTop); - - // Setup buttons - connect(_ui->selectFileButton, &QPushButton::clicked, this, &QGCMAVLinkLogPlayer::_selectLogFileForPlayback); - connect(_ui->playButton, &QPushButton::clicked, this, &QGCMAVLinkLogPlayer::_playPauseToggle); - connect(_ui->positionSlider, &QSlider::valueChanged, this, &QGCMAVLinkLogPlayer::_setPlayheadFromSlider); - connect(_ui->positionSlider, &QSlider::sliderPressed, this, &QGCMAVLinkLogPlayer::_pause); - -#if 0 - // Speed slider is removed from 3.0 release. Too broken to fix. - connect(_ui->speedSlider, &QSlider::valueChanged, this, &QGCMAVLinkLogPlayer::_setAccelerationFromSlider); - _ui->speedSlider->setMinimum(-100); - _ui->speedSlider->setMaximum(100); - _ui->speedSlider->setValue(0); -#endif - - _enablePlaybackControls(false); - - _ui->positionSlider->setMinimum(0); - _ui->positionSlider->setMaximum(100); - -} - -QGCMAVLinkLogPlayer::~QGCMAVLinkLogPlayer() -{ - delete _ui; -} - -void QGCMAVLinkLogPlayer::_playPauseToggle(void) -{ - if (_replayLink->isPlaying()) { - _pause(); - } else { - _replayLink->play(); - } -} - -void QGCMAVLinkLogPlayer::_pause(void) -{ - _replayLink->pause(); -} - -void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void) -{ - // Disallow replay when any links are connected - if (qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()) { - QGCMessageBox::information(tr("Log Replay"), tr("You must close all connections prior to replaying a log.")); - return; - } - - QString logFilename = QGCQFileDialog::getOpenFileName( - this, - tr("Load Telemetry Log File"), - qgcApp()->toolbox()->settingsManager()->appSettings()->telemetrySavePath(), - tr("MAVLink Log Files (*.tlog);;All Files (*)")); - - if (logFilename.isEmpty()) { - return; - } - - LogReplayLinkConfiguration* linkConfig = new LogReplayLinkConfiguration(QString("Log Replay")); - linkConfig->setLogFilename(logFilename); - linkConfig->setName(linkConfig->logFilenameShort()); - _ui->logFileNameLabel->setText(linkConfig->logFilenameShort()); - - LinkManager* linkMgr = qgcApp()->toolbox()->linkManager(); - SharedLinkConfigurationPointer sharedConfig = linkMgr->addConfiguration(linkConfig); - _replayLink = (LogReplayLink*)qgcApp()->toolbox()->linkManager()->createConnectedLink(sharedConfig); - - connect(_replayLink, &LogReplayLink::logFileStats, this, &QGCMAVLinkLogPlayer::_logFileStats); - connect(_replayLink, &LogReplayLink::playbackStarted, this, &QGCMAVLinkLogPlayer::_playbackStarted); - connect(_replayLink, &LogReplayLink::playbackPaused, this, &QGCMAVLinkLogPlayer::_playbackPaused); - connect(_replayLink, &LogReplayLink::playbackPercentCompleteChanged, this, &QGCMAVLinkLogPlayer::_playbackPercentCompleteChanged); - connect(_replayLink, &LogReplayLink::currentLogTimeSecs, this, &QGCMAVLinkLogPlayer::_setCurrentLogTime); - connect(_replayLink, &LogReplayLink::disconnected, this, &QGCMAVLinkLogPlayer::_replayLinkDisconnected); - - _ui->positionSlider->setValue(0); -#if 0 - _ui->speedSlider->setValue(0); -#endif -} - -void QGCMAVLinkLogPlayer::_playbackError(void) -{ - _ui->logFileNameLabel->setText("Error"); - _enablePlaybackControls(false); -} - -QString QGCMAVLinkLogPlayer::_secondsToHMS(int seconds) -{ - int secondsPart = seconds; - int minutesPart = secondsPart / 60; - int hoursPart = minutesPart / 60; - secondsPart -= 60 * minutesPart; - minutesPart -= 60 * hoursPart; - - return QString("%1h:%2m:%3s").arg(hoursPart, 2).arg(minutesPart, 2).arg(secondsPart, 2); -} - -/// Signalled from LogReplayLink once log file information is known -void QGCMAVLinkLogPlayer::_logFileStats(bool logTimestamped, ///< true: timestamped log - int logDurationSeconds, ///< Log duration - int binaryBaudRate) ///< Baud rate for non-timestamped log -{ - Q_UNUSED(logTimestamped); - Q_UNUSED(binaryBaudRate); - - qDebug() << "_logFileStats" << logDurationSeconds; - - _logDurationSeconds = logDurationSeconds; - - _ui->logLengthTime->setText(_secondsToHMS(logDurationSeconds)); -} - -/// Signalled from LogReplayLink when replay starts -void QGCMAVLinkLogPlayer::_playbackStarted(void) -{ - _enablePlaybackControls(true); - _ui->playButton->setChecked(true); - _ui->playButton->setIcon(QIcon(":/res/Pause")); -} - -/// Signalled from LogReplayLink when replay is paused -void QGCMAVLinkLogPlayer::_playbackPaused(void) -{ - _ui->playButton->setIcon(QIcon(":/res/Play")); - _ui->playButton->setChecked(false); -} - -void QGCMAVLinkLogPlayer::_playbackPercentCompleteChanged(int percentComplete) -{ - _ui->positionSlider->blockSignals(true); - _ui->positionSlider->setValue(percentComplete); - _ui->positionSlider->blockSignals(false); -} - -void QGCMAVLinkLogPlayer::_setPlayheadFromSlider(int value) -{ - if (_replayLink) { - _replayLink->movePlayhead(value); - } -} - -void QGCMAVLinkLogPlayer::_enablePlaybackControls(bool enabled) -{ - _ui->playButton->setEnabled(enabled); -#if 0 - _ui->speedSlider->setEnabled(enabled); -#endif - _ui->positionSlider->setEnabled(enabled); -} - -#if 0 -void QGCMAVLinkLogPlayer::_setAccelerationFromSlider(int value) -{ - //qDebug() << value; - if (_replayLink) { - _replayLink->setAccelerationFactor(value); - } - - // Factor: -100: 0.01x, 0: 1.0x, 100: 100x - - float accelerationFactor; - if (value < 0) { - accelerationFactor = 0.01f; - value -= -100; - if (value > 0) { - accelerationFactor *= (float)value; - } - } else if (value > 0) { - accelerationFactor = 1.0f * (float)value; - } else { - accelerationFactor = 1.0f; - } - - _ui->speedLabel->setText(QString("Speed: %1X").arg(accelerationFactor, 5, 'f', 2, '0')); -} -#endif - -void QGCMAVLinkLogPlayer::_replayLinkDisconnected(void) -{ - _enablePlaybackControls(false); - _replayLink = NULL; -} - -void QGCMAVLinkLogPlayer::_setCurrentLogTime(int secs) -{ - if (secs != _lastCurrentTime) { - _lastCurrentTime = secs; - _ui->logCurrentTime->setText(_secondsToHMS(secs)); - } -} diff --git a/src/ui/QGCMAVLinkLogPlayer.h b/src/ui/QGCMAVLinkLogPlayer.h deleted file mode 100644 index dfa80e254cfc4e8242574a28eabd84114916bf47..0000000000000000000000000000000000000000 --- a/src/ui/QGCMAVLinkLogPlayer.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include - -#include "MAVLinkProtocol.h" -#include "LinkInterface.h" -#include "LogReplayLink.h" - -namespace Ui -{ -class QGCMAVLinkLogPlayer; -} - -/** - * @brief Replays MAVLink log files - * - * This class allows to replay MAVLink logs at varying speeds. - * captured flights can be replayed, shown to others and analyzed - * in-depth later on. - */ -class QGCMAVLinkLogPlayer : public QWidget -{ - Q_OBJECT - -public: - explicit QGCMAVLinkLogPlayer(QWidget *parent = 0); - ~QGCMAVLinkLogPlayer(); - -private slots: - void _selectLogFileForPlayback(void); - void _playPauseToggle(void); - void _pause(void); - void _setPlayheadFromSlider(int value); -#if 0 - void _setAccelerationFromSlider(int value); -#endif - void _logFileStats(bool logTimestamped, int logDurationSeconds, int binaryBaudRate); - void _playbackStarted(void); - void _playbackPaused(void); - void _playbackPercentCompleteChanged(int percentComplete); - void _playbackError(void); - void _replayLinkDisconnected(void); - void _setCurrentLogTime(int secs); - -private: - void _finishPlayback(void); - QString _secondsToHMS(int seconds); - void _enablePlaybackControls(bool enabled); - - LogReplayLink* _replayLink; - int _logDurationSeconds; - int _lastCurrentTime; - - Ui::QGCMAVLinkLogPlayer* _ui; -}; - diff --git a/src/ui/QGCMAVLinkLogPlayer.ui b/src/ui/QGCMAVLinkLogPlayer.ui deleted file mode 100644 index 2253c908d1b3f10ecfbfdbf914d1a8bffb812650..0000000000000000000000000000000000000000 --- a/src/ui/QGCMAVLinkLogPlayer.ui +++ /dev/null @@ -1,121 +0,0 @@ - - - QGCMAVLinkLogPlayer - - - - 0 - 0 - 948 - 38 - - - - Form - - - - 12 - - - 0 - - - 4 - - - 0 - - - - - - - - - - - - Start to replay Flight Data - - - Start to replay Flight Data - - - Start to replay Flight Data - - - ... - - - - :/res/Play:/res/Play - - - true - - - false - - - - - - - Time - - - - - - - 10000 - - - 100 - - - true - - - Qt::Horizontal - - - - - - - No Flight Data selected.. - - - - - - - - - - - - - - Select the Flight Data to replay - - - Select the Flight Data to replay - - - Select the Flight Data to replay - - - Replay Flight Data - - - - - - - - - - diff --git a/src/ui/QGCUASFileView.cc b/src/ui/QGCUASFileView.cc deleted file mode 100644 index e2dc5e29a20606c5262660c6e8509958938005fb..0000000000000000000000000000000000000000 --- a/src/ui/QGCUASFileView.cc +++ /dev/null @@ -1,280 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include "QGCUASFileView.h" -#include "FileManager.h" -#include "QGCQFileDialog.h" -#include "UAS.h" - -#include -#include -#include - -QGCUASFileView::QGCUASFileView(QWidget *parent, Vehicle* vehicle) - : QWidget(parent) - , _manager(vehicle->uas()->getFileManager()) - , _currentCommand(commandNone) -{ - _ui.setupUi(this); - - if (vehicle->px4Firmware()) { - _ui.progressBar->reset(); - - // Connect UI signals - connect(_ui.listFilesButton, &QPushButton::clicked, this, &QGCUASFileView::_refreshTree); - connect(_ui.downloadButton, &QPushButton::clicked, this, &QGCUASFileView::_downloadFile); - connect(_ui.uploadButton, &QPushButton::clicked, this, &QGCUASFileView::_uploadFile); - connect(_ui.treeWidget, &QTreeWidget::currentItemChanged, this, &QGCUASFileView::_currentItemChanged); - - // Connect signals from FileManager - connect(_manager, &FileManager::commandProgress, this, &QGCUASFileView::_commandProgress); - connect(_manager, &FileManager::commandComplete, this, &QGCUASFileView::_commandComplete); - connect(_manager, &FileManager::commandError, this, &QGCUASFileView::_commandError); - connect(_manager, &FileManager::listEntry, this, &QGCUASFileView::_listEntryReceived); - } else { - _setAllButtonsEnabled(false); - _ui.statusText->setText(QStringLiteral("Onboard Files not supported by this Vehicle")); - } -} - -/// @brief Downloads the file currently selected in the tree view -void QGCUASFileView::_downloadFile(void) -{ - if (_currentCommand != commandNone) { - qWarning() << QString("Download attempted while another command was in progress: _currentCommand(%1)").arg(_currentCommand); - return; - } - - _ui.statusText->clear(); - - QString downloadToHere = QGCQFileDialog::getExistingDirectory(this, - tr("Download Directory"), - QDir::homePath(), - QGCQFileDialog::ShowDirsOnly | QGCQFileDialog::DontResolveSymlinks); - - // And now download to this location - - QString path; - QString downloadFilename; - - QTreeWidgetItem* item = _ui.treeWidget->currentItem(); - if (item && item->type() == _typeFile) { - do { - QString name = item->text(0).split("\t")[0]; // Strip off file sizes - - // If this is the file name and not a directory keep track of the download file name - if (downloadFilename.isEmpty()) { - downloadFilename = name; - } - - path.prepend("/" + name); - item = item->parent(); - } while (item); - - _setAllButtonsEnabled(false); - _currentCommand = commandDownload; - - _ui.statusText->setText(tr("Downloading: %1").arg(downloadFilename)); - - _manager->streamPath(path, QDir(downloadToHere)); - } -} - -/// @brief uploads a file into the currently selected directory the tree view -void QGCUASFileView::_uploadFile(void) -{ - if (_currentCommand != commandNone) { - qWarning() << QString("Upload attempted while another command was in progress: _currentCommand(%1)").arg(_currentCommand); - return; - } - - _ui.statusText->clear(); - - // get and check directory from list view - QTreeWidgetItem* item = _ui.treeWidget->currentItem(); - if (item && item->type() != _typeDir) { - return; - } - - // Find complete path for upload directory - QString path; - do { - QString name = item->text(0).split("\t")[0]; // Strip off file sizes - path.prepend("/" + name); - item = item->parent(); - } while (item); - - QString uploadFromHere = QGCQFileDialog::getOpenFileName(this, tr("Upload File"), QDir::homePath()); - - _ui.statusText->setText(tr("Uploading: %1").arg(uploadFromHere)); - - qDebug() << "Upload: " << uploadFromHere << "to path" << path; - - _setAllButtonsEnabled(false); - _currentCommand = commandUpload; - - _manager->uploadPath(path, uploadFromHere); -} - -/// @brief Called to update the progress of the download. -/// @param value Progress bar value -void QGCUASFileView::_commandProgress(int value) -{ - _ui.progressBar->setValue(value); -} - -/// @brief Called when an error occurs during a download. -/// @param msg Error message -void QGCUASFileView::_commandError(const QString& msg) -{ - _setAllButtonsEnabled(true); - _currentCommand = commandNone; - _ui.statusText->setText(tr("Error: %1").arg(msg)); -} - -/// @brief Refreshes the directory list tree. -void QGCUASFileView::_refreshTree(void) -{ - if (_currentCommand != commandNone) { - qWarning() << QString("List attempted while another command was in progress: _currentCommand(%1)").arg(_currentCommand); - return; - } - - _ui.treeWidget->clear(); - _ui.statusText->clear(); - - _walkIndexStack.clear(); - _walkItemStack.clear(); - _walkIndexStack.append(0); - _walkItemStack.append(_ui.treeWidget->invisibleRootItem()); - - _setAllButtonsEnabled(false); - _currentCommand = commandList; - - _requestDirectoryList("/"); -} - -/// @brief Adds the specified directory entry to the tree view. -void QGCUASFileView::_listEntryReceived(const QString& entry) -{ - if (_currentCommand != commandList) { - qWarning() << QString("List entry received while no list command in progress: _currentCommand(%1)").arg(_currentCommand); - return; - } - - int type; - if (entry.startsWith("F")) { - type = _typeFile; - } else if (entry.startsWith("D")) { - type = _typeDir; - if (entry == "D." || entry == "D..") { - return; - } - } else { - Q_ASSERT(false); - return; // Silence maybe-unitialized on type - } - - QTreeWidgetItem* item; - item = new QTreeWidgetItem(_walkItemStack.last(), type); - Q_CHECK_PTR(item); - - item->setText(0, entry.right(entry.size() - 1)); -} - -/// @brief Called when a command completes successfully -void QGCUASFileView::_commandComplete(void) -{ - QString statusText; - - if (_currentCommand == commandDownload) { - _currentCommand = commandNone; - _setAllButtonsEnabled(true); - statusText = "Download complete"; - } else if (_currentCommand == commandUpload) { - _currentCommand = commandNone; - _setAllButtonsEnabled(true); - statusText = "Upload complete"; - } else if (_currentCommand == commandList) { - _listComplete(); - } - - _ui.statusText->setText(statusText); - _ui.progressBar->reset(); -} - -void QGCUASFileView::_listComplete(void) -{ - // Walk the current items, traversing down into directories - -Again: - int walkIndex = _walkIndexStack.last(); - QTreeWidgetItem* parentItem = _walkItemStack.last(); - QTreeWidgetItem* childItem = parentItem->child(walkIndex); - - // Loop until we hit a directory - while (childItem && childItem->type() != _typeDir) { - // Move to next index at current level - _walkIndexStack.last() = ++walkIndex; - childItem = parentItem->child(walkIndex); - } - - if (childItem) { - // Move to the next item for processing at this level - _walkIndexStack.last() = ++walkIndex; - - // Push this new directory on the stack - _walkItemStack.append(childItem); - _walkIndexStack.append(0); - - // Ask for the directory list - QString dir; - for (int i=1; i<_walkItemStack.count(); i++) { - QTreeWidgetItem* item = _walkItemStack[i]; - dir.append("/" + item->text(0)); - } - _requestDirectoryList(dir); - } else { - // We have run out of items at the this level, pop the stack and keep going at that level - _walkIndexStack.removeLast(); - _walkItemStack.removeLast(); - if (_walkIndexStack.count() != 0) { - goto Again; - } else { - _setAllButtonsEnabled(true); - _currentCommand = commandNone; - } - } -} - -void QGCUASFileView::_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) -{ - Q_UNUSED(previous); - - _ui.downloadButton->setEnabled(current ? (current->type() == _typeFile) : false); - _ui.uploadButton->setEnabled(current ? (current->type() == _typeDir) : false); -} - -void QGCUASFileView::_requestDirectoryList(const QString& dir) -{ - _manager->listDirectory(dir); -} - -void QGCUASFileView::_setAllButtonsEnabled(bool enabled) -{ - _ui.treeWidget->setEnabled(enabled); - _ui.downloadButton->setEnabled(enabled); - _ui.listFilesButton->setEnabled(enabled); - _ui.uploadButton->setEnabled(enabled); - - if (enabled) { - _currentItemChanged(_ui.treeWidget->currentItem(), NULL); - } -} diff --git a/src/ui/QGCUASFileView.h b/src/ui/QGCUASFileView.h deleted file mode 100644 index 86e74dfdf94cfc1b0b1f7ef618f33ebc46362783..0000000000000000000000000000000000000000 --- a/src/ui/QGCUASFileView.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#pragma once - -#include -#include - -#include "Vehicle.h" -#include "uas/FileManager.h" -#include "ui_QGCUASFileView.h" - -class QGCUASFileView : public QWidget -{ - Q_OBJECT - -public: - explicit QGCUASFileView(QWidget *parent, Vehicle* vehicle); - -protected: - FileManager* _manager; - -private slots: - void _listEntryReceived(const QString& entry); - - void _refreshTree(void); - void _downloadFile(void); - void _uploadFile(void); - - void _commandProgress(int value); - void _commandError(const QString& msg); - void _commandComplete(void); - - void _currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); - -private: - void _listComplete(void); - void _requestDirectoryList(const QString& dir); - void _setAllButtonsEnabled(bool enabled); - - static const int _typeFile = QTreeWidgetItem::UserType + 1; - static const int _typeDir = QTreeWidgetItem::UserType + 2; - static const int _typeError = QTreeWidgetItem::UserType + 3; - - QList _walkIndexStack; - QList _walkItemStack; - Ui::QGCUASFileView _ui; - - enum CommandState { - commandNone, ///< No command active - commandList, ///< List command active - commandDownload, ///< Download command active - commandUpload ///< Upload command active - }; - - CommandState _currentCommand; ///< Current active command -}; - diff --git a/src/ui/QGCUASFileView.ui b/src/ui/QGCUASFileView.ui deleted file mode 100644 index 79ff8f89a75fbad72113ce7ccfa768d616bf65ae..0000000000000000000000000000000000000000 --- a/src/ui/QGCUASFileView.ui +++ /dev/null @@ -1,86 +0,0 @@ - - - QGCUASFileView - - - - 0 - 0 - 216 - 518 - - - - Form - - - - - - List Files - - - - - - - 24 - - - false - - - - - - - Qt::NoContextMenu - - - true - - - - 1 - - - - - - - - false - - - Download File - - - - - - - - 0 - 0 - - - - - - - - - - - false - - - Upload File - - - - - - - - diff --git a/src/ui/QGCUASFileViewMulti.cc b/src/ui/QGCUASFileViewMulti.cc deleted file mode 100644 index 81f07c943dcac7871829ae6c91fa617c0e49e5df..0000000000000000000000000000000000000000 --- a/src/ui/QGCUASFileViewMulti.cc +++ /dev/null @@ -1,75 +0,0 @@ -#include "QGCUASFileViewMulti.h" -#include "ui_QGCUASFileViewMulti.h" -#include "UASInterface.h" -#include "MultiVehicleManager.h" -#include "QGCUASFileView.h" -#include "QGCApplication.h" - -QGCUASFileViewMulti::QGCUASFileViewMulti(const QString& title, QAction* action, QWidget *parent) : - QGCDockWidget(title, action, parent), - ui(new Ui::QGCUASFileViewMulti) -{ - ui->setupUi(this); - setMinimumSize(600, 80); - connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::activeVehicleChanged, this, &QGCUASFileViewMulti::_activeVehicleChanged); - connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::vehicleAdded, this, &QGCUASFileViewMulti::_vehicleAdded); - connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved, this, &QGCUASFileViewMulti::_vehicleRemoved); - - if (qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()) { - _vehicleAdded(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()); - _activeVehicleChanged(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()); - } - - loadSettings(); -} - -void QGCUASFileViewMulti::_vehicleRemoved(Vehicle* vehicle) -{ - UAS* uas = vehicle->uas(); - Q_ASSERT(uas); - - QGCUASFileView* list = lists.value(uas, NULL); - if (list) - { - delete list; - lists.remove(uas); - } -} - -void QGCUASFileViewMulti::_vehicleAdded(Vehicle* vehicle) -{ - UAS* uas = vehicle->uas(); - - if (!lists.contains(uas)) { - QGCUASFileView* list = new QGCUASFileView(ui->stackedWidget, vehicle); - lists.insert(uas, list); - ui->stackedWidget->addWidget(list); - } -} - -void QGCUASFileViewMulti::_activeVehicleChanged(Vehicle* vehicle) -{ - if (vehicle) { - QGCUASFileView* list = lists.value(vehicle->uas(), NULL); - if (list) { - ui->stackedWidget->setCurrentWidget(list); - } - } -} - -QGCUASFileViewMulti::~QGCUASFileViewMulti() -{ - delete ui; -} - -void QGCUASFileViewMulti::changeEvent(QEvent *e) -{ - QWidget::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} diff --git a/src/ui/QGCUASFileViewMulti.h b/src/ui/QGCUASFileViewMulti.h deleted file mode 100644 index 69c05e115751e6d846b9952ea01920b12e3c4e37..0000000000000000000000000000000000000000 --- a/src/ui/QGCUASFileViewMulti.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include "QGCDockWidget.h" -#include "QGCUASFileView.h" -#include "UAS.h" - -namespace Ui -{ -class QGCUASFileViewMulti; -} - -class QGCUASFileViewMulti : public QGCDockWidget -{ - Q_OBJECT - -public: - explicit QGCUASFileViewMulti(const QString& title, QAction* action, QWidget *parent = 0); - ~QGCUASFileViewMulti(); - -protected: - void changeEvent(QEvent *e); - QMap lists; - -private slots: - void _vehicleAdded(Vehicle* vehicle); - void _vehicleRemoved(Vehicle* vehicle); - void _activeVehicleChanged(Vehicle* vehicle); - -private: - Ui::QGCUASFileViewMulti *ui; -}; - diff --git a/src/ui/QGCUASFileViewMulti.ui b/src/ui/QGCUASFileViewMulti.ui deleted file mode 100644 index 3b42db2c8d22c2fc5bcaa45d17443d8ed3ca3ed4..0000000000000000000000000000000000000000 --- a/src/ui/QGCUASFileViewMulti.ui +++ /dev/null @@ -1,27 +0,0 @@ - - - QGCUASFileViewMulti - - - - 0 - 0 - 200 - 300 - - - - Onboard Files - - - - 0 - - - - - - - - - diff --git a/src/ui/linechart/ChartPlot.cc b/src/ui/linechart/ChartPlot.cc deleted file mode 100644 index 574be4c639dd9e0376e1e506d746e4df358dd457..0000000000000000000000000000000000000000 --- a/src/ui/linechart/ChartPlot.cc +++ /dev/null @@ -1,102 +0,0 @@ -#include "ChartPlot.h" -#include "QGCApplication.h" -#include "SettingsManager.h" - -const QColor ChartPlot::baseColors[numColors] = { - QColor(242, 255, 128), - QColor(70, 80, 242), - QColor(232, 33, 47), - QColor(116, 251, 110), - QColor(81, 183, 244), - QColor(234, 38, 107), - QColor(92, 247, 217), - QColor(151, 59, 239), - QColor(231, 72, 28), - QColor(236, 48, 221), - QColor(75, 133, 243), - QColor(203, 254, 121), - QColor(104, 64, 240), - QColor(200, 54, 238), - QColor(104, 250, 138), - QColor(235, 43, 165), - QColor(98, 248, 176), - QColor(161, 252, 116), - QColor(87, 231, 246), - QColor(230, 126, 23) -}; - -ChartPlot::ChartPlot(QWidget* parent): - QwtPlot(parent), - _nextColorIndex(0), - _symbolWidth(2.0f), - _curveWidth(2.0f), - _gridWidth(0.8f) -{ - // Initialize the list of curves. - _curves = QMap(); - // Set the grid. The colorscheme was already set in generateColorScheme(). - _grid = new QwtPlotGrid; - _grid->enableXMin(true); - _grid->attach(this); - _colors = QList(); - ///> Color map for plots, includes 20 colors - ///> Map will start from beginning when the first 20 colors are exceeded - for(int i = 0; i < numColors; ++i) { - _colors.append(baseColors[i]); - } - // Now that all objects have been initialized, color everything. - styleChanged(qgcApp()->toolbox()->settingsManager()->appSettings()->indoorPalette()->rawValue().toBool()); -} - -ChartPlot::~ChartPlot() -{ -} - -QColor ChartPlot::getNextColor() -{ - if(_nextColorIndex >= _colors.count()) { - _nextColorIndex = 0; - } - return _colors[_nextColorIndex++]; -} - -QColor ChartPlot::getColorForCurve(const QString& id) -{ - return _curves.value(id)->pen().color(); -} - -void ChartPlot::shuffleColors() -{ - foreach(QwtPlotCurve* curve, _curves) { - if(curve->isVisible()) { - QPen pen(curve->pen()); - pen.setColor(getNextColor()); - curve->setPen(pen); - } - } -} - -void ChartPlot::styleChanged(bool styleIsDark) -{ - // Generate a new color list for curves and recolor them. - for(int i = 0; i < numColors; ++i) { - _colors[i] = styleIsDark ? baseColors[i].lighter(150) : baseColors[i].darker(150); - } - shuffleColors(); - // Configure the rest of the UI colors based on the current theme. - if(styleIsDark) { - // Set canvas background - setCanvasBackground(QColor(0, 0, 0)); - // Configure the plot grid. - _grid->setMinorPen(QPen(QColor(64, 64, 64), _gridWidth, Qt::SolidLine)); - _grid->setMajorPen(QPen(QColor(96, 96, 96), _gridWidth, Qt::SolidLine)); - } else { - // Set canvas background - setCanvasBackground(QColor(0xFF, 0xFF, 0xFF)); - // Configure the plot grid. - _grid->setMinorPen(QPen(QColor(192, 192, 192), _gridWidth, Qt::SolidLine)); - _grid->setMajorPen(QPen(QColor(128, 128, 128), _gridWidth, Qt::SolidLine)); - } - // And finally refresh the widget to make sure all color changes are redrawn. - replot(); -} diff --git a/src/ui/linechart/ChartPlot.h b/src/ui/linechart/ChartPlot.h deleted file mode 100644 index 51a7892bbdc9ff3730c7f7208ba35ebf57921dd7..0000000000000000000000000000000000000000 --- a/src/ui/linechart/ChartPlot.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include -#include "MainWindow.h" -#include "ScrollZoomer.h" - -class ChartPlot : public QwtPlot -{ - Q_OBJECT -public: - ChartPlot(QWidget *parent = NULL); - virtual ~ChartPlot(); - - /** @brief Get next color of color map */ - QColor getNextColor(); - - /** @brief Get color for curve id */ - QColor getColorForCurve(const QString &id); - - /** @brief Reset color map */ - void shuffleColors(); - -public slots: - - /** @brief Generate coloring for this plot canvas based on current window theme */ - void styleChanged(bool styleIsDark); - -protected: - const static int numColors = 20; - const static QColor baseColors[numColors]; - - QList _colors; ///< Colormap for curves - int _nextColorIndex; ///< Next index in color map - QMap _curves; ///< Plot curves - QwtPlotGrid* _grid; ///< Plot grid - - float _symbolWidth; ///< Width of curve symbols in pixels - float _curveWidth; ///< Width of curve lines in pixels - float _gridWidth; ///< Width of gridlines in pixels -}; - diff --git a/src/ui/linechart/IncrementalPlot.cc b/src/ui/linechart/IncrementalPlot.cc deleted file mode 100644 index 11f336e6a1a8336a6a966867f5248dabd503e77c..0000000000000000000000000000000000000000 --- a/src/ui/linechart/IncrementalPlot.cc +++ /dev/null @@ -1,384 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Implementation of class IncrementalPlot - * @author Lorenz Meier - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "IncrementalPlot.h" -#include -#include -#include -#include - -#include - -CurveData::CurveData(): - d_count(0) -{ -} - -void CurveData::append(double *x, double *y, int count) -{ - int newSize = ( (d_count + count) / 1000 + 1 ) * 1000; - if ( newSize > size() ) { - d_x.resize(newSize); - d_y.resize(newSize); - } - - for ( int i = 0; i < count; i++ ) { - d_x[d_count + i] = x[i]; - d_y[d_count + i] = y[i]; - } - d_count += count; -} - -int CurveData::count() const -{ - return d_count; -} - -int CurveData::size() const -{ - return d_x.size(); -} - -const double* CurveData::x() const -{ - return d_x.data(); -} - -const double* CurveData::y() const -{ - return d_y.data(); -} - -IncrementalPlot::IncrementalPlot(QWidget *parent): - ChartPlot(parent), - symmetric(false) -{ - setStyleText("solid crosses"); - - plotLayout()->setAlignCanvasToScales(true); - - QwtLinearScaleEngine* yScaleEngine = new QwtLinearScaleEngine(); - setAxisScaleEngine(QwtPlot::yLeft, yScaleEngine); - - setAxisAutoScale(xBottom); - setAxisAutoScale(yLeft); - - resetScaling(); - - legend = NULL; -} - -IncrementalPlot::~IncrementalPlot() -{ - -} - -/** - * @param symmetric true will enforce that both axes have the same interval, - * centered around the data plot. A circle will thus remain a circle if true, - * if set to false it might become an ellipse because of axis scaling. - */ -void IncrementalPlot::setSymmetric(bool symmetric) -{ - this->symmetric = symmetric; - updateScale(); // Updates the scaling at replots -} - -void IncrementalPlot::handleLegendClick(QwtPlotItem* item, bool on) -{ - item->setVisible(!on); - replot(); -} - -void IncrementalPlot::showLegend(bool show) -{ - if (show) { - if (legend == NULL) { - legend = new QwtLegend; - legend->setFrameStyle(QFrame::Box); - legend->setDefaultItemMode(QwtLegendData::Checkable); - } - insertLegend(legend, QwtPlot::RightLegend); - } else { - delete legend; - legend = NULL; - } - updateScale(); // Updates the scaling at replots -} - -/** - * Set datapoint and line style. This interface is intended - * to be directly connected to the UI and allows to parse - * human-readable, textual descriptions into plot specs. - * - * Data points: Either "circles", "crosses" or the default "dots" - * Lines: Either "dotted", ("solid"/"line") or no lines if not used - * - * No special formatting is needed, as long as the keywords are contained - * in the string. Lower/uppercase is ignored as well. - * - * @param style Formatting string for line/data point style - */ -void IncrementalPlot::setStyleText(const QString &style) -{ - styleText = style.toLower(); - foreach (QwtPlotCurve* curve, _curves) { - updateStyle(curve); - } - replot(); -} - -void IncrementalPlot::updateStyle(QwtPlotCurve *curve) -{ - if(styleText.isNull()) - return; - - // Since the symbols always use the same color as the curve line, we just use that color. - // This saves us from having to deal with cases where the symbol is NULL. - QColor oldColor = curve->pen().color(); - - // Update the symbol style - QwtSymbol *newSymbol = NULL; - if (styleText.contains("circles")) { - newSymbol = new QwtSymbol(QwtSymbol::Ellipse, Qt::NoBrush, QPen(oldColor, _symbolWidth), QSize(6, 6)); - } else if (styleText.contains("crosses")) { - newSymbol = new QwtSymbol(QwtSymbol::XCross, Qt::NoBrush, QPen(oldColor, _symbolWidth), QSize(5, 5)); - } else if (styleText.contains("rect")) { - newSymbol = new QwtSymbol(QwtSymbol::Rect, Qt::NoBrush, QPen(oldColor, _symbolWidth), QSize(6, 6)); - } - // Else-case already handled by NULL value, which indicates no symbol - curve->setSymbol(newSymbol); - - // Update the line style - if (styleText.contains("dotted")) { - curve->setPen(QPen(oldColor, _curveWidth, Qt::DotLine)); - } else if (styleText.contains("dashed")) { - curve->setPen(QPen(oldColor, _curveWidth, Qt::DashLine)); - } else if (styleText.contains("line") || styleText.contains("solid")) { - curve->setPen(QPen(oldColor, _curveWidth, Qt::SolidLine)); - } else { - curve->setPen(QPen(oldColor, _curveWidth, Qt::NoPen)); - } - curve->setStyle(QwtPlotCurve::Lines); -} - -void IncrementalPlot::resetScaling() -{ - xmin = 0; - xmax = 500; - ymin = xmin; - ymax = xmax; - - setAxisScale(xBottom, xmin+xmin*0.05, xmax+xmax*0.05); - setAxisScale(yLeft, ymin+ymin*0.05, ymax+ymax*0.05); - - replot(); - - // Make sure the first data access hits these - xmin = DBL_MAX; - xmax = DBL_MIN; - ymin = DBL_MAX; - ymax = DBL_MIN; -} - -/** - * Updates the scale calculation and re-plots the whole plot - */ -void IncrementalPlot::updateScale() -{ - const double margin = 0.05; - if(xmin == DBL_MAX) - return; - - double xMinRange = xmin-(qAbs(xmin*margin)); - double xMaxRange = xmax+(qAbs(xmax*margin)); - double yMinRange = ymin-(qAbs(ymin*margin)); - double yMaxRange = ymax+(qAbs(ymax*margin)); - if (symmetric) { - double xRange = xMaxRange - xMinRange; - double yRange = yMaxRange - yMinRange; - - // Get the aspect ratio of the plot - float xSize = width(); - if (legend != NULL) xSize -= legend->width(); - float ySize = height(); - - float aspectRatio = xSize / ySize; - - if (xRange > yRange) { - double yCenter = yMinRange + yRange/2.0; - double xCenter = xMinRange + xRange/2.0; - yMinRange = yCenter - xRange/2.0; - yMaxRange = yCenter + xRange/2.0; - xMinRange = xCenter - (xRange*aspectRatio)/2.0; - xMaxRange = xCenter + (xRange*aspectRatio)/2.0; - } else { - double xCenter = xMinRange + xRange/2.0; - xMinRange = xCenter - (yRange*aspectRatio)/2.0; - xMaxRange = xCenter + (yRange*aspectRatio)/2.0; - } - } - setAxisScale(xBottom, xMinRange, xMaxRange); - setAxisScale(yLeft, yMinRange, yMaxRange); -} - -void IncrementalPlot::appendData(const QString &key, double x, double y) -{ - appendData(key, &x, &y, 1); -} - -void IncrementalPlot::appendData(const QString &key, double *x, double *y, int size) -{ - CurveData* data; - QwtPlotCurve* curve; - if (!d_data.contains(key)) { - data = new CurveData; - d_data.insert(key, data); - } else { - data = d_data.value(key); - } - - // If this is a new curve, create it. - if (!_curves.contains(key)) { - curve = new QwtPlotCurve(key); - _curves.insert(key, curve); - curve->setStyle(QwtPlotCurve::NoCurve); - curve->setPaintAttribute(QwtPlotCurve::FilterPoints); - - // Set the color. Only the pen needs to be set - const QColor &c = getNextColor(); - curve->setPen(c, _symbolWidth); - - qDebug() << "Creating curve" << key << "with color" << c; - - updateStyle(curve); - curve->attach(this); - } else { - curve = _curves.value(key); - } - - data->append(x, y, size); - curve->setRawSamples(data->x(), data->y(), data->count()); - - bool scaleChanged = false; - - // Update scales - for (int i = 0; i xmax) { - xmax = x[i]; - scaleChanged = true; - } - - if (y[i] < ymin) { - ymin = y[i]; - scaleChanged = true; - } - if (y[i] > ymax) { - ymax = y[i]; - scaleChanged = true; - } - } - // setAxisScale(xBottom, xmin+xmin*0.05, xmax+xmax*0.05); - // setAxisScale(yLeft, ymin+ymin*0.05, ymax+ymax*0.05); - - //#ifdef __GNUC__ - //#warning better use QwtData - //#endif - - //replot(); - - if(scaleChanged) { - updateScale(); - } else { - - QwtPlotCanvas *c = static_cast(canvas()); - const bool cacheMode = c->testPaintAttribute(QwtPlotCanvas::BackingStore); - - c->setPaintAttribute(QwtPlotCanvas::BackingStore, false); - // FIXME Check if here all curves should be drawn - // QwtPlotCurve* plotCurve; - // foreach(plotCurve, curves) - // { - // plotCurve->draw(0, curve->dataSize()-1); - // } - - // FIXME: Unsure what this call should be now. - //curve->draw(curve->dataSize() - size, curve->dataSize() - 1); - replot(); - c->setPaintAttribute(QwtPlotCanvas::BackingStore, cacheMode); - - } -} - -/** - * @return Number of copied data points, 0 on failure - */ -int IncrementalPlot::data(const QString &key, double* r_x, double* r_y, int maxSize) -{ - int result = 0; - if (d_data.contains(key)) { - CurveData* d = d_data.value(key); - if (maxSize >= d->count()) { - result = d->count(); - memcpy(r_x, d->x(), sizeof(double) * d->count()); - memcpy(r_y, d->y(), sizeof(double) * d->count()); - } else { - result = 0; - } - } - return result; -} - -/** - * @param show true to show the grid, false else - */ -void IncrementalPlot::showGrid(bool show) -{ - _grid->setVisible(show); - replot(); -} - -bool IncrementalPlot::gridEnabled() const -{ - return _grid->isVisible(); -} - -void IncrementalPlot::removeData() -{ - foreach (QwtPlotCurve* curve, _curves) { - delete curve; - } - _curves.clear(); - - foreach (CurveData* data, d_data) { - delete data; - } - d_data.clear(); - resetScaling(); - replot(); -} diff --git a/src/ui/linechart/IncrementalPlot.h b/src/ui/linechart/IncrementalPlot.h deleted file mode 100644 index 422641df3c4cb38b56d31c1a1389fb3a84d21c00..0000000000000000000000000000000000000000 --- a/src/ui/linechart/IncrementalPlot.h +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Defition of class IncrementalPlot - * @author Lorenz Meier - * - */ - -#pragma once - -#include -#include -#include -#include -#include "ChartPlot.h" - -class QwtPlotCurve; - -/** - * @brief Plot data container for growing data - */ -class CurveData -{ -public: - CurveData(); - - void append(double *x, double *y, int count); - - /** @brief The number of datasets held in the data structure */ - int count() const; - /** @brief The reserved size of the data structure in units */ - int size() const; - const double *x() const; - const double *y() const; - -private: - int d_count; - QVector d_x; - QVector d_y; -}; - -/** - * @brief Incremental plotting widget - * - * This widget plots data incrementally when new data arrives. - * It will only repaint the minimum screen content necessary to avoid - * a too high CPU consumption. It auto-scales the plot to new data. - */ -class IncrementalPlot : public ChartPlot -{ - Q_OBJECT -public: - /** @brief Create a new, empty incremental plot */ - IncrementalPlot(QWidget *parent = NULL); - virtual ~IncrementalPlot(); - - /** @brief Get the state of the grid */ - bool gridEnabled() const; - - /** @brief Read out data from a curve */ - int data(const QString &key, double* r_x, double* r_y, int maxSize); - -public slots: - /** @brief Append one data point */ - void appendData(const QString &key, double x, double y); - - /** @brief Append multiple data points */ - void appendData(const QString &key, double* x, double* y, int size); - - /** @brief Reset the plot scaling to the default value */ - void resetScaling(); - - /** @brief Update the plot scale based on current data/symmetric mode */ - void updateScale(); - - /** @brief Remove all data from the plot and repaint */ - void removeData(); - - /** @brief Show the plot legend */ - void showLegend(bool show); - - /** @brief Show the plot grid */ - void showGrid(bool show); - - /** @brief Set new plot style */ - void setStyleText(const QString &style); - - /** @brief Set symmetric axis scaling mode */ - void setSymmetric(bool symmetric); - -protected slots: - /** @brief Handle the click on a legend item */ - void handleLegendClick(QwtPlotItem* item, bool on); - -protected: - bool symmetric; ///< Enable symmetric plotting - QwtLegend* legend; ///< Plot legend - double xmin; ///< Minimum x value seen - double xmax; ///< Maximum x value seen - double ymin; ///< Minimum y value seen - double ymax; ///< Maximum y value seen - QString styleText; ///< Curve style set by setStyleText - -private: - QMap d_data; ///< Data points - /** Helper function to apply styleText style to the given curve */ - void updateStyle(QwtPlotCurve *curve); -}; - diff --git a/src/ui/linechart/Linechart.ui b/src/ui/linechart/Linechart.ui deleted file mode 100644 index d56d7c2cfe5721c409cf0afc27372737f3528215..0000000000000000000000000000000000000000 --- a/src/ui/linechart/Linechart.ui +++ /dev/null @@ -1,246 +0,0 @@ - - - linechart - - - - 0 - 0 - 1337 - 585 - - - - - 3 - 2 - - - - - 300 - 200 - - - - Form - - - - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - QFrame::NoFrame - - - 1 - - - Qt::Horizontal - - - 10 - - - - - 6 - - - 6 - - - 6 - - - 3 - - - - - - 0 - 0 - - - - - 60 - 150 - - - - - 60 - 150 - - - - false - - - - - - QFrame::NoFrame - - - QFrame::Sunken - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 879 - 462 - - - - - - - - - 4 - - - - - Filter... (Ctrl+F) - - - - - - - - All MAVs - - - - - - - - 0 - - - - - 6 - - - - - Display only variable names in curve list - - - Short names - - - - - - - Display variable units in curve list - - - Display variable units in curve list - - - Show units - - - true - - - - - - - - - 6 - - - QLayout::SetMinimumSize - - - 0 - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Rotate color scheme for all curves - - - Recolor - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 0 - - - - - - - - - - - - - - - - - - - - diff --git a/src/ui/linechart/LinechartPlot.cc b/src/ui/linechart/LinechartPlot.cc deleted file mode 100644 index 9399e2ba379bbebd6c8376eb46c5c237151df512..0000000000000000000000000000000000000000 --- a/src/ui/linechart/LinechartPlot.cc +++ /dev/null @@ -1,990 +0,0 @@ - /*===================================================================== -======================================================================*/ - -/** - * @file - * @brief Line chart for vehicle data - * - * @author Lorenz Meier - * - */ - -#include "float.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ChartPlot.h" - -#include "QGC.h" - -/** - * @brief The default constructor - * - * @param parent The parent widget - * @param interval The maximum interval for which data is stored (default: 30 minutes) in milliseconds - **/ -LinechartPlot::LinechartPlot(QWidget *parent, int plotid, quint64 interval): - ChartPlot(parent), - minTime(0), - lastTime(0), - maxTime(100), - maxInterval(MAX_STORAGE_INTERVAL), - plotPosition(0), - timeScaleStep(DEFAULT_SCALE_INTERVAL), // 10 seconds - automaticScrollActive(false), - m_active(false), - m_groundTime(true), - d_data(NULL), - d_curve(NULL) -{ - this->plotid = plotid; - this->plotInterval = interval; - - maxValue = -DBL_MAX; - minValue = DBL_MAX; - - //lastMaxTimeAdded = QTime(); - - data = QMap(); - scaleMaps = QMap(); - - yScaleEngine = new QwtLinearScaleEngine(); - setAxisScaleEngine(QwtPlot::yLeft, yScaleEngine); - - // Set left scale - //setAxisOptions(QwtPlot::yLeft, QwtAutoScale::Logarithmic); - - // Set bottom scale - setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw()); - setAxisLabelRotation(QwtPlot::xBottom, -25.0); - setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom); - - // Add some space on the left and right side of the scale to prevent flickering - - QwtScaleWidget* bottomScaleWidget = axisWidget(QwtPlot::xBottom); - const int fontMetricsX = QFontMetrics(bottomScaleWidget->font()).height(); - bottomScaleWidget->setMinBorderDist(fontMetricsX * 2, fontMetricsX / 2); - - plotLayout()->setAlignCanvasToScales(true); - - // Start QTimer for plot update - updateTimer = new QTimer(this); - connect(updateTimer, &QTimer::timeout, this, &LinechartPlot::paintRealtime); - //updateTimer->start(DEFAULT_REFRESH_RATE); - - connect(&timeoutTimer, &QTimer::timeout, this, &LinechartPlot::removeTimedOutCurves); - //timeoutTimer.start(5000); -} - -LinechartPlot::~LinechartPlot() -{ -// datalock.lock(); -// // Delete curves -// QMap::iterator i; -// for(i = curves.begin(); i != curves.end(); ++i) { -// // Remove from curve list -// QwtPlotCurve* curve = curves.take(i.key()); -// // Delete the object -// delete curve; -// // Set the pointer null -// curve = NULL; -// } - -// // Delete data -// QMap::iterator j; -// for(j = data.begin(); j != data.end(); ++j) { -// // Remove from data list -// TimeSeriesData* d = data.take(j.key()); -// // Delete the object -// delete d; -// // Set the pointer null -// d = NULL; -// } -// datalock.unlock(); -} - -void LinechartPlot::showEvent(QShowEvent* event) -{ - Q_UNUSED(event); - updateTimer->start(DEFAULT_REFRESH_RATE); -} - -void LinechartPlot::hideEvent(QHideEvent* event) -{ - Q_UNUSED(event); - updateTimer->stop(); -} - -int LinechartPlot::getPlotId() -{ - return this->plotid; -} - -/** - * @param id curve identifier - */ -double LinechartPlot::getCurrentValue(QString id) -{ - return data.value(id)->getCurrentValue(); -} - -/** - * @param id curve identifier - */ -double LinechartPlot::getMean(QString id) -{ - return data.value(id)->getMean(); -} - -/** - * @param id curve identifier - */ -double LinechartPlot::getMedian(QString id) -{ - return data.value(id)->getMedian(); -} - -/** - * @param id curve identifier - */ -double LinechartPlot::getVariance(QString id) -{ - return data.value(id)->getVariance(); -} - -int LinechartPlot::getAverageWindow() -{ - return averageWindowSize; -} - -/** - * @brief Set the plot refresh rate - * The default refresh rate is defined by LinechartPlot::DEFAULT_REFRESH_RATE. - * @param ms The refresh rate in milliseconds - **/ -void LinechartPlot::setRefreshRate(int ms) -{ - updateTimer->setInterval(ms); -} - -void LinechartPlot::setActive(bool active) -{ - m_active = active; -} - -void LinechartPlot::removeTimedOutCurves() -{ - foreach(const QString &key, lastUpdate.keys()) - { - quint64 time = lastUpdate.value(key); - if (QGC::groundTimeMilliseconds() - time > 10000) - { - // Remove this curve - // Delete curves - QwtPlotCurve* curve = _curves.take(key); - // Delete the object - delete curve; - // Set the pointer null - curve = NULL; - - // Notify connected components about the removal - emit curveRemoved(key); - - // Remove from data list - TimeSeriesData* d = data.take(key); - // Delete the object - delete d; - // Set the pointer null - d = NULL; - emit curveRemoved(key); - } - } -} - -/** - * @brief Set the zero (center line) value - * The zero value defines the centerline of the plot. - * - * @param id The id of the curve - * @param zeroValue The zero value - **/ -void LinechartPlot::setZeroValue(QString id, double zeroValue) -{ - if(data.contains(id)) { - data.value(id)->setZeroValue(zeroValue); - } else { - data.insert(id, new TimeSeriesData(this, id, maxInterval, zeroValue)); - } -} - -void LinechartPlot::appendData(QString dataname, quint64 ms, double value) -{ - /* Lock resource to ensure data integrity */ - datalock.lock(); - - /* Check if dataset identifier already exists */ - if(!data.contains(dataname)) { - addCurve(dataname); - enforceGroundTime(m_groundTime); -// qDebug() << "ADDING CURVE WITH" << dataname << ms << value; -// qDebug() << "MINTIME:" << minTime << "MAXTIME:" << maxTime; -// qDebug() << "LASTTIME:" << lastTime; - } - - // Add new value - TimeSeriesData* dataset = data.value(dataname); - - quint64 time; - - // Append data - if (!m_groundTime) - { - // Use timestamp from dataset - time = ms; - } - else - { - time = QGC::groundTimeMilliseconds(); - } - dataset->append(time, value); - - lastUpdate.insert(dataname, time); - - // Scaling values - if(ms < minTime) minTime = ms; - if(ms > maxTime) maxTime = ms; - storageInterval = maxTime - minTime; - - if(time > lastTime) - { - //qDebug() << "UPDATED LAST TIME!" << dataname << time << lastTime; - lastTime = time; - } - - // - if (value < minValue) minValue = value; - if (value > maxValue) maxValue = value; - valueInterval = maxValue - minValue; - - // Assign dataset to curve - QwtPlotCurve* curve = _curves.value(dataname); - curve->setRawSamples(dataset->getPlotX(), dataset->getPlotY(), dataset->getPlotCount()); - - // qDebug() << "mintime" << minTime << "maxtime" << maxTime << "last max time" << "window position" << getWindowPosition(); - - datalock.unlock(); -} - -/** - * @param enforce true to reset the data timestamp with the receive / ground timestamp - */ -void LinechartPlot::enforceGroundTime(bool enforce) -{ - m_groundTime = enforce; - - if (enforce) - { - lastTime = QGC::groundTimeMilliseconds(); - plotPosition = lastTime; - maxTime = lastTime; - } - else - { - lastTime = 0; - plotPosition = 0; - minTime = 0; - maxTime = 100; - } -} - -/** - * @return True if the data points are stamped with the packet receive time - */ -bool LinechartPlot::groundTime() -{ - return m_groundTime; -} - -void LinechartPlot::addCurve(QString id) -{ - QColor currentColor = getNextColor(); - - // Create new curve and set style - QwtPlotCurve* curve = new QwtPlotCurve(id); - // Add curve to list - _curves.insert(id, curve); - - curve->setStyle(QwtPlotCurve::Lines); - curve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); - setCurveColor(id, currentColor); - //curve->setBrush(currentColor); Leads to a filled curve - // curve->setRenderHint(QwtPlotItem::RenderAntialiased); - - curve->attach(this); - //@TODO Color differentiation between the curves will be necessary - - /* Create symbol for datapoints on curve */ - /* - * Symbols have significant performance penalty, better avoid them - * - QwtSymbol sym = QwtSymbol(); - sym.setStyle(QwtSymbol::Ellipse); - sym.setPen(currentColor); - sym.setSize(3); - curve->setSymbol(sym);*/ - - // Create dataset - TimeSeriesData* dataset = new TimeSeriesData(this, id, this->plotInterval, maxInterval); - - // Add dataset to list - data.insert(id, dataset); - - // Notify connected components about new curve - emit curveAdded(id); -} - -/** - * @brief Set the time window for the plot - * The time window defines which data is shown in the plot. - * - * @param end The end of the interval in milliseconds - * */ -void LinechartPlot::setWindowPosition(quint64 end) -{ - windowLock.lock(); - if(end <= this->getMaxTime() && end >= (this->getMinTime() + this->getPlotInterval())) { - plotPosition = end; - setAxisScale(QwtPlot::xBottom, (plotPosition - getPlotInterval()), plotPosition, timeScaleStep); - } - //@TODO Update the rest of the plot and update drawing - windowLock.unlock(); -} - -/** - * @brief Get the time window position - * The position marks the right edge of the plot window - * - * @return The position of the plot window, in milliseconds - **/ -quint64 LinechartPlot::getWindowPosition() -{ - return plotPosition; -} - -/** - * @brief Set the scaling of the (vertical) y axis - * The mapping of the variable values on the drawing pane can be - * adjusted with this method. The default is that the y axis will the chosen - * to fit all curves in their normal base units. This can however hide all - * details if large differences in the data values exist. - * - * The scaling can be changed to best fit, which fits all curves in a +100 to -100 interval. - * The logarithmic scaling does not fit the variables, but instead applies a log10 - * scaling to all variables. - * - * @param scaling LinechartPlot::SCALE_ABSOLUTE for linear scaling, LinechartPlot::SCALE_BEST_FIT for the best fit scaling and LinechartPlot::SCALE_LOGARITHMIC for the logarithmic scaling. - **/ -void LinechartPlot::setScaling(int scaling) -{ - this->scaling = scaling; - switch (scaling) { - case LinechartPlot::SCALE_ABSOLUTE: - setLinearScaling(); - break; - case LinechartPlot::SCALE_LOGARITHMIC: - setLogarithmicScaling(); - break; - } -} - -/** - * @brief Change the visibility of a curve - * - * @param id The string id of the curve - * @param visible The visibility: True to make it visible - **/ -void LinechartPlot::setVisibleById(QString id, bool visible) -{ - if(_curves.contains(id)) { - _curves.value(id)->setVisible(visible); - if(visible) - { - _curves.value(id)->attach(this); - } - else - { - _curves.value(id)->detach(); - } - } -} - -/** - * @brief Hide a curve. - * - * This is a convenience method and maps to setVisible(id, false). - * - * @param id The curve to hide - * @see setVisible() For the implementation - **/ -void LinechartPlot::hideCurve(QString id) -{ - setVisibleById(id, false); -} - -/** - * @brief Show a curve. - * - * This is a convenience method and maps to setVisible(id, true); - * - * @param id The curve to show - * @see setVisible() For the implementation - **/ -void LinechartPlot::showCurve(QString id) -{ - setVisibleById(id, true); -} - -//void LinechartPlot::showCurve(QString id, int position) -//{ -// //@TODO Implement this position-dependent -// curves.value(id)->show(); -//} - -/** - * @brief Set the color of a curve and its symbols. - * - * @param id The id-string of the curve - * @param color The newly assigned color - **/ -void LinechartPlot::setCurveColor(QString id, QColor color) -{ - QwtPlotCurve* curve = _curves.value(id); - // Change the color of the curve. - curve->setPen(QPen(QBrush(color), _curveWidth)); - - //qDebug() << "Setting curve" << id << "to" << color; - - // And change the color of the symbol, making sure to preserve the symbol style - const QwtSymbol *oldSymbol = curve->symbol(); - QwtSymbol *newSymbol = NULL; - if (oldSymbol) { - newSymbol = new QwtSymbol(oldSymbol->style(), QBrush(color), QPen(color, _symbolWidth), QSize(_symbolWidth, _symbolWidth)); - } - curve->setSymbol(newSymbol); -} - -/** - * @brief Check the visibility of a curve - * - * @param id The id of the curve - * @return The visibility, true if it is visible, false otherwise - **/ -bool LinechartPlot::isVisible(QString id) -{ - return _curves.value(id)->isVisible(); -} - -/** - * @return The visibility, true if it is visible, false otherwise - **/ -bool LinechartPlot::anyCurveVisible() -{ - bool visible = false; - foreach (const QString &key, _curves.keys()) - { - if (_curves.value(key)->isVisible()) - { - visible = true; - } - } - - return visible; -} - -/** - * @brief Allows to block interference of the automatic scrolling with user interaction - * When the plot is updated very fast (at 1 ms for example) with new data, it might - * get impossible for an user to interact. Therefore the automatic scrolling must be - * explicitly activated. - * - * @param active The status of automatic scrolling, true to turn it on - **/ -void LinechartPlot::setAutoScroll(bool active) -{ - automaticScrollActive = active; -} - -/** - * @brief Get a list of all curves (visible and not visible curves) - * - * @return The list of curves - **/ -QList LinechartPlot::getCurves() -{ - return _curves.values(); -} - -/** - * @brief Get the smallest time value in all datasets - * - * @return The smallest time value - **/ -quint64 LinechartPlot::getMinTime() -{ - return minTime; -} - -/** - * @brief Get the biggest time value in all datasets - * - * @return The biggest time value - **/ -quint64 LinechartPlot::getMaxTime() -{ - return maxTime; -} - -/** - * @brief Get the plot interval - * The plot interval is the time interval which is displayed on the plot - * - * @return The plot interval in milliseconds - * @see setPlotInterval() - * @see getDataInterval() To get the interval for which data is available - **/ -quint64 LinechartPlot::getPlotInterval() -{ - return plotInterval; -} - -/** - * @brief Set the plot interval - * - * @param interval The time interval to plot, in milliseconds - * @see getPlotInterval() - **/ -void LinechartPlot::setPlotInterval(int interval) -{ - //Only ever increase the amount of stored data, - // so that we allow the user to change between - // different intervals without constantly losing - // data points - if((unsigned)interval > plotInterval) { - - QMap::iterator j; - for(j = data.begin(); j != data.end(); ++j) - { - TimeSeriesData* d = data.value(j.key()); - d->setInterval(interval); - } - } - plotInterval = interval; - if(plotInterval > 5*60*1000) //If the interval is longer than 4 minutes, change the time scale step to 2 minutes - timeScaleStep = 2*60*1000; - else if(plotInterval >= 4*60*1000) //If the interval is longer than 4 minutes, change the time scale step to 1 minutes - timeScaleStep = 1*60*1000; - else if(plotInterval >= 60*1000) //If the interval is longer than a minute, change the time scale step to 30 seconds - timeScaleStep = 30*1000; - else - timeScaleStep = DEFAULT_SCALE_INTERVAL; - -} - -/** - * @brief Get the data interval - * The data interval is defined by the time interval for which data - * values are available. - * - * @return The data interval - * @see getPlotInterval() To get the time interval which is currently displayed by the plot - **/ -quint64 LinechartPlot::getDataInterval() -{ - return storageInterval; -} - -/** - * @brief Set logarithmic scaling for the curve - **/ -void LinechartPlot::setLogarithmicScaling() -{ - yScaleEngine = new QwtLogScaleEngine(); - setAxisScaleEngine(QwtPlot::yLeft, yScaleEngine); -} - -/** - * @brief Set linear scaling for the curve - **/ -void LinechartPlot::setLinearScaling() -{ - yScaleEngine = new QwtLinearScaleEngine(); - setAxisScaleEngine(QwtPlot::yLeft, yScaleEngine); -} - -void LinechartPlot::setAverageWindow(int windowSize) -{ - this->averageWindowSize = windowSize; - foreach(TimeSeriesData* series, data) - { - series->setAverageWindowSize(windowSize); - } -} - -/** - * @brief Paint immediately the plot - * This method is a replacement for replot(). In contrast to replot(), it takes the - * time window size and eventual zoom interaction into account. - **/ -void LinechartPlot::paintRealtime() -{ - if (m_active) { -#if (QGC_EVENTLOOP_DEBUG) - static quint64 timestamp = 0; - qDebug() << "EVENTLOOP: (" << MG::TIME::getGroundTimeNow() - timestamp << ")" << __FILE__ << __LINE__; - timestamp = MG::TIME::getGroundTimeNow(); -#endif - // Update plot window value to new max time if the last time was also the max time - windowLock.lock(); - if (automaticScrollActive) - { - - // FIXME Check, but commenting this out should have been - // beneficial (does only add complexity) - // if (MG::TIME::getGroundTimeNow() > maxTime && abs(MG::TIME::getGroundTimeNow() - maxTime) < 5000000) - // { - // plotPosition = MG::TIME::getGroundTimeNow(); - // } - // else - // { - plotPosition = lastTime;// + lastMaxTimeAdded.msec(); - // } - setAxisScale(QwtPlot::xBottom, plotPosition - plotInterval, plotPosition, timeScaleStep); - - // FIXME Last fix for scroll zoomer is here - //setAxisScale(QwtPlot::yLeft, minValue + minValue * 0.05, maxValue + maxValue * 0.05f, (maxValue - minValue) / 10.0); - /* Notify about change. Even if the window position was not changed - * itself, the relative position of the window to the interval must - * have changed, as the interval likely increased in length */ - emit windowPositionChanged(getWindowPosition()); - } - - windowLock.unlock(); - - replot(); - - /* - QMap::iterator i; - for(i = curves.begin(); i != curves.end(); ++i) { - const bool cacheMode = canvas()->testPaintAttribute(QwtPlotCanvas::PaintCached); - canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false); - i.value()->drawItems(); - canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, cacheMode); - }*/ - - - } -} - -/** - * @brief Removes all data and curves from the plot - **/ -void LinechartPlot::removeAllData() -{ - datalock.lock(); - // Delete curves - QMap::iterator i; - for(i = _curves.begin(); i != _curves.end(); ++i) - { - // Remove from curve list - QwtPlotCurve* curve = _curves.take(i.key()); - // Delete the object - delete curve; - // Set the pointer null - curve = NULL; - - // Notify connected components about the removal - emit curveRemoved(i.key()); - } - - // Delete data - QMap::iterator j; - for(j = data.begin(); j != data.end(); ++j) - { - // Remove from data list - TimeSeriesData* d = data.take(j.key()); - // Delete the object - delete d; - // Set the pointer null - d = NULL; - } - datalock.unlock(); - replot(); -} - - -TimeSeriesData::TimeSeriesData(QwtPlot* plot, QString friendlyName, quint64 plotInterval, quint64 maxInterval, double zeroValue): - minValue(DBL_MAX), - maxValue(DBL_MIN), - zeroValue(0), - count(0), - mean(0.0), - median(0.0), - variance(0.0), - averageWindow(50) -{ - this->plot = plot; - this->friendlyName = friendlyName; - this->maxInterval = maxInterval; - this->zeroValue = zeroValue; - this->plotInterval = plotInterval; - - /* initialize time */ - startTime = QUINT64_MAX; - stopTime = QUINT64_MIN; - - plotCount = 0; -} - -TimeSeriesData::~TimeSeriesData() -{ - -} - -void TimeSeriesData::setInterval(quint64 ms) -{ - plotInterval = ms; -} - -void TimeSeriesData::setAverageWindowSize(int windowSize) -{ - this->averageWindow = windowSize; -} - -/** - * @brief Append a data point to this data set - * - * @param ms The time in milliseconds - * @param value The data value - **/ -void TimeSeriesData::append(quint64 ms, double value) -{ - dataMutex.lock(); - // Qt will automatically use a smart growth strategy: http://doc.qt.io/qt-5/containers.html#growth-strategies - this->ms.append(ms); - this->value.append(value); - this->lastValue = value; - this->mean = 0; - //QList medianList = QList(); - for (unsigned int i = 0; (i < averageWindow) && (((int)count - (int)i) >= 0); ++i) { - this->mean += this->value[count-i]; - //medianList.append(this->value[count-i]); - } - this->mean = mean / static_cast(qMin(averageWindow,static_cast(count))); - - this->variance = 0; - for (unsigned int i = 0; (i < averageWindow) && (((int)count - (int)i) >= 0); ++i) { - this->variance += (this->value[count-i] - mean) * (this->value[count-i] - mean); - } - this->variance = this->variance / static_cast(qMin(averageWindow,static_cast(count))); - -// qSort(medianList); - -// if (medianList.count() > 2) -// { -// if (medianList.count() % 2 == 0) -// { -// median = (medianList.at(medianList.count()/2) + medianList.at(medianList.count()/2+1)) / 2.0; -// } -// else -// { -// median = medianList.at(medianList.count()/2+1); -// } -// } - - // Update statistical values - if(ms < startTime) startTime = ms; - if(ms > stopTime) stopTime = ms; - interval = stopTime - startTime; - - if (interval > plotInterval) { - while (this->ms[count - plotCount] < stopTime - plotInterval) { - plotCount--; - } - } - - count++; - plotCount++; - - if(minValue > value) minValue = value; - if(maxValue < value) maxValue = value; - - // Trim dataset if necessary - if(maxInterval > 0) { - // maxInterval = 0 means infinite - - if(interval > maxInterval && !this->ms.isEmpty() && !this->value.isEmpty()) { - // The time at which this time series should be cut - double minTime = stopTime - maxInterval; - // Delete elements from the start of the list as long the time - // value of this elements is before the cut time - while(this->ms.first() < minTime) { - this->ms.pop_front(); - this->value.pop_front(); - } - } - } - dataMutex.unlock(); -} - -/** - * @brief Get the id of this data set - * - * @return The id-string - **/ -int TimeSeriesData::getID() -{ - return id; -} - -/** - * @brief Get the minimum value in the data set - * - * @return The minimum value - **/ -double TimeSeriesData::getMinValue() -{ - return minValue; -} - -/** - * @brief Get the maximum value in the data set - * - * @return The maximum value - **/ -double TimeSeriesData::getMaxValue() -{ - return maxValue; -} - -/** - * @return the mean - */ -double TimeSeriesData::getMean() -{ - return mean; -} - -/** - * @return the median - */ -double TimeSeriesData::getMedian() -{ - return median; -} - -/** - * @return the variance - */ -double TimeSeriesData::getVariance() -{ - return variance; -} - -double TimeSeriesData::getCurrentValue() -{ - return lastValue; -} - -/** - * @brief Get the zero (center) value in the data set - * The zero value is not a statistical value, but instead manually defined - * when creating the data set. - * @return The zero value - **/ -double TimeSeriesData::getZeroValue() -{ - return zeroValue; -} - -/** - * @brief Set the zero (center) value - * - * @param zeroValue The zero value - * @see getZeroValue() - **/ -void TimeSeriesData::setZeroValue(double zeroValue) -{ - this->zeroValue = zeroValue; -} - -/** - * @brief Get the number of points in the dataset - * - * @return The number of points - **/ -int TimeSeriesData::getCount() const -{ - return count; -} - -/** - * @brief Get the number of points in the plot selection - * - * @return The number of points - **/ -int TimeSeriesData::getPlotCount() const -{ - return plotCount; -} - -/** - * @brief Get the data array size - * The data array size is \e NOT equal to the number of items in the data set, as - * array space is pre-allocated. Use getCount() to get the number of data points. - * - * @return The data array size - * @see getCount() - **/ -int TimeSeriesData::size() const -{ - return ms.size(); -} - -/** - * @brief Get the X (time) values - * - * @return The x values - **/ -const double* TimeSeriesData::getX() const -{ - return ms.data(); -} - -const double* TimeSeriesData::getPlotX() const -{ - return ms.data() + (count - plotCount); -} - -/** - * @brief Get the Y (data) values - * - * @return The y values - **/ -const double* TimeSeriesData::getY() const -{ - return value.data(); -} - -const double* TimeSeriesData::getPlotY() const -{ - return value.data() + (count - plotCount); -} diff --git a/src/ui/linechart/LinechartPlot.h b/src/ui/linechart/LinechartPlot.h deleted file mode 100644 index 2a21e531b99f4c29b547234f6747f953687537c4..0000000000000000000000000000000000000000 --- a/src/ui/linechart/LinechartPlot.h +++ /dev/null @@ -1,297 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Plot of a Linechart - * - * @author Lorenz Meier - * - */ - -#pragma once - -#define QUINT64_MIN Q_UINT64_C(0) -#define QUINT64_MAX Q_UINT64_C(18446744073709551615) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ChartPlot.h" -#include "MG.h" - -class TimeScaleDraw: public QwtScaleDraw -{ -public: - - virtual QwtText label(double v) const { - QDateTime time = MG::TIME::msecToQDateTime(static_cast(v)); - return time.toString("hh:mm:ss"); // was hh:mm:ss:zzz - // Show seconds since system startup - //return QString::number(static_cast(v)/1000000); - } - -}; - - -/** - * @brief Data container - */ -class QwtPlotCurve; - -/** - * @brief Container class for the time series data - * - **/ -class TimeSeriesData -{ -public: - - TimeSeriesData(QwtPlot* plot, QString friendlyName = "data", quint64 plotInterval = 10000, quint64 maxInterval = 0, double zeroValue = 0); - ~TimeSeriesData(); - - void append(quint64 ms, double value); - - QwtScaleMap* getScaleMap(); - - int getCount() const; - int size() const; - const double* getX() const; - const double* getY() const; - - const double* getPlotX() const; - const double* getPlotY() const; - int getPlotCount() const; - - int getID(); - QString getFriendlyName(); - double getMinValue(); - double getMaxValue(); - double getZeroValue(); - /** @brief Get the short-term mean */ - double getMean(); - /** @brief Get the short-term median */ - double getMedian(); - /** @brief Get the short-term variance */ - double getVariance(); - /** @brief Get the current value */ - double getCurrentValue(); - void setZeroValue(double zeroValue); - void setInterval(quint64 ms); - void setAverageWindowSize(int windowSize); - -protected: - QwtPlot* plot; - quint64 startTime; - quint64 stopTime; - quint64 interval; - quint64 plotInterval; - quint64 maxInterval; - int id; - quint64 plotCount; - QString friendlyName; - - double lastValue; ///< The last inserted value - double minValue; ///< The smallest value in the dataset - double maxValue; ///< The largest value in the dataset - double zeroValue; ///< The expected value in the dataset - - QMutex dataMutex; - - QwtScaleMap* scaleMap; - - void updateScaleMap(); - -private: - quint64 count; - QVector ms; - QVector value; - double mean; - double median; - double variance; - unsigned int averageWindow; - QVector outputMs; - QVector outputValue; -}; - - - - - -/** - * @brief Time series plot - **/ -class LinechartPlot : public ChartPlot -{ - Q_OBJECT -public: - LinechartPlot(QWidget *parent = NULL, int plotid=0, quint64 interval = LinechartPlot::DEFAULT_PLOT_INTERVAL); - virtual ~LinechartPlot(); - - void setZeroValue(QString id, double zeroValue); - void removeAllData(); - - QList getCurves(); - bool isVisible(QString id); - /** @brief Check if any curve is visible */ - bool anyCurveVisible(); - - int getPlotId(); - /** @brief Get the number of values to average over */ - int getAverageWindow(); - - quint64 getMinTime(); - quint64 getMaxTime(); - quint64 getPlotInterval(); - quint64 getDataInterval(); - quint64 getWindowPosition(); - - /** @brief Get the short-term mean of a curve */ - double getMean(QString id); - /** @brief Get the short-term median of a curve */ - double getMedian(QString id); - /** @brief Get the short-term variance of a curve */ - double getVariance(QString id); - /** @brief Get the last inserted value */ - double getCurrentValue(QString id); - - static const int SCALE_ABSOLUTE = 0; - static const int SCALE_BEST_FIT = 1; - static const int SCALE_LOGARITHMIC = 2; - - static const int DEFAULT_REFRESH_RATE = 100; ///< The default refresh rate is 10 Hz / every 100 ms - static const int DEFAULT_PLOT_INTERVAL = 1000 * 8; ///< The default plot interval is 15 seconds - static const int DEFAULT_SCALE_INTERVAL = 1000 * 8; - -public slots: - void setRefreshRate(int ms); - /** - * @brief Append data to the plot - * - * The new data point is appended to the curve with the id-String id. If the curve - * doesn't yet exist it is created and added to the plot. - * - * @param uasId id of originating UAS - * @param dataname unique string (also used to label the data) - * @param ms time measure of the data point, in milliseconds - * @param value value of the data point - */ - void appendData(QString dataname, quint64 ms, double value); - void hideCurve(QString id); - void showCurve(QString id); - /** @brief Enable auto-refreshing of plot */ - void setActive(bool active); - - // Functions referring to the currently active plot - void setVisibleById(QString id, bool visible); - - /** - * @brief Set the color of a curve and its symbols. - * - * @param id The id-string of the curve - * @param color The newly assigned color - **/ - void setCurveColor(QString id, QColor color); - - /** @brief Enforce the use of the receive timestamp */ - void enforceGroundTime(bool enforce); - /** @brief Check if the receive timestamp is enforced */ - bool groundTime(); - - // General interaction - void setWindowPosition(quint64 end); - void setPlotInterval(int interval); - void setScaling(int scaling); - void setAutoScroll(bool active); - void paintRealtime(); - - /** @brief Set logarithmic plot y-axis scaling */ - void setLogarithmicScaling(); - /** @brief Set linear plot y-axis scaling */ - void setLinearScaling(); - - /** @brief Set the number of values to average over */ - void setAverageWindow(int windowSize); - void removeTimedOutCurves(); - -protected: - QMap data; - QMap scaleMaps; - QMap lastUpdate; - - //static const quint64 MAX_STORAGE_INTERVAL = Q_UINT64_C(300000); - static const quint64 MAX_STORAGE_INTERVAL = Q_UINT64_C(0); ///< The maximum interval which is stored - // TODO CHECK THIS!!! - int scaling; - QwtScaleEngine* yScaleEngine; - quint64 minTime; ///< The smallest timestamp occurred so far - quint64 lastTime; ///< Last added timestamp - quint64 maxTime; ///< The biggest timestamp occurred so far - quint64 maxInterval; - quint64 storageInterval; - - double maxValue; - double minValue; - double valueInterval; - - int averageWindowSize; ///< Size of sliding average / sliding median - - quint64 plotInterval; - quint64 plotPosition; - QTimer* updateTimer; - QMutex datalock; - QMutex windowLock; - quint64 timeScaleStep; - bool automaticScrollActive; - QTime lastMaxTimeAdded; - int plotid; - bool m_active; ///< Decides wether the plot is active or not - bool m_groundTime; ///< Enforce the use of the receive timestamp instead of the data timestamp - QTimer timeoutTimer; - - // Methods - void addCurve(QString id); - void showEvent(QShowEvent* event); - void hideEvent(QHideEvent* event); - -private: - TimeSeriesData* d_data; - QwtPlotCurve* d_curve; - -signals: - - /** - * @brief This signal is emitted when a new curve is added - * - * @param color The curve color in the diagram - **/ - void curveAdded(QString idstring); - /** - * @brief This signal is emitted when a curve is removed - * - * @param name The id-string of the curve - **/ - void curveRemoved(QString name); - /** - * @brief This signal is emitted when the plot window position changes - * - * @param position The position of the right edge of the window, in milliseconds - **/ - void windowPositionChanged(quint64 position); -}; - diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc deleted file mode 100644 index d2c3945426833f3570ed964ab41de5b53bc4b12a..0000000000000000000000000000000000000000 --- a/src/ui/linechart/LinechartWidget.cc +++ /dev/null @@ -1,951 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Line chart plot widget - * - * @author Lorenz Meier - * @author Thomas Gubler - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "LinechartWidget.h" -#include "LinechartPlot.h" -#include "LogCompressor.h" -#include "QGC.h" -#include "MG.h" -#include "QGCQFileDialog.h" -#include "QGCMessageBox.h" -#include "QGCApplication.h" -#include "SettingsManager.h" - -LinechartWidget::LinechartWidget(int systemid, QWidget *parent) : QWidget(parent), - sysid(systemid), - activePlot(NULL), - curvesLock(new QReadWriteLock()), - plotWindowLock(), - curveListIndex(0), - curveListCounter(0), - curveLabels(new QMap()), - curveMeans(new QMap()), - curveMedians(new QMap()), - curveVariances(new QMap()), - logFile(new QFile()), - logindex(1), - logging(false), - logStartTime(0), - updateTimer(new QTimer()), - selectedMAV(-1), - lastTimestamp(0) -{ - // Add elements defined in Qt Designer - ui.setupUi(this); - this->setMinimumSize(600, 400); - - // Add and customize curve list elements (left side) - curvesWidget = new QWidget(ui.curveListWidget); - ui.curveListWidget->setWidget(curvesWidget); - curvesWidgetLayout = new QGridLayout(curvesWidget); - curvesWidgetLayout->setMargin(6); - curvesWidgetLayout->setSpacing(6); - curvesWidgetLayout->setAlignment(Qt::AlignTop); - curvesWidgetLayout->setColumnMinimumWidth(0, 10); - - curvesWidgetLayout->setColumnStretch(0, 0); - curvesWidgetLayout->setColumnStretch(1, 10); - curvesWidgetLayout->setColumnStretch(2, 80); - curvesWidgetLayout->setColumnStretch(3, 50); - curvesWidgetLayout->setColumnStretch(4, 50); - curvesWidgetLayout->setColumnStretch(5, 50); - curvesWidgetLayout->setColumnStretch(6, 50); - - curvesWidget->setLayout(curvesWidgetLayout); - - // Create curve list headings - connect(ui.recolorButton, &QPushButton::clicked, this, &LinechartWidget::recolor); - connect(ui.shortNameCheckBox, &QCheckBox::clicked, this, &LinechartWidget::setShortNames); - connect(ui.plotFilterLineEdit, &QLineEdit::textChanged, this, &LinechartWidget::_restartFilterTimeout); - QShortcut *shortcut = new QShortcut(this); - shortcut->setKey(QKeySequence(Qt::CTRL + Qt::Key_F)); - connect(shortcut, &QShortcut::activated, this, &LinechartWidget::setPlotFilterLineEditFocus); - - int labelRow = curvesWidgetLayout->rowCount(); - - selectAllCheckBox = new QCheckBox(this); - connect(selectAllCheckBox, &QCheckBox::clicked, this, &LinechartWidget::selectAllCurves); - curvesWidgetLayout->addWidget(selectAllCheckBox, labelRow, 0); - - QWidget* colorIcon = new QWidget(this); - colorIcon->setMinimumSize(QSize(5, 14)); - colorIcon->setMaximumSize(QSize(5, 14)); - curvesWidgetLayout->addWidget(colorIcon, labelRow, 1); - - curvesWidgetLayout->addWidget(new QLabel(tr("Name")), labelRow, 2); - curvesWidgetLayout->addWidget(new QLabel(tr("Val")), labelRow, 3, Qt::AlignRight); - - QLabel* pUnit = new QLabel(tr("Unit")); - curvesWidgetLayout->addWidget(pUnit, labelRow, 4); - - curvesWidgetLayout->addWidget(new QLabel(tr("Mean")), labelRow, 5, Qt::AlignRight); - curvesWidgetLayout->addWidget(new QLabel(tr("Variance")), labelRow, 6, Qt::AlignRight); - - - // Create the layout - createLayout(); - - // And make sure we're listening for future style changes - connect(qgcApp()->toolbox()->settingsManager()->appSettings()->indoorPalette(), &Fact::rawValueChanged, this, &LinechartWidget::recolor); - - updateTimer->setInterval(updateInterval); - connect(updateTimer, &QTimer::timeout, this, &LinechartWidget::refresh); - connect(ui.uasSelectionBox, static_cast(&QComboBox::currentIndexChanged), this, &LinechartWidget::selectActiveSystem); - - readSettings(); - pUnit->setVisible(ui.showUnitsCheckBox->isChecked()); - connect(ui.showUnitsCheckBox, &QCheckBox::clicked, pUnit, &QLabel::setVisible); - - _filterTimer.setInterval(500); - connect(&_filterTimer, &QTimer::timeout, this, &LinechartWidget::_filterTimeout); -} - -LinechartWidget::~LinechartWidget() -{ - writeSettings(); - stopLogging(); - if (activePlot) delete activePlot; - activePlot = NULL; -} - -void LinechartWidget::selectActiveSystem(int mav) -{ - // -1: Unitialized, 0: all - if (mav != selectedMAV && (selectedMAV != -1)) - { - // Delete all curves - // FIXME - } - selectedMAV = mav; -} - -void LinechartWidget::selectAllCurves(bool all) -{ - QMap::iterator i; - for (i = curveLabels->begin(); i != curveLabels->end(); ++i) { - activePlot->setVisibleById(i.key(), all); - } -} - -void LinechartWidget::writeSettings() -{ - QSettings settings; - settings.beginGroup("LINECHART"); - bool enforceGT = (!autoGroundTimeSet && timeButton->isChecked()) ? true : false; - if (timeButton) settings.setValue("ENFORCE_GROUNDTIME", enforceGT); - if (ui.showUnitsCheckBox) settings.setValue("SHOW_UNITS", ui.showUnitsCheckBox->isChecked()); - if (ui.shortNameCheckBox) settings.setValue("SHORT_NAMES", ui.shortNameCheckBox->isChecked()); - settings.endGroup(); -} - -void LinechartWidget::readSettings() -{ - QSettings settings; - settings.beginGroup("LINECHART"); - if (activePlot) { - timeButton->setChecked(settings.value("ENFORCE_GROUNDTIME", timeButton->isChecked()).toBool()); - activePlot->enforceGroundTime(settings.value("ENFORCE_GROUNDTIME", timeButton->isChecked()).toBool()); - timeButton->setChecked(settings.value("ENFORCE_GROUNDTIME", timeButton->isChecked()).toBool()); - //userGroundTimeSet = settings.value("USER_GROUNDTIME", timeButton->isChecked()).toBool(); - } - if (ui.showUnitsCheckBox) ui.showUnitsCheckBox->setChecked(settings.value("SHOW_UNITS", ui.showUnitsCheckBox->isChecked()).toBool()); - if (ui.shortNameCheckBox) ui.shortNameCheckBox->setChecked(settings.value("SHORT_NAMES", ui.shortNameCheckBox->isChecked()).toBool()); - settings.endGroup(); -} - -void LinechartWidget::createLayout() -{ - // Create actions - createActions(); - - // Setup the plot group box area layout - QVBoxLayout* vlayout = new QVBoxLayout(ui.diagramGroupBox); - vlayout->setSpacing(4); - vlayout->setMargin(2); - - // Create plot container widget - activePlot = new LinechartPlot(this, sysid); - // Activate automatic scrolling - activePlot->setAutoScroll(true); - - // TODO Proper Initialization needed - // activePlot = getPlot(0); - // plotContainer->setPlot(activePlot); - - vlayout->addWidget(activePlot); - - QHBoxLayout *hlayout = new QHBoxLayout; - vlayout->addLayout(hlayout); - - // Logarithmic scaling button - scalingLogButton = createButton(this); - scalingLogButton->setText(tr("LOG")); - scalingLogButton->setCheckable(true); - scalingLogButton->setToolTip(tr("Set logarithmic scale for Y axis")); - scalingLogButton->setWhatsThis(tr("Set logarithmic scale for Y axis")); - hlayout->addWidget(scalingLogButton); - - // Averaging spin box - averageSpinBox = new QSpinBox(this); - averageSpinBox->setToolTip(tr("Sliding window size to calculate mean and variance")); - averageSpinBox->setWhatsThis(tr("Sliding window size to calculate mean and variance")); - averageSpinBox->setMinimum(2); - averageSpinBox->setValue(200); - setAverageWindow(200); - averageSpinBox->setMaximum(9999); - hlayout->addWidget(averageSpinBox); - connect(averageSpinBox,static_cast(&QSpinBox::valueChanged), this, &LinechartWidget::setAverageWindow); - - // Log Button - logButton = new QToolButton(this); - logButton->setToolTip(tr("Start to log curve data into a CSV or TXT file")); - logButton->setWhatsThis(tr("Start to log curve data into a CSV or TXT file")); - logButton->setText(tr("Start Logging")); - hlayout->addWidget(logButton); - connect(logButton, &QToolButton::clicked, this, &LinechartWidget::startLogging); - - // Ground time button - timeButton = new QCheckBox(this); - timeButton->setText(tr("Ground Time")); - timeButton->setToolTip(tr("Overwrite timestamp of data from vehicle with ground receive time. Helps if the plots are not visible because of missing or invalid onboard time.")); - timeButton->setWhatsThis(tr("Overwrite timestamp of data from vehicle with ground receive time. Helps if the plots are not visible because of missing or invalid onboard time.")); - hlayout->addWidget(timeButton); - connect(timeButton.data(), &QCheckBox::clicked, activePlot, &LinechartPlot::enforceGroundTime); - connect(timeButton.data(), &QCheckBox::clicked, this, &LinechartWidget::writeSettings); - - hlayout->addStretch(); - - QLabel *timeScaleLabel = new QLabel(tr("Time axis:")); - hlayout->addWidget(timeScaleLabel); - - timeScaleCmb = new QComboBox(this); - timeScaleCmb->addItem(tr("10 seconds"), 10); - timeScaleCmb->addItem(tr("20 seconds"), 20); - timeScaleCmb->addItem(tr("30 seconds"), 30); - timeScaleCmb->addItem(tr("40 seconds"), 40); - timeScaleCmb->addItem(tr("50 seconds"), 50); - timeScaleCmb->addItem(tr("1 minute"), 60); - timeScaleCmb->addItem(tr("2 minutes"), 60*2); - timeScaleCmb->addItem(tr("3 minutes"), 60*3); - timeScaleCmb->addItem(tr("4 minutes"), 60*4); - timeScaleCmb->addItem(tr("5 minutes"), 60*5); - timeScaleCmb->addItem(tr("10 minutes"), 60*10); - //timeScaleCmb->setSizeAdjustPolicy(QComboBox::AdjustToContents); - timeScaleCmb->setMinimumContentsLength(12); - - hlayout->addWidget(timeScaleCmb); - connect(timeScaleCmb, static_cast(&QComboBox::currentIndexChanged), - this, &LinechartWidget::timeScaleChanged); - - // Initialize the "Show units" checkbox. This is configured in the .ui file, so all - // we do here is attach the clicked() signal. - connect(ui.showUnitsCheckBox, &QCheckBox::clicked, this, &LinechartWidget::writeSettings); - - // Add actions - averageSpinBox->setValue(activePlot->getAverageWindow()); - - // Connect notifications from the user interface to the plot - connect(this, &LinechartWidget::curveRemoved, activePlot, &LinechartPlot::hideCurve); - - // Update scrollbar when plot window changes (via translator method setPlotWindowPosition() -// connect(activePlot, SIGNAL(windowPositionChanged(quint64)), this, SLOT(setPlotWindowPosition(quint64))); - connect(activePlot, &LinechartPlot::curveRemoved, this, &LinechartWidget::removeCurve); - - // Update plot when scrollbar is moved (via translator method setPlotWindowPosition() - //TODO: impossible to - connect(this, static_cast(&LinechartWidget::plotWindowPositionUpdated), - activePlot, &LinechartPlot::setWindowPosition); - - // Set scaling - connect(scalingLogButton, &QToolButton::toggled, this, &LinechartWidget::toggleLogarithmicScaling); -} - -void LinechartWidget::timeScaleChanged(int index) -{ - activePlot->setPlotInterval(timeScaleCmb->itemData(index).toInt()*1000); -} - -void LinechartWidget::toggleLogarithmicScaling(bool checked) -{ - if(checked) - activePlot->setLogarithmicScaling(); - else - activePlot->setLinearScaling(); -} - -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, const QVariant &variant, quint64 usec) -{ - QMetaType::Type type = static_cast(variant.type()); - bool ok; - double value = variant.toDouble(&ok); - if(!ok || type == QMetaType::QByteArray || type == QMetaType::QString) - return; - bool isDouble = type == QMetaType::Float || type == QMetaType::Double; - QString curveID = curve + unit; - - if ((selectedMAV == -1 && isVisible()) || (selectedMAV == uasId && isVisible())) - { - // Order matters here, first append to plot, then update curve list - activePlot->appendData(curveID, usec, value); - // Store data - QLabel* label = curveLabels->value(curveID, NULL); - // Make sure the curve will be created if it does not yet exist - if(!label) - { - if(!isDouble) - intData.insert(curveID, 0); - addCurve(curve, unit); - } - - // Add int data - if(!isDouble) - intData.insert(curveID, variant.toInt()); - } - - if (lastTimestamp == 0 && usec != 0) - { - lastTimestamp = usec; - } else if (usec != 0) { - // Difference larger than 3 secs, enforce ground time - if (((qint64)usec - (qint64)lastTimestamp) > 3000) - { - autoGroundTimeSet = true; - // Tick ground time checkbox, but avoid state switching - timeButton->blockSignals(true); - timeButton->setChecked(true); - timeButton->blockSignals(false); - if (activePlot) activePlot->enforceGroundTime(true); - } - lastTimestamp = usec; - } - - // Log data - if (logging) - { - if (activePlot->isVisible(curveID)) - { - if (usec == 0) usec = QGC::groundTimeMilliseconds(); - if (logStartTime == 0) logStartTime = usec; - qint64 time = usec - logStartTime; - if (time < 0) time = 0; - - QString line = QString("%1\t%2\t%3\t%4\n").arg(time).arg(uasId).arg(curve).arg(value, 0, 'e', 15); - logFile->write(line.toLatin1()); - } - } -} - -void LinechartWidget::refresh() -{ - setUpdatesEnabled(false); - QString str; - // Value - QMap::iterator i; - for (i = curveLabels->begin(); i != curveLabels->end(); ++i) { - if (intData.contains(i.key())) { - str.sprintf("% 11i", intData.value(i.key())); - } else { - double val = activePlot->getCurrentValue(i.key()); - int intval = static_cast(val); - if (intval >= 100000 || intval <= -100000) { - str.sprintf("% 11i", intval); - } else if (intval >= 10000 || intval <= -10000) { - str.sprintf("% 11.2f", val); - } else if (intval >= 1000 || intval <= -1000) { - str.sprintf("% 11.4f", val); - } else { - str.sprintf("% 11.6f", val); - } - } - // Value - i.value()->setText(str); - } - // Mean - QMap::iterator j; - for (j = curveMeans->begin(); j != curveMeans->end(); ++j) { - double val = activePlot->getMean(j.key()); - int intval = static_cast(val); - if (intval >= 100000 || intval <= -100000) { - str.sprintf("% 11i", intval); - } else if (intval >= 10000 || intval <= -10000) { - str.sprintf("% 11.2f", val); - } else if (intval >= 1000 || intval <= -1000) { - str.sprintf("% 11.4f", val); - } else { - str.sprintf("% 11.6f", val); - } - j.value()->setText(str); - } -// QMap::iterator k; -// for (k = curveMedians->begin(); k != curveMedians->end(); ++k) -// { -// // Median -// str.sprintf("%+.2f", activePlot->getMedian(k.key())); -// k.value()->setText(str); -// } - QMap::iterator l; - for (l = curveVariances->begin(); l != curveVariances->end(); ++l) { - // Variance - str.sprintf("% 8.3e", activePlot->getVariance(l.key())); - l.value()->setText(str); - } - setUpdatesEnabled(true); -} - -void LinechartWidget::startLogging() -{ - // Check if any curve is enabled - if (!activePlot->anyCurveVisible()) { - QGCMessageBox::critical( - tr("No curves selected for logging."), - tr("Please check all curves you want to log. Currently no data would be logged. Aborting the logging.")); - return; - } - - // Let user select the log file name - // QDate date(QDate::currentDate()); - // QString("./pixhawk-log-" + date.toString("yyyy-MM-dd") + "-" + QString::number(logindex) + ".log") - QString fileName = QGCQFileDialog::getSaveFileName(this, - tr("Save Log File"), - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), - tr("Log Files (*.log)"), - "log"); // Default type - - qDebug() << "SAVE FILE " << fileName; - - if (!fileName.isEmpty()) { - logFile = new QFile(fileName); - if (logFile->open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { - logging = true; - logStartTime = 0; - curvesWidget->setEnabled(false); - logindex++; - logButton->setText(tr("Stop logging")); - disconnect(logButton, &QToolButton::clicked, this, &LinechartWidget::startLogging); - connect(logButton, &QToolButton::clicked, this, &LinechartWidget::stopLogging); - } - } -} - -void LinechartWidget::stopLogging() -{ - logging = false; - curvesWidget->setEnabled(true); - if (logFile->isOpen()) { - logFile->flush(); - logFile->close(); - // Postprocess log file - compressor = new LogCompressor(logFile->fileName(), logFile->fileName()); - connect(compressor, &LogCompressor::finishedFile, this, &LinechartWidget::logfileWritten); - - QMessageBox::StandardButton button = QGCMessageBox::question( - tr("Starting Log Compression"), - tr("Should empty fields (e.g. due to packet drops) be filled with the previous value of the same variable (zero order hold)?"), - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No); - bool fill = (button == QMessageBox::Yes); - - compressor->startCompression(fill); - } - logButton->setText(tr("Start logging")); - disconnect(logButton, &QToolButton::clicked, this, &LinechartWidget::stopLogging); - connect(logButton, &QToolButton::clicked, this, &LinechartWidget::startLogging); -} - -/** - * The average window size defines the width of the sliding average - * filter. It also defines the width of the sliding median filter. - * - * @param windowSize with (in values) of the sliding average/median filter. Minimum is 2 - */ -void LinechartWidget::setAverageWindow(int windowSize) -{ - if (windowSize > 1) activePlot->setAverageWindow(windowSize); -} - -void LinechartWidget::createActions() -{ -} - -/** - * @brief Add a curve to the curve list - * - * @param curve The id-string of the curve - * @see removeCurve() - **/ -void LinechartWidget::addCurve(const QString& curve, const QString& unit) -{ - LinechartPlot* plot = activePlot; - QString curveID = curve + unit; - curveNames.insert(curveID, curve); - int labelRow = curvesWidgetLayout->rowCount(); - - // Checkbox - QCheckBox* checkBox = new QCheckBox(this); - checkBox->setCheckable(true); - checkBox->setObjectName(curveID); - checkBox->setToolTip(tr("Enable the curve in the graph window")); - checkBox->setWhatsThis(tr("Enable the curve in the graph window")); - checkBoxes.insert(curveID, checkBox); - curvesWidgetLayout->addWidget(checkBox, labelRow, 0); - - // Icon - QWidget* colorIcon = new QWidget(this); - colorIcons.insert(curveID, colorIcon); - colorIcon->setMinimumSize(QSize(5, 14)); - colorIcon->setMaximumSize(QSize(5, 14)); - curvesWidgetLayout->addWidget(colorIcon, labelRow, 1); - - // Label - QLabel* label = new QLabel(this); - label->setText(getCurveName(curveID, ui.shortNameCheckBox->isChecked())); - curveNameLabels.insert(curveID, label); - curvesWidgetLayout->addWidget(label, labelRow, 2); - - // Value - QLabel* value = new QLabel(this); - value->setNum(0.00); - value->setStyleSheet(QString("QLabel {font-family:\"Courier\"; font-weight: bold;}")); - value->setToolTip(tr("Current value of %1 in %2 units").arg(curve, unit)); - value->setWhatsThis(tr("Current value of %1 in %2 units").arg(curve, unit)); - curveLabels->insert(curveID, value); - curvesWidgetLayout->addWidget(value, labelRow, 3, Qt::AlignRight); - - // Unit - QLabel* unitLabel = new QLabel(this); - unitLabel->setText(unit); - unitLabel->setToolTip(tr("Unit of ") + curve); - unitLabel->setWhatsThis(tr("Unit of ") + curve); - curveUnits.insert(curveID, unitLabel); - curvesWidgetLayout->addWidget(unitLabel, labelRow, 4); - unitLabel->setVisible(ui.showUnitsCheckBox->isChecked()); - connect(ui.showUnitsCheckBox, &QCheckBox::clicked, unitLabel, &QLabel::setVisible); - - // Mean - QLabel* mean = new QLabel(this); - mean->setNum(0.00); - mean->setStyleSheet(QString("QLabel {font-family:\"Courier\"; font-weight: bold;}")); - mean->setToolTip(tr("Arithmetic mean of %1 in %2 units").arg(curve, unit)); - mean->setWhatsThis(tr("Arithmetic mean of %1 in %2 units").arg(curve, unit)); - curveMeans->insert(curveID, mean); - curvesWidgetLayout->addWidget(mean, labelRow, 5, Qt::AlignRight); - -// // Median -// median = new QLabel(form); -// value->setNum(0.00); -// curveMedians->insert(curve, median); -// horizontalLayout->addWidget(median); - - // Variance - QLabel* variance = new QLabel(this); - variance->setNum(0.00); - variance->setStyleSheet(QString("QLabel {font-family:\"Courier\"; font-weight: bold;}")); - variance->setToolTip(tr("Variance of %1 in (%2)^2 units").arg(curve, unit)); - variance->setWhatsThis(tr("Variance of %1 in (%2)^2 units").arg(curve, unit)); - curveVariances->insert(curveID, variance); - curvesWidgetLayout->addWidget(variance, labelRow, 6, Qt::AlignRight); - - /* Color picker - QColor color = QColorDialog::getColor(Qt::green, this); - if (color.isValid()) { - colorLabel->setText(color.name()); - colorLabel->setPalette(QPalette(color)); - colorLabel->setAutoFillBackground(true); - } - */ - - // Set stretch factors so that the label gets the whole space - - // Load visibility settings - // TODO - - // Connect actions - connect(selectAllCheckBox, &QCheckBox::clicked, checkBox, &QCheckBox::setChecked); - QObject::connect(checkBox, &QCheckBox::clicked, this, &LinechartWidget::takeButtonClick); - QObject::connect(this, &LinechartWidget::curveVisible, plot, &LinechartPlot::setVisibleById); - - // Set UI components to initial state - checkBox->setChecked(false); - plot->setVisibleById(curveID, false); -} - -/** - * @brief Remove the curve from the curve list. - * - * @param curve The curve to remove - * @see addCurve() - **/ -void LinechartWidget::removeCurve(QString curve) -{ - Q_UNUSED(curve) - - QWidget* widget = NULL; - widget = curveLabels->take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - widget = curveMeans->take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - widget = curveMedians->take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - widget = curveVariances->take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - widget = colorIcons.take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - widget = curveNameLabels.take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - widget = curveUnits.take(curve); - curvesWidgetLayout->removeWidget(widget); - widget->deleteLater(); - QCheckBox* checkbox; - checkbox = checkBoxes.take(curve); - curvesWidgetLayout->removeWidget(checkbox); - checkbox->deleteLater(); -// intData->remove(curve); -} - -void LinechartWidget::recolor() -{ - activePlot->styleChanged(qgcApp()->toolbox()->settingsManager()->appSettings()->indoorPalette()->rawValue().toBool()); - foreach (const QString &key, colorIcons.keys()) - { - QWidget* colorIcon = colorIcons.value(key, 0); - if (colorIcon && !colorIcon->styleSheet().isEmpty()) - { - QString colorstyle; - QColor color = activePlot->getColorForCurve(key); - colorstyle = colorstyle.sprintf("QWidget { background-color: #%02X%02X%02X; }", color.red(), color.green(), color.blue()); - colorIcon->setStyleSheet(colorstyle); - } - } -} - -void LinechartWidget::setPlotFilterLineEditFocus() -{ - ui.plotFilterLineEdit->setFocus(Qt::ShortcutFocusReason); -} - -void LinechartWidget::filterCurve(const QString &key, bool match) -{ - if (!checkBoxes[key]->isChecked()) - { - colorIcons[key]->setVisible(match); - curveNameLabels[key]->setVisible(match); - (*curveLabels)[key]->setVisible(match); - (*curveMeans)[key]->setVisible(match); - (*curveVariances)[key]->setVisible(match); - curveUnits[key]->setVisible(match && ui.showUnitsCheckBox->isChecked()); - checkBoxes[key]->setVisible(match); - } -} - -void LinechartWidget::_restartFilterTimeout(void) -{ - _filterTimer.start(); -} - -void LinechartWidget::_filterTimeout(void) -{ - filterCurves(ui.plotFilterLineEdit->text()); -} - -void LinechartWidget::filterCurves(const QString &filter) -{ - //qDebug() << "filterCurves: filter: " << filter; - - if (filter != "") - { - /* Hide Elements which do not match the filter pattern */ - QStringMatcher stringMatcher(filter, Qt::CaseInsensitive); - foreach (const QString &key, colorIcons.keys()) - { - if (stringMatcher.indexIn(key) < 0) - { - filterCurve(key, false); - } - else - { - filterCurve(key, true); - } - } - } - else - { - /* Show all Elements */ - foreach (const QString &key, colorIcons.keys()) - { - filterCurve(key, true); - } - } -} - -QString LinechartWidget::getCurveName(const QString& key, bool shortEnabled) -{ - if (shortEnabled) - { - QString name; - QStringList parts = curveNames.value(key).split("."); - if (parts.length() > 1) - { - name = parts.at(1); - } - else - { - name = parts.at(0); - } - - const int sizeLimit = 20; - - // Replace known words with abbreviations - if (name.length() > sizeLimit) - { - name.replace("gyroscope", "gyro"); - name.replace("accelerometer", "acc"); - name.replace("magnetometer", "mag"); - name.replace("distance", "dist"); - name.replace("ailerons", "ail"); - name.replace("altitude", "alt"); - name.replace("waypoint", "wp"); - name.replace("throttle", "thr"); - name.replace("elevator", "elev"); - name.replace("rudder", "rud"); - name.replace("error", "err"); - name.replace("version", "ver"); - name.replace("message", "msg"); - name.replace("count", "cnt"); - name.replace("value", "val"); - name.replace("source", "src"); - name.replace("index", "idx"); - name.replace("type", "typ"); - name.replace("mode", "mod"); - } - - // Check if sub-part is still exceeding N chars - if (name.length() > sizeLimit) - { - name.replace("a", ""); - name.replace("e", ""); - name.replace("i", ""); - name.replace("o", ""); - name.replace("u", ""); - } - - return name; - } - else - { - return curveNames.value(key); - } -} - -void LinechartWidget::setShortNames(bool enable) -{ - foreach (const QString &key, curveNames.keys()) - { - curveNameLabels.value(key)->setText(getCurveName(key, enable)); - } -} - -void LinechartWidget::showEvent(QShowEvent* event) -{ - Q_UNUSED(event); - setActive(true); -} - -void LinechartWidget::hideEvent(QHideEvent* event) -{ - Q_UNUSED(event); - setActive(false); -} - -void LinechartWidget::setActive(bool active) -{ - if (activePlot) { - activePlot->setActive(active); - } - if (active) { - updateTimer->start(updateInterval); - } else { - updateTimer->stop(); - } -} - -/** - * @brief Set the position of the plot window. - * The plot covers only a portion of the complete time series. The scrollbar - * allows to select a window of the time series. The right edge of the window is - * defined proportional to the position of the scrollbar. - * - * @param scrollBarValue The value of the scrollbar, in the range from MIN_TIME_SCROLLBAR_VALUE to MAX_TIME_SCROLLBAR_VALUE - **/ -void LinechartWidget::setPlotWindowPosition(int scrollBarValue) -{ - plotWindowLock.lockForWrite(); - // Disable automatic scrolling immediately - int scrollBarRange = (MAX_TIME_SCROLLBAR_VALUE - MIN_TIME_SCROLLBAR_VALUE); - double position = (static_cast(scrollBarValue) - MIN_TIME_SCROLLBAR_VALUE) / scrollBarRange; - quint64 scrollInterval; - - // Activate automatic scrolling if scrollbar is at the right edge - if(scrollBarValue > MAX_TIME_SCROLLBAR_VALUE - (MAX_TIME_SCROLLBAR_VALUE - MIN_TIME_SCROLLBAR_VALUE) * 0.01f) { - activePlot->setAutoScroll(true); - } else { - activePlot->setAutoScroll(false); - quint64 rightPosition; - /* If the data exceeds the plot window, choose the position according to the scrollbar position */ - if(activePlot->getDataInterval() > activePlot->getPlotInterval()) { - scrollInterval = activePlot->getDataInterval() - activePlot->getPlotInterval(); - rightPosition = activePlot->getMinTime() + activePlot->getPlotInterval() + (scrollInterval * position); - } else { - /* If the data interval is smaller as the plot interval, clamp the scrollbar to the right */ - rightPosition = activePlot->getMinTime() + activePlot->getPlotInterval(); - } - emit plotWindowPositionUpdated(rightPosition); - } - - - // The slider position must be mapped onto an interval of datainterval - plotinterval, - // because the slider position defines the right edge of the plot window. The leftmost - // slider position must therefore map to the start of the data interval + plot interval - // to ensure that the plot is not empty - - // start> |-- plot interval --||-- (data interval - plotinterval) --| setWindowPosition(rightPosition); - - plotWindowLock.unlock(); -} - -/** - * @brief Receive an updated plot window position. - * The plot window can be changed by the arrival of new data or by - * other user interaction. The scrollbar and other UI components - * can be notified by calling this method. - * - * @param position The absolute position of the right edge of the plot window, in milliseconds - **/ -void LinechartWidget::setPlotWindowPosition(quint64 position) -{ - plotWindowLock.lockForWrite(); - // Calculate the relative position - double pos; - - // A relative position makes only sense if the plot is filled - if(activePlot->getDataInterval() > activePlot->getPlotInterval()) { - //TODO @todo Implement the scrollbar enabling in a more elegant way - //scrollbar->setDisabled(false); - quint64 scrollInterval = position - activePlot->getMinTime() - activePlot->getPlotInterval(); - - - - pos = (static_cast(scrollInterval) / (activePlot->getDataInterval() - activePlot->getPlotInterval())); - } else { - //scrollbar->setDisabled(true); - pos = 1; - } - plotWindowLock.unlock(); - - emit plotWindowPositionUpdated(static_cast(pos * (MAX_TIME_SCROLLBAR_VALUE - MIN_TIME_SCROLLBAR_VALUE))); -} - -/** - * @brief Set the time interval the plot displays. - * The time interval of the plot can be adjusted by this method. If the - * data covers less time than the interval, the plot will be filled from - * the right to left - * - * @param interval The time interval to plot - **/ -void LinechartWidget::setPlotInterval(quint64 interval) -{ - activePlot->setPlotInterval(interval); -} - -/** - * @brief Take the click of a curve activation / deactivation button. - * This method allows to map a button to a plot curve. The text of the - * button must equal the curve name to activate / deactivate. If the checkbox - * was clicked, show the curve color, otherwise clear the coloring. - * - * @param checked The visibility of the curve: true to display the curve, false otherwise - **/ -void LinechartWidget::takeButtonClick(bool checked) -{ - - QCheckBox* button = qobject_cast(QObject::sender()); - - if(button != NULL) - { - activePlot->setVisibleById(button->objectName(), checked); - QWidget* colorIcon = colorIcons.value(button->objectName(), 0); - if (colorIcon) - { - if (checked) - { - QColor color = activePlot->getColorForCurve(button->objectName()); - if (color.isValid()) - { - QString colorstyle; - colorstyle = colorstyle.sprintf("QWidget { background-color: #%02X%02X%02X; }", color.red(), color.green(), color.blue()); - colorIcon->setStyleSheet(colorstyle); - } - } - else - { - colorIcon->setStyleSheet(""); - } - } - } -} - -/** - * @brief Factory method to create a new button. - * - * @param imagename The name of the image (should be placed at the standard icon location) - * @param text The button text - * @param parent The parent object (to ensure that the memory is freed after the deletion of the button) - **/ -QToolButton* LinechartWidget::createButton(QWidget* parent) -{ - QToolButton* button = new QToolButton(parent); - button->setMinimumSize(QSize(20, 20)); - button->setMaximumSize(60, 20); - button->setGeometry(button->x(), button->y(), 20, 20); - return button; -} diff --git a/src/ui/linechart/LinechartWidget.h b/src/ui/linechart/LinechartWidget.h deleted file mode 100644 index 1fdd63ab4aa5c70f25cd0f6277a58e2fa0bc8dfc..0000000000000000000000000000000000000000 --- a/src/ui/linechart/LinechartWidget.h +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2018 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Definition of Line chart plot widget - * - * @author Lorenz Meier - * @author Thomas Gubler - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "LinechartPlot.h" -#include "UASInterface.h" -#include "ui_Linechart.h" - -#include "LogCompressor.h" - -/** - * @brief The linechart widget allows to visualize different timeseries as lineplot. - * The display interval, the timeseries and the scaling can be changed interactively - **/ -class LinechartWidget : public QWidget -{ - Q_OBJECT - -public: - LinechartWidget(int systemid, QWidget *parent = 0); - ~LinechartWidget(); - - static const int MIN_TIME_SCROLLBAR_VALUE = 0; ///< The minimum scrollbar value - static const int MAX_TIME_SCROLLBAR_VALUE = 16383; ///< The maximum scrollbar value - -public slots: - void addCurve(const QString& curve, const QString& unit); - void removeCurve(QString curve); - /** @brief Recolor all curves */ - void recolor(); - /** @brief Set short names for curves */ - void setShortNames(bool enable); - /** @brief Append data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, const QVariant& value, quint64 usec); - /** @brief Hide curves which do not match the filter pattern */ - void filterCurves(const QString &filter); - - void toggleLogarithmicScaling(bool toggled); - void takeButtonClick(bool checked); - void setPlotWindowPosition(int scrollBarValue); - void setPlotWindowPosition(quint64 position); - void setPlotInterval(quint64 interval); - /** @brief Start automatic updates once visible */ - void showEvent(QShowEvent* event); - /** @brief Stop automatic updates once hidden */ - void hideEvent(QHideEvent* event); - void setActive(bool active); - /** @brief Select one MAV for curve display */ - void selectActiveSystem(int mav); - /** @brief Set the number of values to average over */ - void setAverageWindow(int windowSize); - /** @brief Start logging to file */ - void startLogging(); - /** @brief Stop logging to file */ - void stopLogging(); - /** @brief Refresh the view */ - void refresh(); - /** @brief Write the current configuration to disk */ - void writeSettings(); - /** @brief Read the current configuration from disk */ - void readSettings(); - /** @brief Select all curves */ - void selectAllCurves(bool all); - /** @brief Sets the focus to the LineEdit for plot-filtering */ - void setPlotFilterLineEditFocus(); - -private slots: - /** Called when the user changes the time scale combobox. */ - void timeScaleChanged(int index); - /** @brief Toggles visibility of curve based on bool match if corresponding checkbox is not checked */ - void filterCurve(const QString &key, bool match); - -protected: - void addCurveToList(QString curve); - void removeCurveFromList(QString curve); - QToolButton* createButton(QWidget* parent); - void createCurveItem(QString curve); - void createLayout(); - /** @brief Get the name for a curve key */ - QString getCurveName(const QString& key, bool shortEnabled); - - int sysid; ///< ID of the unmanned system this plot belongs to - LinechartPlot* activePlot; ///< Plot for this system - QReadWriteLock* curvesLock; ///< A lock (mutex) for the concurrent access on the curves - QReadWriteLock plotWindowLock; ///< A lock (mutex) for the concurrent access on the window position - - int curveListIndex; - int curveListCounter; ///< Counter of curves in curve list - QMap* curveLabels; ///< References to the curve labels - QMap curveNameLabels; ///< References to the curve labels - QMap curveNames; ///< Full curve names - QMap* curveMeans; ///< References to the curve means - QMap* curveMedians; ///< References to the curve medians - QMap curveUnits; ///< References to the curve units - QMap* curveVariances; ///< References to the curve variances - QMap intData; ///< Current values for integer-valued curves - QMap colorIcons; ///< Reference to color icons - QMap checkBoxes; ///< Reference to checkboxes - - QWidget* curvesWidget; ///< The QWidget containing the curve selection button - QGridLayout* curvesWidgetLayout; ///< The layout for the curvesWidget QWidget - QScrollBar* scrollbar; ///< The plot window scroll bar - QSpinBox* averageSpinBox; ///< Spin box to setup average window filter size - - QAction* addNewCurve; ///< Add curve candidate to the active curves - - QComboBox *timeScaleCmb; - - QToolButton* scalingLogButton; - QToolButton* logButton; - QPointer timeButton; - - QFile* logFile; - unsigned int logindex; - bool logging; - quint64 logStartTime; - QTimer* updateTimer; - LogCompressor* compressor; - QCheckBox* selectAllCheckBox; - int selectedMAV; ///< The MAV for which plot items are accepted, -1 for all systems - quint64 lastTimestamp; - bool userGroundTimeSet; - bool autoGroundTimeSet; - static const int updateInterval = 1000; ///< Time between number updates, in milliseconds - - static const int MAX_CURVE_MENUITEM_NUMBER = 8; - static const int PAGESTEP_TIME_SCROLLBAR_VALUE = (MAX_TIME_SCROLLBAR_VALUE - MIN_TIME_SCROLLBAR_VALUE) / 10; - -private: - Ui::linechart ui; - void createActions(); - -signals: - /** - * @brief This signal is emitted if a curve is removed from the list - * - * @param curve The removed plot curve - **/ - void curveRemoved(QString curve); - - /** - * @brief This signal is emitted if a curve has been moved or added - * - * @param curve The moved or added curve - * @param position The x-position of the curve (The centerline) - **/ - void curveSet(QString curve, int position); - - /** - * @brief This signal is emitted to change the visibility of a curve - * - * @param curve The changed curve - * @pram visible The visibility - **/ - void curveVisible(QString curve, bool visible); - - void plotWindowPositionUpdated(quint64 position); - void plotWindowPositionUpdated(int position); - - /** @brief This signal is emitted once a logfile has been finished writing */ - void logfileWritten(QString fileName); - -private slots: - void _filterTimeout(void); - void _restartFilterTimeout(void); - -private: - QTimer _filterTimer; -}; - diff --git a/src/ui/linechart/Linecharts.cc b/src/ui/linechart/Linecharts.cc deleted file mode 100644 index f94fd88037daa5fded3de0be6cab4f7a5e22cf2b..0000000000000000000000000000000000000000 --- a/src/ui/linechart/Linecharts.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include "Linecharts.h" -#include "MultiVehicleManager.h" -#include "MainWindow.h" -#include "UAS.h" - -Linecharts::Linecharts(const QString& title, QAction* action, MAVLinkDecoder* decoder, QWidget *parent) - : MultiVehicleDockWidget(title, action, parent) - , _mavlinkDecoder(decoder) -{ - init(); - - this->setVisible(false); -} - -QWidget* Linecharts::_newVehicleWidget(Vehicle* vehicle, QWidget* parent) -{ - LinechartWidget* widget = new LinechartWidget(vehicle->id(), parent); - - // Connect valueChanged signals - connect(vehicle->uas(), &UAS::valueChanged, widget, &LinechartWidget::appendData); - - // Connect decoder - connect(_mavlinkDecoder, &MAVLinkDecoder::valueChanged, widget, &LinechartWidget::appendData); - - // Select system - widget->setActive(true); - - return widget; -} diff --git a/src/ui/linechart/Linecharts.h b/src/ui/linechart/Linecharts.h deleted file mode 100644 index c50fe546014bf8565da58002727adb891946c05a..0000000000000000000000000000000000000000 --- a/src/ui/linechart/Linecharts.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "LinechartWidget.h" -#include "Vehicle.h" -#include "MultiVehicleDockWidget.h" -#include "MAVLinkDecoder.h" - -class Linecharts : public MultiVehicleDockWidget -{ - Q_OBJECT -public: - explicit Linecharts(const QString& title, QAction* action, MAVLinkDecoder* decoder, QWidget *parent = 0); - -signals: - /** @brief This signal is emitted once a logfile has been finished writing */ - void logfileWritten(QString fileName); - void visibilityChanged(bool visible); - -protected: - // Override from MultiVehicleDockWidget - virtual QWidget* _newVehicleWidget(Vehicle* vehicle, QWidget* parent); - -private: - MAVLinkDecoder* _mavlinkDecoder; -}; - diff --git a/src/ui/linechart/ScrollZoomer.cc b/src/ui/linechart/ScrollZoomer.cc deleted file mode 100644 index 9618561eab8384659f4304fb2f29a4ee5fe3d36d..0000000000000000000000000000000000000000 --- a/src/ui/linechart/ScrollZoomer.cc +++ /dev/null @@ -1,431 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -class ScrollData -{ -public: - ScrollData(): - scrollBar(NULL), - position(ScrollZoomer::OppositeToScale), -#if QT_VERSION < 0x040000 - mode(QScrollView::Auto) -#else - mode(Qt::ScrollBarAsNeeded) -#endif - { - } - - ~ScrollData() { - delete scrollBar; - } - - ScrollBar *scrollBar; - ScrollZoomer::ScrollBarPosition position; -#if QT_VERSION < 0x040000 - QScrollView::ScrollBarMode mode; -#else - Qt::ScrollBarPolicy mode; -#endif -}; - -ScrollZoomer::ScrollZoomer(QwtPlotCanvas *canvas): - QwtPlotZoomer(canvas), - d_cornerWidget(NULL), - d_hScrollData(NULL), - d_vScrollData(NULL), - d_inZoom(false) -{ - if ( !canvas ) - return; - - d_hScrollData = new ScrollData; - d_vScrollData = new ScrollData; -} - -ScrollZoomer::~ScrollZoomer() -{ - delete d_cornerWidget; - delete d_vScrollData; - delete d_hScrollData; -} - -void ScrollZoomer::rescale() -{ - QwtScaleWidget *xScale = plot()->axisWidget(xAxis()); - QwtScaleWidget *yScale = plot()->axisWidget(yAxis()); - - if ( zoomRectIndex() <= 0 ) { - if ( d_inZoom ) { - xScale->setMinBorderDist(0, 0); - yScale->setMinBorderDist(0, 0); - d_inZoom = false; - } - } else { - if ( !d_inZoom ) { - /* - We set a minimum border distance. - Otherwise the canvas size changes when scrolling, - between situations where the major ticks are at - the canvas borders (requiring extra space for the label) - and situations where all labels can be painted below/top - or left/right of the canvas. - */ - int start, end; - - xScale->getBorderDistHint(start, end); - xScale->setMinBorderDist(start, end); - - yScale->getBorderDistHint(start, end); - yScale->setMinBorderDist(start, end); - - d_inZoom = false; - } - } - - QwtPlotZoomer::rescale(); - updateScrollBars(); -} - -ScrollBar *ScrollZoomer::scrollBar(Qt::Orientation o) -{ - ScrollBar *&sb = (o == Qt::Vertical) - ? d_vScrollData->scrollBar : d_hScrollData->scrollBar; - - if ( sb == NULL ) { - sb = new ScrollBar(o, canvas()); - sb->hide(); - connect(sb, &ScrollBar::valueChanged, this, &ScrollZoomer::scrollBarMoved); - } - return sb; -} - -ScrollBar *ScrollZoomer::horizontalScrollBar() const -{ - return d_hScrollData->scrollBar; -} - -ScrollBar *ScrollZoomer::verticalScrollBar() const -{ - return d_vScrollData->scrollBar; -} - -void ScrollZoomer::setHScrollBarMode(Qt::ScrollBarPolicy mode) -{ - if ( hScrollBarMode() != mode ) { - d_hScrollData->mode = mode; - updateScrollBars(); - } -} - -void ScrollZoomer::setVScrollBarMode(Qt::ScrollBarPolicy mode) -{ - if ( vScrollBarMode() != mode ) { - d_vScrollData->mode = mode; - updateScrollBars(); - } -} - -Qt::ScrollBarPolicy ScrollZoomer::hScrollBarMode() const -{ - return d_hScrollData->mode; -} - -Qt::ScrollBarPolicy ScrollZoomer::vScrollBarMode() const -{ - return d_vScrollData->mode; -} - -void ScrollZoomer::setHScrollBarPosition(ScrollBarPosition pos) -{ - if ( d_hScrollData->position != pos ) { - d_hScrollData->position = pos; - updateScrollBars(); - } -} - -void ScrollZoomer::setVScrollBarPosition(ScrollBarPosition pos) -{ - if ( d_vScrollData->position != pos ) { - d_vScrollData->position = pos; - updateScrollBars(); - } -} - -ScrollZoomer::ScrollBarPosition ScrollZoomer::hScrollBarPosition() const -{ - return d_hScrollData->position; -} - -ScrollZoomer::ScrollBarPosition ScrollZoomer::vScrollBarPosition() const -{ - return d_vScrollData->position; -} - -void ScrollZoomer::setCornerWidget(QWidget *w) -{ - if ( w != d_cornerWidget ) { - if ( canvas() ) { - delete d_cornerWidget; - d_cornerWidget = w; - if ( d_cornerWidget->parent() != canvas() ) { - d_cornerWidget->setParent(canvas()); - } - - updateScrollBars(); - } - } -} - -QWidget *ScrollZoomer::cornerWidget() const -{ - return d_cornerWidget; -} - -bool ScrollZoomer::eventFilter(QObject *o, QEvent *e) -{ - if ( o == canvas() ) { - switch(e->type()) { - case QEvent::Resize: { - const int fw = ((QwtPlotCanvas *)canvas())->frameWidth(); - - QRect rect; - rect.setSize(((QResizeEvent *)e)->size()); - rect.setRect(rect.x() + fw, rect.y() + fw, - rect.width() - 2 * fw, rect.height() - 2 * fw); - - layoutScrollBars(rect); - break; - } - case QEvent::ChildRemoved: { - const QObject *child = ((QChildEvent *)e)->child(); - if ( child == d_cornerWidget ) - d_cornerWidget = NULL; - else if ( child == d_hScrollData->scrollBar ) - d_hScrollData->scrollBar = NULL; - else if ( child == d_vScrollData->scrollBar ) - d_vScrollData->scrollBar = NULL; - break; - } - default: - break; - } - } - return QwtPlotZoomer::eventFilter(o, e); -} - -bool ScrollZoomer::needScrollBar(Qt::Orientation o) const -{ - Qt::ScrollBarPolicy mode; - double zoomMin, zoomMax, baseMin, baseMax; - - if ( o == Qt::Horizontal ) { - mode = d_hScrollData->mode; - baseMin = zoomBase().left(); - baseMax = zoomBase().right(); - zoomMin = zoomRect().left(); - zoomMax = zoomRect().right(); - } else { - mode = d_vScrollData->mode; - baseMin = zoomBase().top(); - baseMax = zoomBase().bottom(); - zoomMin = zoomRect().top(); - zoomMax = zoomRect().bottom(); - } - - bool needed = false; - switch(mode) { - case Qt::ScrollBarAlwaysOn: - needed = true; - break; - case Qt::ScrollBarAlwaysOff: - needed = false; - break; - default: { - if ( baseMin < zoomMin || baseMax > zoomMax ) - needed = true; - break; - } - } - return needed; -} - -void ScrollZoomer::updateScrollBars() -{ - if ( !canvas() ) - return; - - const int xAxis = QwtPlotZoomer::xAxis(); - const int yAxis = QwtPlotZoomer::yAxis(); - - int xScrollBarAxis = xAxis; - if ( hScrollBarPosition() == OppositeToScale ) - xScrollBarAxis = oppositeAxis(xScrollBarAxis); - - int yScrollBarAxis = yAxis; - if ( vScrollBarPosition() == OppositeToScale ) - yScrollBarAxis = oppositeAxis(yScrollBarAxis); - - - QwtPlotLayout *layout = plot()->plotLayout(); - - bool showHScrollBar = needScrollBar(Qt::Horizontal); - if ( showHScrollBar ) { - ScrollBar *sb = scrollBar(Qt::Horizontal); - - sb->setPalette(plot()->palette()); - - const QwtScaleEngine *se = plot()->axisScaleEngine(xAxis); - sb->setInverted(se->testAttribute(QwtScaleEngine::Inverted)); - - sb->setBase(zoomBase().left(), zoomBase().right()); - sb->moveSlider(zoomRect().left(), zoomRect().right()); - - if ( !sb->isVisibleTo(canvas()) ) { - sb->show(); - layout->setCanvasMargin(layout->canvasMargin(xScrollBarAxis) - + sb->extent(), xScrollBarAxis); - } - } else { - if ( horizontalScrollBar() ) { - horizontalScrollBar()->hide(); - layout->setCanvasMargin(layout->canvasMargin(xScrollBarAxis) - - horizontalScrollBar()->extent(), xScrollBarAxis); - } - } - - bool showVScrollBar = needScrollBar(Qt::Vertical); - if ( showVScrollBar ) { - ScrollBar *sb = scrollBar(Qt::Vertical); - - sb->setPalette(plot()->palette()); - - const QwtScaleEngine *se = plot()->axisScaleEngine(xAxis); - sb->setInverted(!(se->testAttribute(QwtScaleEngine::Inverted))); - - sb->setBase(zoomBase().top(), zoomBase().bottom()); - sb->moveSlider(zoomRect().top(), zoomRect().bottom()); - - if ( !sb->isVisibleTo(canvas()) ) { - sb->show(); - layout->setCanvasMargin(layout->canvasMargin(yScrollBarAxis) - + sb->extent(), yScrollBarAxis); - } - } else { - if ( verticalScrollBar() ) { - verticalScrollBar()->hide(); - layout->setCanvasMargin(layout->canvasMargin(yScrollBarAxis) - - verticalScrollBar()->extent(), yScrollBarAxis); - } - } - - if ( showHScrollBar && showVScrollBar ) { - if ( d_cornerWidget == NULL ) { - d_cornerWidget = new QWidget(canvas()); - d_cornerWidget->setPalette(plot()->palette()); - } - d_cornerWidget->show(); - } else { - if ( d_cornerWidget ) - d_cornerWidget->hide(); - } - - layoutScrollBars(((QwtPlotCanvas *)canvas())->contentsRect()); - plot()->updateLayout(); -} - -void ScrollZoomer::layoutScrollBars(const QRect &rect) -{ - int hPos = xAxis(); - if ( hScrollBarPosition() == OppositeToScale ) - hPos = oppositeAxis(hPos); - - int vPos = yAxis(); - if ( vScrollBarPosition() == OppositeToScale ) - vPos = oppositeAxis(vPos); - - ScrollBar *hScrollBar = horizontalScrollBar(); - ScrollBar *vScrollBar = verticalScrollBar(); - - const int hdim = hScrollBar ? hScrollBar->extent() : 0; - const int vdim = vScrollBar ? vScrollBar->extent() : 0; - - if ( hScrollBar && hScrollBar->isVisible() ) { - int x = rect.x(); - int y = (hPos == QwtPlot::xTop) - ? rect.top() : rect.bottom() - hdim + 1; - int w = rect.width(); - - if ( vScrollBar && vScrollBar->isVisible() ) { - if ( vPos == QwtPlot::yLeft ) - x += vdim; - w -= vdim; - } - - hScrollBar->setGeometry(x, y, w, hdim); - } - if ( vScrollBar && vScrollBar->isVisible() ) { - //-- TODO: What is this "pos"? It only gets - // assigned but never used within this - // scope. - int pos = yAxis(); - if ( vScrollBarPosition() == OppositeToScale ) - pos = oppositeAxis(pos); - - int x = (vPos == QwtPlot::yLeft) - ? rect.left() : rect.right() - vdim + 1; - int y = rect.y(); - - int h = rect.height(); - - if ( hScrollBar && hScrollBar->isVisible() ) { - if ( hPos == QwtPlot::xTop ) - y += hdim; - - h -= hdim; - } - - vScrollBar->setGeometry(x, y, vdim, h); - } - if ( hScrollBar && hScrollBar->isVisible() && - vScrollBar && vScrollBar->isVisible() ) { - if ( d_cornerWidget ) { - QRect cornerRect( - vScrollBar->pos().x(), hScrollBar->pos().y(), - vdim, hdim); - d_cornerWidget->setGeometry(cornerRect); - } - } -} - -void ScrollZoomer::scrollBarMoved(Qt::Orientation o, double min, double) -{ - if ( o == Qt::Horizontal ) - move(QPoint(min, zoomRect().top())); - else - move(QPoint(zoomRect().left(), min)); - - emit zoomed(zoomRect()); -} - -int ScrollZoomer::oppositeAxis(int axis) const -{ - switch(axis) { - case QwtPlot::xBottom: - return QwtPlot::xTop; - case QwtPlot::xTop: - return QwtPlot::xBottom; - case QwtPlot::yLeft: - return QwtPlot::yRight; - case QwtPlot::yRight: - return QwtPlot::yLeft; - default: - break; - } - - return axis; -} diff --git a/src/ui/linechart/ScrollZoomer.h b/src/ui/linechart/ScrollZoomer.h deleted file mode 100644 index c89ebe79de8de1d226603158790d9513f7785966..0000000000000000000000000000000000000000 --- a/src/ui/linechart/ScrollZoomer.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#if QT_VERSION < 0x040000 -#include -#endif -#include -#include - -class ScrollData; -class ScrollBar; - -class ScrollZoomer: public QwtPlotZoomer -{ - Q_OBJECT -public: - enum ScrollBarPosition { - AttachedToScale, - OppositeToScale - }; - - ScrollZoomer(QwtPlotCanvas *); - virtual ~ScrollZoomer(); - - ScrollBar *horizontalScrollBar() const; - ScrollBar *verticalScrollBar() const; - -#if QT_VERSION < 0x040000 - void setHScrollBarMode(QScrollView::ScrollBarMode); - void setVScrollBarMode(QScrollView::ScrollBarMode); - - QScrollView::ScrollBarMode vScrollBarMode () const; - QScrollView::ScrollBarMode hScrollBarMode () const; -#else - void setHScrollBarMode(Qt::ScrollBarPolicy); - void setVScrollBarMode(Qt::ScrollBarPolicy); - - Qt::ScrollBarPolicy vScrollBarMode () const; - Qt::ScrollBarPolicy hScrollBarMode () const; -#endif - - void setHScrollBarPosition(ScrollBarPosition); - void setVScrollBarPosition(ScrollBarPosition); - - ScrollBarPosition hScrollBarPosition() const; - ScrollBarPosition vScrollBarPosition() const; - - QWidget* cornerWidget() const; - virtual void setCornerWidget(QWidget *); - - virtual bool eventFilter(QObject *, QEvent *); - - virtual void rescale(); - -protected: - virtual ScrollBar *scrollBar(Qt::Orientation); - virtual void updateScrollBars(); - virtual void layoutScrollBars(const QRect &); - -private slots: - void scrollBarMoved(Qt::Orientation o, double min, double max); - -private: - bool needScrollBar(Qt::Orientation) const; - int oppositeAxis(int) const; - - QWidget *d_cornerWidget; - - ScrollData *d_hScrollData; - ScrollData *d_vScrollData; - - bool d_inZoom; -}; - diff --git a/src/ui/linechart/Scrollbar.cc b/src/ui/linechart/Scrollbar.cc deleted file mode 100644 index cc9da1cec20ef9b3bdbcfd923031101f8736eb0a..0000000000000000000000000000000000000000 --- a/src/ui/linechart/Scrollbar.cc +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include "Scrollbar.h" - -ScrollBar::ScrollBar(QWidget * parent): - QScrollBar(parent) -{ - init(); -} - -ScrollBar::ScrollBar(Qt::Orientation o, - QWidget *parent): - QScrollBar(o, parent) -{ - init(); -} - -ScrollBar::ScrollBar(double minBase, double maxBase, - Qt::Orientation o, QWidget *parent): - QScrollBar(o, parent) -{ - init(); - setBase(minBase, maxBase); - moveSlider(minBase, maxBase); -} - -void ScrollBar::init() -{ - d_inverted = orientation() == Qt::Vertical; - d_baseTicks = 1000000; - d_minBase = 0.0; - d_maxBase = 1.0; - moveSlider(d_minBase, d_maxBase); - - connect(this, &ScrollBar::sliderMoved, this, &ScrollBar::catchSliderMoved); - connect(this, &ScrollBar::valueChanged, this, &ScrollBar::catchValueChanged); -} - -void ScrollBar::setInverted(bool inverted) -{ - if ( d_inverted != inverted ) { - d_inverted = inverted; - moveSlider(minSliderValue(), maxSliderValue()); - } -} - -bool ScrollBar::isInverted() const -{ - return d_inverted; -} - -void ScrollBar::setBase(double min, double max) -{ - if ( min != d_minBase || max != d_maxBase ) { - d_minBase = min; - d_maxBase = max; - - moveSlider(minSliderValue(), maxSliderValue()); - } -} - -void ScrollBar::moveSlider(double min, double max) -{ - const int sliderTicks = qRound((max - min) / - (d_maxBase - d_minBase) * d_baseTicks); - - // setRange initiates a valueChanged of the scrollbars - // in some situations. So we block - // and unblock the signals. - - blockSignals(true); - - setRange(sliderTicks / 2, d_baseTicks - sliderTicks / 2); - int steps = sliderTicks / 200; - if ( steps <= 0 ) - steps = 1; - - setSingleStep(steps); - setPageStep(sliderTicks); - - int tick = mapToTick(min + (max - min) / 2); - if ( isInverted() ) - tick = d_baseTicks - tick; - - setSliderPosition(tick); - blockSignals(false); -} - -double ScrollBar::minBaseValue() const -{ - return d_minBase; -} - -double ScrollBar::maxBaseValue() const -{ - return d_maxBase; -} - -void ScrollBar::sliderRange(int value, double &min, double &max) const -{ - if ( isInverted() ) - value = d_baseTicks - value; - - const int visibleTicks = pageStep(); - - min = mapFromTick(value - visibleTicks / 2); - max = mapFromTick(value + visibleTicks / 2); -} - -double ScrollBar::minSliderValue() const -{ - double min, dummy; - sliderRange(value(), min, dummy); - - return min; -} - -double ScrollBar::maxSliderValue() const -{ - double max, dummy; - sliderRange(value(), dummy, max); - - return max; -} - -int ScrollBar::mapToTick(double v) const -{ - return (int) ( ( v - d_minBase) / (d_maxBase - d_minBase ) * d_baseTicks ); -} - -double ScrollBar::mapFromTick(int tick) const -{ - return d_minBase + ( d_maxBase - d_minBase ) * tick / d_baseTicks; -} - -void ScrollBar::catchValueChanged(int value) -{ - double min, max; - sliderRange(value, min, max); - emit valueChanged(orientation(), min, max); -} - -void ScrollBar::catchSliderMoved(int value) -{ - double min, max; - sliderRange(value, min, max); - emit sliderMoved(orientation(), min, max); -} - -int ScrollBar::extent() const -{ - QStyleOptionSlider opt; - opt.init(this); - opt.subControls = QStyle::SC_None; - opt.activeSubControls = QStyle::SC_None; - opt.orientation = orientation(); - opt.minimum = minimum(); - opt.maximum = maximum(); - opt.sliderPosition = sliderPosition(); - opt.sliderValue = value(); - opt.singleStep = singleStep(); - opt.pageStep = pageStep(); - opt.upsideDown = invertedAppearance(); - if (orientation() == Qt::Horizontal) - opt.state |= QStyle::State_Horizontal; - return style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this); -} diff --git a/src/ui/linechart/Scrollbar.h b/src/ui/linechart/Scrollbar.h deleted file mode 100644 index 7466014cb315e3762a8e33369981d6b354489db0..0000000000000000000000000000000000000000 --- a/src/ui/linechart/Scrollbar.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include - -class ScrollBar: public QScrollBar -{ - Q_OBJECT - -public: - ScrollBar(QWidget *parent = NULL); - ScrollBar(Qt::Orientation, QWidget *parent = NULL); - ScrollBar(double minBase, double maxBase, - Qt::Orientation o, QWidget *parent = NULL); - - void setInverted(bool); - bool isInverted() const; - - double minBaseValue() const; - double maxBaseValue() const; - - double minSliderValue() const; - double maxSliderValue() const; - - int extent() const; - -signals: - void sliderMoved(Qt::Orientation, double, double); - void valueChanged(Qt::Orientation, double, double); - -public slots: - virtual void setBase(double min, double max); - virtual void moveSlider(double min, double max); - -protected: - void sliderRange(int value, double &min, double &max) const; - int mapToTick(double) const; - double mapFromTick(int) const; - -private slots: - void catchValueChanged(int value); - void catchSliderMoved(int value); - -private: - void init(); - - bool d_inverted; - double d_minBase; - double d_maxBase; - int d_baseTicks; -};