mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Add Elevation Widget to Train Video Overlays (#3411)
* 1 - Add forceSquareRatio to MeterWidget * 2 - Adjust default colors and add background text. * 3 - Add Elevation widget, included in default layout visible only on slope mode. Based on the work done by Vianney Voyer Co-authored-by: Peter <pkanatselis@gmail.com>
This commit is contained in:
@@ -83,4 +83,13 @@
|
||||
<MainColor R="255" G="0" B="0" A="180" />
|
||||
<Text>load</Text>
|
||||
</meter>
|
||||
<!-- START Changes for elevation widget -->
|
||||
<meter name="elevation" container="Video" source="Elevation" type="Elevation">
|
||||
<RelativeSize Width="40.0" Height="15.0" />
|
||||
<RelativePosition X="20.0" Y="92.0" />
|
||||
<BackgroundColor R="200" G="200" B="200" A="125" />
|
||||
<OutlineColor R="255" G="255" B="255" A="250" />
|
||||
<MainColor R="255" G="0" B="0" A="250" />
|
||||
</meter>
|
||||
<!-- END Changes for elevation widget -->
|
||||
</layout>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <QtGui>
|
||||
#include <QGraphicsPathItem>
|
||||
#include "MeterWidget.h"
|
||||
#include "ErgFile.h"
|
||||
#include "Context.h"
|
||||
|
||||
MeterWidget::MeterWidget(QString Name, QWidget *parent, QString Source) : QWidget(parent), m_Name(Name), m_container(parent), m_Source(Source)
|
||||
{
|
||||
@@ -37,12 +39,13 @@ MeterWidget::MeterWidget(QString Name, QWidget *parent, QString Source) : QWidge
|
||||
m_OutlineColor = QColor(128,128,128,180);
|
||||
m_MainFont = QFont(this->font().family(), 64);
|
||||
m_AltFont = QFont(this->font().family(), 48);
|
||||
m_BackgroundColor = QColor(96, 96, 96, 200);
|
||||
m_BackgroundColor = QColor(96, 96, 96, 0);
|
||||
m_RangeMin = 0;
|
||||
m_RangeMax = 100;
|
||||
m_Angle = 180.0;
|
||||
m_SubRange = 10;
|
||||
boundingRectVisibility = false;
|
||||
forceSquareRatio = true;
|
||||
}
|
||||
|
||||
void MeterWidget::SetRelativeSize(float RelativeWidth, float RelativeHeight)
|
||||
@@ -75,7 +78,15 @@ void MeterWidget::AdjustSizePos()
|
||||
|
||||
void MeterWidget::ComputeSize()
|
||||
{
|
||||
m_Width = m_Height = (m_container->width() * m_RelativeWidth + m_container->height() * m_RelativeHeight) / 2;
|
||||
if (forceSquareRatio)
|
||||
{
|
||||
m_Width = m_Height = (m_container->width() * m_RelativeWidth + m_container->height() * m_RelativeHeight) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Width = m_container->width() * m_RelativeWidth;
|
||||
m_Height = m_container->height() * m_RelativeHeight;
|
||||
}
|
||||
}
|
||||
|
||||
QSize MeterWidget::sizeHint() const
|
||||
@@ -119,12 +130,7 @@ void MeterWidget::setBoundingRectVisibility(bool show, QColor boundingRectColor
|
||||
|
||||
TextMeterWidget::TextMeterWidget(QString Name, QWidget *parent, QString Source) : MeterWidget(Name, parent, Source)
|
||||
{
|
||||
}
|
||||
|
||||
void TextMeterWidget::ComputeSize()
|
||||
{
|
||||
m_Width = m_container->width() * m_RelativeWidth;
|
||||
m_Height = m_container->height() * m_RelativeHeight;
|
||||
forceSquareRatio = false;
|
||||
}
|
||||
|
||||
void TextMeterWidget::paintEvent(QPaintEvent* paintevent)
|
||||
@@ -132,6 +138,7 @@ void TextMeterWidget::paintEvent(QPaintEvent* paintevent)
|
||||
MeterWidget::paintEvent(paintevent);
|
||||
|
||||
m_MainBrush = QBrush(m_MainColor);
|
||||
m_BackgroundBrush = QBrush(m_BackgroundColor);
|
||||
m_OutlinePen = QPen(m_OutlineColor);
|
||||
m_OutlinePen.setWidth(1);
|
||||
m_OutlinePen.setStyle(Qt::SolidLine);
|
||||
@@ -140,6 +147,12 @@ void TextMeterWidget::paintEvent(QPaintEvent* paintevent)
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
//draw background
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(m_BackgroundBrush);
|
||||
if (Text!=QString(""))
|
||||
painter.drawRect (0, 0, m_Width, m_Height);
|
||||
|
||||
QPainterPath my_painterPath;
|
||||
my_painterPath.addText(QPointF(0,0),m_MainFont,Text);
|
||||
my_painterPath.addText(QPointF(QFontMetrics(m_MainFont).width(Text), 0),m_AltFont,AltText);
|
||||
@@ -297,3 +310,94 @@ void NeedleMeterWidget::paintEvent(QPaintEvent* paintevent)
|
||||
painter.drawPath(my_painterPath);
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
ElevationMeterWidget::ElevationMeterWidget(QString Name, QWidget *parent, QString Source, Context *context) : MeterWidget(Name, parent, Source), context(context)
|
||||
{
|
||||
forceSquareRatio = false;
|
||||
gradientValue = 0.0;
|
||||
}
|
||||
|
||||
void ElevationMeterWidget::paintEvent(QPaintEvent* paintevent)
|
||||
{
|
||||
// TODO : show Power when not in slope simulation mode
|
||||
if (!context || !context->currentErgFile() || context->currentErgFile()->Points.size()<=1)
|
||||
return;
|
||||
|
||||
MeterWidget::paintEvent(paintevent);
|
||||
|
||||
m_MainBrush = QBrush(m_MainColor);
|
||||
m_BackgroundBrush = QBrush(m_BackgroundColor);
|
||||
m_OutlinePen = QPen(m_OutlineColor);
|
||||
m_OutlinePen.setWidth(1);
|
||||
m_OutlinePen.setStyle(Qt::SolidLine);
|
||||
|
||||
//painter
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// Find min/max
|
||||
double minX, minY, maxX, maxY, cyclistX=0.0;
|
||||
// (based on ErgFilePlot.cpp)
|
||||
minX=maxX=context->currentErgFile()->Points[0].x; // meters
|
||||
minY=maxY=context->currentErgFile()->Points[0].y; // meters or altitude???
|
||||
foreach(ErgFilePoint x, context->currentErgFile()->Points)
|
||||
{
|
||||
if (x.y > maxY) maxY = x.y;
|
||||
if (x.x > maxX) maxX = x.x;
|
||||
if (x.y < minY) minY = x.y;
|
||||
if (x.x < minX) minX = x.x;
|
||||
}
|
||||
// check if slope shown will not be too inconsistent (based on widget's width/height ratio)
|
||||
// we accept 20 times i.e. 5% gradient will be shown as 45°
|
||||
if ( m_Width!=0 && (maxY-minY) / 0.05 < (double)m_Height * 0.80 * (maxX-minX) / (double)m_Width)
|
||||
maxY = minY + (double)m_Height * 0.80 * (maxX-minX) / (double)m_Width * 0.05;
|
||||
double bubbleSize = (double)m_Height*0.010f;
|
||||
minY -= (maxY-minY) * 0.20f; // add 20% as bottom headroom (slope gradient will be shown there in a bubble)
|
||||
|
||||
// this->Value should hold the current distance in meters.
|
||||
cyclistX = (this->Value * 1000.0 - minX) * (double)m_Width / (maxX-minX);
|
||||
|
||||
//Get point to create the polygon
|
||||
QPolygon polygon;
|
||||
polygon << QPoint(0.0, (double)m_Height);
|
||||
double x, y, pt=0;
|
||||
double nextX = 1;
|
||||
for( pt=0; pt < context->currentErgFile()->Points.size(); pt++)
|
||||
{
|
||||
for ( ; x < nextX && pt < context->currentErgFile()->Points.size(); pt++)
|
||||
{
|
||||
x = (context->currentErgFile()->Points[pt].x - minX) * (double)m_Width / (maxX-minX);
|
||||
y = (context->currentErgFile()->Points[pt].y - minY) * (double)m_Height / (maxY-minY);
|
||||
}
|
||||
// Add points to polygon only once every time the x coordinate integer part changes.
|
||||
polygon << QPoint(x, (double)m_Height - y);
|
||||
nextX = floor(x) + 1.0;
|
||||
}
|
||||
polygon << QPoint((double) m_Width, (double)m_Height);
|
||||
polygon << QPoint(fmin((double) m_Width,cyclistX+bubbleSize), (double)m_Height);
|
||||
polygon << QPoint(cyclistX, (double)m_Height-bubbleSize);
|
||||
polygon << QPoint(fmax(0.0, cyclistX-bubbleSize), (double)m_Height);
|
||||
|
||||
painter.setPen(m_OutlinePen);
|
||||
painter.setBrush(m_BackgroundBrush);
|
||||
painter.drawPolygon(polygon);
|
||||
|
||||
m_OutlinePen = QPen(m_MainColor);
|
||||
m_OutlinePen.setWidth(1);
|
||||
m_OutlinePen.setStyle(Qt::SolidLine);
|
||||
painter.setPen(m_OutlinePen);
|
||||
painter.drawLine(cyclistX, 0.0, cyclistX, (double)m_Height-bubbleSize);
|
||||
|
||||
//Cosmetic enhancment: Display grade as #.#%
|
||||
std::string sGrad;
|
||||
QString s_grad ="";
|
||||
s_grad = ((-1.0 < this->gradientValue && this->gradientValue < 0.0)?QString("-"):QString("")) + QString::number((int) this->gradientValue);
|
||||
s_grad += QString(".") + QString::number(abs((int)(this->gradientValue * 10.0) % 10)) + QString("%");
|
||||
|
||||
// Display gradient text to the right of the line until the middle, then display to the left of the line
|
||||
if (cyclistX < m_Width*0.5) {
|
||||
painter.drawText((double)cyclistX+5, ((double)m_Height * 0.95), s_grad);
|
||||
} else {
|
||||
painter.drawText((double)cyclistX-45, ((double)m_Height * 0.95), s_grad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define _MeterWidget_h 1
|
||||
|
||||
#include <QWidget>
|
||||
#include "Context.h"
|
||||
|
||||
class MeterWidget : public QWidget
|
||||
{
|
||||
@@ -59,6 +60,7 @@ class MeterWidget : public QWidget
|
||||
float m_RangeMin, m_RangeMax;
|
||||
float m_Angle;
|
||||
int m_SubRange;
|
||||
bool forceSquareRatio;
|
||||
|
||||
QColor m_MainColor;
|
||||
QColor m_ScaleColor;
|
||||
@@ -83,7 +85,6 @@ class TextMeterWidget : public MeterWidget
|
||||
{
|
||||
public:
|
||||
explicit TextMeterWidget(QString name, QWidget *parent = 0, QString Source = QString("None"));
|
||||
virtual void ComputeSize();
|
||||
virtual void paintEvent(QPaintEvent* paintevent);
|
||||
};
|
||||
|
||||
@@ -109,5 +110,15 @@ class NeedleMeterWidget : public MeterWidget
|
||||
virtual void paintEvent(QPaintEvent* paintevent);
|
||||
};
|
||||
|
||||
class ElevationMeterWidget : public MeterWidget
|
||||
{
|
||||
public:
|
||||
explicit ElevationMeterWidget(QString name, QWidget *parent = 0, QString Source = QString("None"), Context *context = NULL);
|
||||
virtual void paintEvent(QPaintEvent* paintevent);
|
||||
float gradientValue;
|
||||
void setContext(Context *context) { this->context = context; }
|
||||
private:
|
||||
Context *context;
|
||||
};
|
||||
|
||||
#endif // _MeterWidget_h
|
||||
|
||||
@@ -47,7 +47,7 @@ void VideoLayoutParser::SetDefaultValues()
|
||||
meterWidget->m_MainColor = QColor(255,0,0,200);
|
||||
meterWidget->m_ScaleColor = QColor(255,255,255,200);
|
||||
meterWidget->m_OutlineColor = QColor(100,100,100,200);
|
||||
meterWidget->m_BackgroundColor = QColor(100,100,100,200);
|
||||
meterWidget->m_BackgroundColor = QColor(100,100,100,0);
|
||||
meterWidget->m_MainFont = QFont(meterWidget->font().family(), 64);
|
||||
meterWidget->m_AltFont = QFont(meterWidget->font().family(), 48);
|
||||
}
|
||||
@@ -134,6 +134,10 @@ bool VideoLayoutParser::startElement( const QString&, const QString&,
|
||||
{
|
||||
meterWidget = new CircularBargraphMeterWidget(meterName, containerWidget, source);
|
||||
}
|
||||
else if (meterType == QString("Elevation"))
|
||||
{
|
||||
meterWidget = new ElevationMeterWidget(meterName, containerWidget, source);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QObject::tr("Error creating meter");
|
||||
|
||||
@@ -316,6 +316,23 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
|
||||
p_meterWidget->Text = QString::number((int)p_meterWidget->Value);
|
||||
p_meterWidget->AltText = QString(".") +QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + (metric ? tr(" kph") : tr(" mph"));
|
||||
}
|
||||
else if (p_meterWidget->Source() == QString("Elevation"))
|
||||
{
|
||||
// Do not show in ERG mode
|
||||
if (rtd.mode == ERG || rtd.mode == MRC)
|
||||
{
|
||||
p_meterWidget->setWindowOpacity(0); // Hide the widget
|
||||
}
|
||||
p_meterWidget->Value = rtd.getDistance();
|
||||
ElevationMeterWidget* elevationMeterWidget = dynamic_cast<ElevationMeterWidget*>(p_meterWidget);
|
||||
if (!elevationMeterWidget)
|
||||
qDebug() << "Error: Elevation keyword used but widget is not elevation type";
|
||||
else
|
||||
{
|
||||
elevationMeterWidget->setContext(context);
|
||||
elevationMeterWidget->gradientValue = rtd.getSlope();
|
||||
}
|
||||
}
|
||||
else if (p_meterWidget->Source() == QString("Cadence"))
|
||||
{
|
||||
p_meterWidget->Value = rtd.getCadence();
|
||||
|
||||
Reference in New Issue
Block a user