QGroundControl UI customization

#1

Hi All,

I’m pretty new to the drone scene, so please forgive any newbie mistakes I might (actually, will definitely) make.

I wanted to customize the UI of QGroundControl. I do not have any real idea where to start. I read the developer pages on their website here. Unfortunately, I was not able to make heads nor tails of where I am to start for this task.

I’m looking to completely overhaul the UI to use faded text, movable buttons, etc…

I have started looking into Qt and I believe I can do most of it with QML, but I needed some guidance as to where I would start modifying the UI files. Do I have to recompile the entire code or is there a directory where I can just add the modified QML files?

If someone could throw some light on to this, that would be great.

#2

Ok, well that’s going to be pretty involved! Qml files are compiled into resources so you need to recompile each time you change them. If you look at MainWindowInner.qml that is the starting point for the ui. From there you should be able to pull the string and work your way to all of the other parts of the ui.

#3

Hello,

I’m also learning QML and going deep into QGroundControl. In order to customize UI, Im using:

  • Qt Creator (as IDE)
  • GNU/Linux (as OS)
  • grep & find (helps a lot searching the code)

Resources for the code I use:

It is very important that you understand perfectly how C++ integrates with QML

Finnally, compile much faster with:

#4

Thanks for the heads up @DonLakeFlyer and @chodjo.

I have just had the chance to get back to looking at this project. I got around to compiling it. Now I will start taking a look at modifying the UI.

@DonLakeFlyer, I was wondering from which file I would start modifying the UI… Thank you for the information.

Any idea on how I would change the map provider, and bring in the map that gives a 3D perspective?

#5

Start here and follow where it goes.

#6

First of all, I’m just trying to learn the code, so you should take my advice and guiding taken with a grain of salt.

You can set different maps in The APPLICATION SETTINGS > GENERAL tab, under MAP PROVIDER.

So we start in MainWindowInner.qml. In the app we should go to the Application Settings tab in the main toolbar. So checking the qml, we find there is defined a custom type MainToolBar with id toolBar and defined as the main UI. We so, check MainToolBar.qml and get a QGCToolBarButton custom type:

        QGCToolBarButton {
            id:                 settingsButton
            anchors.top:        parent.top
            anchors.bottom:     parent.bottom
            exclusiveGroup:     mainActionGroup
            source:             "/res/QGCLogoWhite"
            logo:               true
            onClicked:          toolBar.showSettingsView()
            visible:            !QGroundControl.corePlugin.options.combineSettingsAndSetup
        }

So back to MainWindowInner.qml and see that onShowSettingsView points to mainWindow.showSettingsView:

function showSettingsView() {
    rootLoader.sourceComponent = null
    if(currentPopUp) {
        currentPopUp.close()
    }
    //-- In settings view, the full height is available. Set to 0 so it is ignored.
    ScreenTools.availableHeight = 0
    hideAllViews()
    if (settingsViewLoader.source != _settingsViewSource) {
        settingsViewLoader.source  = _settingsViewSource
    }
    settingsViewLoader.visible  = true
    toolBar.checkSettingsButton()
}

_settingsViewSource is a property string that points to “AppSettings.qml”, so there we go. Here we have a rectangle that holds a QGCFlickable, where a Repeater (http://doc.qt.io/qt-5/qml-qtquick-repeater.html) instantiates a number of QGCButton type components using a model:

            model:  QGroundControl.corePlugin.settingsPages

So now, based on how C++ integrates with QML, we have to search, in this case, for a Q_PROPERTY called settingsPage. In my case, a grep search through the code takes me to QGCCorePlugin.h were we find:

Q_PROPERTY(QVariantList         settingsPages           READ settingsPages                                  NOTIFY settingsPagesChanged)

So, lets take a look at that code in QGCCorePlugin.cc:

QVariantList &QGCCorePlugin::settingsPages()
{
if(!_p->pGeneral) {
_p->pGeneral = new QmlComponentInfo(tr(“General”),
QUrl::fromUserInput(“qrc:/qml/GeneralSettings.qml”),
QUrl::fromUserInput(“qrc:/res/gear-white.svg”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pGeneral));
_p->pCommLinks = new QmlComponentInfo(tr(“Comm Links”),
QUrl::fromUserInput(“qrc:/qml/LinkSettings.qml”),
QUrl::fromUserInput(“qrc:/res/waves.svg”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pCommLinks));
_p->pOfflineMaps = new QmlComponentInfo(tr(“Offline Maps”),
QUrl::fromUserInput(“qrc:/qml/OfflineMap.qml”),
QUrl::fromUserInput(“qrc:/res/waves.svg”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pOfflineMaps));
_p->pMAVLink = new QmlComponentInfo(tr(“MAVLink”),
QUrl::fromUserInput(“qrc:/qml/MavlinkSettings.qml”),
QUrl::fromUserInput(“qrc:/res/waves.svg”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pMAVLink));
_p->pConsole = new QmlComponentInfo(tr(“Console”),
QUrl::fromUserInput(“qrc:/qml/QGroundControl/Controls/AppMessages.qml”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pConsole));
#if defined(QT_DEBUG)
//-- These are always present on Debug builds
_p->pMockLink = new QmlComponentInfo(tr(“Mock Link”),
QUrl::fromUserInput(“qrc:/qml/MockLink.qml”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pMockLink));
_p->pDebug = new QmlComponentInfo(tr(“Debug”),
QUrl::fromUserInput(“qrc:/qml/DebugWindow.qml”));
_p->settingsList.append(QVariant::fromValue((QmlComponentInfo*)_p->pDebug));
#endif

The code is pointing us to GeneralSettings.qml.

                    //-- Map Provider
                    Row {
                        spacing:    ScreenTools.defaultFontPixelWidth
                        visible:    _mapProvider.visible
                        QGCLabel {
                            text:       qsTr("Map Provider:")
                            width:      _labelWidth
                            anchors.verticalCenter: parent.verticalCenter
                        }
                        FactComboBox {
                            width:      _editFieldWidth
                            fact:       _mapProvider
                            indexModel: false
                            anchors.verticalCenter: parent.verticalCenter
                        }
                    }

We have a Fact defined:

property Fact _mapProvider:                 QGroundControl.settingsManager.flightMapSettings.mapProvider

So here is where map provider is defined. But we dont want to know who is the provider, but where its implemented the flight map. But now we know how the app calls to get the name of the map he wants to provide. So another grep search:

jguillen@HarryPotter:~/workspace/qgroundcontrol/src$ grep -r “QGroundControl.settingsManager.flightMapSettings.mapProvider” .
./ui/preferences/GeneralSettings.qml: property Fact _mapProvider: QGroundControl.settingsManager.flightMapSettings.mapProvider
./FlightMap/FlightMap.qml: target: QGroundControl.settingsManager.flightMapSettings.mapProvider
jguillen@HarryPotter:~/workspace/qgroundcontrol/src$

So we open FlightMap.qml and find that has a Map QML type (http://doc.qt.io/qt-5/qml-qtlocation-map.html). You can follow from here.

Good luck :wink:

#7

Hi! Thanks for sharing, this info is helping me a lot.
I’m trying to develop some improvements on QGC. Mainly add sliders (just like virtual joystick) on mainview to send PWM commands to FC channels.
I’m wondering about the best way to do this. Is it possible to edit these .qml files in design mode?

#8

You can only edit .qml files in a text editor.

#9

Isn’t it MainWindowHybrid.qml starting point for linux/windows/Mac and MainWindowNative.qml starting point for android

#10

MainWindowInner.qml is the starting point for everything which then loads either MainWindowHybrid for desktop buids and MainWindowNative for mobile builds.