/*===================================================================== QGroundControl Open Source Ground Control Station (c) 2009, 2014 QGROUNDCONTROL PROJECT This file is part of the QGROUNDCONTROL project QGROUNDCONTROL 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. QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . ======================================================================*/ /// @file /// @author Don Gagne #include "RCChannelWidget.h" #include #define DIMMEST_COLOR QColor::fromRgb(0,100,0) #define MIDBRIGHT_COLOR QColor::fromRgb(0,180,0) #define BRIGHTEST_COLOR QColor::fromRgb(64,255,0) RCChannelWidget::RCChannelWidget(QWidget *parent) : QGroupBox(parent), _value(_centerValue), _min(_centerValue), _max(_centerValue), _trim(_centerValue), _minValid(false), _maxValid(false), _showMinMax(false), _showTrim(false) { } /// @brief Draws the control void RCChannelWidget::paintEvent(QPaintEvent *event) { // Let the group box draw the outer border QGroupBox::paintEvent(event); // Now we draw the innner contents QPainter painter(this); int fontHeight = painter.fontMetrics().height(); int rowHeigth = fontHeight + 2; painter.setBrush(Qt::Dense4Pattern); painter.setPen(QColor::fromRgb(128,128,64)); int curVal = _value; if (curVal > _maxRange) { curVal = _maxRange; } if (curVal < _minRange) { curVal = _minRange; } if (isEnabled()) { QLinearGradient hGradientBrush(0, 0, this->width(), this->height()); hGradientBrush.setColorAt(0.0,DIMMEST_COLOR); hGradientBrush.setColorAt(0.5,MIDBRIGHT_COLOR); hGradientBrush.setColorAt(1.0, BRIGHTEST_COLOR); // Calculate how much horizontal space we need to show a min/max value. We must be able to display four numeric // digits for the rc value, plus we add another digit for spacing. int minMaxDisplayWidth = painter.fontMetrics().width("00000"); // Draw the value axis line with center and end point tick marks. We need to leave enough space on the left and the right // for the Min/Max value displays. QRect rcValueAxis(minMaxDisplayWidth, rowHeigth * 2, width() - (minMaxDisplayWidth * 2), rowHeigth); int yLine = rcValueAxis.y() + rcValueAxis.height() / 2; painter.drawLine(rcValueAxis.left(), yLine, rcValueAxis.right(), yLine); painter.drawLine(rcValueAxis.left(), rcValueAxis.top(), rcValueAxis.left(), rcValueAxis.bottom()); painter.drawLine(rcValueAxis.right(), rcValueAxis.top(), rcValueAxis.right(), rcValueAxis.bottom()); painter.drawLine(rcValueAxis.left() + rcValueAxis.width() / 2, rcValueAxis.top(), rcValueAxis.left() + rcValueAxis.width() / 2, rcValueAxis.bottom()); painter.setPen(QColor::fromRgb(50,255,50)); painter.setBrush(hGradientBrush); if (_showMinMax) { QString text; // Draw the Min numeric value display to the left painter.drawText(0, rowHeigth, minMaxDisplayWidth, fontHeight, Qt::AlignHCenter | Qt::AlignBottom, "Min"); if (_minValid) { text = QString::number(_min); } else { text = "----"; } painter.drawText(0, rowHeigth * 2, minMaxDisplayWidth, fontHeight, Qt::AlignHCenter | Qt::AlignBottom, text); // Draw the Max numeric value display to the right painter.drawText(width() - minMaxDisplayWidth, rowHeigth, minMaxDisplayWidth, fontHeight, Qt::AlignHCenter | Qt::AlignBottom, "Max"); if (_maxValid) { text = QString::number(_max); } else { text = QString::number(_max); } painter.drawText(width() - minMaxDisplayWidth, rowHeigth * 2, minMaxDisplayWidth, fontHeight, Qt::AlignHCenter | Qt::AlignBottom, text); // Draw the Min/Max tick marks on the axis int xTick; if (_minValid) { int xTick = rcValueAxis.left() + (rcValueAxis.width() * ((float)(_min-_minRange) / (_maxRange-_minRange))); painter.drawLine(xTick, rcValueAxis.top(), xTick, rcValueAxis.bottom()); } if (_maxValid) { xTick = rcValueAxis.left() + (rcValueAxis.width() * ((float)(_max-_minRange) / (_maxRange-_minRange))); painter.drawLine(xTick, rcValueAxis.top(), xTick, rcValueAxis.bottom()); } } if (_showTrim) { // Draw the Trim value pointer _drawValuePointer(&painter, rcValueAxis.left() + (rcValueAxis.width() * ((float)(_trim-_minRange) / (_maxRange-_minRange))), // x position for tip of triangle (rowHeigth * 2) + (rowHeigth / 2) - 1, // y position for tip of triangle rowHeigth / 2, // heigth of triangle false); // draw upside down // Draw the Trim value label QString trimStr = tr("Trim %1").arg(QString::number(_trim)); int trimTextWidth = painter.fontMetrics().width(trimStr); painter.drawText(rcValueAxis.left() + (rcValueAxis.width() * ((float)(_trim-_minRange) / (_maxRange-_minRange))) - (trimTextWidth / 2), rowHeigth, trimTextWidth, fontHeight, Qt::AlignLeft | Qt::AlignBottom, trimStr); } // Draw the RC value pointer _drawValuePointer(&painter, rcValueAxis.left() + (rcValueAxis.width() * ((float)(curVal-_minRange) / (_maxRange-_minRange))), // x position for tip of triangle (rowHeigth * 2) + (rowHeigth / 2) + 1, // y position for tip of triangle rowHeigth / 2, // heigth of triangle true); // draw right side up // Draw the control value QString valueStr = QString::number(_value); int valueTextWidth = painter.fontMetrics().width(valueStr); painter.drawText(rcValueAxis.left() + (rcValueAxis.width() * ((float)(_value-_minRange) / (_maxRange-_minRange))) - (valueTextWidth / 2), rowHeigth * 3, valueTextWidth, fontHeight, Qt::AlignLeft | Qt::AlignBottom, valueStr); painter.setPen(QColor::fromRgb(0,128,0)); painter.setBrush(hGradientBrush); } else { painter.setPen(QColor(Qt::gray)); painter.drawText(0, 0, width(), height(), Qt::AlignHCenter | Qt::AlignVCenter, tr("not available")); } } void RCChannelWidget::setValue(int value) { _value = value; update(); } void RCChannelWidget::showMinMax(bool show) { _showMinMax = show; update(); } void RCChannelWidget::showTrim(bool show) { _showTrim = show; update(); } void RCChannelWidget::setValueAndMinMax(int val, int min, int max) { setValue(val); setMinMax(min,max); } void RCChannelWidget::setMinMax(int min, int max) { _min = min; _max = max; update(); } void RCChannelWidget::setTrim(int value) { _trim = value; update(); } /// @brief Draw rc value pointer triangle. /// @param painter Draw using this painter /// @param x X position for tip of triangle /// @param y Y position for tip of triangle /// @param heigth Height of triangle /// @param rightSideUp true: draw triangle right side up, false: draw triangle upside down void RCChannelWidget::_drawValuePointer(QPainter* painter, int xTip, int yTip, int height, bool rightSideUp) { QPointF trianglePoints[3]; // Topmost tip of triangle points to value trianglePoints[0].setX(xTip); trianglePoints[0].setY(yTip); int yBottom; if (rightSideUp) { yBottom = yTip + height; } else { yBottom = yTip - height; } // Right bottom tip of triangle trianglePoints[1].setX(xTip + (height * 0.75)); trianglePoints[1].setY(yBottom); // Left bottom tip of triangle trianglePoints[2].setX(xTip - (height * 0.75)); trianglePoints[2].setY(yBottom); painter->drawPolygon (trianglePoints, 3); } /// @brief Set whether the Min range value is valid or not. void RCChannelWidget::setMinValid(bool valid) { _minValid = valid; update(); } /// @brief Set whether the Max range value is valid or not. void RCChannelWidget::setMaxValid(bool valid) { _maxValid = valid; update(); }