From 35c36da060a9d1d674de4e77f2b02222f144d762 Mon Sep 17 00:00:00 2001 From: edouard Date: Fri, 17 Sep 2010 20:49:24 +0000 Subject: [PATCH] OP-160 Rough draft of mixer curve widget, for comments. I will make it look nicer later, this is just for seeing what can be done. git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1677 ebee16cc-31ac-478f-84a7-5cbb03baadba --- ground/src/plugins/config/airframe.ui | 18 ++ ground/src/plugins/config/config.pro | 10 +- ground/src/plugins/config/configgadget.qrc | 1 + ground/src/plugins/config/images/curve-bg.svg | 128 +++++++++++++ ground/src/plugins/config/mixercurveline.cpp | 139 ++++++++++++++ ground/src/plugins/config/mixercurveline.h | 71 +++++++ ground/src/plugins/config/mixercurvepoint.cpp | 173 ++++++++++++++++++ ground/src/plugins/config/mixercurvepoint.h | 71 +++++++ .../src/plugins/config/mixercurvewidget.cpp | 123 +++++++++++++ ground/src/plugins/config/mixercurvewidget.h | 59 ++++++ 10 files changed, 791 insertions(+), 2 deletions(-) create mode 100644 ground/src/plugins/config/images/curve-bg.svg create mode 100644 ground/src/plugins/config/mixercurveline.cpp create mode 100644 ground/src/plugins/config/mixercurveline.h create mode 100644 ground/src/plugins/config/mixercurvepoint.cpp create mode 100644 ground/src/plugins/config/mixercurvepoint.h create mode 100644 ground/src/plugins/config/mixercurvewidget.cpp create mode 100644 ground/src/plugins/config/mixercurvewidget.h diff --git a/ground/src/plugins/config/airframe.ui b/ground/src/plugins/config/airframe.ui index 5118e7d58..96e027f6a 100644 --- a/ground/src/plugins/config/airframe.ui +++ b/ground/src/plugins/config/airframe.ui @@ -107,8 +107,26 @@ Aircraft type: + + + + 90 + 70 + 131 + 131 + + + + + + MixerCurveWidget + QWidget +
mixercurvewidget.h
+ 1 +
+
diff --git a/ground/src/plugins/config/config.pro b/ground/src/plugins/config/config.pro index 9f9c00fe6..475bf9340 100644 --- a/ground/src/plugins/config/config.pro +++ b/ground/src/plugins/config/config.pro @@ -17,7 +17,10 @@ HEADERS += configplugin.h \ configtaskwidget.h \ configairframewidget.h \ configtelemetrywidget.h \ - configahrswidget.h + configahrswidget.h \ + mixercurvewidget.h \ + mixercurvepoint.h \ + mixercurveline.h SOURCES += configplugin.cpp \ configgadgetconfiguration.cpp \ configgadgetwidget.cpp \ @@ -29,7 +32,10 @@ SOURCES += configplugin.cpp \ configservowidget.cpp \ configairframewidget.cpp \ configtelemetrywidget.cpp \ - configahrswidget.cpp + configahrswidget.cpp \ + mixercurvewidget.cpp \ + mixercurvepoint.cpp \ + mixercurveline.cpp FORMS += settingswidget.ui \ airframe.ui \ telemetry.ui \ diff --git a/ground/src/plugins/config/configgadget.qrc b/ground/src/plugins/config/configgadget.qrc index 903601653..0b36bd1f6 100644 --- a/ground/src/plugins/config/configgadget.qrc +++ b/ground/src/plugins/config/configgadget.qrc @@ -6,5 +6,6 @@ images/ahrs-calib.svg images/AHRS-v1.3.png images/paper-plane.svg + images/curve-bg.svg diff --git a/ground/src/plugins/config/images/curve-bg.svg b/ground/src/plugins/config/images/curve-bg.svg new file mode 100644 index 000000000..4b424a335 --- /dev/null +++ b/ground/src/plugins/config/images/curve-bg.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/src/plugins/config/mixercurveline.cpp b/ground/src/plugins/config/mixercurveline.cpp new file mode 100644 index 000000000..d3ace9220 --- /dev/null +++ b/ground/src/plugins/config/mixercurveline.cpp @@ -0,0 +1,139 @@ +/** + ****************************************************************************** + * + * @file mixercurveline.h + * @author Edouard Lafargue Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Configuration Plugin + * @{ + * @brief A line connecting two mixer points + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "mixercurveline.h" +#include "mixercurvepoint.h" + +#include + +static const double Pi = 3.14159265358979323846264338327950288419717; +static double TwoPi = 2.0 * Pi; + +Edge::Edge(Node *sourceNode, Node *destNode) + : arrowSize(10) +{ + setAcceptedMouseButtons(0); + source = sourceNode; + dest = destNode; + source->addEdge(this); + dest->addEdge(this); + adjust(); +} + +Edge::~Edge() +{ +} + +Node *Edge::sourceNode() const +{ + return source; +} + +void Edge::setSourceNode(Node *node) +{ + source = node; + adjust(); +} + +Node *Edge::destNode() const +{ + return dest; +} + +void Edge::setDestNode(Node *node) +{ + dest = node; + adjust(); +} + +void Edge::adjust() +{ + if (!source || !dest) + return; + + QLineF line(mapFromItem(source, 0, 0), mapFromItem(dest, 0, 0)); + qreal length = line.length(); + + prepareGeometryChange(); + + if (length > qreal(20.)) { + QPointF edgeOffset((line.dx() * 10) / length, (line.dy() * 10) / length); + sourcePoint = line.p1() + edgeOffset; + destPoint = line.p2() - edgeOffset; + } else { + sourcePoint = destPoint = line.p1(); + } +} + +QRectF Edge::boundingRect() const +{ + if (!source || !dest) + return QRectF(); + + qreal penWidth = 1; + qreal extra = (penWidth + arrowSize) / 2.0; + + return QRectF(sourcePoint, QSizeF(destPoint.x() - sourcePoint.x(), + destPoint.y() - sourcePoint.y())) + .normalized() + .adjusted(-extra, -extra, extra, extra); +} + +void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + if (!source || !dest) + return; + + QLineF line(sourcePoint, destPoint); + if (qFuzzyCompare(line.length(), qreal(0.))) + return; + + // Draw the line itself + painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter->drawLine(line); + + // Draw the arrows + double angle = ::acos(line.dx() / line.length()); + if (line.dy() >= 0) + angle = TwoPi - angle; + + QPointF sourceArrowP1 = sourcePoint + QPointF(sin(angle + Pi / 3) * arrowSize, + cos(angle + Pi / 3) * arrowSize); + QPointF sourceArrowP2 = sourcePoint + QPointF(sin(angle + Pi - Pi / 3) * arrowSize, + cos(angle + Pi - Pi / 3) * arrowSize); + QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * arrowSize, + cos(angle - Pi / 3) * arrowSize); + QPointF destArrowP2 = destPoint + QPointF(sin(angle - Pi + Pi / 3) * arrowSize, + cos(angle - Pi + Pi / 3) * arrowSize); + + painter->setBrush(Qt::black); + painter->drawPolygon(QPolygonF() << line.p1() << sourceArrowP1 << sourceArrowP2); + painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); +} diff --git a/ground/src/plugins/config/mixercurveline.h b/ground/src/plugins/config/mixercurveline.h new file mode 100644 index 000000000..540a36457 --- /dev/null +++ b/ground/src/plugins/config/mixercurveline.h @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * + * @file mixercurveline.h + * @author Edouard Lafargue Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Configuration Plugin + * @{ + * @brief A line connecting two mixer points + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This is inspired by the elastic nodes and edges demo in the Qt examples + * I have reinventing the wheel! + */ + +#ifndef MIXERCURVELINE_H +#define MIXERCURVELINE_H + +#include + +class Node; + +class Edge : public QGraphicsItem +{ +public: + Edge(Node *sourceNode, Node *destNode); + ~Edge(); + + Node *sourceNode() const; + void setSourceNode(Node *node); + + Node *destNode() const; + void setDestNode(Node *node); + + void adjust(); + + enum { Type = UserType + 2 }; + int type() const { return Type; } + +protected: + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +private: + Node *source, *dest; + + QPointF sourcePoint; + QPointF destPoint; + qreal arrowSize; +}; + +#endif // MIXERCURVELINE_H + diff --git a/ground/src/plugins/config/mixercurvepoint.cpp b/ground/src/plugins/config/mixercurvepoint.cpp new file mode 100644 index 000000000..127f2d825 --- /dev/null +++ b/ground/src/plugins/config/mixercurvepoint.cpp @@ -0,0 +1,173 @@ +/** + ****************************************************************************** + * + * @file mixercurvepoint.h + * @author Edouard Lafargue Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Configuration Plugin + * @{ + * @brief A point on the mixer curve + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "mixercurveline.h" +#include "mixercurvepoint.h" +#include "mixercurvewidget.h" + +Node::Node(MixerCurveWidget *graphWidget) + : graph(graphWidget) +{ + setFlag(ItemIsMovable); + setFlag(ItemSendsGeometryChanges); + setCacheMode(DeviceCoordinateCache); + setZValue(-1); +} + +void Node::addEdge(Edge *edge) +{ + edgeList << edge; + edge->adjust(); +} + +QList Node::edges() const +{ + return edgeList; +} + +void Node::calculateForces() +{ + if (!scene() || scene()->mouseGrabberItem() == this) { + newPos = pos(); + return; + } + + // Sum up all forces pushing this item away + qreal xvel = 0; + qreal yvel = 0; + foreach (QGraphicsItem *item, scene()->items()) { + Node *node = qgraphicsitem_cast(item); + if (!node) + continue; + + QLineF line(mapFromItem(node, 0, 0), QPointF(0, 0)); + qreal dx = line.dx(); + qreal dy = line.dy(); + double l = 2.0 * (dx * dx + dy * dy); + if (l > 0) { + xvel += (dx * 150.0) / l; + yvel += (dy * 150.0) / l; + } + } + + // Now subtract all forces pulling items together + double weight = (edgeList.size() + 1) * 10; + foreach (Edge *edge, edgeList) { + QPointF pos; + if (edge->sourceNode() == this) + pos = mapFromItem(edge->destNode(), 0, 0); + else + pos = mapFromItem(edge->sourceNode(), 0, 0); + xvel += pos.x() / weight; + yvel += pos.y() / weight; + } + + if (qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1) + xvel = yvel = 0; + + QRectF sceneRect = scene()->sceneRect(); + newPos = pos() + QPointF(xvel, yvel); + newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)); + newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)); +} + +bool Node::advance() +{ + if (newPos == pos()) + return false; + + setPos(newPos); + return true; +} + +QRectF Node::boundingRect() const +{ + qreal adjust = 2; + return QRectF(-10 - adjust, -10 - adjust, + 23 + adjust, 23 + adjust); +} + +QPainterPath Node::shape() const +{ + QPainterPath path; + path.addEllipse(-10, -10, 20, 20); + return path; +} + +void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + painter->setPen(Qt::NoPen); + painter->setBrush(Qt::darkGray); + painter->drawEllipse(-7, -7, 20, 20); + + QRadialGradient gradient(-3, -3, 10); + if (option->state & QStyle::State_Sunken) { + gradient.setCenter(3, 3); + gradient.setFocalPoint(3, 3); + gradient.setColorAt(1, QColor(Qt::yellow).light(120)); + gradient.setColorAt(0, QColor(Qt::darkYellow).light(120)); + } else { + gradient.setColorAt(0, Qt::yellow); + gradient.setColorAt(1, Qt::darkYellow); + } + painter->setBrush(gradient); + painter->setPen(QPen(Qt::black, 0)); + painter->drawEllipse(-10, -10, 20, 20); +} + +QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) +{ + switch (change) { + case ItemPositionHasChanged: + foreach (Edge *edge, edgeList) + edge->adjust(); + graph->itemMoved(); + break; + default: + break; + }; + + return QGraphicsItem::itemChange(change, value); +} + +void Node::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + update(); + QGraphicsItem::mousePressEvent(event); +} + +void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + update(); + QGraphicsItem::mouseReleaseEvent(event); +} diff --git a/ground/src/plugins/config/mixercurvepoint.h b/ground/src/plugins/config/mixercurvepoint.h new file mode 100644 index 000000000..75de06543 --- /dev/null +++ b/ground/src/plugins/config/mixercurvepoint.h @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * + * @file mixercurvepoint.h + * @author Edouard Lafargue Copyright (C) 2010. + * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Configuration Plugin + * @{ + * @brief A point on the mixer curve + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIXERCURVEPOINT_H +#define MIXERCURVEPOINT_H + +#include +#include + +class Edge; +class MixerCurveWidget; +QT_BEGIN_NAMESPACE +class QGraphicsSceneMouseEvent; +QT_END_NAMESPACE + +class Node : public QGraphicsItem +{ +public: + Node(MixerCurveWidget *graphWidget); + + void addEdge(Edge *edge); + QList edges() const; + + enum { Type = UserType + 1 }; + int type() const { return Type; } + + void calculateForces(); + bool advance(); + + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + +private: + QList edgeList; + QPointF newPos; + MixerCurveWidget *graph; +}; + +#endif // MIXERCURVEPOINT_H diff --git a/ground/src/plugins/config/mixercurvewidget.cpp b/ground/src/plugins/config/mixercurvewidget.cpp new file mode 100644 index 000000000..a7cd15fb1 --- /dev/null +++ b/ground/src/plugins/config/mixercurvewidget.cpp @@ -0,0 +1,123 @@ +/** + ****************************************************************************** + * + * @file mixercurvewidget.cpp + * @author Edouard Lafargue Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief A widget which displays an adjustable mixer curve + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "mixercurvewidget.h" +#include "mixercurveline.h" +#include "mixercurvepoint.h" + +#include +#include + + + +/* + * Initialize the widget + */ +MixerCurveWidget::MixerCurveWidget(QWidget *parent) : QGraphicsView(parent) +{ + + // Create a layout, add a QGraphicsView and put the SVG inside. + // The Mixer Curve widget looks like this: + // |--------------------| + // | | + // | | + // | Graph | + // | | + // | | + // | | + // |--------------------| + + + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setRenderHint(QPainter::Antialiasing); + + QGraphicsScene *scene = new QGraphicsScene(this); + QSvgRenderer *renderer = new QSvgRenderer(); + plot = new QGraphicsSvgItem(); + renderer->load(QString(":/configgadget/images/curve-bg.svg")); + plot->setSharedRenderer(renderer); + //plot->setElementId("map"); + scene->addItem(plot); + plot->setZValue(-1); + scene->setSceneRect(plot->boundingRect()); + setScene(scene); + + Node *node1 = new Node(this); + Node *node2 = new Node(this); + Node *node3 = new Node(this); + Node *node4 = new Node(this); + Node *node5 = new Node(this); + scene->addItem(node1); + scene->addItem(node2); + scene->addItem(node3); + scene->addItem(node4); + scene->addItem(node5); + + scene->addItem(new Edge(node1, node2)); + scene->addItem(new Edge(node2, node3)); + scene->addItem(new Edge(node3, node4)); + scene->addItem(new Edge(node4, node5)); + + qreal w = plot->boundingRect().width()/5; + + node1->setPos(w-w/2,50); + node2->setPos(2*w-w/2, 50); + node3->setPos(3*w-w/2, 50); + node4->setPos(4*w-w/2, 50); + node5->setPos(5*w-w/2, 50); + + +} + +MixerCurveWidget::~MixerCurveWidget() +{ + +} + +void MixerCurveWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + // Thit fitInView method should only be called now, once the + // widget is shown, otherwise it cannot compute its values and + // the result is usually a ahrsbargraph that is way too small. + fitInView(plot, Qt::KeepAspectRatio); + +} + +void MixerCurveWidget::resizeEvent(QResizeEvent* event) +{ + Q_UNUSED(event); + fitInView(plot, Qt::KeepAspectRatio); +} + + + +void MixerCurveWidget::itemMoved() +{ + +} diff --git a/ground/src/plugins/config/mixercurvewidget.h b/ground/src/plugins/config/mixercurvewidget.h new file mode 100644 index 000000000..8f305bf09 --- /dev/null +++ b/ground/src/plugins/config/mixercurvewidget.h @@ -0,0 +1,59 @@ +/** + ****************************************************************************** + * + * @file mixercurvewidget.h + * @author Edouard Lafargue Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Configuration Plugin + * @{ + * @brief A widget which displays a mixer curve + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIXERCURVEWIDGET_H_ +#define MIXERCURVEWIDGET_H_ + +#include +#include +#include + + +class MixerCurveWidget : public QGraphicsView +{ + Q_OBJECT + +public: + MixerCurveWidget(QWidget *parent = 0); + ~MixerCurveWidget(); + void itemMoved(); + +public slots: + + +private slots: + +private: + QGraphicsSvgItem *plot; + +protected: + void showEvent(QShowEvent *event); + void resizeEvent(QResizeEvent *event); + + +}; +#endif /* MIXERCURVEWIDGET_H_ */