diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index fcf375d399d2fe112f6ea55d17a8d4911f4853c8..e8940419a76eaef6b6f2ea33248f963c7b5f268c 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -301,7 +301,8 @@ FORMS += src/ui/MainWindow.ui \ src/ui/configuration/ApmFirmwareConfig.ui \ src/ui/px4_configuration/QGCPX4AirframeConfig.ui \ src/ui/px4_configuration/QGCPX4MulticopterConfig.ui \ - src/ui/px4_configuration/QGCPX4SensorCalibration.ui + src/ui/px4_configuration/QGCPX4SensorCalibration.ui \ + src/ui/designer/QGCXYPlot.ui INCLUDEPATH += src \ src/ui \ @@ -449,7 +450,6 @@ HEADERS += src/MG.h \ src/ui/designer/QGCComboBox.h \ src/ui/designer/QGCTextLabel.h \ src/ui/submainwindow.h \ - src/ui/dockwidgettitlebareventfilter.h \ src/ui/uas/UASQuickView.h \ src/ui/uas/UASQuickViewItem.h \ src/ui/linechart/ChartPlot.h \ @@ -507,7 +507,8 @@ HEADERS += src/MG.h \ src/ui/QGCBaseParamWidget.h \ src/ui/px4_configuration/QGCPX4MulticopterConfig.h \ src/ui/px4_configuration/QGCPX4SensorCalibration.h \ - src/ui/dockwidgeteventfilter.h + src/ui/designer/QGCXYPlot.h \ + src/ui/menuactionhelper.h # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::HEADERS += src/ui/map3D/QGCGoogleEarthView.h @@ -672,7 +673,6 @@ SOURCES += src/main.cc \ src/ui/designer/QGCComboBox.cc \ src/ui/designer/QGCTextLabel.cc \ src/ui/submainwindow.cpp \ - src/ui/dockwidgettitlebareventfilter.cpp \ src/ui/uas/UASQuickViewItem.cc \ src/ui/uas/UASQuickView.cc \ src/ui/linechart/ChartPlot.cc \ @@ -730,7 +730,8 @@ SOURCES += src/main.cc \ src/ui/QGCBaseParamWidget.cc \ src/ui/px4_configuration/QGCPX4MulticopterConfig.cc \ src/ui/px4_configuration/QGCPX4SensorCalibration.cc \ - src/ui/dockwidgeteventfilter.cpp + src/ui/designer/QGCXYPlot.cc \ + src/ui/menuactionhelper.cpp # Enable Google Earth only on Mac OS and Windows with Visual Studio compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += src/ui/map3D/QGCGoogleEarthView.cc diff --git a/src/ui/HDDisplay.cc b/src/ui/HDDisplay.cc index 7c11cd86bd8b5bcc2c736fc9689a1f3974f68280..d3c12290aacc01b6db03377f51cc1f29d95e76aa 100644 --- a/src/ui/HDDisplay.cc +++ b/src/ui/HDDisplay.cc @@ -27,7 +27,7 @@ #include "MainWindow.h" #include -HDDisplay::HDDisplay(QStringList* plotList, QString title, QWidget *parent) : +HDDisplay::HDDisplay(const QStringList &plotList, QString title, QWidget *parent) : QGraphicsView(parent), uas(NULL), xCenterOffset(0.0f), @@ -60,11 +60,8 @@ HDDisplay::HDDisplay(QStringList* plotList, QString title, QWidget *parent) : setAutoFillBackground(true); // Add all items in accept list to gauge - if (plotList) { - for(int i = 0; i < plotList->length(); ++i) { - addGauge(plotList->at(i)); - } - } + for(int i = 0; i < plotList.length(); ++i) + addGauge(plotList.at(i)); restoreState(); // Set preferred size diff --git a/src/ui/HDDisplay.h b/src/ui/HDDisplay.h index f6c5295d79edfc53b2c175ce9f1990e9682fffd3..e39090d7c499d1ee674345dfdf6adba954fea5e0 100644 --- a/src/ui/HDDisplay.h +++ b/src/ui/HDDisplay.h @@ -60,7 +60,7 @@ class HDDisplay : public QGraphicsView { Q_OBJECT public: - HDDisplay(QStringList* plotList, QString title="", QWidget *parent = 0); + HDDisplay(const QStringList& plotList, QString title="", QWidget *parent = 0); ~HDDisplay(); public slots: diff --git a/src/ui/HSIDisplay.cc b/src/ui/HSIDisplay.cc index a1e0cc1c89ba1d6950f83463a4bf49b9e3d0ca86..4e05a479a6068578c6d521f623216e916f81289f 100644 --- a/src/ui/HSIDisplay.cc +++ b/src/ui/HSIDisplay.cc @@ -49,7 +49,7 @@ This file is part of the QGROUNDCONTROL project HSIDisplay::HSIDisplay(QWidget *parent) : - HDDisplay(NULL, "HSI", parent), + HDDisplay(QStringList(), "HSI", parent), dragStarted(false), leftDragStarted(false), mouseHasMoved(false), diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index f3d65230bde412ab17311442f5232b7dc04b4bfb..a958dc1ed9f7b27d9abfcb90baa675059ba8f23f 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -39,8 +39,6 @@ This file is part of the QGROUNDCONTROL project #include #include #include -#include "dockwidgettitlebareventfilter.h" -#include "dockwidgeteventfilter.h" #include "QGC.h" #include "MAVLinkSimulationLink.h" #include "SerialLink.h" @@ -72,6 +70,7 @@ This file is part of the QGROUNDCONTROL project #include #include "SerialSettingsDialog.h" #include "terminalconsole.h" +#include "menuactionhelper.h" #ifdef QGC_OSG_ENABLED #include "Q3DWidgetFactory.h" @@ -128,12 +127,12 @@ MainWindow::MainWindow(QWidget *parent): autoReconnect(false), simulationLink(NULL), lowPowerMode(false), - isAdvancedMode(false), mavlink(new MAVLinkProtocol()), - dockWidgetTitleBarEnabled(true), - customMode(CUSTOM_MODE_NONE) + customMode(CUSTOM_MODE_NONE), + menuActionHelper(new MenuActionHelper()) { this->setAttribute(Qt::WA_DeleteOnClose); + connect(menuActionHelper, SIGNAL(needToShowDockWidget(QString,bool)),SLOT(showDockWidget(QString,bool))); //TODO: move protocol outside UI connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection); loadSettings(); @@ -155,7 +154,7 @@ void MainWindow::init() if (settings.contains("ADVANCED_MODE")) { - isAdvancedMode = settings.value("ADVANCED_MODE").toBool(); + menuActionHelper->setAdvancedMode(settings.value("ADVANCED_MODE").toBool()); } if (!settings.contains("CURRENT_VIEW")) @@ -182,6 +181,7 @@ void MainWindow::init() // Setup user interface ui.setupUi(this); hide(); + menuActionHelper->setMenu(ui.menuTools); // We only need this menu if we have more than one system // ui.menuConnected_Systems->setEnabled(false); @@ -386,12 +386,8 @@ MainWindow::~MainWindow() } } // Delete all UAS objects - - - if (debugConsole) - { - delete debugConsole; - } + delete debugConsole; + delete menuActionHelper; for (int i=0;ideleteLater(); @@ -439,17 +435,6 @@ void MainWindow::buildCustomWidget() QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); - /*QDockWidget* dock = new QDockWidget(tool->windowTitle(), this); - dock->setObjectName(tool->objectName()+"_DOCK"); - dock->setWidget(tool); - connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater())); - QAction* showAction = new QAction(widgets.at(i)->windowTitle(), this); - showAction->setCheckable(true); - connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool))); - connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool))); - widgets.at(i)->setMainMenuAction(showAction); - ui.menuTools->addAction(showAction);*/ - // Load dock widget location (default is bottom) Qt::DockWidgetArea location = tool->getDockWidgetArea(currentView); @@ -495,6 +480,8 @@ void MainWindow::buildCommonWidgets() { // Add generic MAVLink decoder mavlinkDecoder = new MAVLinkDecoder(mavlink, this); + connect(mavlinkDecoder, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), + this, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64))); // Log player logPlayer = new QGCMAVLinkLogPlayer(mavlink, customStatusBar); @@ -577,36 +564,19 @@ void MainWindow::buildCommonWidgets() } // Dock widgets - QAction* tempAction = ui.menuTools->addAction(tr("Control")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - createDockWidget(simView,new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",VIEW_SIMULATION,Qt::LeftDockWidgetArea); createDockWidget(plannerView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_MISSION,Qt::LeftDockWidgetArea); createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea); - { - //createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea); - QAction* tempAction = ui.menuTools->addAction(tr("Mission Plan")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - menuToDockNameMap[tempAction] = "WAYPOINT_LIST_DOCKWIDGET"; - } - createDockWidget(simView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea); createDockWidget(engineeringView,new QGCMAVLinkInspector(mavlink,this),tr("MAVLink Inspector"),"MAVLINK_INSPECTOR_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea); createDockWidget(engineeringView,new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea); createDockWidget(simView,new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea); + menuActionHelper->createToolAction(tr("Status Details"), "UAS_STATUS_DETAILS_DOCKWIDGET"); - { - QAction* tempAction = ui.menuTools->addAction(tr("Status Details")); - menuToDockNameMap[tempAction] = "UAS_STATUS_DETAILS_DOCKWIDGET"; - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - } { if (!debugConsole) { @@ -614,40 +584,22 @@ void MainWindow::buildCommonWidgets() debugConsole->setWindowTitle("Communications Console"); debugConsole->hide(); QAction* tempAction = ui.menuTools->addAction(tr("Communication Console")); - //menuToDockNameMap[tempAction] = "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET"; tempAction->setCheckable(true); connect(tempAction,SIGNAL(triggered(bool)),debugConsole,SLOT(setShown(bool))); - } } createDockWidget(simView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea); - { - QAction* tempAction = ui.menuTools->addAction(tr("Flight Display")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - menuToDockNameMap[tempAction] = "HEAD_DOWN_DISPLAY_1_DOCKWIDGET"; - } - - { - QAction* tempAction = ui.menuTools->addAction(tr("Actuator Status")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - menuToDockNameMap[tempAction] = "HEAD_DOWN_DISPLAY_2_DOCKWIDGET"; - } - - { - QAction* tempAction = ui.menuTools->addAction(tr("Radio Control")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - } + menuActionHelper->createToolAction(tr("Flight Display"), "HEAD_DOWN_DISPLAY_1_DOCKWIDGET"); + menuActionHelper->createToolAction(tr("Actuator Status"), "HEAD_DOWN_DISPLAY_2_DOCKWIDGET"); + menuActionHelper->createToolAction(tr("Radio Control")); - createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5); + createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,QSize(this->width()/1.5,0)); - createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5); + createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,QSize(this->width()/1.5,0)); - createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5); - createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8); + createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,QSize(this->width()/1.5,0)); + createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,QSize(this->width()/1.8,0)); QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this); infoview->addSource(mavlinkDecoder); @@ -730,83 +682,40 @@ void MainWindow::buildCommonWidgets() void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area) { - QList actionlist = ui.menuTools->actions(); - bool found = false; - QAction *targetAction; - for (int i=0;itext() == title) - { - found = true; - targetAction = actionlist[i]; - } - } - if (!found) - { - QAction* tempAction = ui.menuTools->addAction(title); - tempAction->setCheckable(true); - menuToDockNameMap[tempAction] = widget->objectName(); - if (!centralWidgetToDockWidgetsMap.contains(view)) - { - centralWidgetToDockWidgetsMap[view] = QMap(); - } - centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget; - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool))); - connect(widget, SIGNAL(destroyed()), tempAction, SLOT(deleteLater())); - tempAction->setChecked(widget->isVisible()); - } - else - { - if (!menuToDockNameMap.contains(targetAction)) - { - menuToDockNameMap[targetAction] = widget->objectName(); - //menuToDockNameMap[targetAction] = title; - } - if (!centralWidgetToDockWidgetsMap.contains(view)) - { - centralWidgetToDockWidgetsMap[view] = QMap(); - } - centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget; - connect(widget, SIGNAL(visibilityChanged(bool)), targetAction, SLOT(setChecked(bool))); - } + menuActionHelper->createToolActionForCustomDockWidget(title, widget->objectName(), widget, view); parent->addDockWidget(area,widget); } -QDockWidget* MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight) +QDockWidget* MainWindow::createDockWidget(QWidget *subMainWindowParent,QWidget *child,const QString& title,const QString& objectName,VIEW_SECTIONS view,Qt::DockWidgetArea area,const QSize& minSize) { - child->setObjectName(objectname); - QDockWidget *widget = new QDockWidget(title,this); - dockWidgets.append(widget); - setDockWidgetTitleBar(widget); - widget->setObjectName(child->objectName()); - widget->setWidget(child); - if (minheight != 0 || minwidth != 0) - { - widget->setMinimumHeight(minheight); - widget->setMinimumWidth(minwidth); - } - addTool(qobject_cast(parent),view,widget,title,area); - connect(child, SIGNAL(destroyed()), widget, SLOT(deleteLater())); - connect(widget, SIGNAL(destroyed()), this, SLOT(dockWidgetDestroyed())); + SubMainWindow *parent = qobject_cast(subMainWindowParent); + Q_ASSERT(parent); + QDockWidget* dockWidget = menuActionHelper->createDockWidget(title, objectName); + child->setObjectName(objectName); + dockWidget->setWidget(child); //Set child objectName before setting dockwidget, since the dock widget might react to object name changes + connect(child, SIGNAL(destroyed()), dockWidget, SLOT(deleteLater())); //Our dockwidget only has only child widget, so kill the dock widget if the child is deleted - return widget; + if (minSize.height() >= 0) + dockWidget->setMinimumHeight(minSize.height()); + if (minSize.width() >= 0) + dockWidget->setMinimumWidth(minSize.width()); + addTool(parent,view,dockWidget,title,area); + return dockWidget; } -void MainWindow::dockWidgetDestroyed() -{ - QDockWidget *dock = dynamic_cast(QObject::sender()); - Q_ASSERT(dock); - if(!dock) return; - dockWidgets.removeAll(dock); +void MainWindow::showDockWidget(const QString& name, bool show) +{ + QDockWidget *dockWidget = menuActionHelper->getDockWidget(currentView, name); + if(dockWidget) + dockWidget->setVisible(show); + else if (show) + loadDockWidget(name); } -void MainWindow::loadDockWidget(QString name) +void MainWindow::loadDockWidget(const QString& name) { - if (centralWidgetToDockWidgetsMap[currentView].contains(name)) - { + if(menuActionHelper->containsDockWidget(currentView, name)) return; - } if (name.startsWith("HIL_CONFIG")) { //It's a HIL widget. @@ -839,8 +748,6 @@ void MainWindow::loadDockWidget(QString name) else if (name == "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET") { //This is now a permanently detached window. - //centralWidgetToDockWidgetsMap[currentView][name] = console; - //createDockWidget(centerStack->currentWidget(),new DebugConsole(this),tr("Communication Console"),"COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea); } else if (name == "HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET") { @@ -848,21 +755,19 @@ void MainWindow::loadDockWidget(QString name) } else if (name == "HEAD_DOWN_DISPLAY_1_DOCKWIDGET") { - //FIXME: memory of acceptList will never be freed again - QStringList* acceptList = new QStringList(); - acceptList->append("-3.3,ATTITUDE.roll,rad,+3.3,s"); - acceptList->append("-3.3,ATTITUDE.pitch,deg,+3.3,s"); - acceptList->append("-3.3,ATTITUDE.yaw,deg,+3.3,s"); + QStringList acceptList; + acceptList.append("-3.3,ATTITUDE.roll,rad,+3.3,s"); + acceptList.append("-3.3,ATTITUDE.pitch,deg,+3.3,s"); + acceptList.append("-3.3,ATTITUDE.yaw,deg,+3.3,s"); HDDisplay *hddisplay = new HDDisplay(acceptList,"Flight Display",this); hddisplay->addSource(mavlinkDecoder); createDockWidget(centerStack->currentWidget(),hddisplay,tr("Flight Display"),"HEAD_DOWN_DISPLAY_1_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } else if (name == "HEAD_DOWN_DISPLAY_2_DOCKWIDGET") { - //FIXME: memory of acceptList2 will never be freed again - QStringList* acceptList2 = new QStringList(); - acceptList2->append("0,RAW_PRESSURE.pres_abs,hPa,65500"); - HDDisplay *hddisplay = new HDDisplay(acceptList2,"Actuator Status",this); + QStringList acceptList; + acceptList.append("0,RAW_PRESSURE.pres_abs,hPa,65500"); + HDDisplay *hddisplay = new HDDisplay(acceptList,"Actuator Status",this); hddisplay->addSource(mavlinkDecoder); createDockWidget(centerStack->currentWidget(),hddisplay,tr("Actuator Status"),"HEAD_DOWN_DISPLAY_2_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } @@ -873,7 +778,6 @@ void MainWindow::loadDockWidget(QString name) } else if (name == "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET") { - // createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Head Up Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); createDockWidget(centerStack->currentWidget(),new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET") @@ -894,80 +798,6 @@ void MainWindow::loadDockWidget(QString name) } } -void MainWindow::setDockWidgetTitleBar(QDockWidget* widget) -{ - QWidget* oldTitleBar = widget->titleBarWidget(); - - // In advanced mode, we use the default titlebar provided by Qt. - if (isAdvancedMode) - { - widget->setTitleBarWidget(0); - } - // Otherwise, if just a textlabel should be shown, make that the titlebar. - else if (dockWidgetTitleBarEnabled) - { - QLabel* label = new QLabel(this); - label->setText(widget->windowTitle()); - label->installEventFilter(new DockWidgetTitleBarEventFilter()); //Ignore mouse clicks - widget->installEventFilter(new DockWidgetEventFilter()); //Update label if window title changes - widget->setTitleBarWidget(label); - } - // And if nothing should be shown, use an empty widget. - else - { - QWidget* newTitleBar = new QWidget(this); - widget->setTitleBarWidget(newTitleBar); - } - - // Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(), - // it doesn't delete the old titlebar object. - if (oldTitleBar) - { - delete oldTitleBar; - } -} - -void MainWindow::showTool(bool show) -{ - //Called when a menu item is clicked on, regardless of view. - - QAction* act = qobject_cast(sender()); - if (menuToDockNameMap.contains(act)) - { - QString name = menuToDockNameMap[act]; - if (centralWidgetToDockWidgetsMap.contains(currentView)) - { - if (centralWidgetToDockWidgetsMap[currentView].contains(name)) - { - if (show) - { - centralWidgetToDockWidgetsMap[currentView][name]->show(); - } - else - { - centralWidgetToDockWidgetsMap[currentView][name]->hide(); - } - } - else if (show) - { - loadDockWidget(name); - } - } - } - //QWidget* widget = qVariantValue(act->data()); - //widget->setVisible(show); -} -/*void addToolByName(QString name,SubMainWindow parent,const QString& title, Qt::DockWidgetArea area) -{ - if (name == "Control") - { - QDockWidget *widget = new QDockWidget(tr("Control"),this); - dockToTitleBarMap[widget] = widget->titleBarWidget(); - widget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET"); - widget->setWidget(new UASControlWidget(this)); - addTool(parent,VIEW_SIMULATION,widget,tr("Control"),area); - } -}*/ void MainWindow::addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSection, const QString& title) { Q_UNUSED(title); @@ -977,7 +807,6 @@ void MainWindow::addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSe if (centerStack->indexOf(widget) == -1) { centerStack->addWidget(widget); - centralWidgetToDockWidgetsMap[viewSection] = QMap(); } } @@ -996,18 +825,11 @@ void MainWindow::showHILConfigurationWidget(UASInterface* uas) if (mav && !hilDocks.contains(mav->getUASID())) { - //QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool " + QString::number(ui.menuTools->actions().size())); - //createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea); - QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this); QString hilDockName = tr("HIL Config %1").arg(uas->getUASName()); - QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockName.toUpper().replace(" ", "_"),VIEW_SIMULATION,Qt::LeftDockWidgetArea); + QString hilDockObjectName = QString("HIL_CONFIG_%1").arg(uas->getUASName().toUpper().replace(' ','_')); + QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockObjectName,VIEW_SIMULATION,Qt::LeftDockWidgetArea); hilDocks.insert(mav->getUASID(), hilDock); - - // if (currentView != VIEW_SIMULATION) - // hilDock->hide(); - // else - // hilDock->show(); } } @@ -1035,33 +857,28 @@ void MainWindow::connectCommonWidgets() void MainWindow::createCustomWidget() { - //void MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight) - //QDockWidget* dock = new QDockWidget("Unnamed Tool", this); - if (QGCToolWidget::instances()->isEmpty()) { // This is the first widget ui.menuTools->addSeparator(); } - QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool " + QString::number(ui.menuTools->actions().size())); - createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea); - //tool->setObjectName("UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())); + QString objectName; + int customToolIndex = 0; + //Find the next unique object name that we can use + do { + ++customToolIndex; + objectName = QString("CUSTOM_TOOL_%1").arg(customToolIndex) + "DOCK"; + } while(QGCToolWidget::instances()->contains(objectName)); + + QString title = tr("Custom Tool %1").arg(customToolIndex ); + + QGCToolWidget* tool = new QGCToolWidget(objectName, title); + createDockWidget(centerStack->currentWidget(),tool,title,objectName,currentView,Qt::BottomDockWidgetArea); + QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); settings.setValue(QString("TOOL_PARENT_") + tool->objectName(),currentView); settings.endGroup(); - - //connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater())); - //dock->setWidget(tool); - - //QAction* showAction = new QAction(tool->getTitle(), this); - //showAction->setCheckable(true); - //connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool))); - //connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool))); - //tool->setMainMenuAction(showAction); - //ui.menuTools->addAction(showAction); - //this->addDockWidget(Qt::BottomDockWidgetArea, dock); - //dock->setVisible(true); } void MainWindow::loadCustomWidget() @@ -1072,7 +889,7 @@ void MainWindow::loadCustomWidget() } void MainWindow::loadCustomWidget(const QString& fileName, int view) { - QGCToolWidget* tool = new QGCToolWidget("", this); + QGCToolWidget* tool = new QGCToolWidget("", "", this); if (tool->loadSettings(fileName, true)) { qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName(); @@ -1091,16 +908,12 @@ void MainWindow::loadCustomWidget(const QString& fileName, int view) createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); break; default: - { + { //Delete tool, create menu item to tie it to. customWidgetNameToFilenameMap[tool->objectName()+"DOCK"] = fileName; - QAction* tempAction = ui.menuTools->addAction(tool->getTitle()); - menuToDockNameMap[tempAction] = tool->objectName()+"DOCK"; - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); + menuActionHelper->createToolAction(tool->getTitle(), tool->objectName()+"DOCK"); tool->deleteLater(); - //createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - } + } break; } } @@ -1112,7 +925,7 @@ void MainWindow::loadCustomWidget(const QString& fileName, int view) void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance) { - QGCToolWidget* tool = new QGCToolWidget("", this); + QGCToolWidget* tool = new QGCToolWidget("", "", this); if (tool->loadSettings(fileName, true) || !singleinstance) { qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName(); @@ -1136,35 +949,18 @@ void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance) createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); break; default: - { + { //Delete tool, create menu item to tie it to. customWidgetNameToFilenameMap[tool->objectName()+"DOCK"] = fileName; - QAction* tempAction = ui.menuTools->addAction(tool->getTitle()); - menuToDockNameMap[tempAction] = tool->objectName()+"DOCK"; - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); + QAction *action = menuActionHelper->createToolAction(tool->getTitle(), tool->objectName()+"DOCK"); + ui.menuTools->addAction(action); tool->deleteLater(); - //createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - } + } break; } settings.endGroup(); - // Add widget to UI - /*QDockWidget* dock = new QDockWidget(tool->getTitle(), this); - connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater())); - dock->setWidget(tool); - tool->setParent(dock); - - QAction* showAction = new QAction(tool->getTitle(), this); - showAction->setCheckable(true); - connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool))); - connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool))); - tool->setMainMenuAction(showAction); - ui.menuTools->addAction(showAction); - this->addDockWidget(Qt::BottomDockWidgetArea, dock); - dock->hide();*/ } else { @@ -1214,7 +1010,7 @@ void MainWindow::loadSettings() darkStyleFileName = settings.value("DARK_STYLE_FILENAME", darkStyleFileName).toString(); lightStyleFileName = settings.value("LIGHT_STYLE_FILENAME", lightStyleFileName).toString(); lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool(); - dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled).toBool(); + bool dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",menuActionHelper->dockWidgetTitleBarsEnabled()).toBool(); settings.endGroup(); enableDockWidgetTitleBars(dockWidgetTitleBarEnabled); } @@ -1241,6 +1037,7 @@ void MainWindow::storeSettings() } settings.setValue("LOW_POWER_MODE", lowPowerMode); settings.setValue("QGC_CUSTOM_MODE", (int)customMode); + QGCToolWidget::storeWidgetsToSettings(settings); settings.sync(); } @@ -1308,17 +1105,12 @@ void MainWindow::saveScreen() } void MainWindow::enableDockWidgetTitleBars(bool enabled) { - dockWidgetTitleBarEnabled = enabled; + menuActionHelper->setDockWidgetTitleBarsEnabled(enabled); QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); - settings.setValue("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled); + settings.setValue("DOCK_WIDGET_TITLEBARS",enabled); settings.endGroup(); settings.sync(); - - for (int i = 0; i < dockWidgets.size(); i++) - { - setDockWidgetTitleBar(dockWidgets[i]); - } } void MainWindow::enableAutoReconnect(bool enabled) @@ -1355,7 +1147,6 @@ bool MainWindow::loadStyle(QGC_MAINWINDOW_STYLE style, QString cssFile) // And trigger any changes to other UI elements that are watching for // theme changes. emit styleChanged(style); - emit styleChanged(); // Finally restore the cursor before returning. qApp->restoreOverrideCursor(); @@ -1488,8 +1279,8 @@ void MainWindow::connectCommonActions() // Connect actions from ui connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink())); - ui.actionAdvanced_Mode->setChecked(isAdvancedMode); - connect(ui.actionAdvanced_Mode,SIGNAL(triggered()),this,SLOT(setAdvancedMode())); + ui.actionAdvanced_Mode->setChecked(menuActionHelper->isAdvancedMode()); + connect(ui.actionAdvanced_Mode,SIGNAL(toggled(bool)),this,SLOT(setAdvancedMode(bool))); // Connect internal actions connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*))); @@ -1852,6 +1643,7 @@ void MainWindow::UASCreated(UASInterface* uas) connect(uas, SIGNAL(systemSpecsChanged(int)), this, SLOT(UASSpecsChanged(int))); + connect(uas, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), this, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64))); // HIL showHILConfigurationWidget(uas); @@ -2085,16 +1877,11 @@ void MainWindow::loadViewState() win->restoreState(settings.value(getWindowStateKey()).toByteArray(), QGC::applicationVersion()); } } -void MainWindow::setAdvancedMode() +void MainWindow::setAdvancedMode(bool isAdvancedMode) { - isAdvancedMode = !isAdvancedMode; + menuActionHelper->setAdvancedMode(isAdvancedMode); ui.actionAdvanced_Mode->setChecked(isAdvancedMode); settings.setValue("ADVANCED_MODE",isAdvancedMode); - - for (int i = 0; i < dockWidgets.size(); i++) - { - setDockWidgetTitleBar(dockWidgets[i]); - } } void MainWindow::loadEngineerView() @@ -2217,11 +2004,16 @@ void MainWindow::loadMAVLinkView() //} -QList MainWindow::listLinkMenuActions(void) +QList MainWindow::listLinkMenuActions() { return ui.menuNetwork->actions(); } +bool MainWindow::dockWidgetTitleBarsEnabled() const +{ + return menuActionHelper->dockWidgetTitleBarsEnabled(); +} + #ifdef MOUSE_ENABLED_LINUX bool MainWindow::x11Event(XEvent *event) { diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index b5a5b50304cde6ce358c402df64054418aaf2884..cc98d0f1678e3493fb2a117bd0b71be18c021f53 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -86,6 +86,7 @@ class QGCStatusBar; class Linecharts; class QGCDataPlot2D; class JoystickWidget; +class MenuActionHelper; /** * @brief Main Application Window @@ -142,41 +143,38 @@ public: static const QString defaultLightStyle; /** @brief Get current visual style */ - QGC_MAINWINDOW_STYLE getStyle() + QGC_MAINWINDOW_STYLE getStyle() const { return currentStyle; } /** @brief Get current light visual stylesheet */ - QString getLightStyleSheet() + QString getLightStyleSheet() const { return lightStyleFileName; } /** @brief Get current dark visual stylesheet */ - QString getDarkStyleSheet() + QString getDarkStyleSheet() const { return darkStyleFileName; } /** @brief Get auto link reconnect setting */ - bool autoReconnectEnabled() + bool autoReconnectEnabled() const { return autoReconnect; } /** @brief Get title bar mode setting */ - bool dockWidgetTitleBarsEnabled() - { - return dockWidgetTitleBarEnabled; - } + bool dockWidgetTitleBarsEnabled() const; /** @brief Get low power mode setting */ - bool lowPowerModeEnabled() + bool lowPowerModeEnabled() const { return lowPowerMode; } - void setCustomMode(enum MainWindow::CUSTOM_MODE mode) + void setCustomMode(MainWindow::CUSTOM_MODE mode) { if (mode != CUSTOM_MODE_UNCHANGED) { @@ -184,12 +182,12 @@ public: } } - enum MainWindow::CUSTOM_MODE getCustomMode() + MainWindow::CUSTOM_MODE getCustomMode() const { return customMode; } - QList listLinkMenuActions(void); + QList listLinkMenuActions(); public slots: /** @brief Shows a status message on the bottom status bar */ @@ -224,7 +222,7 @@ public slots: void saveScreen(); /** @brief Sets advanced mode, allowing for editing of tool widget locations */ - void setAdvancedMode(); + void setAdvancedMode(bool isAdvancedMode); /** @brief Load configuration views */ void loadHardwareConfigView(); void loadSoftwareConfigView(); @@ -283,16 +281,6 @@ public slots: /** @brief Load data view, allowing to plot flight data */ // void loadDataView(QString fileName); - /** - * @brief Shows a Docked Widget based on the action sender - * - * This slot is written to be used in conjunction with the addTool() function - * It shows the QDockedWidget based on the action sender - * - */ - void showTool(bool visible); - - /** * @brief Shows a Widget from the center stack based on the action sender * @@ -308,13 +296,14 @@ public slots: void commsWidgetDestroyed(QObject *obj); protected slots: - /** @brief Called by a dock widget when it is has been deleted */ - void dockWidgetDestroyed(); + void showDockWidget(const QString &name, bool show); signals: void styleChanged(MainWindow::QGC_MAINWINDOW_STYLE newTheme); - void styleChanged(); void initStatusChanged(const QString& message, int alignment, const QColor &color); + /** Emitted when any value changes from any source */ + void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec); + #ifdef MOUSE_ENABLED_LINUX /** @brief Forward X11Event to catch 3DMouse inputs */ void x11EventOccured(XEvent *event); @@ -362,8 +351,9 @@ protected: * @param location The default location for the QDockedWidget in case there is no previous key in the settings */ void addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area); - void loadDockWidget(QString name); - QDockWidget* createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth=0,int minheight=0); + void loadDockWidget(const QString &name); + + QDockWidget* createDockWidget(QWidget *subMainWindowParent,QWidget *child,const QString& title,const QString& objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,const QSize& minSize = QSize()); /** * @brief Adds an already instantiated QWidget to the center stack * @@ -514,11 +504,7 @@ protected: private: QList commsWidgetList; QMap customWidgetNameToFilenameMap; - QMap menuToDockNameMap; - QList dockWidgets; - QMap > centralWidgetToDockWidgetsMap; - bool isAdvancedMode; ///< If enabled dock widgets can be moved and floated. - bool dockWidgetTitleBarEnabled; ///< If enabled, dock widget titlebars are displayed when NOT in advanced mode. + MenuActionHelper *menuActionHelper; Ui::MainWindow ui; /** @brief Set the appropriate titlebar for a given dock widget. @@ -529,6 +515,7 @@ private: QString getWindowStateKey(); QString getWindowGeometryKey(); + friend class MenuActionHelper; //For VIEW_SECTIONS }; #endif /* _MAINWINDOW_H_ */ diff --git a/src/ui/QGCPX4VehicleConfig.cc b/src/ui/QGCPX4VehicleConfig.cc index d2419ec37a383d4c18f45c861176f178b3c1dfbf..3cc3603b794b0e5dee295b8341769fa0c75648ec 100644 --- a/src/ui/QGCPX4VehicleConfig.cc +++ b/src/ui/QGCPX4VehicleConfig.cc @@ -576,7 +576,7 @@ void QGCPX4VehicleConfig::loadQgcConfig(bool primary) { if (file.toLower().endsWith(".qgw")) { QWidget* parent = left?ui->generalLeftContents:ui->generalRightContents; - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget("", "", parent); if (tool->loadSettings(generaldir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -651,7 +651,7 @@ void QGCPX4VehicleConfig::loadQgcConfig(bool primary) foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) { if (file.toLower().endsWith(".qgw")) { - tool = new QGCToolWidget("", tab); + tool = new QGCToolWidget("", "", tab); if (tool->loadSettings(newdir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -698,7 +698,7 @@ void QGCPX4VehicleConfig::loadQgcConfig(bool primary) foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) { if (file.toLower().endsWith(".qgw")) { - tool = new QGCToolWidget("", tab); + tool = new QGCToolWidget("", "", tab); tool->addUAS(mav); if (tool->loadSettings(newdir.absoluteFilePath(file), false)) { @@ -953,10 +953,8 @@ void QGCPX4VehicleConfig::loadConfig() { parent = ui->generalRightContents; } - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget(parametersname, parametersname, parent); tool->addUAS(mav); - tool->setTitle(parametersname); - tool->setObjectName(parametersname); tool->setSettings(genset); QList paramlist = tool->getParamList(); for (int i=0;igeneralRightContents; } - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget(parametersname, parametersname, parent); tool->addUAS(mav); - tool->setTitle(parametersname); - tool->setObjectName(parametersname); tool->setSettings(advset); QList paramlist = tool->getParamList(); for (int i=0;igeneralLeftContents:ui->generalRightContents; - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget("", "", parent); if (tool->loadSettings(generaldir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -291,7 +291,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) { if (file.toLower().endsWith(".qgw")) { QWidget* parent = left?ui->advancedLeftContents:ui->advancedRightContents; - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget("", "", parent); if (tool->loadSettings(vehicledir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -342,7 +342,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) { if (file.toLower().endsWith(".qgw")) { - tool = new QGCToolWidget("", tab); + tool = new QGCToolWidget("", "", tab); if (tool->loadSettings(newdir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -389,7 +389,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) { if (file.toLower().endsWith(".qgw")) { - tool = new QGCToolWidget("", tab); + tool = new QGCToolWidget("","", tab); tool->addUAS(mav); if (tool->loadSettings(newdir.absoluteFilePath(file), false)) { @@ -411,7 +411,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) // Load general calibration for autopilot //TODO: Handle this more gracefully, maybe have it scan the directory for multiple calibration entries? - tool = new QGCToolWidget("", ui->sensorContents); + tool = new QGCToolWidget("", "", ui->sensorContents); tool->addUAS(mav); if (tool->loadSettings(autopilotdir.absolutePath() + "/general/calibration/calibration.qgw", false)) { @@ -426,7 +426,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) } // Load vehicle-specific autopilot configuration - tool = new QGCToolWidget("", ui->sensorContents); + tool = new QGCToolWidget("", "", ui->sensorContents); tool->addUAS(mav); if (tool->loadSettings(autopilotdir.absolutePath() + "/" + mav->getSystemTypeName().toLower() + "/calibration/calibration.qgw", false)) { @@ -681,10 +681,8 @@ void QGCVehicleConfig::loadConfig() { parent = ui->generalRightContents; } - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget(parametersname, parametersname, parent); tool->addUAS(mav); - tool->setTitle(parametersname); - tool->setObjectName(parametersname); tool->setSettings(genset); QList paramlist = tool->getParamList(); for (int i=0;igeneralRightContents; } - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget(parametersname, parametersname, parent); tool->addUAS(mav); - tool->setTitle(parametersname); - tool->setObjectName(parametersname); tool->setSettings(advset); QList paramlist = tool->getParamList(); for (int i=0;i 1) { tooltitle = parameterName.split("_")[0] + "_"; } - tool->setTitle(tooltitle); - tool->setObjectName(tooltitle); + QGCToolWidget *tool = new QGCToolWidget(tooltitle, tooltitle, parent); //tool->setSettings(set); libParamToWidgetMap.insert(parameterName,tool); toolWidgets.append(tool); diff --git a/src/ui/designer/QGCComboBox.cc b/src/ui/designer/QGCComboBox.cc index c5ae6a4b59dec841ec584f6c8b7379be145d0f96..1b8345bf221afb5a23c5e546fa31b29fd09c0728 100644 --- a/src/ui/designer/QGCComboBox.cc +++ b/src/ui/designer/QGCComboBox.cc @@ -167,70 +167,42 @@ void QGCComboBox::selectParameter(int paramIndex) } } -void QGCComboBox::startEditMode() +void QGCComboBox::setEditMode(bool editMode) { - ui->nameLabel->hide(); - ui->writeButton->hide(); - ui->readButton->hide(); - - ui->editInfoCheckBox->show(); - ui->editDoneButton->show(); - ui->editNameLabel->show(); - ui->editRefreshParamsButton->show(); - ui->editSelectParamComboBox->show(); - ui->editSelectComponentComboBox->show(); - ui->editStatusLabel->show(); - ui->writeButton->hide(); - ui->readButton->hide(); - ui->editLine1->show(); - ui->editLine2->show(); - ui->editAddItemButton->show(); - ui->editRemoveItemButton->show(); - ui->editItemValueSpinBox->show(); - ui->editItemNameLabel->show(); - ui->itemValueLabel->show(); - ui->itemNameLabel->show(); - if (isDisabled) - { - ui->editOptionComboBox->setEnabled(true); + if(!editMode) { + // Store component id + selectComponent(ui->editSelectComponentComboBox->currentIndex()); + // Store parameter name and id + selectParameter(ui->editSelectParamComboBox->currentIndex()); } - isInEditMode = true; -} - -void QGCComboBox::endEditMode() -{ - // Store component id - selectComponent(ui->editSelectComponentComboBox->currentIndex()); - // Store parameter name and id - selectParameter(ui->editSelectParamComboBox->currentIndex()); - - // Min/max - - ui->editInfoCheckBox->hide(); - ui->editDoneButton->hide(); - ui->editNameLabel->hide(); - ui->editRefreshParamsButton->hide(); - ui->editSelectParamComboBox->hide(); - ui->editSelectComponentComboBox->hide(); - ui->editStatusLabel->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - ui->writeButton->show(); - ui->readButton->show(); - ui->editAddItemButton->hide(); - ui->editRemoveItemButton->hide(); - ui->editItemValueSpinBox->hide(); - ui->editItemNameLabel->hide(); - ui->itemValueLabel->hide(); - ui->itemNameLabel->hide(); - ui->nameLabel->show(); + ui->nameLabel->setVisible(!editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + + ui->editInfoCheckBox->setVisible(editMode); + ui->editDoneButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editRefreshParamsButton->setVisible(editMode); + ui->editSelectParamComboBox->setVisible(editMode); + ui->editSelectComponentComboBox->setVisible(editMode); + ui->editStatusLabel->setVisible(editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + ui->editAddItemButton->setVisible(editMode); + ui->editRemoveItemButton->setVisible(editMode); + ui->editItemValueSpinBox->setVisible(editMode); + ui->editItemNameLabel->setVisible(editMode); + ui->itemValueLabel->setVisible(editMode); + ui->itemNameLabel->setVisible(editMode); if (isDisabled) { - ui->editOptionComboBox->setEnabled(false); + ui->editOptionComboBox->setEnabled(editMode); } - isInEditMode = false; - emit editingFinished(); + + QGCToolWidgetItem::setEditMode(editMode); } void QGCComboBox::setParamPending() diff --git a/src/ui/designer/QGCComboBox.h b/src/ui/designer/QGCComboBox.h index 9b4b9c68a54f3cd2d93a5d33b3250c5d67821330..c81a636feeefdbb5065e2325c5959a5b78a8462e 100644 --- a/src/ui/designer/QGCComboBox.h +++ b/src/ui/designer/QGCComboBox.h @@ -22,9 +22,9 @@ public: explicit QGCComboBox(QWidget *parent = 0); ~QGCComboBox(); + virtual void setEditMode(bool editMode) override; + public slots: - void startEditMode(); - void endEditMode(); /** @brief Queue parameter for sending to the MAV (add to pending list)*/ void setParamPending(); /** @brief Update the UI with the new parameter value */ diff --git a/src/ui/designer/QGCCommandButton.cc b/src/ui/designer/QGCCommandButton.cc index 24bdc7d37e3fa9b1ba73e6e80a5b32b2ea29aae2..69efc00607f7efc6ef897206c3d5e12624353cae 100644 --- a/src/ui/designer/QGCCommandButton.cc +++ b/src/ui/designer/QGCCommandButton.cc @@ -159,93 +159,33 @@ void QGCCommandButton::setCommandButtonName(QString text) ui->commandButton->setText(text); } -void QGCCommandButton::startEditMode() +void QGCCommandButton::setEditMode(bool editMode) { // Hide elements - ui->commandButton->hide(); - ui->nameLabel->hide(); - - ui->editCommandComboBox->blockSignals(false); - ui->editCommandComboBox->show(); - ui->editFinishButton->show(); - ui->editNameLabel->show(); - ui->editButtonName->show(); - ui->editConfirmationCheckBox->show(); - ui->editComponentSpinBox->show(); - ui->editParamsVisibleCheckBox->show(); - ui->editParam1SpinBox->show(); - ui->editParam2SpinBox->show(); - ui->editParam3SpinBox->show(); - ui->editParam4SpinBox->show(); - ui->editParam5SpinBox->show(); - ui->editParam6SpinBox->show(); - ui->editParam7SpinBox->show(); - ui->editLine1->show(); - ui->editLine2->show(); - - // Attempt to undock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(true); - break; - } - } while (p && !dock); - - isInEditMode = true; -} - -void QGCCommandButton::endEditMode() -{ - ui->editCommandComboBox->blockSignals(true); - ui->editCommandComboBox->hide(); - ui->editFinishButton->hide(); - ui->editNameLabel->hide(); - ui->editButtonName->hide(); - ui->editConfirmationCheckBox->hide(); - ui->editComponentSpinBox->hide(); - ui->editParamsVisibleCheckBox->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - if (!ui->editParamsVisibleCheckBox->isChecked()) - { - ui->editParam1SpinBox->hide(); - ui->editParam2SpinBox->hide(); - ui->editParam3SpinBox->hide(); - ui->editParam4SpinBox->hide(); - ui->editParam5SpinBox->hide(); - ui->editParam6SpinBox->hide(); - ui->editParam7SpinBox->hide(); - } - - ui->commandButton->show(); - ui->nameLabel->show(); - - // Write to settings - emit editingFinished(); - - // Attempt to dock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(false); - break; - } - } while (p && !dock); - - isInEditMode = false; + ui->commandButton->setVisible(!editMode); + ui->nameLabel->setVisible(!editMode); + + ui->editCommandComboBox->blockSignals(!editMode); + ui->editCommandComboBox->setVisible(editMode); + ui->editFinishButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editButtonName->setVisible(editMode); + ui->editConfirmationCheckBox->setVisible(editMode); + ui->editComponentSpinBox->setVisible(editMode); + ui->editParamsVisibleCheckBox->setVisible(editMode); + bool showParams = editMode || ui->editParamsVisibleCheckBox->isChecked(); + ui->editParam1SpinBox->setVisible(showParams); + ui->editParam2SpinBox->setVisible(showParams); + ui->editParam3SpinBox->setVisible(showParams); + ui->editParam4SpinBox->setVisible(showParams); + ui->editParam5SpinBox->setVisible(showParams); + ui->editParam6SpinBox->setVisible(showParams); + ui->editParam7SpinBox->setVisible(showParams); + + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + + QGCToolWidgetItem::setEditMode(editMode); } void QGCCommandButton::writeSettings(QSettings& settings) diff --git a/src/ui/designer/QGCCommandButton.h b/src/ui/designer/QGCCommandButton.h index 320cc97fbae314bb16de86913f0a9ca9f9d3f20a..a1c858a675995ccbbc0ecee833823bae0ac3e4c0 100644 --- a/src/ui/designer/QGCCommandButton.h +++ b/src/ui/designer/QGCCommandButton.h @@ -18,11 +18,11 @@ public: explicit QGCCommandButton(QWidget *parent = 0); ~QGCCommandButton(); + virtual void setEditMode(bool editMode) override; + public slots: void sendCommand(); void setCommandButtonName(QString text); - void startEditMode(); - void endEditMode(); void writeSettings(QSettings& settings); void readSettings(const QSettings& settings); void readSettings(const QString& pre,const QVariantMap& settings); diff --git a/src/ui/designer/QGCParamSlider.cc b/src/ui/designer/QGCParamSlider.cc index 6331ac7212ae5101fecce37672a8ff915a79b27a..c5f2da52d903d5f7522f13d74111178f749a48dc 100644 --- a/src/ui/designer/QGCParamSlider.cc +++ b/src/ui/designer/QGCParamSlider.cc @@ -207,74 +207,57 @@ void QGCParamSlider::selectParameter(int paramIndex) } } -void QGCParamSlider::startEditMode() +void QGCParamSlider::setEditMode(bool editMode) { - ui->valueSlider->hide(); - ui->doubleValueSpinBox->hide(); - ui->intValueSpinBox->hide(); - ui->nameLabel->hide(); - ui->writeButton->hide(); - ui->readButton->hide(); - - ui->editInfoCheckBox->show(); - ui->editDoneButton->show(); - ui->editNameLabel->show(); - ui->editRefreshParamsButton->show(); - ui->editSelectParamComboBox->show(); - ui->editSelectComponentComboBox->show(); - ui->editStatusLabel->show(); - ui->editMinSpinBox->show(); - ui->editMaxSpinBox->show(); - ui->writeButton->hide(); - ui->readButton->hide(); - ui->editLine1->show(); - ui->editLine2->show(); - isInEditMode = true; -} + if(!editMode) { + // Store component id + selectComponent(ui->editSelectComponentComboBox->currentIndex()); -void QGCParamSlider::endEditMode() -{ - // Store component id - selectComponent(ui->editSelectComponentComboBox->currentIndex()); + // Store parameter name and id + selectParameter(ui->editSelectParamComboBox->currentIndex()); - // Store parameter name and id - selectParameter(ui->editSelectParamComboBox->currentIndex()); - - // Min/max - parameterMin = ui->editMinSpinBox->value(); - parameterMax = ui->editMaxSpinBox->value(); + // Min/max + parameterMin = ui->editMinSpinBox->value(); + parameterMax = ui->editMaxSpinBox->value(); - ui->editInfoCheckBox->hide(); - ui->editDoneButton->hide(); - ui->editNameLabel->hide(); - ui->editRefreshParamsButton->hide(); - ui->editSelectParamComboBox->hide(); - ui->editSelectComponentComboBox->hide(); - ui->editStatusLabel->hide(); - ui->editMinSpinBox->hide(); - ui->editMaxSpinBox->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - ui->writeButton->show(); - ui->readButton->show(); - ui->valueSlider->show(); - switch ((int)parameterValue.type()) - { - case QVariant::Char: - case QVariant::Int: - case QVariant::UInt: - ui->intValueSpinBox->show(); - break; - case QMetaType::Float: - ui->doubleValueSpinBox->show(); - break; - default: - qCritical() << "ERROR: NO VALID PARAM TYPE"; - return; + switch ((int)parameterValue.type()) + { + case QVariant::Char: + case QVariant::Int: + case QVariant::UInt: + ui->intValueSpinBox->show(); + break; + case QMetaType::Float: + ui->doubleValueSpinBox->show(); + break; + default: + qCritical() << "ERROR: NO VALID PARAM TYPE"; + return; + } + } else { + ui->doubleValueSpinBox->hide(); + ui->intValueSpinBox->hide(); } - ui->nameLabel->show(); - isInEditMode = false; - emit editingFinished(); + ui->valueSlider->setVisible(!editMode); + ui->nameLabel->setVisible(!editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + + ui->editInfoCheckBox->setVisible(editMode); + ui->editDoneButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editRefreshParamsButton->setVisible(editMode); + ui->editSelectParamComboBox->setVisible(editMode); + ui->editSelectComponentComboBox->setVisible(editMode); + ui->editStatusLabel->setVisible(editMode); + ui->editMinSpinBox->setVisible(editMode); + ui->editMaxSpinBox->setVisible(editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + + QGCToolWidgetItem::setEditMode(editMode); } void QGCParamSlider::setParamPending() diff --git a/src/ui/designer/QGCParamSlider.h b/src/ui/designer/QGCParamSlider.h index 74df0db05ed39547e0deab222262f2c339215800..b5b5862d1464cd060e717fbd0e94a3d2f2b138c1 100644 --- a/src/ui/designer/QGCParamSlider.h +++ b/src/ui/designer/QGCParamSlider.h @@ -20,9 +20,9 @@ public: explicit QGCParamSlider(QWidget *parent = 0); ~QGCParamSlider(); + virtual void setEditMode(bool editMode) override; + public slots: - void startEditMode(); - void endEditMode(); /** @brief Queue parameter for sending to the MAV (add to pending list)*/ void setParamPending(); /** @brief Set the slider value as parameter value */ diff --git a/src/ui/designer/QGCRadioChannelDisplay.h b/src/ui/designer/QGCRadioChannelDisplay.h index 59bb65438aa0a1edc5638d2c25a16452ad203468..2b90a946f5f595c1d3f7a761b092d122d1119165 100644 --- a/src/ui/designer/QGCRadioChannelDisplay.h +++ b/src/ui/designer/QGCRadioChannelDisplay.h @@ -20,6 +20,7 @@ public: int value() { return m_value; } int min() { return m_min; } int max() { return m_max; } + protected: void paintEvent(QPaintEvent *event); private: diff --git a/src/ui/designer/QGCTextLabel.cc b/src/ui/designer/QGCTextLabel.cc index ceb645ffcf27ac3189103e9f0d709c8cd2432ef3..0a74c9d7f4b689b98b78dcf3df9cd32749d8420f 100644 --- a/src/ui/designer/QGCTextLabel.cc +++ b/src/ui/designer/QGCTextLabel.cc @@ -31,61 +31,17 @@ QGCTextLabel::~QGCTextLabel() delete ui; } -void QGCTextLabel::startEditMode() +void QGCTextLabel::setEditMode(bool editMode) { - // Hide elements - ui->editFinishButton->show(); - ui->editNameLabel->show(); - ui->editLine1->show(); - ui->editLine2->show(); - ui->isMavCommand->show(); - - // Attempt to undock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(true); - break; - } - } while (p && !dock); - - isInEditMode = true; -} - -void QGCTextLabel::endEditMode() -{ - update_isMavCommand(); - ui->editFinishButton->hide(); - ui->editNameLabel->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - ui->isMavCommand->hide(); - - // Write to settings - emit editingFinished(); - - // Attempt to dock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(false); - break; - } - } while (p && !dock); - - isInEditMode = false; + if(!editMode) + update_isMavCommand(); + ui->editFinishButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + ui->isMavCommand->setVisible(editMode); + + QGCToolWidgetItem::setEditMode(editMode); } void QGCTextLabel::writeSettings(QSettings& settings) diff --git a/src/ui/designer/QGCTextLabel.h b/src/ui/designer/QGCTextLabel.h index a1c1d1d6cbf46931a1a73542a6aca857727e4c87..bc0a799cc8be7ba2baacb550fd6365368d7f1007 100644 --- a/src/ui/designer/QGCTextLabel.h +++ b/src/ui/designer/QGCTextLabel.h @@ -19,9 +19,8 @@ public: ~QGCTextLabel(); void setActiveUAS(UASInterface *uas); void enableText(int num); + virtual void setEditMode(bool editMode) override; public slots: - void startEditMode(); - void endEditMode(); void writeSettings(QSettings& settings); void readSettings(const QSettings& settings); void readSettings(const QString& pre,const QVariantMap& settings); diff --git a/src/ui/designer/QGCToolWidget.cc b/src/ui/designer/QGCToolWidget.cc index 73eae34c9805d3b1435d5488e53b45f7fcf29f0d..2eeae5b26f3a963f71d66a83463b63492ef6608d 100644 --- a/src/ui/designer/QGCToolWidget.cc +++ b/src/ui/designer/QGCToolWidget.cc @@ -13,10 +13,11 @@ #include "QGCParamSlider.h" #include "QGCComboBox.h" #include "QGCTextLabel.h" +#include "QGCXYPlot.h" #include "QGCCommandButton.h" #include "UASManager.h" -QGCToolWidget::QGCToolWidget(const QString& title, QWidget *parent, QSettings* settings) : +QGCToolWidget::QGCToolWidget(const QString& objectName, const QString& title, QWidget *parent, QSettings* settings) : QWidget(parent), mav(NULL), mainMenuAction(NULL), @@ -27,12 +28,6 @@ QGCToolWidget::QGCToolWidget(const QString& title, QWidget *parent, QSettings* s ui->setupUi(this); if (settings) loadSettings(*settings); - if (title == "Unnamed Tool") - { - widgetTitle = QString("%1 %2").arg(title).arg(QGCToolWidget::instances()->count()); - } - //qDebug() << "WidgetTitle" << widgetTitle; - createActions(); toolLayout = ui->toolLayout; toolLayout->setAlignment(Qt::AlignTop); @@ -50,15 +45,16 @@ QGCToolWidget::QGCToolWidget(const QString& title, QWidget *parent, QSettings* s } connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*))); - // Enforce storage if this not loaded from settings - // is MUST NOT BE SAVED if it was loaded from settings! - //if (!settings) storeWidgetsToSettings(); + if(!objectName.isEmpty()) { + instances()->insert(objectName, this); + setObjectName(objectName); + } //Otherwise we must call loadSettings() immediately to set the object name } QGCToolWidget::~QGCToolWidget() { if (mainMenuAction) mainMenuAction->deleteLater(); - if (QGCToolWidget::instances()) QGCToolWidget::instances()->remove(widgetTitle); + if (QGCToolWidget::instances()) QGCToolWidget::instances()->remove(objectName()); delete ui; } @@ -98,11 +94,10 @@ QList QGCToolWidget::createWidgetsFromSettings(QWidget* parent, QString name = settings->value("TITLE", "").toString(); QString objname = settings->value("OBJECT_NAME", "").toString(); - if (!instances()->contains(name) && name.length() != 0) + if (!instances()->contains(objname) && !objname.isEmpty()) { //qDebug() << "CREATED WIDGET:" << name; - QGCToolWidget* tool = new QGCToolWidget(name, parent, settings); - tool->setObjectName(objname); + QGCToolWidget* tool = new QGCToolWidget(objname, name, parent, settings); newWidgets.append(tool); } else if (name.length() == 0) @@ -154,12 +149,13 @@ bool QGCToolWidget::loadSettings(const QString& settings, bool singleinstance) QStringList groups = set.childGroups(); if (groups.length() > 0) { - QString widgetName = groups.first(); - this->setObjectName(widgetName); - if (singleinstance && QGCToolWidget::instances()->keys().contains(widgetName)) return false; + QString objectName = groups.first(); + setObjectName(objectName); + if (singleinstance && QGCToolWidget::instances()->contains(objectName)) return false; + instances()->insert(objectName, this); // Do not use setTitle() here, // interferes with loading settings - widgetTitle = widgetName; + widgetTitle = objectName; //qDebug() << "WIDGET TITLE LOADED: " << widgetName; loadSettings(set); return true; @@ -277,6 +273,11 @@ void QGCToolWidget::loadSettings(QVariantMap& settings) item = new QGCComboBox(this); //qDebug() << "CREATED COMBOBOX"; } + else if (type == "XYPLOT") + { + item = new QGCXYPlot(this); + //qDebug() << "CREATED XYPlot"; + } if (item) { // Configure and add to layout @@ -335,6 +336,11 @@ void QGCToolWidget::loadSettings(QSettings& settings) item->setObjectName(settings.value("QGC_TEXT_ID").toString()); item->setActiveUAS(mav); } + else if (type == "XYPLOT") + { + item = new QGCXYPlot(this); + item->setActiveUAS(mav); + } if (item) { @@ -354,26 +360,13 @@ void QGCToolWidget::loadSettings(QSettings& settings) settings.endGroup(); } -void QGCToolWidget::storeWidgetsToSettings(QString settingsFile) +void QGCToolWidget::storeWidgetsToSettings(QSettings &settings) //static { - // Store list of widgets - QSettings* settings; - if (!settingsFile.isEmpty()) - { - settings = new QSettings(settingsFile, QSettings::IniFormat); - //qDebug() << "STORING SETTINGS TO" << settings->fileName(); - } - else - { - settings = new QSettings(); - //qDebug() << "STORING SETTINGS TO DEFAULT" << settings->fileName(); - } - - settings->beginGroup("Custom_Tool_Widgets"); - int preArraySize = settings->beginReadArray("QGC_TOOL_WIDGET_NAMES"); - settings->endArray(); + settings.beginGroup("Custom_Tool_Widgets"); + int preArraySize = settings.beginReadArray("QGC_TOOL_WIDGET_NAMES"); + settings.endArray(); - settings->beginWriteArray("QGC_TOOL_WIDGET_NAMES"); + settings.beginWriteArray("QGC_TOOL_WIDGET_NAMES"); int num = 0; for (int i = 0; i < qMax(preArraySize, instances()->size()); ++i) { @@ -382,44 +375,34 @@ void QGCToolWidget::storeWidgetsToSettings(QString settingsFile) // Updating value if (!instances()->values().at(i)->fromMetaData()) { - settings->setArrayIndex(num++); - settings->setValue("TITLE", instances()->values().at(i)->getTitle()); - settings->setValue("OBJECT_NAME", instances()->values().at(i)->objectName()); - //qDebug() << "WRITING TITLE" << instances()->values().at(i)->getTitle(); + settings.setArrayIndex(num++); + settings.setValue("TITLE", instances()->values().at(i)->getTitle()); + settings.setValue("OBJECT_NAME", instances()->values().at(i)->objectName()); + qDebug() << "WRITING TITLE" << instances()->values().at(i)->getTitle() << "object:" << instances()->values().at(i)->objectName(); } } else { // Deleting old value - settings->remove("TITLE"); + settings.remove("TITLE"); } } - settings->endArray(); + settings.endArray(); // Store individual widget items for (int i = 0; i < instances()->size(); ++i) { - instances()->values().at(i)->storeSettings(*settings); + instances()->values().at(i)->storeSettings(settings); } - settings->endGroup(); - settings->sync(); - delete settings; -} - -void QGCToolWidget::storeSettings() -{ - QSettings settings; - storeSettings(settings); -} - -void QGCToolWidget::storeSettings(const QString& settingsFile) -{ - QSettings settings(settingsFile, QSettings::IniFormat); - storeSettings(settings); + settings.endGroup(); + settings.sync(); } void QGCToolWidget::storeSettings(QSettings& settings) { + /* This function should be called from storeWidgetsToSettings() which sets up the group etc */ + Q_ASSERT(settings.group() == "Custom_Tool_Widgets"); + if (isFromMetaData) { //Refuse to store if this is loaded from metadata or dynamically generated. @@ -429,17 +412,11 @@ void QGCToolWidget::storeSettings(QSettings& settings) settings.beginGroup(widgetTitle); settings.beginWriteArray("QGC_TOOL_WIDGET_ITEMS"); int k = 0; // QGCToolItem counter - for (int j = 0; j < children().size(); ++j) - { - // Store only QGCToolWidgetItems - QGCToolWidgetItem* item = dynamic_cast(children().at(j)); - if (item) - { - // Only count actual tool widget item children - settings.setArrayIndex(k++); - // Store the ToolWidgetItem - item->writeSettings(settings); - } + foreach(QGCToolWidgetItem *item, toolItemList) { + // Only count actual tool widget item children + settings.setArrayIndex(k++); + // Store the ToolWidgetItem + item->writeSettings(settings); } //qDebug() << "WROTE" << k << "SUB-WIDGETS TO SETTINGS"; settings.endArray(); @@ -462,6 +439,7 @@ void QGCToolWidget::contextMenuEvent (QContextMenuEvent* event) menu.addAction(addParamAction); menu.addAction(addCommandAction); menu.addAction(addLabelAction); + menu.addAction(addPlotAction); menu.addSeparator(); menu.addAction(setTitleAction); menu.addAction(exportAction); @@ -501,6 +479,10 @@ void QGCToolWidget::createActions() addLabelAction->setStatusTip(tr("Add a new label to the tool")); connect(addLabelAction, SIGNAL(triggered()), this, SLOT(addLabel())); + addPlotAction = new QAction(tr("New &XY Plot"), this); + addPlotAction->setStatusTip(tr("Add a XY Plot to the tool")); + connect(addPlotAction, SIGNAL(triggered()), this, SLOT(addPlot())); + 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())); @@ -525,66 +507,39 @@ QMap* QGCToolWidget::instances() return instances; } -QList* QGCToolWidget::itemList() -{ - static QList* instances; - if (!instances) instances = new QList(); - return instances; -} void QGCToolWidget::addParam(int uas,int component,QString paramname,QVariant value) { isFromMetaData = true; QGCParamSlider* slider = new QGCParamSlider(this); - connect(slider, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(slider); + addToolWidget(slider); slider->setActiveUAS(mav); slider->setParameterValue(uas,component,0,-1,paramname,value); - - } void QGCToolWidget::addParam() { - QGCParamSlider* slider = new QGCParamSlider(this); - connect(slider, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(slider); - slider->startEditMode(); + addToolWidgetAndEdit(new QGCParamSlider(this)); } void QGCToolWidget::addCommand() { - QGCCommandButton* button = new QGCCommandButton(this); - connect(button, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(button); - button->startEditMode(); + addToolWidgetAndEdit(new QGCCommandButton(this)); } void QGCToolWidget::addLabel() { - QGCTextLabel* label= new QGCTextLabel(this); - connect(label, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(label); - label->startEditMode(); + addToolWidgetAndEdit(new QGCTextLabel(this)); +} + +void QGCToolWidget::addPlot() +{ + addToolWidgetAndEdit(new QGCXYPlot(this)); +} + +void QGCToolWidget::addToolWidgetAndEdit(QGCToolWidgetItem* widget) +{ + addToolWidget(widget); + widget->startEditMode(); } void QGCToolWidget::addToolWidget(QGCToolWidgetItem* widget) @@ -594,11 +549,21 @@ void QGCToolWidget::addToolWidget(QGCToolWidgetItem* widget) ui->hintLabel->deleteLater(); ui->hintLabel = NULL; } - connect(widget, SIGNAL(destroyed()), this, SLOT(storeSettings())); + connect(widget, SIGNAL(editingFinished()), this, SLOT(storeWidgetsToSettings())); + connect(widget, SIGNAL(destroyed()), this, SLOT(widgetRemoved())); toolLayout->addWidget(widget); toolItemList.append(widget); } +void QGCToolWidget::widgetRemoved() +{ + //Must static cast and not dynamic cast since the object is in the destructor + //and we only want to use it as a pointer value + QGCToolWidgetItem *widget = static_cast(QObject::sender()); + toolItemList.removeAll(widget); + storeWidgetsToSettings(); +} + void QGCToolWidget::exportWidget() { const QString widgetFileExtension(".qgw"); @@ -607,7 +572,8 @@ void QGCToolWidget::exportWidget() { fileName = fileName.append(widgetFileExtension); } - storeSettings(fileName); + QSettings settings(fileName, QSettings::IniFormat); + storeSettings(settings); } void QGCToolWidget::importWidget() @@ -617,7 +583,7 @@ void QGCToolWidget::importWidget() loadSettings(fileName); } -const QString QGCToolWidget::getTitle() +QString QGCToolWidget::getTitle() const { return widgetTitle; } @@ -640,20 +606,18 @@ void QGCToolWidget::setTitle() void QGCToolWidget::setTitle(const QString& title) { - if (instances()->contains(widgetTitle)) instances()->remove(widgetTitle); - if (!instances()->contains(title)) instances()->insert(title, this); - // Sets title and calls setWindowTitle on QWidget widgetTitle = title; QWidget::setWindowTitle(title); - setObjectName(widgetTitle); QDockWidget* dock = dynamic_cast(this->parentWidget()); - if (dock) { + if (dock) dock->setWindowTitle(widgetTitle); - dock->setObjectName(widgetTitle+"DOCK"); - } emit titleChanged(title); if (mainMenuAction) mainMenuAction->setText(title); + + //Do not save the settings here, because this function might be + //called while loading, and thus saving here could end up clobbering + //all of the other widgets } void QGCToolWidget::setMainMenuAction(QAction* action) @@ -667,7 +631,7 @@ void QGCToolWidget::deleteWidget() // Hide this->hide(); - instances()->remove(getTitle()); + instances()->remove(objectName()); QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); diff --git a/src/ui/designer/QGCToolWidget.h b/src/ui/designer/QGCToolWidget.h index 5d1f56d0c94781353070237fe589c99e28087f08..7ab9ef679d8ba35752ad113c58727d77bf446f5c 100644 --- a/src/ui/designer/QGCToolWidget.h +++ b/src/ui/designer/QGCToolWidget.h @@ -19,7 +19,7 @@ class QGCToolWidget : public QWidget Q_OBJECT public: - explicit QGCToolWidget(const QString& title=QString("Unnamed Tool"), QWidget *parent = 0, QSettings* settings = 0); + explicit QGCToolWidget(const QString& objectName, const QString& title, QWidget *parent = 0, QSettings* settings = 0); ~QGCToolWidget(); /** @brief Factory method to instantiate all tool widgets */ @@ -29,12 +29,15 @@ public: /** @brief All instances of this class */ static QMap* instances(); /** @brief Get title of widget */ - const QString getTitle(); + QString getTitle() const; - int isVisible(int view) { return viewVisible.value(view, false); } + int isVisible(int view) const { return viewVisible.value(view, false); } Qt::DockWidgetArea getDockWidgetArea(int view) { return dockWidgetArea.value(view, Qt::BottomDockWidgetArea); } void setParent(QWidget *parent); + /** @brief Store all widgets of this type to QSettings */ + static void storeWidgetsToSettings(QSettings &settingsFile); + public slots: void addUAS(UASInterface* uas); /** @brief Delete this widget */ @@ -44,27 +47,24 @@ public slots: /** @brief Import settings for this widget from a file */ void importWidget(); /** @brief Store all widgets of this type to QSettings */ - static void storeWidgetsToSettings(QString settingsFile=QString()); + void storeWidgetsToSettings() { QSettings settings; QGCToolWidget::storeWidgetsToSettings(settings); } + +public: void loadSettings(QVariantMap& settings); /** @brief Load this widget from a QSettings object */ void loadSettings(QSettings& settings); /** @brief Load this widget from a settings file */ bool loadSettings(const QString& settings, bool singleinstance=false); - /** @brief Store this widget to a QSettings object */ - void storeSettings(QSettings& settings); - /** @brief Store this widget to a settings file */ - void storeSettings(const QString& settingsFile); - /** @brief Store this widget to a settings file */ - void storeSettings(); /** @brief Store the view id and dock widget area */ void setViewVisibilityAndDockWidgetArea(int view, bool visible, Qt::DockWidgetArea area); void setSettings(QVariantMap& settings); QList getParamList(); void setParameterValue(int uas, int component, QString parameterName, const QVariant value); - bool fromMetaData() { return isFromMetaData; } + bool fromMetaData() const { return isFromMetaData; } void showLabel(QString name,int num); + signals: - void titleChanged(QString); + void titleChanged(const QString &title); protected: bool isFromMetaData; @@ -74,6 +74,7 @@ protected: QVariantMap settingsMap; QAction* addParamAction; QAction* addCommandAction; + QAction* addPlotAction; QAction* addLabelAction; QAction* setTitleAction; QAction* deleteAction; @@ -85,13 +86,13 @@ protected: QMap dockWidgetArea; ///< Dock widget area desired by this widget QMap viewVisible; ///< Visibility in one view QString widgetTitle; - static int instanceCount; ///< Number of instances around void contextMenuEvent(QContextMenuEvent* event); void createActions(); - QList* itemList(); /** @brief Add an existing tool widget */ void addToolWidget(QGCToolWidgetItem* widget); + /** @brief Add an existing tool widget and set it to edit mode */ + void addToolWidgetAndEdit(QGCToolWidgetItem* widget); void hideEvent(QHideEvent* event); public slots: @@ -100,10 +101,21 @@ public slots: protected slots: void addParam(); void addCommand(); + void addPlot(); void addLabel(); void setTitle(); + void widgetRemoved(); private: + /** Do not use this from outside the class to set the object name, + * because we cannot track changes to the object name, and the + * QObject::setObjectName() function is not virtual. Instead only + * pass in the object name to the constructor, or use the , then + * never change it again. */ + void setObjectName(const QString &name) { QWidget::setObjectName(name); } + /** Helper for storeWidgetsToSettings() */ + void storeSettings(QSettings& settings); + Ui::QGCToolWidget *ui; }; diff --git a/src/ui/designer/QGCToolWidgetItem.cc b/src/ui/designer/QGCToolWidgetItem.cc index 0d7f95e5cdc28b73a1ad6e1ceebb9ac05113dbd1..236ae6e486835f4a7af7829e99a14b7cebb46564 100644 --- a/src/ui/designer/QGCToolWidgetItem.cc +++ b/src/ui/designer/QGCToolWidgetItem.cc @@ -5,12 +5,13 @@ #include "QGCToolWidget.h" #include "UASManager.h" +#include QGCToolWidgetItem::QGCToolWidgetItem(const QString& name, QWidget *parent) : QWidget(parent), + uas(NULL), isInEditMode(false), qgcToolWidgetItemName(name), - uas(NULL), _component(-1) { startEditAction = new QAction(tr("Edit %1").arg(qgcToolWidgetItemName), this); @@ -20,11 +21,6 @@ QGCToolWidgetItem::QGCToolWidgetItem(const QString& name, QWidget *parent) : deleteAction = new QAction(tr("Delete %1").arg(qgcToolWidgetItemName), this); connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteLater())); - QGCToolWidget* tool = dynamic_cast(parent); - if (tool) { - connect(this, SIGNAL(editingFinished()), tool, SLOT(storeWidgetsToSettings())); - } - connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); // Set first UAS if it exists @@ -54,3 +50,25 @@ void QGCToolWidgetItem::setActiveUAS(UASInterface *uas) { this->uas = uas; } + +void QGCToolWidgetItem::setEditMode(bool editMode) +{ + isInEditMode = editMode; + + // Attempt to undock the dock widget + QWidget* p = this; + QDockWidget* dock; + + do { + p = p->parentWidget(); + dock = dynamic_cast(p); + + if (dock) + { + dock->setFloating(editMode); + break; + } + } while (p && !dock); + + emit editingFinished(); +} diff --git a/src/ui/designer/QGCToolWidgetItem.h b/src/ui/designer/QGCToolWidgetItem.h index ac0912348753f50ab47c84fd2d555266f3983509..a3b96861090809f709bd0b7024f1c4cfbae3e250 100644 --- a/src/ui/designer/QGCToolWidgetItem.h +++ b/src/ui/designer/QGCToolWidgetItem.h @@ -18,9 +18,12 @@ public: return _component; } + virtual void setEditMode(bool editMode); + bool isEditMode() const { return isInEditMode; } public slots: - virtual void startEditMode() {} - virtual void endEditMode() {} + void startEditMode() { setEditMode(true); } + void endEditMode() { setEditMode(false); } + virtual void setComponent(int comp) { _component = comp; } @@ -33,15 +36,18 @@ signals: void editingFinished(); protected: + void contextMenuEvent (QContextMenuEvent* event); + UASInterface* uas; + +private: QAction* startEditAction; QAction* stopEditAction; QAction* deleteAction; bool isInEditMode; QString qgcToolWidgetItemName; - UASInterface* uas; int _component; ///< The MAV component (the process or device ID) - void contextMenuEvent (QContextMenuEvent* event); + }; diff --git a/src/ui/designer/QGCXYPlot.cc b/src/ui/designer/QGCXYPlot.cc new file mode 100644 index 0000000000000000000000000000000000000000..58fcb0ea02611b15cda52da288b5423e3f8c6df6 --- /dev/null +++ b/src/ui/designer/QGCXYPlot.cc @@ -0,0 +1,426 @@ +#include + +#include "QGCXYPlot.h" +#include "ui_QGCXYPlot.h" + +#include "MAVLinkProtocol.h" +#include "UASManager.h" +#include "IncrementalPlot.h" +#include +#include +#include +#include + +class XYPlotCurve : public QwtPlotItem +{ +public: + XYPlotCurve() { + m_maxStorePoints = 10000; + m_maxShowPoints = 15; + setItemAttribute(QwtPlotItem::AutoScale); + minMaxSet = false; + m_color = Qt::white; + m_smoothPoints = 1; + m_startIndex = -1; //Disable + } + + void setMaxDataStorePoints(int max) { m_maxStorePoints = max; itemChanged(); } + void setMaxDataShowPoints(int max) { m_maxShowPoints = max; itemChanged(); } + void setSmoothPoints(int smoothPoints) { m_smoothPoints = smoothPoints; itemChanged(); } + int maxDataStorePoints() const { return m_maxStorePoints; } + int maxDataShowPoints() const { return m_maxShowPoints; } + int smoothPoints() const { return m_smoothPoints; } + + /** Append data, returning the number of removed items */ + int appendData(const QPointF &data) { + if(!minMaxSet) { + xmin = xmax = data.x(); + ymin = ymax = data.y(); + minMaxSet = true; + } else if(m_autoScale) { + xmin = qMin(xmin, data.x()); + xmax = qMax(xmax, data.x()); + ymin = qMin(ymin, data.y()); + ymax = qMax(ymax, data.y()); + } + + m_data.append(data); + int removed = 0; + while(m_data.size() > m_maxStorePoints) { + ++removed; + m_data.removeFirst(); + } + itemChanged(); + return removed; + } + void clear() { + minMaxSet = false; + m_data.clear(); + itemChanged(); + } + void setColor(const QColor &color) { + m_color = color; + } + void unsetMinMax() { + if(m_autoScale) + return; + m_autoScale = true; + //Recalculate the automatic scale + if(m_data.isEmpty()) + minMaxSet = false; + else { + minMaxSet = true; + xmax = xmin = m_data.at(0).x(); + ymax = ymin = m_data.at(0).y(); + for(int i = 1; i < m_data.size(); i++) { + xmin = qMin(xmin, m_data.at(i).x()); + xmax = qMax(xmax, m_data.at(i).x()); + ymin = qMin(ymin, m_data.at(i).y()); + ymax = qMax(ymax, m_data.at(i).y()); + } + } + } + void setMinMax(double xmin, double xmax, double ymin, double ymax ) + { + this->xmin = xmin; + this->xmax = xmax; + this->ymin = ymin; + this->ymax = ymax; + m_autoScale = false; + minMaxSet = true; + itemChanged(); + } + void setStartIndex(int time) { /** Set to -1 to just use latest */ + m_startIndex = time; + itemChanged(); + } + int dataSize() const { return m_data.size(); } + + double xMin() const { return xmin; } + double xMax() const { return xmax; } + double yMin() const { return ymin; } + double yMax() const { return ymax; } + + virtual QwtDoubleRect boundingRect() const { + if(!minMaxSet) + return QwtDoubleRect(1,1,-2,-2); + return QwtDoubleRect(xmin,ymin,xmax-xmin,ymax-ymin); + } + +protected: + /* From QwtPlotItem. Draw the complete series */ + virtual void draw (QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &canvasRect) const + { + Q_UNUSED(canvasRect); + QPointF lastPoint; + if(m_data.isEmpty()) + return; + QPointF smoothTotal(0,0); + int smoothCount = 0; + int start; + int count; + if(m_startIndex >= 0) { + int end = qMin(m_startIndex, m_data.size()-1); + start = qBound(0, end - m_maxShowPoints, m_data.size()-1); + count = end - start; + } else { + start = qMax(0,m_data.size() - m_maxShowPoints); + count = qMin(m_data.size()-start, m_maxShowPoints); + } + for(int i = qMax(0,start - m_smoothPoints); i < start; ++i) { + smoothTotal += m_data.at(i); + ++smoothCount; + } + for(int i = 0; i < count; ++i) { + QPointF point = m_data.at(i+start); + if(m_smoothPoints > 1) { + smoothTotal += point; + if(smoothCount >= m_smoothPoints) { + Q_ASSERT(i + start - m_smoothPoints >= 0); + smoothTotal -= m_data.at(i + start - m_smoothPoints); + } else + ++smoothCount; + point = smoothTotal/smoothCount; + } + QPointF paintCoord = QPointF(xMap.xTransform(point.x()), yMap.xTransform(point.y())); + m_color.setAlpha((m_maxShowPoints - count + i)*255/m_maxShowPoints); + p->setPen(m_color); + if(i != 0) + p->drawLine(lastPoint, paintCoord); + if(i == count-1) { + //Draw marker for first point + const int marker_radius = 2; + QRectF marker = QRectF(paintCoord.x()-marker_radius, paintCoord.y()-marker_radius, marker_radius*2+1,marker_radius*2+1); + p->fillRect(marker,QBrush(m_color)); + } + lastPoint = paintCoord; + } + } + +private: + QList< QPointF > m_data; + int m_maxStorePoints; + int m_maxShowPoints; + int m_smoothPoints; /** Number of points to average across */ + mutable QColor m_color; + + double xmin; + double xmax; + double ymin; + double ymax; + bool minMaxSet; + bool m_autoScale; + int m_startIndex; +}; + +QGCXYPlot::QGCXYPlot(QWidget *parent) : + QGCToolWidgetItem("XY Plot", parent), + ui(new Ui::QGCXYPlot), + plot(0), + xycurve(0), + x(0), + x_timestamp_us(0), + x_valid(false), + y(0), + y_timestamp_us(0), + y_valid(false), + max_timestamp_diff_us(10000) /* Default to 10ms tolerance between x and y values */ + + +{ + uas = 0; + ui->setupUi(this); + plot = new QwtPlot(); + + ui->xyPlotLayout->addWidget(plot); + + connect(ui->editFinishButton, SIGNAL(clicked()), this, SLOT(endEditMode())); + + connect(MainWindow::instance(), SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), + this, SLOT(appendData(int,QString,QString,QVariant,quint64))); + + connect(ui->editXParam, SIGNAL(editTextChanged(QString)), this, SLOT(clearPlot())); + connect(ui->editYParam, SIGNAL(editTextChanged(QString)), this, SLOT(clearPlot())); + + plot->plotLayout()->setAlignCanvasToScales(true); + + QwtLinearScaleEngine* yScaleEngine = new QwtLinearScaleEngine(); + plot->setAxisScaleEngine(QwtPlot::yLeft, yScaleEngine); + + plot->setAxisAutoScale(QwtPlot::xBottom); + plot->setAxisAutoScale(QwtPlot::yLeft); + plot->setAutoReplot(); + xycurve = new XYPlotCurve(); + xycurve->attach(plot); + styleChanged(MainWindow::instance()->getStyle()); + connect(MainWindow::instance(), SIGNAL(styleChanged(MainWindow::QGC_MAINWINDOW_STYLE)), + this, SLOT(styleChanged(MainWindow::QGC_MAINWINDOW_STYLE))); + connect(ui->minX, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxX, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->minY, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxY, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->automaticAxisRange, SIGNAL(toggled(bool)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxDataShowSpinBox, SIGNAL(valueChanged(int)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxDataStoreSpinBox, SIGNAL(valueChanged(int)),this, SLOT(updateMinMaxSettings())); + connect(ui->smoothSpinBox, SIGNAL(valueChanged(int)),this, SLOT(updateMinMaxSettings())); + setEditMode(false); +} + +QGCXYPlot::~QGCXYPlot() +{ + delete ui; +} + +void QGCXYPlot::clearPlot() +{ + xycurve->clear(); + plot->clear(); + ui->timeScrollBar->setMaximum(xycurve->dataSize()); + ui->timeScrollBar->setValue(ui->timeScrollBar->maximum()); +} + +void QGCXYPlot::setEditMode(bool editMode) +{ + ui->lblXParam->setVisible(editMode); + ui->lblYParam->setVisible(editMode); + ui->editXParam->setVisible(editMode); + ui->editYParam->setVisible(editMode); + ui->editFinishButton->setVisible(editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + ui->lblMaxDataStore->setVisible(editMode); + ui->lblMaxDataShow->setVisible(editMode); + ui->lblMaxX->setVisible(editMode); + ui->lblMaxY->setVisible(editMode); + ui->lblMinX->setVisible(editMode); + ui->lblMinY->setVisible(editMode); + ui->maxX->setVisible(editMode); + ui->maxY->setVisible(editMode); + ui->minX->setVisible(editMode); + ui->minY->setVisible(editMode); + ui->maxDataShowSpinBox->setVisible(editMode); + ui->maxDataStoreSpinBox->setVisible(editMode); + ui->automaticAxisRange->setVisible(editMode); + ui->lblSmooth->setVisible(editMode); + ui->smoothSpinBox->setVisible(editMode); + + if(!editMode) { + plot->setAxisTitle(QwtPlot::xBottom, ui->editXParam->currentText()); + plot->setAxisTitle(QwtPlot::yLeft, ui->editYParam->currentText()); + } + + QGCToolWidgetItem::setEditMode(editMode); + updateMinMaxSettings(); //Do this after calling the parent +} + +void QGCXYPlot::writeSettings(QSettings& settings) +{ + settings.setValue("TYPE", "XYPLOT"); + settings.setValue("QGC_XYPLOT_X", ui->editXParam->currentText()); + settings.setValue("QGC_XYPLOT_Y", ui->editYParam->currentText()); + settings.setValue("QGC_XYPLOT_MINX", ui->minX->value()); + settings.setValue("QGC_XYPLOT_MAXX", ui->maxX->value()); + settings.setValue("QGC_XYPLOT_MINY", ui->minY->value()); + settings.setValue("QGC_XYPLOT_MAXY", ui->maxY->value()); + settings.setValue("QGC_XYPLOT_MAXDATA_STORE", ui->maxDataStoreSpinBox->value()); + settings.setValue("QGC_XYPLOT_MAXDATA_SHOW", ui->maxDataShowSpinBox->value()); + settings.setValue("QGC_XYPLOT_AUTO", ui->automaticAxisRange->isChecked()); + settings.setValue("QGC_XYPLOT_SMOOTH", ui->smoothSpinBox->value()); + + settings.sync(); +} +void QGCXYPlot::readSettings(const QString& pre,const QVariantMap& settings) +{ + ui->editXParam->setEditText(settings.value(pre + "QGC_XYPLOT_X", "").toString()); + ui->editYParam->setEditText(settings.value(pre + "QGC_XYPLOT_Y", "").toString()); + ui->automaticAxisRange->setChecked(settings.value(pre + "QGC_XYPLOT_AUTO", true).toBool()); + ui->minX->setValue(settings.value(pre + "QGC_XYPLOT_MINX", 0).toDouble()); + ui->maxX->setValue(settings.value(pre + "QGC_XYPLOT_MAXX", 0).toDouble()); + ui->minY->setValue(settings.value(pre + "QGC_XYPLOT_MINY", 0).toDouble()); + ui->maxY->setValue(settings.value(pre + "QGC_XYPLOT_MAXY", 0).toDouble()); + ui->maxDataStoreSpinBox->setValue(settings.value(pre + "QGC_XYPLOT_MAXDATA_STORE", 10000).toInt()); + ui->maxDataShowSpinBox->setValue(settings.value(pre + "QGC_XYPLOT_MAXDATA_SHOW", 15).toInt()); + ui->smoothSpinBox->setValue(settings.value(pre + "QGC_XYPLOT_SMOOTH", 1).toInt()); + plot->setAxisTitle(QwtPlot::xBottom, ui->editXParam->currentText()); + plot->setAxisTitle(QwtPlot::yLeft, ui->editYParam->currentText()); + updateMinMaxSettings(); +} + +void QGCXYPlot::readSettings(const QSettings& settings) +{ + ui->editXParam->setEditText(settings.value("QGC_XYPLOT_X", "").toString()); + ui->editYParam->setEditText(settings.value("QGC_XYPLOT_Y", "").toString()); + ui->automaticAxisRange->setChecked(settings.value("QGC_XYPLOT_AUTO", true).toBool()); + ui->minX->setValue(settings.value("QGC_XYPLOT_MINX", 0).toDouble()); + ui->maxX->setValue(settings.value("QGC_XYPLOT_MAXX", 0).toDouble()); + ui->minY->setValue(settings.value("QGC_XYPLOT_MINY", 0).toDouble()); + ui->maxY->setValue(settings.value("QGC_XYPLOT_MAXY", 0).toDouble()); + ui->maxDataStoreSpinBox->setValue(settings.value("QGC_XYPLOT_MAXDATA_STORE", 10000).toInt()); + ui->maxDataShowSpinBox->setValue(settings.value("QGC_XYPLOT_MAXDATA_SHOW", 15).toInt()); + ui->smoothSpinBox->setValue(settings.value("QGC_XYPLOT_SMOOTH", 1).toInt()); + plot->setAxisTitle(QwtPlot::xBottom, ui->editXParam->currentText()); + plot->setAxisTitle(QwtPlot::yLeft, ui->editYParam->currentText()); + updateMinMaxSettings(); +} + +void QGCXYPlot::appendData(int uasId, const QString& curve, const QString& unit, const QVariant& variant, quint64 usec) +{ + Q_UNUSED(uasId); + Q_UNUSED(unit); + if(isEditMode()) { + //When in edit mode, add all the items to the combo box + if(ui->editXParam->findText(curve) == -1) { + ui->editXParam->blockSignals(true); + ui->editYParam->blockSignals(true); + QString oldX = ui->editXParam->currentText(); + QString oldY = ui->editYParam->currentText(); + ui->editXParam->addItem(curve); //Annoyingly this can wipe out the current text + ui->editYParam->addItem(curve); + ui->editXParam->setEditText(oldX); + ui->editYParam->setEditText(oldY); + ui->editXParam->blockSignals(false); + ui->editYParam->blockSignals(false); + } + } + + if(ui->stopStartButton->isChecked()) + return; + + bool ok; + if(curve == ui->editXParam->currentText()) { + x = variant.toDouble(&ok); + if(!ok) + return; + x_timestamp_us = usec; + x_valid = true; + } else if(curve == ui->editYParam->currentText()) { + y = variant.toDouble(&ok); + if(!ok) + return; + y_timestamp_us = usec; + y_valid = true; + } else + return; + + if(x_valid && y_valid && (int)qAbs(y_timestamp_us - x_timestamp_us) <= max_timestamp_diff_us) { + int removed = xycurve->appendData( QPointF(x,y) ); + x_valid = false; + y_valid = false; + bool atMaximum = (ui->timeScrollBar->value() == ui->timeScrollBar->maximum()); + if(ui->timeScrollBar->maximum() != xycurve->dataSize()) { + ui->timeScrollBar->setMaximum(xycurve->dataSize()); + if(atMaximum) + ui->timeScrollBar->setValue(ui->timeScrollBar->maximum()); + } else if(!atMaximum) { //Move the scrollbar to keep current value selected + int value = qMax(ui->timeScrollBar->minimum(), ui->timeScrollBar->value() - removed); + ui->timeScrollBar->setValue(value); + xycurve->setStartIndex(value); + } + } +} + +void QGCXYPlot::styleChanged(MainWindow::QGC_MAINWINDOW_STYLE style) +{ + if (style == MainWindow::QGC_MAINWINDOW_STYLE_LIGHT) + xycurve->setColor(Qt::black); + else + xycurve->setColor(Qt::white); +} + +void QGCXYPlot::updateMinMaxSettings() +{ + bool automatic = ui->automaticAxisRange->isChecked(); + ui->minX->setEnabled(!automatic); + ui->maxX->setEnabled(!automatic); + ui->minY->setEnabled(!automatic); + ui->maxY->setEnabled(!automatic); + if(automatic) { + xycurve->unsetMinMax(); + } else { + xycurve->setMinMax(ui->minX->value(), ui->maxX->value(), ui->minY->value(), ui->maxY->value()); + } + xycurve->setMaxDataStorePoints(ui->maxDataStoreSpinBox->value()); + xycurve->setMaxDataShowPoints(ui->maxDataShowSpinBox->value()); + xycurve->setSmoothPoints(ui->smoothSpinBox->value()); +} + +void QGCXYPlot::on_maxDataShowSpinBox_valueChanged(int value) +{ + ui->maxDataStoreSpinBox->setMinimum(value); + if(ui->maxDataStoreSpinBox->value() < value) + ui->maxDataStoreSpinBox->setValue(value); +} + +void QGCXYPlot::on_stopStartButton_toggled(bool checked) +{ + if(!checked) + clearPlot(); +} + +void QGCXYPlot::on_timeScrollBar_valueChanged(int value) +{ + if(value == ui->timeScrollBar->maximum()) + xycurve->setStartIndex(-1); + else + xycurve->setStartIndex(value); +} diff --git a/src/ui/designer/QGCXYPlot.h b/src/ui/designer/QGCXYPlot.h new file mode 100644 index 0000000000000000000000000000000000000000..77159d6823041a8a08a3be8ecd523a732595c410 --- /dev/null +++ b/src/ui/designer/QGCXYPlot.h @@ -0,0 +1,54 @@ +#ifndef QGCXYPLOT_H +#define QGCXYPLOT_H + +#include "QGCToolWidgetItem.h" +#include "MainWindow.h" + +namespace Ui +{ +class QGCXYPlot; +} + +class UASInterface; +class QwtPlot; +class XYPlotCurve; + +class QGCXYPlot : public QGCToolWidgetItem +{ + Q_OBJECT + +public: + explicit QGCXYPlot(QWidget *parent = 0); + ~QGCXYPlot(); + virtual void setEditMode(bool editMode); + +public slots: + void writeSettings(QSettings& settings); + void readSettings(const QSettings& settings); + void readSettings(const QString& pre,const QVariantMap& settings); + void appendData(int uasId, const QString& curve, const QString& unit, const QVariant& variant, quint64 usec); + void clearPlot(); + void styleChanged(MainWindow::QGC_MAINWINDOW_STYLE style); + void updateMinMaxSettings(); + +private slots: + void on_maxDataShowSpinBox_valueChanged(int value); + void on_stopStartButton_toggled(bool checked); + + void on_timeScrollBar_valueChanged(int value); + +private: + Ui::QGCXYPlot *ui; + QwtPlot *plot; + XYPlotCurve* xycurve; + + double x; /**< Last unused value for the x-coordinate */ + quint64 x_timestamp_us; /**< Timestamp that we last recieved a value for x */ + bool x_valid; /**< Whether we have recieved an x value but so far no corresponding y value */ + double y; /**< Last unused value for the x-coordinate */ + quint64 y_timestamp_us; /**< Timestamp that we last recieved a value for x */ + bool y_valid; /**< Whether we have recieved an x value but so far no corresponding y value */ + int max_timestamp_diff_us; /**< Only combine x and y to a data point if the timestamp for both doesn't differ by more than this */ +}; + +#endif // QGCXYPLOT_H diff --git a/src/ui/designer/QGCXYPlot.ui b/src/ui/designer/QGCXYPlot.ui new file mode 100644 index 0000000000000000000000000000000000000000..ab9659517540a669a5e82c645391427fbbd2b10a --- /dev/null +++ b/src/ui/designer/QGCXYPlot.ui @@ -0,0 +1,473 @@ + + + QGCXYPlot + + + + 0 + 0 + 771 + 365 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + + 50 + 0 + + + + X Parameter: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + editXParam + + + + + + + + 0 + 0 + + + + true + + + QComboBox::InsertAlphabetically + + + QComboBox::AdjustToContents + + + 10 + + + + + + + + 50 + 0 + + + + Y Parameter: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + editYParam + + + + + + + + 0 + 0 + + + + true + + + QComboBox::InsertAlphabetically + + + QComboBox::AdjustToContents + + + 10 + + + + + + + + + + + Number of data points to &show: + + + maxDataShowSpinBox + + + + + + + 2 + + + 999 + + + 15 + + + + + + + To s&tore: + + + maxDataStoreSpinBox + + + + + + + 10 + + + 999999999 + + + 15 + + + + + + + Number of points to average, to provide a smoothing effect of the plotted values + + + S&mooth: + + + smoothSpinBox + + + + + + + Number of points to average, to provide a smoothing effect of the plotted values + + + 1 + + + 99999 + + + + + + + Automatic Axis Range + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + &Min X: + + + minX + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + &Max X: + + + maxX + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Min &Y: + + + minY + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Ma&x Y: + + + maxY + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + + + 6 + + + + + + 0 + 0 + + + + 2 + + + true + + + Qt::Horizontal + + + + + + + + :/files/images/actions/media-playback-stop.svg + :/files/images/actions/media-playback-start.svg:/files/images/actions/media-playback-stop.svg + + + + 16 + 16 + + + + true + + + false + + + false + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Done + + + false + + + true + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + editXParam + editYParam + maxDataShowSpinBox + maxDataStoreSpinBox + smoothSpinBox + automaticAxisRange + minX + maxX + minY + maxY + editFinishButton + + + + + + diff --git a/src/ui/dockwidgeteventfilter.cpp b/src/ui/dockwidgeteventfilter.cpp deleted file mode 100644 index 260e3a5466614e1eb81f9827f6feb55a0ddfa238..0000000000000000000000000000000000000000 --- a/src/ui/dockwidgeteventfilter.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include - -#include "dockwidgeteventfilter.h" - -DockWidgetEventFilter::DockWidgetEventFilter(QObject *parent) : QObject(parent) {} - -bool DockWidgetEventFilter::eventFilter(QObject *object,QEvent *event) -{ - if (event->type() == QEvent::WindowTitleChange) - { - QDockWidget *dock = dynamic_cast(object); - if(dock) { - QLabel *label = dynamic_cast(dock->titleBarWidget()); - if(label) - label->setText(dock->windowTitle()); - } - } - return QObject::eventFilter(object,event); -} diff --git a/src/ui/dockwidgeteventfilter.h b/src/ui/dockwidgeteventfilter.h deleted file mode 100644 index 60de1e4002bb942f609cb2fe859c8d18b82d9d24..0000000000000000000000000000000000000000 --- a/src/ui/dockwidgeteventfilter.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DOCKWIDGETEVENTFILTER_H -#define DOCKWIDGETEVENTFILTER_H - -#include - -/** Event filter to update a QLabel titleBarWidget if the window's title changes */ -class DockWidgetEventFilter : public QObject -{ - Q_OBJECT -public: - DockWidgetEventFilter(QObject *parent = 0); -protected: - virtual bool eventFilter(QObject *object,QEvent *event) override; -}; - -#endif // DOCKWIDGETEVENTFILTER_H diff --git a/src/ui/dockwidgettitlebareventfilter.cpp b/src/ui/dockwidgettitlebareventfilter.cpp deleted file mode 100644 index 52519215ade4e5fb6d1fcb8927a4366fdf6f7da5..0000000000000000000000000000000000000000 --- a/src/ui/dockwidgettitlebareventfilter.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "dockwidgettitlebareventfilter.h" -#include -#include -DockWidgetTitleBarEventFilter::DockWidgetTitleBarEventFilter(QObject *parent) : QObject(parent) -{ -} -bool DockWidgetTitleBarEventFilter::eventFilter(QObject *object,QEvent *event) -{ - if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) - { - return true; - } - return QObject::eventFilter(object,event); -} diff --git a/src/ui/dockwidgettitlebareventfilter.h b/src/ui/dockwidgettitlebareventfilter.h deleted file mode 100644 index d57edef1fb862711ba55d810b34614bc38dfad0f..0000000000000000000000000000000000000000 --- a/src/ui/dockwidgettitlebareventfilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef DOCKWIDGETTITLEBAREVENTFILTER_H -#define DOCKWIDGETTITLEBAREVENTFILTER_H - -#include - -class DockWidgetTitleBarEventFilter : public QObject -{ - Q_OBJECT -public: - explicit DockWidgetTitleBarEventFilter(QObject *parent = 0); -protected: - bool eventFilter(QObject *object,QEvent *event); -signals: - -public slots: - -}; - -#endif // DOCKWIDGETTITLEBAREVENTFILTER_H diff --git a/src/ui/linechart/IncrementalPlot.cc b/src/ui/linechart/IncrementalPlot.cc index 6a5e13f4de9c553cc2cec6266e2055f049c54ef0..5826d09d39890adeb2eb1f45c484edb9ac79e668 100644 --- a/src/ui/linechart/IncrementalPlot.cc +++ b/src/ui/linechart/IncrementalPlot.cc @@ -157,36 +157,43 @@ void IncrementalPlot::showLegend(bool show) */ void IncrementalPlot::setStyleText(const QString &style) { + styleText = style.toLower(); foreach (QwtPlotCurve* curve, curves) { - // Style of datapoints - if (style.toLower().contains("circles")) { - curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); - } else if (style.toLower().contains("crosses")) { - curve->setSymbol(QwtSymbol(QwtSymbol::XCross, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(5, 5)) ); - } else if (style.toLower().contains("rect")) { - curve->setSymbol(QwtSymbol(QwtSymbol::Rect, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); - } else if (style.toLower().contains("line")) { // Show no symbol - curve->setSymbol(QwtSymbol(QwtSymbol::NoSymbol, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); - } + updateStyle(curve); + } + replot(); +} - // Style of lines - if (style.toLower().contains("dotted")) { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DotLine)); - } else if (style.toLower().contains("dashed")) { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DashLine)); - } else if (style.toLower().contains("line") || style.toLower().contains("solid")) { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::SolidLine)); - } else { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::NoPen)); - } - curve->setStyle(QwtPlotCurve::Lines); +void IncrementalPlot::updateStyle(QwtPlotCurve *curve) +{ + if(styleText.isNull()) + return; + // Style of datapoints + if (styleText.contains("circles")) { + curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); + } else if (styleText.contains("crosses")) { + curve->setSymbol(QwtSymbol(QwtSymbol::XCross, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(5, 5)) ); + } else if (styleText.contains("rect")) { + curve->setSymbol(QwtSymbol(QwtSymbol::Rect, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); + } else if (styleText.contains("line")) { // Show no symbol + curve->setSymbol(QwtSymbol(QwtSymbol::NoSymbol, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); + } + // Style of lines + if (styleText.contains("dotted")) { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DotLine)); + } else if (styleText.contains("dashed")) { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DashLine)); + } else if (styleText.contains("line") || styleText.contains("solid")) { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::SolidLine)); + } else { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::NoPen)); } - replot(); + curve->setStyle(QwtPlotCurve::Lines); } void IncrementalPlot::resetScaling() @@ -275,7 +282,7 @@ void IncrementalPlot::appendData(const QString &key, double *x, double *y, int s const QColor &c = getNextColor(); curve->setSymbol(QwtSymbol(QwtSymbol::XCross, QBrush(c), QPen(c, symbolWidth), QSize(5, 5)) ); - + updateStyle(curve); //Apply any user-set style curve->attach(this); } else { curve = curves.value(key); @@ -374,7 +381,7 @@ void IncrementalPlot::showGrid(bool show) replot(); } -bool IncrementalPlot::gridEnabled() +bool IncrementalPlot::gridEnabled() const { return grid->isVisible(); } diff --git a/src/ui/linechart/IncrementalPlot.h b/src/ui/linechart/IncrementalPlot.h index 0b7f2d3b4f3a381cbfcb13e4c9e0a67561ab223f..cb9784ee7d15028c25d9a0841f5bb7510f4ec1c1 100644 --- a/src/ui/linechart/IncrementalPlot.h +++ b/src/ui/linechart/IncrementalPlot.h @@ -81,7 +81,7 @@ public: virtual ~IncrementalPlot(); /** @brief Get the state of the grid */ - bool gridEnabled(); + bool gridEnabled() const; /** @brief Read out data from a curve */ int data(const QString &key, double* r_x, double* r_y, int maxSize); @@ -125,10 +125,12 @@ protected: 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); }; #endif /* INCREMENTALPLOT_H */ diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc index 00750f9171075934c3e2b1b04ccb0449c6b6c678..7b74f9b333c3bdeb02f2eac83065516014ec3569 100644 --- a/src/ui/linechart/LinechartWidget.cc +++ b/src/ui/linechart/LinechartWidget.cc @@ -140,7 +140,7 @@ LinechartWidget::LinechartWidget(int systemid, QWidget *parent) : QWidget(parent createLayout(); // And make sure we're listening for future style changes - connect(MainWindow::instance(), SIGNAL(styleChanged()), this, SLOT(recolor())); + connect(MainWindow::instance(), SIGNAL(styleChanged(MainWindow::QGC_MAINWINDOW_STYLE)), this, SLOT(recolor())); updateTimer->setInterval(updateInterval); connect(updateTimer, SIGNAL(timeout()), this, SLOT(refresh())); diff --git a/src/ui/menuactionhelper.cpp b/src/ui/menuactionhelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..459ebaade3b6604c54b8ad7aff3d0ac89f44f867 --- /dev/null +++ b/src/ui/menuactionhelper.cpp @@ -0,0 +1,175 @@ +#include "menuactionhelper.h" + +MenuActionHelper::MenuActionHelper(QObject *parent) : QObject(parent), + m_isAdvancedMode(false), + m_dockWidgetTitleBarsEnabled(true), + m_addedCustomSeperator(false) +{ +} + +QAction *MenuActionHelper::createToolAction(const QString &title, const QString &name) +{ + QAction *action = m_menuToDockNameMap.key(name); //For sanity, check that the action is not NULL + if(action) { + qWarning() << "createToolAction was called for action" << name << "which already exists in the menu"; + return action; + } + + action = new QAction(title, NULL); + action->setCheckable(true); + connect(action,SIGNAL(triggered(bool)),this,SLOT(showTool(bool))); + m_menuToDockNameMap[action] = name; + m_menu->addAction(action); + return action; +} + +void MenuActionHelper::removeDockWidget() +{ + QObject *dockWidget = QObject::sender(); //Note that we can't cast to QDockWidget because we are in its destructor + Q_ASSERT(dockWidget); + + qDebug() << "Dockwidget:" << dockWidget->objectName() << "of type" << dockWidget->metaObject()->className(); + + QAction *action = m_menuToDockNameMap.key(dockWidget->objectName()); + if(action) { + m_menuToDockNameMap.remove(action); + action->deleteLater(); + } + QMap >::iterator it; + for (it = m_centralWidgetToDockWidgetsMap.begin(); it != m_centralWidgetToDockWidgetsMap.end(); ++it) { + QMap::iterator it2 = it.value().begin(); + while( it2 != it.value().end()) { + if(it2.value() == dockWidget) + it2 = it.value().erase(it2); + else + ++it2; + } + } + //Don't delete the dockWidget because this could have been called from the dockWidget destructor + m_dockWidgets.removeAll(static_cast(dockWidget)); +} + +QAction *MenuActionHelper::createToolActionForCustomDockWidget(const QString &title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view) { + bool found = false; + QAction *action = NULL; + foreach(QAction *act, m_menuToDockNameMap.keys()) { + if(act->text() == title) { + found = true; + action = act; + } + } + + if(!found) + action = createToolAction(title, name); + else + m_menuToDockNameMap[action] = name; + + m_centralWidgetToDockWidgetsMap[view][name] = dockWidget; + connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget()),Qt::UniqueConnection); //Use UniqueConnection since we might have already created this connection in createDockWidget + connect(dockWidget, SIGNAL(visibilityChanged(bool)), action, SLOT(setChecked(bool))); + action->setChecked(dockWidget->isVisible()); + return action; +} + +QDockWidget* MenuActionHelper::createDockWidget(const QString& title,const QString& name) +{ + QDockWidget *dockWidget = new QDockWidget(title); + m_dockWidgets.append(dockWidget); + setDockWidgetTitleBar(dockWidget); + dockWidget->setObjectName(name); + connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget())); + + return dockWidget; +} + +bool MenuActionHelper::containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const { + + return m_centralWidgetToDockWidgetsMap.contains(view) && m_centralWidgetToDockWidgetsMap[view].contains(name); +} + +QDockWidget *MenuActionHelper::getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const { + if(!m_centralWidgetToDockWidgetsMap.contains(view)) + return NULL; + return m_centralWidgetToDockWidgetsMap[view].value(name); +} + +void MenuActionHelper::showTool(bool show) { + //Called when a menu item is clicked on, regardless of view. + QAction* act = qobject_cast(sender()); + Q_ASSERT(act); + if (m_menuToDockNameMap.contains(act)) { + QString name = m_menuToDockNameMap[act]; + emit needToShowDockWidget(name, show); + } +} + +void MenuActionHelper::setDockWidgetTitleBarsEnabled(bool enabled) +{ + m_dockWidgetTitleBarsEnabled = enabled; + for (int i = 0; i < m_dockWidgets.size(); i++) + setDockWidgetTitleBar(m_dockWidgets[i]); +} + + +void MenuActionHelper::setAdvancedMode(bool advancedMode) +{ + m_isAdvancedMode = advancedMode; + for (int i = 0; i < m_dockWidgets.size(); i++) + setDockWidgetTitleBar(m_dockWidgets[i]); +} + +void MenuActionHelper::setDockWidgetTitleBar(QDockWidget* widget) +{ + Q_ASSERT(widget); + QWidget* oldTitleBar = widget->titleBarWidget(); + + // In advanced mode, we use the default titlebar provided by Qt. + if (m_isAdvancedMode) + { + widget->setTitleBarWidget(0); + } + // Otherwise, if just a textlabel should be shown, make that the titlebar. + else if (m_dockWidgetTitleBarsEnabled) + { + QLabel* label = new QLabel(widget); + label->setText(widget->windowTitle()); + label->installEventFilter(this); //Ignore mouse clicks + widget->installEventFilter(this); //Update label if window title changes. See eventFilter below + widget->setTitleBarWidget(label); + } + // And if nothing should be shown, use an empty widget. + else + { + QWidget* newTitleBar = new QWidget(widget); + widget->setTitleBarWidget(newTitleBar); + } + + // Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(), + // it doesn't delete the old titlebar object. + delete oldTitleBar; +} + +bool MenuActionHelper::eventFilter(QObject *object,QEvent *event) +{ + if (event->type() == QEvent::WindowTitleChange) + { + QDockWidget *dock = qobject_cast(object); + if(dock) { + // Update the dock title bar label + QLabel *label = dynamic_cast(dock->titleBarWidget()); + if(label) + label->setText(dock->windowTitle()); + // Now update the action label + QString oldObjectName = dock->objectName(); + QAction *action = m_menuToDockNameMap.key(oldObjectName); + if(action) + action->setText(dock->windowTitle()); + //Now modify the object name - it is a strange naming scheme.. + } + } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) + { + if(qobject_cast(object)) + return true; + } + return QObject::eventFilter(object,event); +} diff --git a/src/ui/menuactionhelper.h b/src/ui/menuactionhelper.h new file mode 100644 index 0000000000000000000000000000000000000000..cde788348868daa6581b481128b222bb4003fb8d --- /dev/null +++ b/src/ui/menuactionhelper.h @@ -0,0 +1,50 @@ +#ifndef MENUACTIONHELPER_H +#define MENUACTIONHELPER_H + +#include "MainWindow.h" + +class MenuActionHelper : public QObject +{ + Q_OBJECT +public: + MenuActionHelper(QObject *parent = NULL); + ~MenuActionHelper() {} + + /** @brief Get title bar mode setting */ + bool dockWidgetTitleBarsEnabled() const { return m_dockWidgetTitleBarsEnabled; } + void setDockWidgetTitleBarsEnabled(bool enabled); + bool isAdvancedMode() const { return m_isAdvancedMode; } + void setAdvancedMode(bool advancedMode); + QAction *createToolAction(const QString &title, const QString &name = QString()); + QAction *createToolActionForCustomDockWidget(const QString& title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view); + QDockWidget *createDockWidget(const QString& title, const QString& name); + bool containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const; + QDockWidget *getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const; + + /** QMenu to add QActions to */ + void setMenu(QMenu *menu) { m_menu = menu; } + +protected: + virtual bool eventFilter(QObject *object,QEvent *event); + +private slots: + void removeDockWidget(); + /** @brief Shows a Docked Widget based on the action sender */ + void showTool(bool show); + +signals: + void needToShowDockWidget(const QString& name, bool show); +private: + QMap m_menuToDockNameMap; + QList m_dockWidgets; + QMap > m_centralWidgetToDockWidgetsMap; + bool m_isAdvancedMode; ///< If enabled dock widgets can be moved and floated. + bool m_dockWidgetTitleBarsEnabled; ///< If enabled, dock widget titlebars are displayed when NOT in advanced mode. + QMenu *m_menu; ///< \see setMenu() + bool m_addedCustomSeperator; ///< Whether we have added a seperator between the actions and the custom actions + + void setDockWidgetTitleBar(QDockWidget* widget); + +}; + +#endif // MENUACTIONHELPER_H