Improved area labels layout
[GPXSee.git] / src / GUI / mapitem.cpp
bloba1de70d80e60c980459f9e3f9460ef14efa7fe15
1 #include <cmath>
2 #include <QCursor>
3 #include <QPainter>
4 #include <QGraphicsSceneMouseEvent>
5 #include "map/map.h"
6 #include "mapaction.h"
7 #include "tooltip.h"
8 #include "mapitem.h"
9 #ifdef Q_OS_ANDROID
10 #include "popup.h"
11 #endif // Q_OS_ANDROID
14 static void growLeft(Map *map, const Coordinates &c, QRectF &rect)
16 QPointF p(map->ll2xy(c));
18 if (p.x() < rect.left())
19 rect.setLeft(p.x());
22 static void growRight(Map *map, const Coordinates &c, QRectF &rect)
25 QPointF p(map->ll2xy(c));
27 if (p.x() > rect.right())
28 rect.setRight(p.x());
31 static void growTop(Map *map, const Coordinates &c, QRectF &rect)
33 QPointF p(map->ll2xy(c));
35 if (p.y() > rect.top())
36 rect.setTop(p.y());
39 static void growBottom(Map *map, const Coordinates &c, QRectF &rect)
41 QPointF p(map->ll2xy(c));
43 if (p.y() < rect.bottom())
44 rect.setBottom(p.y());
47 static QRectF bbox(const RectC &rect, Map *map, int samples = 100)
49 if (!rect.isValid())
50 return QRectF();
52 double dx = rect.width() / samples;
53 double dy = rect.height() / samples;
55 QPointF tl(map->ll2xy(rect.topLeft()));
56 QPointF br(map->ll2xy(rect.bottomRight()));
57 QRectF prect(tl, br);
59 for (int i = 0; i <= samples; i++) {
60 double x = remainder(rect.left() + i * dx, 360.0);
61 growTop(map, Coordinates(x, rect.bottom()), prect);
62 growBottom(map, Coordinates(x, rect.top()), prect);
65 for (int i = 0; i <= samples; i++) {
66 double y = rect.bottom() + i * dy;
67 growLeft(map, Coordinates(rect.left(), y), prect);
68 growRight(map, Coordinates(rect.right(), y), prect);
71 return prect;
74 ToolTip MapItem::info(bool extended) const
76 Q_UNUSED(extended);
77 ToolTip tt;
79 if (!_name.isEmpty())
80 tt.insert(tr("Name"), _name);
81 if (!_fileName.isEmpty())
82 tt.insert(tr("File"), Util::displayName(_fileName));
84 return tt;
87 MapItem::MapItem(MapAction *action, Map *map, GraphicsItem *parent)
88 : PlaneItem(parent)
90 Map *src = action->data().value<Map*>();
91 Q_ASSERT(map->isReady());
93 _name = src->name();
94 _fileName = src->path();
95 _bounds = src->llBounds();
97 connect(this, &MapItem::triggered, action, &MapAction::trigger);
99 _digitalZoom = 0;
101 _width = 2;
102 _opacity = 0.5;
103 QBrush brush(Qt::SolidPattern);
104 _pen = QPen(brush, _width);
106 updatePainterPath(map);
108 setCursor(Qt::ArrowCursor);
109 setAcceptHoverEvents(true);
112 void MapItem::updatePainterPath(Map *map)
114 _painterPath = QPainterPath();
116 QRectF r(bbox(_bounds, map));
118 if (r.left() > r.right()) {
119 QRectF r1(bbox(RectC(_bounds.topLeft(),
120 Coordinates(180, _bounds.bottomRight().lat())), map));
121 QRectF r2(bbox(RectC(Coordinates(-180, _bounds.topLeft().lat()),
122 _bounds.bottomRight()), map));
124 _painterPath.addRect(r1);
125 _painterPath.addRect(r2);
126 } else
127 _painterPath.addRect(r);
130 void MapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
131 QWidget *widget)
133 Q_UNUSED(option);
134 Q_UNUSED(widget);
136 painter->setPen(_width ? _pen : QPen(Qt::NoPen));
137 painter->drawPath(_painterPath);
138 painter->fillPath(_painterPath, _brush);
140 //QPen p = QPen(QBrush(Qt::red), 0);
141 //painter->setPen(p);
142 //painter->drawRect(boundingRect());
145 void MapItem::setMap(Map *map)
147 prepareGeometryChange();
148 updatePainterPath(map);
151 void MapItem::setColor(const QColor &color)
153 if (_pen.color() == color)
154 return;
156 QColor bc(color);
157 bc.setAlphaF(_opacity * color.alphaF());
159 _pen.setColor(color);
160 _brush = QBrush(bc);
161 update();
164 void MapItem::setOpacity(qreal opacity)
166 if (_opacity == opacity)
167 return;
169 _opacity = opacity;
170 QColor bc(_pen.color());
171 bc.setAlphaF(_opacity * _pen.color().alphaF());
172 _brush = QBrush(bc);
174 update();
177 void MapItem::setWidth(qreal width)
179 if (_width == width)
180 return;
182 prepareGeometryChange();
184 _width = width;
185 _pen.setWidthF(_width * pow(2, -_digitalZoom));
188 void MapItem::setPenStyle(Qt::PenStyle style)
190 if (_pen.style() == style)
191 return;
193 _pen.setStyle(style);
194 update();
197 void MapItem::setDigitalZoom(int zoom)
199 if (_digitalZoom == zoom)
200 return;
202 prepareGeometryChange();
204 _digitalZoom = zoom;
205 _pen.setWidthF(_width * pow(2, -_digitalZoom));
208 void MapItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
210 Q_UNUSED(event);
212 _pen.setWidthF((_width + 1) * pow(2, -_digitalZoom));
213 update();
215 #ifdef Q_OS_ANDROID
216 GraphicsScene *gs = dynamic_cast<GraphicsScene *>(scene());
217 if (gs)
218 Popup::show(event->screenPos(), info(gs->showExtendedInfo()),
219 event->widget());
220 #endif // Q_OS_ANDROID
223 void MapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
225 Q_UNUSED(event);
227 _pen.setWidthF(_width * pow(2, -_digitalZoom));
228 update();
231 void MapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
233 Q_UNUSED(event);
235 emit triggered();