diff --git a/src/Train/MeterWidget.cpp b/src/Train/MeterWidget.cpp index 53d4980287..9baa845113 100644 --- a/src/Train/MeterWidget.cpp +++ b/src/Train/MeterWidget.cpp @@ -54,6 +54,7 @@ MeterWidget::MeterWidget(QString Name, QWidget *parent, QString Source) : QWidge m_SubRange = 10; m_Zoom = 16; boundingRectVisibility = false; + backgroundVisibility = false; forceSquareRatio = true; } @@ -117,19 +118,29 @@ QSize MeterWidget::minimumSize() const void MeterWidget::paintEvent(QPaintEvent* paintevent) { Q_UNUSED(paintevent); + if(!boundingRectVisibility && !backgroundVisibility) return; + + QPainter painter(this); + painter.setClipRegion(videoContainerRegion); + painter.setRenderHint(QPainter::Antialiasing); + + int radius = qMin(m_Width, m_Height) * 0.1; + if(backgroundVisibility) painter.setBrush(QBrush(m_BackgroundColor)); + else painter.setBrush(Qt::NoBrush); + if (boundingRectVisibility) { - m_OutlinePen = QPen(boundingRectColor); + m_OutlinePen = QPen(m_BoundingRectColor); m_OutlinePen.setWidth(2); m_OutlinePen.setStyle(Qt::SolidLine); - //painter - QPainter painter(this); - painter.setClipRegion(videoContainerRegion); - painter.setRenderHint(QPainter::Antialiasing); - painter.setPen(m_OutlinePen); - painter.drawRect (1, 1, m_Width-2, m_Height-2); + painter.drawRoundedRect (1, 1, m_Width-2, m_Height-2, radius, radius); + } + else + { + painter.setPen(Qt::NoPen); + painter.drawRoundedRect (0, 0, m_Width, m_Height, radius, radius); } } @@ -141,7 +152,7 @@ void MeterWidget::setColor(QColor mainColor) void MeterWidget::setBoundingRectVisibility(bool show, QColor boundingRectColor) { this->boundingRectVisibility=show; - this->boundingRectColor = boundingRectColor; + this->m_BoundingRectColor = boundingRectColor; } TextMeterWidget::TextMeterWidget(QString Name, QWidget *parent, QString Source) : MeterWidget(Name, parent, Source) @@ -154,7 +165,6 @@ 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); @@ -164,21 +174,32 @@ void TextMeterWidget::paintEvent(QPaintEvent* paintevent) painter.setClipRegion(videoContainerRegion); 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); QRectF ValueBoundingRct = my_painterPath.boundingRect(); - // define scale + // We use leading whitespace for alignment which boundingRect() does not count + ValueBoundingRct.setLeft(qMin(0.0, ValueBoundingRct.left())); + + // The scale should not change with the string content, we use Font ascent and descent + ValueBoundingRct.setTop(qMin(ValueBoundingRct.top(), qreal(qMin(-QFontMetrics(m_MainFont).ascent(), + -QFontMetrics(m_AltFont).ascent())))); + ValueBoundingRct.setBottom(qMax(ValueBoundingRct.bottom(), qreal(qMax(QFontMetrics(m_MainFont).descent(), + QFontMetrics(m_AltFont).descent())))); + + // scale to fit the available space float fontscale = qMin(m_Width / ValueBoundingRct.width(), m_Height / ValueBoundingRct.height()); painter.scale(fontscale, fontscale); - painter.translate(-ValueBoundingRct.x()+(m_Width/fontscale - ValueBoundingRct.width())/2, -ValueBoundingRct.y()+(m_Height/fontscale - ValueBoundingRct.height())/2); + + float translationX = -ValueBoundingRct.x(); // AlignLeft + + if(alignment == Qt::AlignHCenter) + translationX += (m_Width/fontscale - ValueBoundingRct.width())/2; + else if(alignment == Qt::AlignRight) + translationX += (m_Width/fontscale - ValueBoundingRct.width()); + + painter.translate(translationX, -ValueBoundingRct.y()+(m_Height/fontscale - ValueBoundingRct.height())/2); // Write Value painter.setPen(m_OutlinePen); diff --git a/src/Train/MeterWidget.h b/src/Train/MeterWidget.h index 0b02d03b40..1ca12b660e 100644 --- a/src/Train/MeterWidget.h +++ b/src/Train/MeterWidget.h @@ -51,7 +51,9 @@ class MeterWidget : public QWidget void setBoundingRectVisibility(bool show, QColor boundingRectColor = QColor(255,0,0,255)); float Value, ValueMin, ValueMax; - QString Text, AltText; + QString Text, AltText, AltTextSuffix; + Qt::Alignment alignment; + int textWidth; protected: QString m_Name; @@ -72,6 +74,7 @@ class MeterWidget : public QWidget QColor m_ScaleColor; QColor m_OutlineColor; QColor m_BackgroundColor; + QColor m_BoundingRectColor; QFont m_MainFont; QFont m_AltFont; @@ -81,8 +84,8 @@ class MeterWidget : public QWidget QPen m_OutlinePen; QPen m_ScalePen; + bool backgroundVisibility; bool boundingRectVisibility; - QColor boundingRectColor; friend class VideoLayoutParser; }; diff --git a/src/Train/VideoLayoutParser.cpp b/src/Train/VideoLayoutParser.cpp index 91574964e3..0033a7a79a 100644 --- a/src/Train/VideoLayoutParser.cpp +++ b/src/Train/VideoLayoutParser.cpp @@ -37,23 +37,23 @@ VideoLayoutParser::VideoLayoutParser (QList* metersWidget, QListm_RelativeWidth = 20.0; - meterWidget->m_RelativeHeight = 20.0; - meterWidget->m_RelativePosX = 50.0; - meterWidget->m_RelativePosY = 80.0; - - meterWidget->m_RangeMin = 0.0; - meterWidget->m_RangeMax = 80.0; - 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,0); - meterWidget->m_MainFont = QFont(meterWidget->font().family(), 64); - meterWidget->m_AltFont = QFont(meterWidget->font().family(), 48); - meterWidget->m_VideoContainer = VideoContainer; - } + meterWidget->m_RelativeWidth = 20.0; + meterWidget->m_RelativeHeight = 20.0; + meterWidget->m_RelativePosX = 50.0; + meterWidget->m_RelativePosY = 80.0; + meterWidget->m_RangeMin = 0.0; + meterWidget->m_RangeMax = 80.0; + 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,0); + meterWidget->m_BoundingRectColor = QColor(150,150,150,100); + meterWidget->m_MainFont = QFont(meterWidget->font().family(), 64); + meterWidget->m_AltFont = QFont(meterWidget->font().family(), 48); + meterWidget->m_VideoContainer = VideoContainer; + meterWidget->Text = ""; + meterWidget->AltText = ""; + meterWidget->AltTextSuffix = ""; } QColor GetColorFromFields(const QXmlAttributes& qAttributes) @@ -77,6 +77,15 @@ bool VideoLayoutParser::startElement( const QString&, const QString&, const QString& qName, const QXmlAttributes& qAttributes) { + QString source; + QString meterName; + QString meterType; + QString container; // will be "Video" when not defined otherwise another meter name (allows positioning of one meter inside another one) + int textWidth; + Qt::Alignment alignment; + bool boundingRectVisibility; + bool backgroundVisibility; + if(skipLayout) return true; buffer.clear(); @@ -114,6 +123,32 @@ bool VideoLayoutParser::startElement( const QString&, const QString&, else meterType = QString("Text"); + i = qAttributes.index("alignment"); + if(i >= 0) + if(qAttributes.value(i) == QString("AlignLeft")) alignment = Qt::AlignLeft; + else if(qAttributes.value(i) == QString("AlignRight")) alignment = Qt::AlignRight; + else alignment = Qt::AlignHCenter; + else + alignment = Qt::AlignHCenter; + + i = qAttributes.index("textWidth"); + if(i >= 0) + textWidth = qAttributes.value(i).toInt(); + else + textWidth = 0; + + i = qAttributes.index("BoundingRect"); + if(i >= 0 && qAttributes.value(i) == QString("true")) + boundingRectVisibility = true; + else + boundingRectVisibility = false; + + i = qAttributes.index("Background"); + if(i >= 0 && qAttributes.value(i) == QString("true")) + backgroundVisibility = true; + else + backgroundVisibility = false; + //TODO: allow creation of meter when container will be created later QWidget* containerWidget = NULL; if (container == QString("Video")) @@ -159,7 +194,14 @@ bool VideoLayoutParser::startElement( const QString&, const QString&, qDebug() << QObject::tr("Error creating meter"); } - SetDefaultValues(); + if (meterWidget) + { + SetDefaultValues(); + meterWidget->textWidth = textWidth; + meterWidget->alignment = alignment; + meterWidget->boundingRectVisibility = boundingRectVisibility; + meterWidget->backgroundVisibility = backgroundVisibility; + } } else if ((qName == "MainColor") && meterWidget) meterWidget->m_MainColor = GetColorFromFields(qAttributes); @@ -169,6 +211,8 @@ bool VideoLayoutParser::startElement( const QString&, const QString&, meterWidget->m_ScaleColor = GetColorFromFields(qAttributes); else if ((qName == "BackgroundColor") && meterWidget) meterWidget->m_BackgroundColor = GetColorFromFields(qAttributes); + else if ((qName == "BoundingRectColor") && meterWidget) + meterWidget->m_BoundingRectColor = GetColorFromFields(qAttributes); else if ((qName == "RelativeSize") && meterWidget) { @@ -204,6 +248,8 @@ bool VideoLayoutParser::startElement( const QString&, const QString&, if ((i = qAttributes.index("Size")) >= 0) FontSize = qAttributes.value(i).toInt(); meterWidget->m_MainFont = QFont(FontName, FontSize); + // Set fixed width, otherwise the meter digits keep moving sideways from a thin "1" to a fat "5" + meterWidget->m_MainFont.setFixedPitch(true); } else if ((qName == "AltFont") && meterWidget) { @@ -215,6 +261,11 @@ bool VideoLayoutParser::startElement( const QString&, const QString&, if ((i = qAttributes.index("Size")) >= 0) FontSize = qAttributes.value(i).toInt(); meterWidget->m_AltFont = QFont(FontName, FontSize); + meterWidget->m_AltFont.setFixedPitch(true); + } + else if(qName != "layouts" && qName != "Text" && qName != "AltText" && qName != "Angle" && qName != "SubRange") + { + qDebug() << QObject::tr("Unknown start element ") << qName; } return true; @@ -241,6 +292,8 @@ bool VideoLayoutParser::endElement( const QString&, const QString&, const QStrin meterWidget->m_Zoom = buffer.toInt(); else if (qName == "Text") meterWidget->Text = QString(buffer); + else if (qName == "AltText") + meterWidget->AltTextSuffix = QString(buffer); else if (qName == "meter") { diff --git a/src/Train/VideoLayoutParser.h b/src/Train/VideoLayoutParser.h index e0c5277007..70b99378da 100644 --- a/src/Train/VideoLayoutParser.h +++ b/src/Train/VideoLayoutParser.h @@ -46,18 +46,11 @@ class VideoLayoutParser : public QXmlDefaultHandler QList* layoutNames; QWidget* VideoContainer; + MeterWidget* meterWidget; QString buffer; - int nonameindex; int layoutPosition; bool skipLayout; - - QString source; - QString meterName; - QString meterType; - QString container; // will be "Video" when not defined otherwise another meter name (allows positioning of one meter inside another one) - - MeterWidget* meterWidget; }; #endif // _VideoLayoutParser_h diff --git a/src/Train/VideoWindow.cpp b/src/Train/VideoWindow.cpp index 32fc06213c..3187661e22 100644 --- a/src/Train/VideoWindow.cpp +++ b/src/Train/VideoWindow.cpp @@ -326,13 +326,13 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd) std::string smyStr1 = myQstr1.toStdString(); if (p_meterWidget->Source() == QString("None")) { - //Nothing + p_meterWidget->AltText = p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("Speed")) { p_meterWidget->Value = rtd.getSpeed() * (metric ? 1.0 : MILES_PER_KM); - 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")); + p_meterWidget->Text = QString::number((int)p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") +QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + (metric ? tr(" kph") : tr(" mph")) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("Elevation")) { @@ -368,58 +368,73 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd) else if (p_meterWidget->Source() == QString("Cadence")) { p_meterWidget->Value = rtd.getCadence(); - p_meterWidget->Text = QString::number((int)p_meterWidget->Value); + p_meterWidget->Text = QString::number((int)p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("Watt")) { p_meterWidget->Value = rtd.getWatts(); - p_meterWidget->Text = QString::number((int)p_meterWidget->Value); + p_meterWidget->Text = QString::number((int)p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = p_meterWidget->AltTextSuffix; + } + else if (p_meterWidget->Source() == QString("Altitude")) + { + p_meterWidget->Value = rtd.getAltitude() * (metric ? 1.0 : FEET_PER_METER); + p_meterWidget->Text = QString::number((int)p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = (metric ? tr(" m") : tr(" feet")) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("HRM")) { p_meterWidget->Value = rtd.getHr(); - p_meterWidget->Text = QString::number((int)p_meterWidget->Value); + p_meterWidget->Text = QString::number((int)p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("Load")) { if (rtd.mode == ERG || rtd.mode == MRC) { p_meterWidget->Value = rtd.getLoad(); - p_meterWidget->Text = QString("%1").arg(round(p_meterWidget->Value)); - p_meterWidget->AltText = tr("w"); + p_meterWidget->Text = QString("%1").arg(round(p_meterWidget->Value)).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = tr("w") + p_meterWidget->AltTextSuffix; } else { p_meterWidget->Value = rtd.getSlope(); - p_meterWidget->Text = QString("%1").arg(p_meterWidget->Value, 0, 'f', 1); - p_meterWidget->AltText = tr("%"); + p_meterWidget->Text = QString::number((int)p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") + QString::number(abs((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10))) + tr("%") + p_meterWidget->AltTextSuffix; } } else if (p_meterWidget->Source() == QString("Distance")) { p_meterWidget->Value = rtd.getDistance() * (metric ? 1.0 : MILES_PER_KM); - 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(" km") : tr(" mi")); + p_meterWidget->Text = QString::number((int) p_meterWidget->Value).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") +QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + (metric ? tr(" km") : tr(" mi")) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("Time")) { p_meterWidget->Value = round(rtd.value(RealtimeData::Time)/100.0)/10.0; - p_meterWidget->Text = time_to_string(p_meterWidget->Value); + p_meterWidget->Text = time_to_string(trunc(p_meterWidget->Value)).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") + QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("LapTime")) { p_meterWidget->Value = round(rtd.value(RealtimeData::LapTime)/100.0)/10.0; - p_meterWidget->Text = time_to_string(p_meterWidget->Value); + p_meterWidget->Text = time_to_string(trunc(p_meterWidget->Value)).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") + QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("LapTimeRemaining")) { p_meterWidget->Value = round(rtd.value(RealtimeData::LapTimeRemaining)/100.0)/10.0; - p_meterWidget->Text = time_to_string(p_meterWidget->Value); + p_meterWidget->Text = time_to_string(trunc(p_meterWidget->Value)).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") + QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("ErgTimeRemaining")) { p_meterWidget->Value = round(rtd.value(RealtimeData::ErgTimeRemaining)/100.0)/10.0; - p_meterWidget->Text = time_to_string(p_meterWidget->Value); + p_meterWidget->Text = time_to_string(trunc(p_meterWidget->Value)).rightJustified(p_meterWidget->textWidth); + p_meterWidget->AltText = QString(".") + QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + p_meterWidget->AltTextSuffix; } else if (p_meterWidget->Source() == QString("TrainerStatus")) { + p_meterWidget->AltText = p_meterWidget->AltTextSuffix; + if (!rtd.getTrainerStatusAvailable()) { // we don't have status from trainer thus we cannot indicate anything on screen p_meterWidget->Text = tr("");