From c664ad332c741f69dc95fcea71fb7b55067d4f36 Mon Sep 17 00:00:00 2001
From: lm <pixhawk@switched.com>
Date: Thu, 30 Dec 2010 19:31:18 +0100
Subject: [PATCH] Working on new interactive control widget building, fixed
 timer bug in global position message

---
 qgroundcontrol.pro                   |  20 +++++--
 src/uas/UAS.cc                       |  40 ++++++++++++-
 src/uas/UAS.h                        |  13 ++++-
 src/ui/MainWindow.cc                 |  12 ++++
 src/ui/MainWindow.h                  |   3 +
 src/ui/MainWindow.ui                 |  11 ++--
 src/ui/designer/QGCActionButton.cc   |  32 +++++++++++
 src/ui/designer/QGCActionButton.h    |  26 +++++++++
 src/ui/designer/QGCActionButton.ui   |  99 ++++++++++++++++++++++++++++++++
 src/ui/designer/QGCParamSlider.cc    |  37 +++++++++++-
 src/ui/designer/QGCParamSlider.h     |   9 ++-
 src/ui/designer/QGCParamSlider.ui    | 107 +++++++++++++++++++++++++++++++----
 src/ui/designer/QGCToolWidget.cc     | 100 ++++++++++++++++++++++++++++++++
 src/ui/designer/QGCToolWidget.h      |  45 +++++++++++++++
 src/ui/designer/QGCToolWidget.ui     |  21 +++++++
 src/ui/designer/QGCToolWidgetItem.cc |  37 ++++++++++++
 src/ui/designer/QGCToolWidgetItem.h  |  32 +++++++++++
 17 files changed, 618 insertions(+), 26 deletions(-)
 create mode 100644 src/ui/designer/QGCActionButton.cc
 create mode 100644 src/ui/designer/QGCActionButton.h
 create mode 100644 src/ui/designer/QGCActionButton.ui
 create mode 100644 src/ui/designer/QGCToolWidget.cc
 create mode 100644 src/ui/designer/QGCToolWidget.h
 create mode 100644 src/ui/designer/QGCToolWidget.ui
 create mode 100644 src/ui/designer/QGCToolWidgetItem.cc
 create mode 100644 src/ui/designer/QGCToolWidgetItem.h

diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index eadd028..443a94c 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -151,7 +151,10 @@ FORMS += src/ui/MainWindow.ui \
     src/ui/SlugsPIDControl.ui \
     src/ui/SlugsVideoCamControl.ui \
     src/ui/SlugsPadCameraControl.ui \
-    src/ui/uas/QGCUnconnectedInfoWidget.ui
+    src/ui/uas/QGCUnconnectedInfoWidget.ui \
+    src/ui/designer/QGCToolWidget.ui \
+    src/ui/designer/QGCParamSlider.ui \
+    src/ui/designer/QGCActionButton.ui
 
 INCLUDEPATH += src \
     src/ui \
@@ -166,7 +169,8 @@ INCLUDEPATH += src \
     src/ui/mavlink \
     src/ui/param \
     src/ui/watchdog \
-    src/ui/map3D
+    src/ui/map3D \
+    src/ui/designer
 
 HEADERS += src/MG.h \
     src/Core.h \
@@ -252,7 +256,11 @@ HEADERS += src/MG.h \
     src/ui/SlugsPadCameraControl.h \
     src/ui/QGCMainWindowAPConfigurator.h \
     src/comm/MAVLinkSwarmSimulationLink.h \
