1 /**********************************************************************************************
2 Copyright (C) 2015 Christian Eichler <code@christian-eichler.de>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 **********************************************************************************************/
18
19 #include "CMainWindow.h"
20 #include "gis/trk/CGisItemTrk.h"
21 #include "gis/trk/CKnownExtension.h"
22 #include "helpers/CDraw.h"
23 #include "widgets/CColorLegend.h"
24
25 #include <QtWidgets>
26
CColorLegend(QWidget * parent,CGisItemTrk * trk)27 CColorLegend::CColorLegend(QWidget* parent, CGisItemTrk* trk)
28 : QWidget(parent)
29 , INotifyTrk(CGisItemTrk::eVisualColorLegend)
30 , trk(trk)
31 {
32 colorRect = QRect(0, 0, colorWidth, colorHeight);
33 colorRect.moveCenter(QPoint(xOffset + colorWidth / 2, height() / 2));
34
35 if(nullptr != trk)
36 {
37 background = true;
38 xOffset = 5;
39
40 trk->registerVisual(this);
41
42 // read data from trk
43 CColorLegend::updateData();
44 }
45 }
46
~CColorLegend()47 CColorLegend::~CColorLegend()
48 {
49 if(trk)
50 {
51 trk->unregisterVisual(this);
52 }
53 }
54
setMouseFocus(const CTrackData::trkpt_t * pt)55 void CColorLegend::setMouseFocus(const CTrackData::trkpt_t* pt)
56 {
57 if(nullptr == pt)
58 {
59 val = NOFLOAT;
60 return;
61 }
62
63 QString colorSource = trk->getColorizeSource();
64 auto valueFunc = CKnownExtension::get(colorSource).valueFunc;
65 const qreal factor = CKnownExtension::get(colorSource).factor;
66
67 val = factor * valueFunc(*pt);
68 val = qMin(val, maximum);
69 val = qMax(val, minimum);
70 }
71
updateData()72 void CColorLegend::updateData()
73 {
74 if(!trk->getColorizeSource().isEmpty() && (trk->getColorizeSource() != "activity"))
75 {
76 unit = trk->getColorizeUnit();
77 minimum = trk->getColorizeLimitLow();
78 maximum = trk->getColorizeLimitHigh();
79
80 update();
81 show();
82 }
83 else
84 {
85 hide();
86 }
87 }
88
setMinimum(qreal min)89 void CColorLegend::setMinimum(qreal min)
90 {
91 minimum = min;
92 update();
93 }
94
setMaximum(qreal max)95 void CColorLegend::setMaximum(qreal max)
96 {
97 maximum = max;
98 update();
99 }
100
setUnit(const QString & unit)101 void CColorLegend::setUnit(const QString& unit)
102 {
103 this->unit = unit;
104 update();
105 }
106
paintLabel(QPainter & p,qreal value)107 int CColorLegend::paintLabel(QPainter& p, qreal value)
108 {
109 const int fontHeight = QFontMetrics(p.font()).ascent() + 1;
110 const qreal relativePos = (value - minimum) / (maximum - minimum);
111 const int posY = colorRect.bottom() + fontHeight / 2 - (2 + colorRect.height()) * relativePos + 1;
112
113 int posX = xOffset + colorWidth + 3;
114
115 p.setPen( QPen(QBrush(palette().color(QPalette::Foreground)), 2.) );
116 p.drawLine(posX, posY - fontHeight / 2 + 1, posX + 2, posY - fontHeight / 2 + 1);
117
118 if(value == minimum || value == maximum
119 || (posY > colorRect.top() + 3 * fontHeight / 2 && posY < colorRect.bottom() - fontHeight / 2))
120 {
121 posX += 5;
122 int precision = !((int)value == value); // returns 0 or 1
123 const QString& labelText = QString("%1%2").arg(value, 0, 'f', precision).arg(unit);
124
125 p.drawText(posX, posY, labelText);
126 posX += QFontMetrics(p.font()).width(labelText);
127 }
128
129 return posX;
130 }
131
resizeEvent(QResizeEvent * event)132 void CColorLegend::resizeEvent(QResizeEvent* event)
133 {
134 QWidget::resizeEvent(event);
135
136 colorRect.setHeight(height() - 20);
137 colorRect.moveCenter(QPoint(xOffset + colorWidth / 2, height() / 2));
138 updateGeometry();
139 }
140
legendRound(qreal value,int powOffset)141 static qreal legendRound(qreal value, int powOffset)
142 {
143 if(value == 0)
144 {
145 return 0;
146 }
147
148 int l10 = (int) (value > 0) ? log10(value) : log10(-value);
149
150 qreal div = pow(10, l10 + powOffset);
151 return ceil(value / div) * div;
152 }
153
paintEvent(QPaintEvent *)154 void CColorLegend::paintEvent(QPaintEvent*/*event*/)
155 {
156 const QFont& font = CMainWindow::self().getMapFont();
157 if(isEnabled())
158 {
159 QPainter p(this);
160 p.setFont(font);
161
162 if(background)
163 {
164 p.setRenderHint(QPainter::Antialiasing);
165 p.setOpacity(0.6);
166
167 p.setPen( QPen(QBrush(Qt::darkGray), 2.) );
168 p.setBrush(palette().color(backgroundRole()));
169 p.drawRoundedRect(1, 1, width() - 2, height() - 2, RECT_RADIUS, RECT_RADIUS);
170
171 p.setOpacity(1.f);
172 p.setRenderHint(QPainter::Antialiasing, false);
173 }
174
175 // draw the black frame
176 QRect borderRect(colorRect);
177 borderRect += QMargins(1, 1, 1, 1);
178 p.setPen( QPen(
179 QBrush(palette().color(QPalette::Foreground)),
180 2.,
181 Qt::SolidLine,
182 Qt::SquareCap,
183 Qt::MiterJoin
184 )
185 );
186 p.drawRect(borderRect);
187
188 // draw the gradient
189 QLinearGradient grad(colorRect.topLeft(), colorRect.bottomLeft());
190 grad.setColorAt(1.00, QColor( 0, 0, 255)); // blue
191 grad.setColorAt(0.60, QColor( 0, 255, 0)); // green
192 grad.setColorAt(0.40, QColor(255, 255, 0)); // yellow
193 grad.setColorAt(0.00, QColor(255, 0, 0)); // red
194 p.fillRect(colorRect, grad);
195
196 int reqWidth = paintLabel(p, minimum);
197 reqWidth = qMax(paintLabel(p, maximum), reqWidth);
198
199 // draw values inbetween min/max
200 const qreal delta = maximum - minimum;
201 qint32 step = legendRound(delta / 8, 0);
202 qint32 roundedMinimum = legendRound(minimum, delta > 60 ? -1 : 0);
203
204 for(qint32 v = roundedMinimum; v < maximum; v += step)
205 {
206 reqWidth = qMax(paintLabel(p, v), reqWidth);
207 }
208
209 if(reqWidth + 5 != width())
210 {
211 setMinimumWidth(reqWidth + 5);
212 resize(reqWidth + 5, height());
213 }
214
215 if(val != NOFLOAT)
216 {
217 qreal y = qFloor(colorRect.bottom() - (val - minimum) * (colorRect.height() - 1) / (maximum - minimum));
218 p.setPen(QPen(Qt::darkGray, 2));
219 p.drawLine(colorRect.left() + 2, y, colorRect.right() - 2, y);
220 }
221
222 p.end();
223 }
224 }
225