Use new GUI icons that fit the recent platform styles.
[GPXSee.git] / src / GUI / graphitem.cpp
blob2c076b79c50a077670b05d4ad1e6a3128a96803e
1 #include <QPainter>
2 #include <QGraphicsSceneMouseEvent>
3 #include "popup.h"
4 #include "graphitem.h"
7 GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
8 const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
9 : GraphicsItem(parent), _graph(graph), _type(type), _secondaryGraph(0)
11 _units = Metric;
12 _sx = 0; _sy = 0;
13 _color = color;
15 _pen = QPen(GraphItem::color(), width, style, Qt::FlatCap);
17 _time = _graph.hasTime();
18 setZValue(2.0);
19 setAcceptHoverEvents(true);
21 updateBounds();
24 void GraphItem::updateShape()
26 QPainterPathStroker s;
27 s.setWidth(_pen.width() + 1);
28 _shape = s.createStroke(_path);
31 void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
32 QWidget *widget)
34 Q_UNUSED(option);
35 Q_UNUSED(widget);
37 painter->setPen(_pen);
38 painter->drawPath(_path);
40 //painter->setPen(Qt::red);
41 //painter->drawRect(boundingRect());
44 void GraphItem::setGraphType(GraphType type)
46 if (type == _type)
47 return;
49 prepareGeometryChange();
51 _type = type;
52 updatePath();
53 updateBounds();
56 const QColor &GraphItem::color() const
58 return (_useStyle && _graph.color().isValid())
59 ? _graph.color() : _color;
62 void GraphItem::setColor(const QColor &color)
64 _color = color;
65 updateColor();
68 void GraphItem::updateColor()
70 _pen.setColor(color());
71 update();
74 void GraphItem::setWidth(int width)
76 if (width == _pen.width())
77 return;
79 prepareGeometryChange();
81 _pen.setWidth(width);
83 updateShape();
86 void GraphItem::updateStyle()
88 updateColor();
89 if (_secondaryGraph)
90 _secondaryGraph->updateStyle();
93 const GraphSegment *GraphItem::segment(qreal x, GraphType type) const
95 int low = 0;
96 int high = _graph.size() - 1;
97 int mid = 0;
99 while (low <= high) {
100 mid = (high + low) / 2;
101 const GraphPoint &p = _graph.at(mid).last();
102 if (p.x(_type) > x)
103 high = mid - 1;
104 else if (p.x(_type) < x)
105 low = mid + 1;
106 else
107 return &(_graph.at(mid));
110 if (_graph.at(mid).last().x(type) < x)
111 return (mid == _graph.size() - 1) ? 0 : &(_graph.at(mid+1));
112 else
113 return &(_graph.at(mid));
116 qreal GraphItem::yAtX(qreal x) const
118 const GraphSegment *seg = segment(x, _type);
119 if (!seg)
120 return NAN;
122 int low = 0;
123 int high = seg->count() - 1;
124 int mid = 0;
126 if (!(x >= seg->at(low).x(_type) && x <= seg->at(high).x(_type)))
127 return NAN;
129 while (low <= high) {
130 mid = (high + low) / 2;
131 const GraphPoint &p = seg->at(mid);
132 if (p.x(_type) > x)
133 high = mid - 1;
134 else if (p.x(_type) < x)
135 low = mid + 1;
136 else
137 return p.y();
140 QLineF l;
141 if (seg->at(mid).x(_type) < x)
142 l = QLineF(seg->at(mid).x(_type), seg->at(mid).y(),
143 seg->at(mid+1).x(_type), seg->at(mid+1).y());
144 else
145 l = QLineF(seg->at(mid-1).x(_type), seg->at(mid-1).y(),
146 seg->at(mid).x(_type), seg->at(mid).y());
148 return l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
151 qreal GraphItem::distanceAtTime(qreal time) const
153 if (!_time)
154 return NAN;
156 const GraphSegment *seg = segment(time, Time);
157 if (!seg)
158 return NAN;
160 int low = 0;
161 int high = seg->count() - 1;
162 int mid = 0;
164 if (!(time >= seg->at(low).t() && time <= seg->at(high).t()))
165 return NAN;
167 while (low <= high) {
168 mid = (high + low) / 2;
169 const GraphPoint &p = seg->at(mid);
170 if (p.t() > time)
171 high = mid - 1;
172 else if (p.t() < time)
173 low = mid + 1;
174 else
175 return seg->at(mid).s();
178 QLineF l;
179 if (seg->at(mid).t() < time)
180 l = QLineF(seg->at(mid).t(), seg->at(mid).s(), seg->at(mid+1).t(),
181 seg->at(mid+1).s());
182 else
183 l = QLineF(seg->at(mid-1).t(), seg->at(mid-1).s(),
184 seg->at(mid).t(), seg->at(mid).s());
186 return l.pointAt((time - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
189 qreal GraphItem::timeAtDistance(qreal distance) const
191 if (!_time)
192 return NAN;
194 const GraphSegment *seg = segment(distance, Distance);
195 if (!seg)
196 return NAN;
198 int low = 0;
199 int high = seg->count() - 1;
200 int mid = 0;
202 if (!(distance >= seg->at(low).s() && distance <= seg->at(high).s()))
203 return NAN;
205 while (low <= high) {
206 mid = (high + low) / 2;
207 const GraphPoint &p = seg->at(mid);
208 if (p.s() > distance)
209 high = mid - 1;
210 else if (p.s() < distance)
211 low = mid + 1;
212 else
213 return seg->at(mid).t();
216 QLineF l;
217 if (seg->at(mid).s() < distance)
218 l = QLineF(seg->at(mid).s(), seg->at(mid).t(), seg->at(mid+1).s(),
219 seg->at(mid+1).t());
220 else
221 l = QLineF(seg->at(mid-1).s(), seg->at(mid-1).t(),
222 seg->at(mid).s(), seg->at(mid).t());
224 return l.pointAt((distance - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
227 GraphItem::SegmentTime GraphItem::date(qreal x)
229 const GraphSegment *seg = segment(x, _type);
230 return seg ? SegmentTime(seg->start(), seg->first().t()) : SegmentTime();
233 void GraphItem::hover(bool hover)
235 if (hover) {
236 _pen.setWidth(_pen.width() + 1);
237 setZValue(zValue() + 1.0);
238 } else {
239 _pen.setWidth(_pen.width() - 1);
240 setZValue(zValue() - 1.0);
243 update();
246 void GraphItem::setScale(qreal sx, qreal sy)
248 if (_sx == sx && _sy == sy)
249 return;
251 prepareGeometryChange();
253 _sx = sx; _sy = sy;
254 updatePath();
257 void GraphItem::updatePath()
259 if (_sx == 0 && _sy == 0)
260 return;
262 prepareGeometryChange();
264 _path = QPainterPath();
266 if (!(_type == Time && !_time)) {
267 for (int i = 0; i < _graph.size(); i++) {
268 const GraphSegment &segment = _graph.at(i);
270 _path.moveTo(segment.first().x(_type) * _sx, -segment.first().y()
271 * _sy);
272 for (int i = 1; i < segment.size(); i++)
273 _path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y()
274 * _sy);
278 updateShape();
281 void GraphItem::updateBounds()
283 if (_type == Time && !_time) {
284 _bounds = QRectF();
285 return;
288 qreal bottom, top, left, right;
290 QPointF p = QPointF(_graph.first().first().x(_type),
291 -_graph.first().first().y());
292 bottom = p.y(); top = p.y(); left = p.x(); right = p.x();
294 for (int i = 0; i < _graph.size(); i++) {
295 const GraphSegment &segment = _graph.at(i);
297 for (int j = 0; j < segment.size(); j++) {
298 p = QPointF(segment.at(j).x(_type), -segment.at(j).y());
299 bottom = qMax(bottom, p.y()); top = qMin(top, p.y());
300 right = qMax(right, p.x()); left = qMin(left, p.x());
304 if (left == right)
305 _bounds = QRectF();
306 else
307 _bounds = QRectF(QPointF(left, top), QPointF(right, bottom));
310 qreal GraphItem::max() const
312 qreal ret = _graph.first().first().y();
314 for (int i = 0; i < _graph.size(); i++) {
315 const GraphSegment &segment = _graph.at(i);
317 for (int j = 0; j < segment.size(); j++) {
318 qreal y = segment.at(j).y();
319 if (y > ret)
320 ret = y;
324 return ret;
327 qreal GraphItem::min() const
329 qreal ret = _graph.first().first().y();
331 for (int i = 0; i < _graph.size(); i++) {
332 const GraphSegment &segment = _graph.at(i);
334 for (int j = 0; j < segment.size(); j++) {
335 qreal y = segment.at(j).y();
336 if (y < ret)
337 ret = y;
341 return ret;
344 qreal GraphItem::avg() const
346 qreal sum = 0;
348 for (int i = 0; i < _graph.size(); i++) {
349 const GraphSegment &segment = _graph.at(i);
351 for (int j = 1; j < segment.size(); j++)
352 sum += segment.at(j).y() * (segment.at(j).s() - segment.at(j-1).s());
355 return sum/_graph.last().last().s();
358 void GraphItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
360 Q_UNUSED(event);
362 _pen.setWidth(_pen.width() + 1);
363 setZValue(zValue() + 1.0);
364 update();
366 emit selected(true);
369 void GraphItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
371 Q_UNUSED(event);
373 _pen.setWidth(_pen.width() - 1);
374 setZValue(zValue() - 1.0);
375 update();
377 emit selected(false);
380 void GraphItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
382 Popup::show(event->screenPos(), info(), event->widget());
383 GraphicsItem::mousePressEvent(event);