-    src/ui/uas/QGCUnconnectedInfoWidget.h
+    src/ui/uas/QGCUnconnectedInfoWidget.h \
+    src/ui/designer/QGCToolWidget.h \
+    src/ui/designer/QGCParamSlider.h \
+    src/ui/designer/QGCActionButton.h \
+    src/ui/designer/QGCToolWidgetItem.h
 
 # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler
 macx|win32-msvc2008: {
@@ -369,7 +377,11 @@ SOURCES += src/main.cc \
     src/ui/SlugsPadCameraControl.cpp \
     src/ui/QGCMainWindowAPConfigurator.cc \
     src/comm/MAVLinkSwarmSimulationLink.cc \
-    src/ui/uas/QGCUnconnectedInfoWidget.cc
+    src/ui/uas/QGCUnconnectedInfoWidget.cc \
+    src/ui/designer/QGCToolWidget.cc \
+    src/ui/designer/QGCParamSlider.cc \
+    src/ui/designer/QGCActionButton.cc \
+    src/ui/designer/QGCToolWidgetItem.cc
 
 macx|win32-msvc2008: {
     SOURCES += src/ui/map3D/QGCGoogleEarthView.cc
diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc
index a7510d4..2098388 100644
--- a/src/uas/UAS.cc
+++ b/src/uas/UAS.cc
@@ -86,7 +86,8 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(),
         roll(0.0),
         pitch(0.0),
         yaw(0.0),
-        statusTimeout(new QTimer(this))
+        statusTimeout(new QTimer(this)),
+        paramsOnceRequested(false)
 {
     color = UASInterface::getNextColor();
     setBattery(LIPOLY, 3);
@@ -356,7 +357,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message)
             {
                 mavlink_global_position_int_t pos;
                 mavlink_msg_global_position_int_decode(&message, &pos);
-                quint64 time = QGC::groundTimeUsecs();
+                quint64 time = QGC::groundTimeUsecs()/1000;
                 latitude = pos.lat/(double)1E7;
                 longitude = pos.lon/(double)1E7;
                 altitude = pos.alt/1000.0;
@@ -474,7 +475,23 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message)
             {
                 mavlink_param_value_t value;
                 mavlink_msg_param_value_decode(&message, &value);
-                emit parameterChanged(uasId, message.compid, QString((char*)value.param_id), value.param_value);
+
+                QString parameterName = QString((char*)value.param_id);
+                int component = message.compid;
+                float val = value.param_value;
+
+                // Insert component if necessary
+                if (!parameters.contains(component))
+                {
+                    parameters.insert(component, new QMap<QString, float>());
+                }
+
+                // Insert parameter into registry
+                if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName);
+                parameters.value(component)->insert(parameterName, val);
+
+                // Emit change
+                emit parameterChanged(uasId, message.compid, parameterName, val);
             }
             break;
         case MAVLINK_MSG_ID_DEBUG:
@@ -820,6 +837,23 @@ quint64 UAS::getUnixTime(quint64 time)
     }
 }
 
+QList<QString> UAS::getParameterNames(int component)
+{
+    if (parameters.contains(component))
+    {
+        return parameters.value(component)->keys();
+    }
+    else
+    {
+        return QList<QString>();
+    }
+}
+
+QList<int> UAS::getComponentIds()
+{
+    return parameters.keys();
+}
+
 void UAS::setMode(int mode)
 {
     if ((uint8_t)mode >= MAV_MODE_LOCKED && (uint8_t)mode <= MAV_MODE_RC_TRAINING)
diff --git a/src/uas/UAS.h b/src/uas/UAS.h
index 7826b81..d246b67 100644
--- a/src/uas/UAS.h
+++ b/src/uas/UAS.h
@@ -153,6 +153,8 @@ protected:
     double pitch;
     double yaw;
     QTimer* statusTimeout;      ///< Timer for various status timeouts
+    QMap<int, QMap<QString, float>* > parameters; ///< All parameters
+    bool paramsOnceRequested;   ///< If the parameter list has been read at least once
 
     /** @brief Set the current battery type */
     void setBattery(BatteryType type, int cells);
@@ -199,7 +201,7 @@ public slots:
 
     //void requestWaypoints();  FIXME tbd
     //void clearWaypointList();   FIXME tbd
-    void requestParameters();
+
     /** @brief Enable the motors */
     void enable_motors();
     /** @brief Disable the motors */
@@ -230,6 +232,9 @@ public slots:
     /** @brief Set current mode of operation, e.g. auto or manual */
     void setMode(int mode);
 
+    /** @brief Request all parameters */
+    void requestParameters();
+
     /** @brief Set a system parameter */
     void setParameter(int component, QString id, float value);
 
@@ -238,6 +243,12 @@ public slots:
     /** @brief Read parameters from permanent storage */
     void readParametersFromStorage();
 
+    /** @brief Get the names of all parameters */
+    QList<QString> getParameterNames(int component);
+
+    /** @brief Get the ids of all components */
+    QList<int> getComponentIds();
+
     void enableAllDataTransmission(int rate);
     void enableRawSensorDataTransmission(int rate);
     void enableExtendedSystemStatusTransmission(int rate);
diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc
index ddad6c0..325f627 100644
--- a/src/ui/MainWindow.cc
+++ b/src/ui/MainWindow.cc
@@ -26,6 +26,7 @@
 #include "MainWindow.h"
 #include "JoystickWidget.h"
 #include "GAudioOutput.h"
+#include "QGCToolWidget.h"
 
 #ifdef QGC_OSG_ENABLED
 #include "Q3DWidgetFactory.h"
@@ -107,6 +108,8 @@ MainWindow::MainWindow(QWidget *parent):
 
     // Create actions
     connectCommonActions();
+    // Add option for custom widgets
+    connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget()));
 
     // Set dock options
     setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);
