1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-25 10:52:11 +01:00

303 lines
8.7 KiB
C++

#include "monitorwidget.h"
#include <utils/stylehelper.h>
#include <QObject>
#include <QDebug>
#include <QtGui/QFont>
namespace {
/**
* Create an SVG item and connect it to an element of the SVG file previously loaded into the parent item.
* This then allows to show, hide, move, scale and rotate the element.
* Opacity can also be changed.
* Other characteristics (color, ...) of the element cannot be modified.
*/
// TODO move to some utility class that can be reused by other SVG manipulating code
QGraphicsSvgItem *createSvgItem(QGraphicsSvgItem *parent, QString elementId)
{
QGraphicsSvgItem *item = new QGraphicsSvgItem(parent);
QSvgRenderer *renderer = parent->renderer();
// connect item to its corresponding element
item->setSharedRenderer(renderer);
item->setElementId(elementId);
// move item to its location
QMatrix elementMatrix = renderer->matrixForElement(elementId);
QRectF elementRect = elementMatrix.mapRect(renderer->boundsOnElement(elementId));
item->setPos(elementRect.x(), elementRect.y());
return item;
}
/**
* Create a text item based on a svg rectangle.
* The rectangle must be in the correct location (hint: use a "text" layer on top of the "background layer")
* The font size will be set to match as well as possible the rectangle height but it is not guaranteed.
*
* It is possible to show the text rectangle to help understand layout issues.
*
*/
// TODO move to some utility class that can be reused by other SVG manipulating code
QGraphicsTextItem *createTextItem(QGraphicsSvgItem *parent, QString elementId, QString fontName,
bool showRect = false)
{
if (showRect) {
// create and display the text rectangle
// needs to be done first otherwise the rectangle will blank out the text.
createSvgItem(parent, elementId);
}
QGraphicsTextItem *item = new QGraphicsTextItem();
QSvgRenderer *renderer = parent->renderer();
// move new text item to location of rectangle element
QMatrix elementMatrix = renderer->matrixForElement(elementId);
QRectF elementRect = elementMatrix.mapRect(renderer->boundsOnElement(elementId));
qreal fontPointSizeF = elementRect.height();
QTransform matrix;
matrix.translate(elementRect.x(), elementRect.y() - (fontPointSizeF / 2.0));
item->setParentItem(parent);
item->setTransform(matrix, false);
// to right align or center text we must provide a text width
// item->setTextWidth(elementRect.width());
// create font to match the rectangle height
// there is not guaranteed that all fonts will play well...
QFont font(fontName);
// not sure if PreferMatch helps to get the correct font size (i.e. that fits the text rectangle nicely)
font.setStyleStrategy(QFont::PreferMatch);
font.setPointSizeF(fontPointSizeF);
item->setFont(font);
#ifdef DEBUG_FONT
// just in case
qDebug() << "Font point size: " << fontPointSizeF;
qDebug() << "Font pixel size: " << font.pixelSize();
qDebug() << "Font point size: " << font.pointSize();
qDebug() << "Font point size F: " << font.pointSizeF();
qDebug() << "Font exact match: " << font.exactMatch();
QFontInfo fontInfo(font);
qDebug() << "Font info pixel size: " << fontInfo.pixelSize();
qDebug() << "Font info point size: " << fontInfo.pointSize();
qDebug() << "Font info point size F: " << fontInfo.pointSizeF();
qDebug() << "Font info exact match: " << fontInfo.exactMatch();
#endif
return item;
}
} // anonymous namespace
MonitorWidget::MonitorWidget(QWidget *parent) :
QGraphicsView(parent), aspectRatioMode(Qt::KeepAspectRatio)
{
setMinimumSize(195, 25);
QGraphicsScene *scene = new QGraphicsScene();
setScene(scene);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
// no scroll bars
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setStyleSheet("QGraphicsView{background:transparent;}");
setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor()));
setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
QSvgRenderer *renderer = new QSvgRenderer();
if (renderer->load(QString(":/telemetry/images/tx-rx.svg"))) {
// create graph
graph = new QGraphicsSvgItem();
graph->setSharedRenderer(renderer);
graph->setElementId("background");
graph->setFlags(QGraphicsItem::ItemClipsChildrenToShape | QGraphicsItem::ItemClipsToShape);
scene->addItem(graph);
int i;
// create tx nodes
i = 0;
while (true) {
QString id = QString("tx%0").arg(i);
QString bgId = QString("tx_bg%0").arg(i);
if (!renderer->elementExists(id) || !renderer->elementExists(bgId)) {
break;
}
QGraphicsSvgItem *item = createSvgItem(graph, bgId);
item->setElementId(id);
txNodes.append(item);
i++;
}
// create rx nodes
i = 0;
while (true) {
QString id = QString("rx%0").arg(i);
QString bgId = QString("rx_bg%0").arg(i);
if (!renderer->elementExists(id) || !renderer->elementExists(bgId)) {
break;
}
QGraphicsSvgItem *item = createSvgItem(graph, bgId);
item->setElementId(id);
rxNodes.append(item);
i++;
}
if (renderer->elementExists("txSpeed")) {
txSpeed = createTextItem(graph, "txSpeed", "Helvetica");
txSpeed->setDefaultTextColor(Qt::white);
} else {
txSpeed = NULL;
}
if (renderer->elementExists("rxSpeed")) {
rxSpeed = createTextItem(graph, "rxSpeed", "Helvetica");
rxSpeed->setDefaultTextColor(Qt::white);
} else {
rxSpeed = NULL;
}
// scene->setSceneRect(graph->boundingRect());
}
connected = false;
setMin(0.0);
setMax(1200.0);
telemetryUpdated(0.0, 0.0);
}
MonitorWidget::~MonitorWidget()
{
while (!txNodes.isEmpty()) {
delete txNodes.takeFirst();
}
while (!rxNodes.isEmpty()) {
delete rxNodes.takeFirst();
}
if (txSpeed) {
delete txSpeed;
}
if (rxSpeed) {
delete rxSpeed;
}
}
/*!
\brief Enables/Disables OpenGL
*/
// void LineardialGadgetWidget::enableOpenGL(bool flag)
// {
// if (flag) {
// setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
// } else {
// setViewport(new QWidget);
// }
// }
void MonitorWidget::telemetryConnected()
{
qDebug() << "telemetry connected";
if (!connected) {
// flash the lights
setToolTip(tr("Connected"));
telemetryUpdated(maxValue, maxValue);
connected = true;
}
}
void MonitorWidget::telemetryDisconnected()
{
qDebug() << "telemetry disconnected";
if (connected) {
connected = false;
setToolTip(tr("Disconnected"));
// flash the lights???
telemetryUpdated(maxValue, maxValue);
telemetryUpdated(0.0, 0.0);
}
}
/*!
\brief Called by the UAVObject which got updated
Updates the numeric value and/or the icon if the dial wants this.
*/
void MonitorWidget::telemetryUpdated(double txRate, double rxRate)
{
double txIndex = (txRate - minValue) / (maxValue - minValue) * txNodes.count();
double rxIndex = (rxRate - minValue) / (maxValue - minValue) * rxNodes.count();
if (connected) {
this->setToolTip(QString("Tx: %0 bytes/s, Rx: %1 bytes/s").arg(txRate).arg(rxRate));
}
for (int i = 0; i < txNodes.count(); i++) {
QGraphicsItem *node = txNodes.at(i);
bool visible = ( /*connected &&*/ (i < txIndex));
if (visible != node->isVisible()) {
node->setVisible(visible);
node->update();
}
}
for (int i = 0; i < rxNodes.count(); i++) {
QGraphicsItem *node = rxNodes.at(i);
bool visible = ( /*connected &&*/ (i < rxIndex));
if (visible != node->isVisible()) {
node->setVisible(visible);
node->update();
}
}
if (txSpeed) {
if (connected) {
txSpeed->setPlainText(QString("%0").arg(txRate));
}
txSpeed->setVisible(connected);
txSpeed->update();
}
if (rxSpeed) {
if (connected) {
rxSpeed->setPlainText(QString("%0").arg(rxRate));
}
rxSpeed->setVisible(connected);
rxSpeed->update();
}
update();
}
void MonitorWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event);
fitInView(graph, aspectRatioMode);
}
void MonitorWidget::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
fitInView(graph, aspectRatioMode);
}