diff --git a/QGCApplication.pro b/QGCApplication.pro index 012a15bf96449ada84ca6a83be23d07b8e1f6468..c22ef5ed3dd275143120eeae0b42a1650270beb1 100644 --- a/QGCApplication.pro +++ b/QGCApplication.pro @@ -87,9 +87,11 @@ MacBuild { } iOSBuild { - QMAKE_INFO_PLIST = $${BASEDIR}/ios/iOS-Info.plist - ICON = $${BASEDIR}/resources/icons/macx.icns - OTHER_FILES += $${BASEDIR}/iOS-Info.plist + QMAKE_INFO_PLIST = $${BASEDIR}/ios/iOS-Info.plist + ICON = $${BASEDIR}/resources/icons/macx.icns + OTHER_FILES += $${BASEDIR}/iOS-Info.plist + LIBS += -framework AVFoundation + OBJECTIVE_SOURCES += src/audio/QGCAudioWorker_iOS.mm } LinuxBuild { diff --git a/QGCCommon.pri b/QGCCommon.pri index f67098d4b0e1127e79b77333c65f0abf69f3a77c..ba1da391f7dfeadcdbab411199390daa8ef7c247 100644 --- a/QGCCommon.pri +++ b/QGCCommon.pri @@ -49,6 +49,7 @@ linux { macx-clang | macx-llvm { message("Mac build") CONFIG += MacBuild + DEFINES += __macos__ QMAKE_CXXFLAGS += -fvisibility=hidden } else { error("Unsupported Mac toolchain, only 64-bit LLVM+clang is supported") @@ -60,6 +61,7 @@ linux { message("iOS build") CONFIG += iOSBuild MobileBuild app_bundle DEFINES += __ios__ + QMAKE_IOS_DEPLOYMENT_TARGET = 8.0 warning("iOS build is experimental and not yet fully functional") } else { error("Unsupported build platform, only Linux, Windows, Android and Mac (Mac OS and iOS) are supported") diff --git a/QGCExternalLibs.pri b/QGCExternalLibs.pri index 1c5693a801f3a8fc6b90df4188e6fc5584f4be0e..c038837b2759dc4cd120b6a5866e3dc0795e1a68 100644 --- a/QGCExternalLibs.pri +++ b/QGCExternalLibs.pri @@ -260,7 +260,7 @@ contains (DEFINES, DISABLE_SPEECH) { } } # Mac support is built into OS 10.6+. -else:MacBuild { +else:MacBuild|iOSBuild { message("Including support for speech output") DEFINES += QGC_SPEECH_ENABLED } diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index 899327f93cca337806fcd8087b9e55929822492c..e44afcb992311ce66179366082426ba849038b86 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -140,8 +140,7 @@ static QObject* qgroundcontrolQmlGlobalSingletonFactory(QQmlEngine*, QJSEngine*) } #if defined(QGC_GST_STREAMING) -#ifdef Q_OS_MAC -#ifndef __ios__ +#if defined(__macos__) #ifdef QGC_INSTALL_RELEASE static void qgcputenv(const QString& key, const QString& root, const QString& path) { @@ -151,7 +150,6 @@ static void qgcputenv(const QString& key, const QString& root, const QString& pa #endif #endif #endif -#endif /** * @brief Constructor for the main application. diff --git a/src/QGCMessageBox.h b/src/QGCMessageBox.h index 984bdfd766542a3f35f1233ec49ebaacb50281e8..d587b16c8dd916b043e88b70bf30055111ceb4c4 100644 --- a/src/QGCMessageBox.h +++ b/src/QGCMessageBox.h @@ -116,7 +116,7 @@ private: #endif #endif { -#ifdef Q_OS_MAC +#ifdef __macos__ QString emptyTitle; QMessageBox box(icon, emptyTitle, title, buttons, parent); box.setDefaultButton(defaultButton); diff --git a/src/QmlControls/ScreenToolsController.cc b/src/QmlControls/ScreenToolsController.cc index 77c0bd14f2c643cc8e163923982b19b04da1e670..a20c8dad4bc50e41b52f8c26686a2ee899e8a620 100644 --- a/src/QmlControls/ScreenToolsController.cc +++ b/src/QmlControls/ScreenToolsController.cc @@ -28,15 +28,18 @@ #include "MainWindow.h" #ifdef Q_OS_WIN -const double ScreenToolsController::_defaultFontPixelSizeRatio = 1.0; -#elif __mobile__ -const double ScreenToolsController::_defaultFontPixelSizeRatio = 1.0; +const double ScreenToolsController::_defaultFontPixelSizeRatio = 1.0; +#elif __android__ +const double ScreenToolsController::_defaultFontPixelSizeRatio = 1.0; +#elif __ios__ +const double ScreenToolsController::_defaultFontPixelSizeRatio = 0.8; #else -const double ScreenToolsController::_defaultFontPixelSizeRatio = 0.8; +const double ScreenToolsController::_defaultFontPixelSizeRatio = 0.8; #endif -const double ScreenToolsController::_smallFontPixelSizeRatio = 0.75; -const double ScreenToolsController::_mediumFontPixelSizeRatio = 1.22; -const double ScreenToolsController::_largeFontPixelSizeRatio = 1.66; + +const double ScreenToolsController::_smallFontPixelSizeRatio = 0.75; +const double ScreenToolsController::_mediumFontPixelSizeRatio = 1.22; +const double ScreenToolsController::_largeFontPixelSizeRatio = 1.66; ScreenToolsController::ScreenToolsController() { diff --git a/src/QmlControls/SubMenuButton.qml b/src/QmlControls/SubMenuButton.qml index 3b0074bf3ed546e4f95bd812400873d02a9ca710..791362bedab6d2c601e03368921b27be7407f58e 100644 --- a/src/QmlControls/SubMenuButton.qml +++ b/src/QmlControls/SubMenuButton.qml @@ -39,7 +39,7 @@ Button { verticalAlignment: TextEdit.AlignVCenter horizontalAlignment: TextEdit.AlignHCenter color: showHighlight ? qgcPal.buttonHighlightText : qgcPal.buttonText - font.pixelSize: ScreenTools.isMobile ? ScreenTools.defaultFontPixelSize * 0.65 : ScreenTools.defaultFontPixelSize + font.pixelSize: ScreenTools.isMobile ? ScreenTools.defaultFontPixelSize * 0.75 : ScreenTools.defaultFontPixelSize text: control.text Rectangle { diff --git a/src/QtLocationPlugin/OpenPilotMaps.cc b/src/QtLocationPlugin/OpenPilotMaps.cc index af11c36762491e37e1a4cb7a3dd0843859baddc9..bacb6b569ec94a08a2bf6fd458024e59baeef372 100644 --- a/src/QtLocationPlugin/OpenPilotMaps.cc +++ b/src/QtLocationPlugin/OpenPilotMaps.cc @@ -196,7 +196,7 @@ void UrlFactory::_tryCorrectGoogleVersions() _network->setProxy(tProxy); QString url = "http://maps.google.com/maps?output=classic"; qheader.setUrl(QUrl(url)); -#if defined Q_OS_MACX +#if defined Q_OS_MAC QByteArray userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0"; #elif defined Q_OS_WIN32 QByteArray userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7"; diff --git a/src/QtLocationPlugin/qgeotilefetcherqgc.cpp b/src/QtLocationPlugin/qgeotilefetcherqgc.cpp index 5fc341bcac67719c3ebdb9c5a585bdc70d2f81b2..54c32d0be107ddde87a0b70f96f611a4dc3b44d5 100644 --- a/src/QtLocationPlugin/qgeotilefetcherqgc.cpp +++ b/src/QtLocationPlugin/qgeotilefetcherqgc.cpp @@ -55,7 +55,7 @@ QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent) : QGeoTileFetcher(parent) , m_networkManager(new QNetworkAccessManager(this)) -#if defined Q_OS_MACX +#if defined Q_OS_MAC , m_userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0") #elif defined Q_OS_WIN32 , m_userAgent("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7") diff --git a/src/VideoStreaming/VideoStreaming.cc b/src/VideoStreaming/VideoStreaming.cc index ec45ababcb08285c3390d490f25fa8db6cc497f3..ce2b10f59e835339f48eddc1a50f901cf91fdddb 100644 --- a/src/VideoStreaming/VideoStreaming.cc +++ b/src/VideoStreaming/VideoStreaming.cc @@ -75,8 +75,7 @@ void initializeVideoStreaming(int &argc, char* argv[]) GST_PLUGIN_STATIC_REGISTER(x264); #endif -#ifdef Q_OS_MAC -#ifndef __ios__ +#ifdef __macos__ #ifdef QGC_INSTALL_RELEASE QString currentDir = QCoreApplication::applicationDirPath(); qgcputenv("GST_PLUGIN_SCANNER", currentDir, "/gst-plugin-scanner"); @@ -92,7 +91,6 @@ void initializeVideoStreaming(int &argc, char* argv[]) // } #endif #endif -#endif #else Q_UNUSED(argc); diff --git a/src/ViewWidgets/ViewWidget.qml b/src/ViewWidgets/ViewWidget.qml index b8cfc7e7cd2a8c00dc12604164e4c83189b4c73e..acdca20f5287d9cdc48812b0e4f9a8529d8eebc2 100644 --- a/src/ViewWidgets/ViewWidget.qml +++ b/src/ViewWidgets/ViewWidget.qml @@ -1,4 +1,4 @@ -import QtQuick 2.2 +import QtQuick 2.5 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.2 @@ -6,78 +6,78 @@ import QGroundControl.Palette 1.0 import QGroundControl.Controllers 1.0 Rectangle { - property Component connectedComponent: __componentConnected - property Component disconnectedComponent: __componentDisconnected + property Component connectedComponent: __componentConnected + property Component disconnectedComponent: __componentDisconnected - QGCPalette { id: __qgcPal; colorGroupEnabled: enabled } - ViewWidgetController { id: __controller } + QGCPalette { id: __qgcPal; colorGroupEnabled: enabled } + ViewWidgetController { id: __controller } - color: __qgcPal.window + color: __qgcPal.window - Component.onCompleted: __controller.checkForVehicle() + Component.onCompleted: __controller.checkForVehicle() - Connections { - target: __controller + Connections { + target: __controller - onPluginConnected: { - pageLoader.autopilot = autopilot - pageLoader.sourceComponent = connectedComponent - } + onPluginConnected: { + pageLoader.autopilot = autopilot + pageLoader.sourceComponent = connectedComponent + } - onPluginDisconnected: { + onPluginDisconnected: { pageLoader.sourceComponent = null - pageLoader.sourceComponent = disconnectedComponent - pageLoader.autopilot = null - } - } + pageLoader.sourceComponent = disconnectedComponent + pageLoader.autopilot = null + } + } - Loader { - id: pageLoader + Loader { + id: pageLoader - anchors.fill: parent + anchors.fill: parent - property var autopilot + property var autopilot - sourceComponent: __componentDisconnected - } + sourceComponent: __componentDisconnected + } - Component { - id: __componentConnected + Component { + id: __componentConnected - Rectangle { - QGCPalette { id: __qgcPal; colorGroupEnabled: enabled } + Rectangle { + QGCPalette { id: __qgcPal; colorGroupEnabled: enabled } - anchors.fill: parent - color: __qgcPal.window + anchors.fill: parent + color: __qgcPal.window - QGCLabel { - anchors.fill: parent + QGCLabel { + anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter - text: "missing connected implementation" - } - } - } + text: "missing connected implementation" + } + } + } - Component { - id: __componentDisconnected + Component { + id: __componentDisconnected - Rectangle { - QGCPalette { id: __qgcPal; colorGroupEnabled: enabled } + Rectangle { + QGCPalette { id: __qgcPal; colorGroupEnabled: enabled } - anchors.fill: parent - color: __qgcPal.window + anchors.fill: parent + color: __qgcPal.window - QGCLabel { - anchors.fill: parent + QGCLabel { + anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter - text: "no vehicle connected" - } - } - } + text: "no vehicle connected" + } + } + } } diff --git a/src/audio/QGCAudioWorker.cpp b/src/audio/QGCAudioWorker.cpp index 9d772671a0e0298444b5acca65e9bd3bed83f104..5829359eea38df332fc14f8a03356f5be4bcc03a 100644 --- a/src/audio/QGCAudioWorker.cpp +++ b/src/audio/QGCAudioWorker.cpp @@ -8,7 +8,7 @@ #include "QGCAudioWorker.h" #include "GAudioOutput.h" -#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED +#if (defined __macos__) && defined QGC_SPEECH_ENABLED #include static SpeechChannel sc; @@ -53,6 +53,10 @@ MacSpeech macSpeech; #endif +#if (defined __ios__) && defined QGC_SPEECH_ENABLED +extern void iOSSpeak(QString msg); +#endif + // Speech synthesis is only supported with MSVC compiler #if defined _MSC_VER && defined QGC_SPEECH_ENABLED // Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx @@ -168,8 +172,10 @@ void QGCAudioWorker::say(QString inText, int severity) unsigned int espeak_size = strlen(text.toStdString().c_str()) + 1; espeak_Synth(text.toStdString().c_str(), espeak_size, 0, POS_CHARACTER, 0, espeakCHARS_AUTO, NULL, NULL); -#elif defined Q_OS_MAC && defined QGC_SPEECH_ENABLED +#elif (defined __macos__) && defined QGC_SPEECH_ENABLED macSpeech.say(text.toStdString().c_str()); +#elif (defined __ios__) && defined QGC_SPEECH_ENABLED + iOSSpeak(text); #else // Make sure there isn't an unused variable warning when speech output is disabled Q_UNUSED(inText); diff --git a/src/audio/QGCAudioWorker_iOS.mm b/src/audio/QGCAudioWorker_iOS.mm new file mode 100644 index 0000000000000000000000000000000000000000..9dbec3a776b928572c90bbed490d06714017ba3e --- /dev/null +++ b/src/audio/QGCAudioWorker_iOS.mm @@ -0,0 +1,84 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2015 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief TTS for iOS + * + * @author Gus Grubba + * + */ + +#include + +#include "QGC.h" + +#if (defined __ios__) && defined QGC_SPEECH_ENABLED + +#import + +class SpeakIOS +{ +public: + SpeakIOS (); + ~SpeakIOS (); + void speak (QString msg ); +private: + AVSpeechSynthesizer *_synth; +}; + +SpeakIOS::SpeakIOS() + : _synth([[AVSpeechSynthesizer alloc] init]) +{ + +} + +SpeakIOS::~SpeakIOS() +{ + [_synth release]; +} + +void SpeakIOS::speak(QString msg) +{ + while ([_synth isSpeaking]) { + QGC::SLEEP::msleep(100); + } + NSString *msg_ns = [NSString stringWithCString:msg.toStdString().c_str() encoding:[NSString defaultCStringEncoding]]; + AVSpeechUtterance *utterance = [[[AVSpeechUtterance alloc] initWithString: msg_ns] autorelease]; + AVSpeechSynthesisVoice* currentVoice = [AVSpeechSynthesisVoice voiceWithLanguage:[AVSpeechSynthesisVoice currentLanguageCode]]; + utterance.voice = currentVoice; + //utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"en-US"]; + utterance.rate = 0.5; + [_synth speakUtterance:utterance]; +} + +//-- The one and only static singleton +SpeakIOS kSpeakIOS; + +void iOSSpeak(QString msg) +{ + kSpeakIOS.speak(msg); +} + +#endif + diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 3fb78aad7e08cd5604976f37875243bce7bd6879..3eedde152f969e7262f840cdb111f37a6460a535 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -73,7 +73,7 @@ QGCFlightGearLink::QGCFlightGearLink(Vehicle* vehicle, QString startupArguments, 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); @@ -92,15 +92,15 @@ 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, SIGNAL(readyRead()), this, SLOT(readBytes())); - - + + // Connect to the various HIL signals that we use to then send information across the UDP protocol to FlightGear. connect(_vehicle->uas(), SIGNAL(hilControlsChanged(quint64, float, float, float, float, quint8, quint8)), this, SLOT(updateControls(quint64,float,float,float,float,quint8,quint8))); @@ -112,38 +112,38 @@ void QGCFlightGearLink::run() _vehicle->uas(), SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); connect(this, SIGNAL(sensorHilOpticalFlowChanged(quint64, qint16, qint16, float,float, quint8, float)), _vehicle->uas(), SLOT(sendHilOpticalFlow(quint64, qint16, qint16, float, float, quint8, float))); - + // Start a new QProcess to run FlightGear in _fgProcess = new QProcess(this); Q_CHECK_PTR(_fgProcess); _fgProcess->moveToThread(this); - + connect(_fgProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); #ifdef DEBUG_FLIGHTGEAR_CONNECT connect(_fgProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(_printFgfsOutput())); connect(_fgProcess, SIGNAL(readyReadStandardError()), this, SLOT(_printFgfsError())); #endif - + if (!_fgProcessWorkingDirPath.isEmpty()) { _fgProcess->setWorkingDirectory(_fgProcessWorkingDirPath); - qDebug() << "Working directory" << _fgProcess->workingDirectory(); + 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. + // 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); + _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(); @@ -413,13 +413,13 @@ void QGCFlightGearLink::readBytes() 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[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; + 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(); @@ -534,67 +534,67 @@ 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 + // 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 + 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 @@ -657,8 +657,8 @@ bool QGCFlightGearLink::connectSimulation() #endif // Now set the FG arguments to the arguments from the UI _fgArgList = uiArgList; - -#if defined Q_OS_MACX + +#if defined __macos__ // 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"); @@ -674,7 +674,7 @@ bool QGCFlightGearLink::connectSimulation() 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. @@ -689,31 +689,31 @@ bool QGCFlightGearLink::connectSimulation() QFile file(fgrunPrefsFile); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); - QString lookahead; // lookahead for continuation lines + 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(); - } - } - + 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); @@ -726,17 +726,17 @@ bool QGCFlightGearLink::connectSimulation() } 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 seperated by ';' so don't do QDir::absolutePath on it + // Scenery can contain multiple paths seperated by ';' so don't do QDir::absolutePath on it fgSceneryPath = regExp.cap(1); qDebug() << "fg_scenery" << fgSceneryPath; continue; @@ -753,7 +753,7 @@ bool QGCFlightGearLink::connectSimulation() #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()); @@ -769,7 +769,7 @@ bool QGCFlightGearLink::connectSimulation() if (msgBox.exec() == QMessageBox::Cancel) { return false; } - + // Let the user pick the right directory QString dirPath = QGCFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName); if (dirPath.isEmpty()) { @@ -779,7 +779,7 @@ bool QGCFlightGearLink::connectSimulation() 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; @@ -801,7 +801,7 @@ bool QGCFlightGearLink::connectSimulation() fgRootPath.clear(); } } - + // Alert the user if we couldn't find an --fg-root if (fgRootPath.isEmpty()) { QString errMsg; @@ -825,12 +825,12 @@ bool QGCFlightGearLink::connectSimulation() fgSceneryPath = argValue; qDebug() << "--fg-scenery override" << argValue; } else if (!fgSceneryPath.isEmpty()) { - _fgArgList += "--fg-scenery=" + fgSceneryPath; - } - + _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. + // it can be multiple paths. if (fgSceneryPath.isEmpty()) { QString errMsg; if (fgSceneryDirOverride) { @@ -844,7 +844,7 @@ bool QGCFlightGearLink::connectSimulation() #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()) { @@ -852,27 +852,27 @@ bool QGCFlightGearLink::connectSimulation() 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 QGroundControl 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); @@ -880,31 +880,31 @@ bool QGCFlightGearLink::connectSimulation() QGCMessageBox::critical(tr("FlightGear HIL"), tr("Incorrect QGroundControl 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 QGroundControl install the latest file.").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 QGroundControl to install the latest version of the file.").arg(_fgProtocolFileFullyQualified)); if (!QFile::remove(_fgProtocolFileFullyQualified)) { @@ -913,7 +913,7 @@ bool QGCFlightGearLink::connectSimulation() } } } - + if (!QFileInfo(_fgProtocolFileFullyQualified).exists()) { QMessageBox msgBox(QMessageBox::Critical, tr("FlightGear Failed to Start"), @@ -925,7 +925,7 @@ bool QGCFlightGearLink::connectSimulation() 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) { @@ -935,7 +935,7 @@ bool QGCFlightGearLink::connectSimulation() #else QString copyCmd = QString("sudo cp %1 %2").arg(qgcProtocolFileFullyQualified).arg(_fgProtocolFileFullyQualified); #endif - + QMessageBox msgBox(QMessageBox::Critical, tr("Copy failed"), #ifdef Q_OS_WIN32 @@ -953,7 +953,7 @@ bool QGCFlightGearLink::connectSimulation() return false; } } - + // Start the engines to save a startup step if (_vehicle->vehicleType() == MAV_TYPE_QUADROTOR) { // Start all engines of the quad @@ -964,20 +964,20 @@ bool QGCFlightGearLink::connectSimulation() } else { _fgArgList << "--prop:/engines/engine/running=true"; } - + // We start out at our home position _fgArgList << QString("--lat=%1").arg(qgcApp()->toolbox()->homePositionManager()->getHomeLatitude()); _fgArgList << QString("--lon=%1").arg(qgcApp()->toolbox()->homePositionManager()->getHomeLongitude()); // 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(qgcApp()->toolbox()->homePositionManager()->getHomeAltitude()); - + #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; } diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index e80be31f811f6a0dd9f3995affd8eeee1fc2ccf0..6d1d5b0c478924b281efcc9b2a166561ff40178a 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -265,7 +265,7 @@ MainWindow::MainWindow() connect(_ui.actionStatusBar, &QAction::triggered, this, &MainWindow::showStatusBarCallback); // Set OS dependent keyboard shortcuts for the main window, non OS dependent shortcuts are set in MainWindow.ui -#ifdef Q_OS_MACX +#ifdef __macos__ _ui.actionSetup->setShortcut(QApplication::translate("MainWindow", "Meta+1", 0)); _ui.actionPlan->setShortcut(QApplication::translate("MainWindow", "Meta+2", 0)); _ui.actionFlight->setShortcut(QApplication::translate("MainWindow", "Meta+3", 0)); @@ -290,7 +290,7 @@ MainWindow::MainWindow() menuBar()->hide(); #endif show(); -#ifdef Q_OS_MAC +#ifdef __macos__ // TODO HACK // This is a really ugly hack. For whatever reason, by having a QQuickWidget inside a // QDockWidget (MainToolBar above), the main menu is not shown when the app first diff --git a/src/ui/MainWindow.qml b/src/ui/MainWindow.qml index a5f020236d4122abfb0be5a04b21d864e49df800..edfc0d8ad2dbf709a21e2b693238f31ece5d82c3 100644 --- a/src/ui/MainWindow.qml +++ b/src/ui/MainWindow.qml @@ -40,7 +40,7 @@ Item { QGCPalette { id: __qgcPal; colorGroupEnabled: true } - property real tbHeight: ScreenTools.isMobile ? (ScreenTools.isTinyScreen ? (mainWindow.width * 0.0666) : (mainWindow.width * 0.0444)) : ScreenTools.defaultFontPixelSize * 4 + property real tbHeight: ScreenTools.isMobile ? (ScreenTools.isTinyScreen ? (mainWindow.width * 0.0666) : (mainWindow.width * 0.05)) : ScreenTools.defaultFontPixelSize * 4 property int tbCellHeight: tbHeight * 0.75 property real tbSpacing: ScreenTools.isMobile ? width * 0.00824 : 9.54 property real tbButtonWidth: tbCellHeight * 1.3 diff --git a/src/ui/toolbar/MainToolBar.qml b/src/ui/toolbar/MainToolBar.qml index 9d110d0abd41c72424dfdc7ac8157cbf9e3464a9..577c5fba07dffb3ac71b7f2dd87bb76ea966c365 100644 --- a/src/ui/toolbar/MainToolBar.qml +++ b/src/ui/toolbar/MainToolBar.qml @@ -421,7 +421,7 @@ Rectangle { id: toolBarMessage width: toolBarMessageArea.width - toolBarMessageCloseButton.width wrapMode: Text.WordWrap - color: qgcPal.warningText + color: "#e4e428" lineHeightMode: Text.ProportionalHeight lineHeight: 1.15 anchors.margins: mainWindow.tbSpacing