@@ -694,7 +697,16 @@ void MainWindow::connectCommonWidgets()
         // it notifies that a waypoint global goes to do create and a map graphic too
         connect(waypointsDockWidget->widget(), SIGNAL(createWaypointAtMap(QPointF)), mapWidget, SLOT(createWaypointGraphAtMap(QPointF)));
     }
+}
 
+void MainWindow::createCustomWidget()
+{
+    qDebug() << "ADDING CUSTOM WIDGET";
+    QGCToolWidget* tool = new QGCToolWidget(this);
+    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
+    dock->setWidget(tool);
+    this->addDockWidget(Qt::LeftDockWidgetArea, dock);
+    dock->setVisible(true);
 }
 
 void MainWindow::connectPxWidgets()
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index f866e9a..4e4302e 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -140,6 +140,9 @@ public slots:
     /** @brief Reload the CSS style sheet */
     void reloadStylesheet();
 
+    /** @brief Add a custom tool widget */
+    void createCustomWidget();
+
     void closeEvent(QCloseEvent* event);
 
     /*
diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui
index de35a73..934850a 100644
--- a/src/ui/MainWindow.ui
+++ b/src/ui/MainWindow.ui
@@ -38,7 +38,7 @@
      <x>0</x>
      <y>0</y>
      <width>1000</width>
-     <height>22</height>
+     <height>25</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuMGround">
@@ -46,6 +46,7 @@
      <string>File</string>
     </property>
     <addaction name="actionJoystick_Settings"/>
+    <addaction name="actionNewCustomWidget"/>
     <addaction name="actionSimulate"/>
     <addaction name="separator"/>
     <addaction name="actionExit"/>
@@ -108,7 +109,6 @@
    <addaction name="menuPerspectives"/>
    <addaction name="menuHelp"/>
   </widget>
-
   <widget class="QStatusBar" name="statusBar"/>
   <action name="actionExit">
    <property name="icon">
@@ -430,6 +430,11 @@
     <string>Pilot</string>
    </property>
   </action>
+  <action name="actionNewCustomWidget">
+   <property name="text">
+    <string>New Custom Widget</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources>
@@ -454,5 +459,3 @@
   </connection>
  </connections>
 </ui>
-
-
diff --git a/src/ui/designer/QGCActionButton.cc b/src/ui/designer/QGCActionButton.cc
new file mode 100644
index 0000000..84c5f2f
--- /dev/null
+++ b/src/ui/designer/QGCActionButton.cc
@@ -0,0 +1,32 @@
+#include "QGCActionButton.h"
+#include "ui_QGCActionButton.h"
+
+QGCActionButton::QGCActionButton(QWidget *parent) :
+    QGCToolWidgetItem(parent),
+    ui(new Ui::QGCActionButton)
+{
+    ui->setupUi(this);
+    connect(ui->editFinishButton, SIGNAL(clicked()), this, SLOT(endEditMode()));
+    endEditMode();
+}
+
+QGCActionButton::~QGCActionButton()
+{
+    delete ui;
+}
+
+void QGCActionButton::startEditMode()
+{
+    ui->editActionComboBox->show();
+    ui->editActionsRefreshButton->show();
+    ui->editFinishButton->show();
+    isInEditMode = true;
+}
+
+void QGCActionButton::endEditMode()
+{
+    ui->editActionComboBox->hide();
+    ui->editActionsRefreshButton->hide();
+    ui->editFinishButton->hide();
+    isInEditMode = false;
+}
diff --git a/src/ui/designer/QGCActionButton.h b/src/ui/designer/QGCActionButton.h
new file mode 100644
index 0000000..63556d6
--- /dev/null
+++ b/src/ui/designer/QGCActionButton.h
@@ -0,0 +1,26 @@
+#ifndef QGCACTIONBUTTON_H
+#define QGCACTIONBUTTON_H
+
+#include "QGCToolWidgetItem.h"
+
+namespace Ui {
+    class QGCActionButton;
+}
+
+class QGCActionButton : public QGCToolWidgetItem
+{
+    Q_OBJECT
+
+public:
+    explicit QGCActionButton(QWidget *parent = 0);
+    ~QGCActionButton();
+
+public slots:
+    void startEditMode();
+    void endEditMode();
+
+private:
+    Ui::QGCActionButton *ui;
+};
+
+#endif // QGCACTIONBUTTON_H
diff --git a/src/ui/designer/QGCActionButton.ui b/src/ui/designer/QGCActionButton.ui
new file mode 100644
index 0000000..8622481
--- /dev/null
+++ b/src/ui/designer/QGCActionButton.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QGCActionButton</class>
+ <widget class="QWidget" name="QGCActionButton">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>111</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="1" column="0" colspan="2">
+    <widget class="QLabel" name="nameLabel">
+     <property name="text">
+      <string>Description</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="QPushButton" name="actionButton">
+     <property name="text">
+      <string>Button name</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QComboBox" name="editActionComboBox"/>
+   </item>
+   <item row="2" column="1">
+    <widget class="QPushButton" name="editActionsRefreshButton">
+     <property name="text">
+      <string>Refresh Actions</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="2">
+    <widget class="QPushButton" name="editFinishButton">
+     <property name="text">
+      <string>Done</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="QLineEdit" name="editButtonName">
+     <property name="text">
+      <string>Button name</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0" colspan="2">
+    <widget class="QLineEdit" name="editNameLabel">
+     <property name="text">
+      <string>Description</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>editButtonName</sender>
+   <signal>textChanged(QString)</signal>
+   <receiver>actionButton</receiver>
+   <slot>setWindowTitle(QString)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>310</x>
+     <y>22</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>310</x>
+     <y>55</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>editNameLabel</sender>
+   <signal>textChanged(QString)</signal>
+   <receiver>nameLabel</receiver>
+   <slot>setText(QString)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>116</x>
+     <y>22</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>116</x>
+     <y>55</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/ui/designer/QGCParamSlider.cc b/src/ui/designer/QGCParamSlider.cc
index bfaf3e3..3b8435e 100644
--- a/src/ui/designer/QGCParamSlider.cc
+++ b/src/ui/designer/QGCParamSlider.cc
@@ -1,11 +1,16 @@
+#include <QMenu>
+#include <QContextMenuEvent>
+
 #include "QGCParamSlider.h"
 #include "ui_QGCParamSlider.h"
 
 QGCParamSlider::QGCParamSlider(QWidget *parent) :
-    QWidget(parent),
+    QGCToolWidgetItem(parent),
     ui(new Ui::QGCParamSlider)
 {
     ui->setupUi(this);
+    endEditMode();
+    connect(ui->doneButton, SIGNAL(clicked()), this, SLOT(endEditMode()));
 }
 
 QGCParamSlider::~QGCParamSlider()
@@ -13,6 +18,36 @@ QGCParamSlider::~QGCParamSlider()
     delete ui;
 }
 
+void QGCParamSlider::startEditMode()
+{
+    ui->doneButton->show();
+    ui->maxLabel->show();
+    ui->minLabel->show();
+    ui->nameLineEdit->show();
+    ui->instructionsLabel->show();
+    ui->refreshParamsButton->show();
+    ui->selectParamComboBox->show();
+    ui->minSpinBox->show();
+    ui->maxSpinBox->show();
+    ui->typeComboBox->show();
+    isInEditMode = true;
+}
+
+void QGCParamSlider::endEditMode()
+{
+    ui->doneButton->hide();
+    ui->maxLabel->hide();
+    ui->minLabel->hide();
+    ui->nameLineEdit->hide();
+    ui->instructionsLabel->hide();
+    ui->refreshParamsButton->hide();
+    ui->selectParamComboBox->hide();
+    ui->minSpinBox->hide();
+    ui->maxSpinBox->hide();
+    ui->typeComboBox->hide();
+    isInEditMode = false;
+}
+
 void QGCParamSlider::changeEvent(QEvent *e)
 {
     QWidget::changeEvent(e);
diff --git a/src/ui/designer/QGCParamSlider.h b/src/ui/designer/QGCParamSlider.h
index 56f063b..3f73ec5 100644
--- a/src/ui/designer/QGCParamSlider.h
+++ b/src/ui/designer/QGCParamSlider.h
@@ -2,13 +2,16 @@
 #define QGCPARAMSLIDER_H
 
 #include <QWidget>
+#include <QAction>
 #include <QtDesigner/QDesignerExportWidget>
 
+#include "QGCToolWidgetItem.h"
+
 namespace Ui {
     class QGCParamSlider;
 }
 
-class QDESIGNER_WIDGET_EXPORT QGCParamSlider : public QWidget
+class QDESIGNER_WIDGET_EXPORT QGCParamSlider : public QGCToolWidgetItem
 {
     Q_OBJECT
 
@@ -16,6 +19,10 @@ public:
     explicit QGCParamSlider(QWidget *parent = 0);
     ~QGCParamSlider();
 
+public slots:
+    void startEditMode();
+    void endEditMode();
+
 protected:
     void changeEvent(QEvent *e);
 
diff --git a/src/ui/designer/QGCParamSlider.ui b/src/ui/designer/QGCParamSlider.ui
index 9534679..c702252 100644
--- a/src/ui/designer/QGCParamSlider.ui
+++ b/src/ui/designer/QGCParamSlider.ui
@@ -6,41 +6,124 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>400</width>
-    <height>22</height>
+    <width>436</width>
+    <height>136</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QHBoxLayout" name="horizontalLayout">
-   <property name="spacing">
-    <number>8</number>
-   </property>
-   <property name="margin">
-    <number>0</number>
-   </property>
-   <item>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="1" column="0">
+    <widget class="QLineEdit" name="nameLineEdit">
+     <property name="text">
+      <string>Informal Name..</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1" colspan="2">
+    <widget class="QComboBox" name="typeComboBox">
+     <item>
+      <property name="text">
+       <string>Float</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>Integer</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>Double</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>Short</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>Byte/Char</string>
+      </property>
+     </item>
+    </widget>
+   </item>
+   <item row="1" column="3">
+    <widget class="QLabel" name="minLabel">
+     <property name="text">
+      <string>Min</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="5">
+    <widget class="QLabel" name="maxLabel">
+     <property name="text">
+      <string>Max</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
     <widget class="QLabel" name="nameLabel">
      <property name="text">
       <string>Name</string>
      </property>
     </widget>
    </item>
-   <item>
+   <item row="2" column="1">
     <widget class="QLabel" name="valueLabel">
      <property name="text">
       <string>0.00</string>
      </property>
     </widget>
    </item>
-   <item>
+   <item row="2" column="2" colspan="2">
+    <widget class="QDoubleSpinBox" name="minSpinBox"/>
+   </item>
+   <item row="2" column="4">
     <widget class="QSlider" name="valueSlider">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </widget>
    </item>
+   <item row="2" column="5">
+    <widget class="QDoubleSpinBox" name="maxSpinBox"/>
+   </item>
+   <item row="3" column="5">
+    <widget class="QPushButton" name="doneButton">
+     <property name="text">
+      <string>Done</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QComboBox" name="selectParamComboBox">
+     <item>
+      <property name="text">
+       <string>Select Parameter..</string>
+      </property>
+     </item>
+    </widget>
+   </item>
+   <item row="3" column="2" colspan="2">
+    <widget class="QPushButton" name="refreshParamsButton">
+     <property name="enabled">
+      <bool>true</bool>
+     </property>
+     <property name="text">
+      <string>Refresh</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0" colspan="6">
+    <widget class="QLabel" name="instructionsLabel">
+     <property name="text">
+      <string>Please configure the parameter slider now:</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>
diff --git a/src/ui/designer/QGCToolWidget.cc b/src/ui/designer/QGCToolWidget.cc
new file mode 100644
index 0000000..ff52d6a
--- /dev/null
+++ b/src/ui/designer/QGCToolWidget.cc
@@ -0,0 +1,100 @@
+#include "QGCToolWidget.h"
+#include "ui_QGCToolWidget.h"
+
+#include <QMenu>
+#include <QList>
+#include <QInputDialog>
+#include <QDockWidget>
+#include <QContextMenuEvent>
+#include "QGCParamSlider.h"
+#include "QGCActionButton.h"
+#include "UASManager.h"
+
+QGCToolWidget::QGCToolWidget(QWidget *parent) :
+        QWidget(parent),
+        toolLayout(new QVBoxLayout(this)),
+        mav(NULL),
+        ui(new Ui::QGCToolWidget)
+{
+    ui->setupUi(this);
+    createActions();
+    toolLayout->setAlignment(Qt::AlignTop);
+
+    QList<UASInterface*> systems = UASManager::instance()->getUASList();
+    foreach (UASInterface* uas, systems)
+    {
+        UAS* newMav = dynamic_cast<UAS*>(uas);
+        if (newMav)
+        {
+            addUAS(uas);
+        }
+    }
+    connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*)));
+}
+
+QGCToolWidget::~QGCToolWidget()
+{
+    delete ui;
+}
+
+void QGCToolWidget::addUAS(UASInterface* uas)
+{
+    UAS* newMav = dynamic_cast<UAS*>(uas);
+    if (newMav)
+    {
+        // FIXME Convert to list
+        if (mav == NULL) mav = newMav;
+    }
+}
+
+void QGCToolWidget::contextMenuEvent (QContextMenuEvent* event)
+{
+    QMenu menu(this);
+    menu.addAction(addParamAction);
+    menu.addAction(addButtonAction);
+    menu.addAction(setTitleAction);
+    menu.exec(event->globalPos());
+}
+
+void QGCToolWidget::createActions()
+{
+    addParamAction = new QAction(tr("New &Parameter Slider"), this);
+    addParamAction->setStatusTip(tr("Add a parameter setting slider widget to the tool"));
+    connect(addParamAction, SIGNAL(triggered()), this, SLOT(addParam()));
+
+    addButtonAction = new QAction(tr("New MAV &Action Button"), this);
+    addButtonAction->setStatusTip(tr("Add a new action button to the tool"));
+    connect(addButtonAction, SIGNAL(triggered()), this, SLOT(addAction()));
+
+    setTitleAction = new QAction(tr("Set Widget Title"), this);
+    setTitleAction->setStatusTip(tr("Set the title caption of this tool widget"));
+    connect(setTitleAction, SIGNAL(triggered()), this, SLOT(setTitle()));
+}
+
+void QGCToolWidget::addParam()
+{
+    QGCParamSlider* slider = new QGCParamSlider(this);
+    toolLayout->addWidget(slider);
+    slider->startEditMode();
+}
+
+void QGCToolWidget::addAction()
+{
+    QGCActionButton* button = new QGCActionButton(this);
+    toolLayout->addWidget(button);
+    button->startEditMode();
+}
+
+void QGCToolWidget::setTitle()
+{
+    QDockWidget* parent = dynamic_cast<QDockWidget*>(this->parentWidget());
+    if (parent)
+    {
+    bool ok;
+        QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"),
+                                             tr("Widget title:"), QLineEdit::Normal,
+                                             parent->windowTitle(), &ok);
+        if (ok && !text.isEmpty())
+        parent->setWindowTitle(text);
+    }
+}
diff --git a/src/ui/designer/QGCToolWidget.h b/src/ui/designer/QGCToolWidget.h
new file mode 100644
index 0000000..90d90ea
--- /dev/null
+++ b/src/ui/designer/QGCToolWidget.h
@@ -0,0 +1,45 @@
+#ifndef QGCTOOLWIDGET_H
+#define QGCTOOLWIDGET_H
+
+#include <QWidget>
+#include <QAction>
+#include <QVBoxLayout>
+
+#include "UAS.h"
+
+namespace Ui {
+    class QGCToolWidget;
+}
+
+class QGCToolWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit QGCToolWidget(QWidget *parent = 0);
+    ~QGCToolWidget();
+
+public slots:
+    void addUAS(UASInterface* uas);
+
+protected:
+    QAction* addParamAction;
+    QAction* addButtonAction;
+    QAction* setTitleAction;
+    QVBoxLayout* toolLayout;
+    UAS* mav;
+
+    void contextMenuEvent(QContextMenuEvent* event);
+    void createActions();
+
+protected slots:
+    void addParam();
+    void addAction();
+    void setTitle();
+
+
+private:
+    Ui::QGCToolWidget *ui;
+};
+
+#endif // QGCTOOLWIDGET_H
diff --git a/src/ui/designer/QGCToolWidget.ui b/src/ui/designer/QGCToolWidget.ui
new file mode 100644
index 0000000..212fe67
--- /dev/null
+++ b/src/ui/designer/QGCToolWidget.ui
@@ -0,0 +1,21 @@
+<ui version="4.0">
+ <author/>
+ <comment/>
+ <exportmacro/>
+ <class>QGCToolWidget</class>
+ <widget class="QWidget" name="QGCToolWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+ </widget>
+ <pixmapfunction/>
+ <connections/>
+</ui>
diff --git a/src/ui/designer/QGCToolWidgetItem.cc b/src/ui/designer/QGCToolWidgetItem.cc
new file mode 100644
index 0000000..b1f9559
--- /dev/null
+++ b/src/ui/designer/QGCToolWidgetItem.cc
@@ -0,0 +1,37 @@
+#include "QGCToolWidgetItem.h"
+
+#include <QMenu>
+#include <QContextMenuEvent>
+
+QGCToolWidgetItem::QGCToolWidgetItem(QWidget *parent) :
+    QWidget(parent),
+    isInEditMode(false),
+    _component(-1)
+{
+    startEditAction = new QAction("Edit Slider", this);
+    connect(startEditAction, SIGNAL(triggered()), this, SLOT(startEditMode()));
+    stopEditAction = new QAction("Finish Editing Slider", this);
+    connect(stopEditAction, SIGNAL(triggered()), this, SLOT(endEditMode()));
+
+    endEditMode();
+}
+
+QGCToolWidgetItem::~QGCToolWidgetItem()
+{
+    delete startEditAction;
+    delete stopEditAction;
+}
+
+void QGCToolWidgetItem::contextMenuEvent (QContextMenuEvent* event)
+{
+    QMenu menu(this);
+    if (!isInEditMode)
+    {
+        menu.addAction(startEditAction);
+    }
+    else
+    {
+        menu.addAction(stopEditAction);
+    }
+    menu.exec(event->globalPos());
+}
diff --git a/src/ui/designer/QGCToolWidgetItem.h b/src/ui/designer/QGCToolWidgetItem.h
new file mode 100644
index 0000000..2577f43
--- /dev/null
+++ b/src/ui/designer/QGCToolWidgetItem.h
@@ -0,0 +1,32 @@
+#ifndef QGCTOOLWIDGETITEM_H
+#define QGCTOOLWIDGETITEM_H
+
+#include <QWidget>
+#include <QAction>
+
+class QGCToolWidgetItem : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit QGCToolWidgetItem(QWidget *parent = 0);
+    ~QGCToolWidgetItem();
+
+    int component() {return _component;}
+
+public slots:
+    virtual void startEditMode() {}
+    virtual void endEditMode() {}
+    virtual void setComponent(int comp) {_component = comp;}
+
+protected:
+    QAction* startEditAction;
+    QAction* stopEditAction;
+
+    bool isInEditMode;
+    int _component;          ///< The MAV component (the process or device ID)
+
+    void contextMenuEvent (QContextMenuEvent* event);
+
+};
+
+#endif // QGCTOOLWIDGETITEM_H