From 399023184cf6f2e342a9aac4cefc9c63f6b6c128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Fri, 30 May 2025 06:27:42 +0200 Subject: [PATCH] Added tracks/routes legend --- gpxsee.pro | 2 + src/GUI/coordinatesitem.cpp | 4 +- src/GUI/coordinatesitem.h | 1 - src/GUI/gui.cpp | 11 +++++ src/GUI/gui.h | 1 + src/GUI/legenditem.cpp | 93 +++++++++++++++++++++++++++++++++++++ src/GUI/legenditem.h | 39 ++++++++++++++++ src/GUI/mapview.cpp | 67 ++++++++++++++++++++++++-- src/GUI/mapview.h | 5 ++ src/GUI/pathitem.h | 15 ++++-- src/GUI/routeitem.h | 6 --- src/GUI/settings.cpp | 1 + src/GUI/settings.h | 1 + src/GUI/trackitem.h | 8 ---- 14 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 src/GUI/legenditem.cpp create mode 100644 src/GUI/legenditem.h diff --git a/gpxsee.pro b/gpxsee.pro index 972276aa..2df63d0b 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -23,6 +23,7 @@ greaterThan(QT_MAJOR_VERSION, 5) { CONFIG += object_parallel_to_source INCLUDEPATH += ./src HEADERS += src/common/config.h \ + src/GUI/legenditem.h \ src/common/garmin.h \ src/common/coordinates.h \ src/common/hash.h \ @@ -276,6 +277,7 @@ HEADERS += src/common/config.h \ src/data/geojsonparser.h SOURCES += src/main.cpp \ + src/GUI/legenditem.cpp \ src/common/coordinates.cpp \ src/common/rectc.cpp \ src/common/range.cpp \ diff --git a/src/GUI/coordinatesitem.cpp b/src/GUI/coordinatesitem.cpp index dbf3911b..b85ba01d 100644 --- a/src/GUI/coordinatesitem.cpp +++ b/src/GUI/coordinatesitem.cpp @@ -14,7 +14,6 @@ CoordinatesItem::CoordinatesItem(QGraphicsItem *parent) : QGraphicsItem(parent) _drawBackground = false; _font.setPixelSize(FONT_SIZE); _font.setFamily(FONT_FAMILY); - _digitalZoom = 0; setAcceptHoverEvents(true); @@ -77,8 +76,7 @@ void CoordinatesItem::setUnits(Units units) void CoordinatesItem::setDigitalZoom(qreal zoom) { - _digitalZoom = zoom; - setScale(pow(2, -_digitalZoom)); + setScale(pow(2, -zoom)); } QString CoordinatesItem::text() const diff --git a/src/GUI/coordinatesitem.h b/src/GUI/coordinatesitem.h index 0112e17b..c612fd32 100644 --- a/src/GUI/coordinatesitem.h +++ b/src/GUI/coordinatesitem.h @@ -35,7 +35,6 @@ private: Units _units; QRectF _boundingRect; QFont _font; - qreal _digitalZoom; QColor _color, _bgColor; bool _drawBackground; }; diff --git a/src/GUI/gui.cpp b/src/GUI/gui.cpp index 1f3bf9b4..2ee572a3 100644 --- a/src/GUI/gui.cpp +++ b/src/GUI/gui.cpp @@ -448,6 +448,11 @@ void GUI::createActions() _showTicksAction->setCheckable(true); connect(_showTicksAction, &QAction::triggered, _mapView, &MapView::showTicks); + _showLegendAction = new QAction(tr("Legend"), this); + _showLegendAction->setMenuRole(QAction::NoRole); + _showLegendAction->setCheckable(true); + connect(_showLegendAction, &QAction::triggered, _mapView, + &MapView::showLegend); QActionGroup *markerInfoGroup = new QActionGroup(this); connect(markerInfoGroup, &QActionGroup::triggered, this, &GUI::showPathMarkerInfo); @@ -719,6 +724,7 @@ void GUI::createMenus() dataMenu->addAction(_showWaypointLabelsAction); dataMenu->addAction(_showRouteWaypointsAction); dataMenu->addAction(_showTicksAction); + dataMenu->addAction(_showLegendAction); QMenu *markerMenu = dataMenu->addMenu(tr("Position info")); markerMenu->menuAction()->setMenuRole(QAction::NoRole); markerMenu->addAction(_hideMarkersAction); @@ -2609,6 +2615,7 @@ void GUI::writeSettings() WRITE(waypointLabels, _showWaypointLabelsAction->isChecked()); WRITE(routeWaypoints, _showRouteWaypointsAction->isChecked()); WRITE(pathTicks, _showTicksAction->isChecked()); + WRITE(legend, _showLegendAction->isChecked()); WRITE(positionMarkers, _showMarkersAction->isChecked() || _showMarkerDateAction->isChecked() || _showMarkerCoordinatesAction->isChecked()); @@ -2900,6 +2907,10 @@ void GUI::readSettings(QString &activeMap, QStringList &disabledPOIs, _showTicksAction->setChecked(true); _mapView->showTicks(true); } + if (READ(legend).toBool()) { + _showLegendAction->setChecked(true); + _mapView->showLegend(true); + } if (READ(useStyles).toBool()) { _useStylesAction->setChecked(true); _mapView->useStyles(true); diff --git a/src/GUI/gui.h b/src/GUI/gui.h index f8020de7..2c64b35d 100644 --- a/src/GUI/gui.h +++ b/src/GUI/gui.h @@ -293,6 +293,7 @@ private: QAction *_showMarkerDateAction; QAction *_showMarkerCoordinatesAction; QAction *_showTicksAction; + QAction *_showLegendAction; QAction *_useStylesAction; QAction *_showCoordinatesAction; QAction *_openOptionsAction; diff --git a/src/GUI/legenditem.cpp b/src/GUI/legenditem.cpp new file mode 100644 index 00000000..9bf0ecc5 --- /dev/null +++ b/src/GUI/legenditem.cpp @@ -0,0 +1,93 @@ +#include +#include "font.h" +#include "legenditem.h" + +#define PADDING 4 + +LegendItem::LegendItem(QGraphicsItem *parent) : QGraphicsItem(parent) +{ + _color = Qt::black; + _bgColor = Qt::white; + _drawBackground = false; + _font.setPixelSize(FONT_SIZE); + _font.setFamily(FONT_FAMILY); +} + +void LegendItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + painter->setRenderHint(QPainter::Antialiasing, false); + + if (_drawBackground) { + painter->setPen(Qt::NoPen); + QColor bc(_bgColor); + bc.setAlpha(196); + painter->setBrush(QBrush(bc)); + painter->drawRect(_boundingRect); + painter->setBrush(Qt::NoBrush); + } + + QFontMetrics fm(_font); + painter->setFont(_font); + + for (int i = 0; i < _items.size(); i++) { + const Item &itm = _items.at(i); + + painter->setBrush(itm.color); + painter->setPen(QPen(Qt::black)); + painter->drawRect(0, i * (FONT_SIZE + PADDING), FONT_SIZE * 2, FONT_SIZE); + painter->setPen(QPen(_color)); + painter->drawText(FONT_SIZE * 2 + PADDING, i * (FONT_SIZE + PADDING) + + fm.ascent(), itm.text); + } + + //painter->setPen(Qt::red); + //painter->setBrush(Qt::NoBrush); + //painter->drawRect(boundingRect()); +} + +void LegendItem::addItem(const QColor &color, const QString &text) +{ + prepareGeometryChange(); + + _items.append(Item(color, text)); + + QFontMetrics fm(_font); + qreal maxWidth = qMax((int)_boundingRect.width() - (FONT_SIZE * 2 + PADDING), + fm.tightBoundingRect(text).width()); + _boundingRect = QRectF(0, 0, FONT_SIZE * 2 + PADDING + maxWidth, + _items.size() * (FONT_SIZE + PADDING) - (PADDING - 1)); +} + +void LegendItem::setColor(const QColor &color) +{ + _color = color; + update(); +} + +void LegendItem::setBackgroundColor(const QColor &color) +{ + _bgColor = color; + update(); +} + +void LegendItem::drawBackground(bool draw) +{ + _drawBackground = draw; + update(); +} + +void LegendItem::clear() +{ + prepareGeometryChange(); + _items.clear(); + _boundingRect = QRectF(); +} + +void LegendItem::setDigitalZoom(qreal zoom) +{ + setScale(pow(2, -zoom)); +} diff --git a/src/GUI/legenditem.h b/src/GUI/legenditem.h new file mode 100644 index 00000000..1c7daa9c --- /dev/null +++ b/src/GUI/legenditem.h @@ -0,0 +1,39 @@ +#ifndef LEGENDITEM_H +#define LEGENDITEM_H + +#include + +class LegendItem : public QGraphicsItem +{ +public: + LegendItem(QGraphicsItem *parent = 0); + + QRectF boundingRect() const {return _boundingRect;} + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + + void setDigitalZoom(qreal zoom); + void addItem(const QColor &color, const QString &text); + void setColor(const QColor &color); + void setBackgroundColor(const QColor &color); + void drawBackground(bool draw); + void clear(); + +private: + struct Item + { + Item(const QColor &color, const QString &text) + : color(color), text(text) {} + + QColor color; + QString text; + }; + + QList _items; + QRectF _boundingRect; + QColor _color, _bgColor; + QFont _font; + bool _drawBackground; +}; + +#endif // LEGENDITEM_H diff --git a/src/GUI/mapview.cpp b/src/GUI/mapview.cpp index 86940503..31f6e9a7 100644 --- a/src/GUI/mapview.cpp +++ b/src/GUI/mapview.cpp @@ -31,6 +31,7 @@ #define MARGIN 10 #define SCALE_OFFSET 7 #define COORDINATES_OFFSET SCALE_OFFSET +#define LEGEND_OFFSET SCALE_OFFSET MapView::MapView(Map *map, POI *poi, QWidget *parent) : QGraphicsView(parent) @@ -87,6 +88,11 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent) : QGraphicsView(parent) _motionInfo->setVisible(false); _scene->addItem(_motionInfo); + _legend = new LegendItem(); + _legend->setZValue(2.0); + _legend->setVisible(false); + _scene->addItem(_legend); + _mapOpacity = 1.0; _backgroundColor = Qt::white; _markerColor = Qt::red; @@ -141,6 +147,26 @@ void MapView::centerOn(const QPointF &pos) _cursorCoordinates->setCoordinates(Coordinates()); } +void MapView::updateLegend() +{ + _legend->clear(); + + if (_showTracks) { + for (int i = 0; i < _tracks.size(); i++) + addLegendEntry(_tracks.at(i)); + } + if (_showRoutes) { + for (int i = 0; i < _routes.size(); i++) + addLegendEntry(_routes.at(i)); + } +} + +void MapView::addLegendEntry(const PathItem *ti) +{ + _legend->addItem(ti->color(), ti->name().isEmpty() + ? QFileInfo(ti->file()).fileName() : ti->name()); +} + PathItem *MapView::addTrack(const Track &track) { if (!track.isValid()) { @@ -148,10 +174,12 @@ PathItem *MapView::addTrack(const Track &track) return 0; } + QColor color(_palette.nextColor()); + TrackItem *ti = new TrackItem(track, _map); _tracks.append(ti); _tr |= ti->path().boundingRect(); - ti->setColor(_palette.nextColor()); + ti->setColor(color); ti->setWidth(_trackWidth); ti->setPenStyle(_trackStyle); ti->setVisible(_showTracks); @@ -164,8 +192,10 @@ PathItem *MapView::addTrack(const Track &track) ti->showTicks(_showPathTicks); _scene->addItem(ti); - if (_showTracks) + if (_showTracks) { addPOI(_poi->points(ti->path())); + addLegendEntry(ti); + } return ti; } @@ -196,8 +226,10 @@ PathItem *MapView::addRoute(const Route &route) ri->showTicks(_showPathTicks); _scene->addItem(ri); - if (_showRoutes) + if (_showRoutes) { addPOI(_poi->points(ri->path())); + addLegendEntry(ri); + } return ri; } @@ -397,6 +429,8 @@ void MapView::setPalette(const Palette &palette) _routes.at(i)->setColor(_palette.nextColor()); for (int i = 0; i < _areas.count(); i++) _areas.at(i)->setColor(_palette.nextColor()); + + updateLegend(); } void MapView::setMap(Map *map) @@ -684,7 +718,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale, { QRect orig; qreal ratio, diff, q, p; - QPointF scenePos, scalePos, posPos, motionPos; + QPointF scenePos, scalePos, posPos, motionPos, legendPos; bool hidpi = _hidpi && _deviceRatio > 1.0; int zoom; @@ -699,6 +733,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale, scalePos = _mapScale->pos(); posPos = _positionCoordinates->pos(); motionPos = _motionInfo->pos(); + legendPos = _legend->pos(); if (orig.height() * (target.width() / target.height()) - orig.width() < 0) { ratio = target.height() / target.width(); @@ -756,6 +791,10 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale, _motionInfo->setPos(mapToScene(adj.topRight().toPoint() + QPoint( (-COORDINATES_OFFSET - _motionInfo->boundingRect().width()) * p, (COORDINATES_OFFSET + _motionInfo->boundingRect().height()) * p))); + _legend->setDigitalZoom(_digitalZoom - log2(p)); + _legend->setPos(mapToScene(adj.topRight().toPoint() + QPoint( + (-LEGEND_OFFSET - _legend->boundingRect().width()) * p, + LEGEND_OFFSET * p))); // Print the view render(painter, target, adj.toRect()); @@ -776,6 +815,8 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale, _positionCoordinates->setPos(posPos); _motionInfo->setDigitalZoom(_digitalZoom); _motionInfo->setPos(motionPos); + _legend->setDigitalZoom(_digitalZoom); + _legend->setPos(legendPos); // Exit plot mode _plot = false; @@ -795,12 +836,15 @@ void MapView::clear() _scene->removeItem(_positionCoordinates); _scene->removeItem(_crosshair); _scene->removeItem(_motionInfo); + _scene->removeItem(_legend); _scene->clear(); _scene->addItem(_mapScale); _scene->addItem(_cursorCoordinates); _scene->addItem(_positionCoordinates); _scene->addItem(_crosshair); _scene->addItem(_motionInfo); + _legend->clear(); + _scene->addItem(_legend); _palette.reset(); @@ -822,6 +866,7 @@ void MapView::showTracks(bool show) for (int i = 0; i < _tracks.count(); i++) _tracks.at(i)->setVisible(show); + updateLegend(); updatePOI(); } @@ -832,6 +877,7 @@ void MapView::showRoutes(bool show) for (int i = 0; i < _routes.count(); i++) _routes.at(i)->setVisible(show); + updateLegend(); updatePOI(); } @@ -978,6 +1024,12 @@ void MapView::showMotionInfo(bool show) _scene->invalidate(); } +void MapView::showLegend(bool show) +{ + _legend->setVisible(show); + _scene->invalidate(); +} + void MapView::showOverlappedPOIs(bool show) { _overlapPOIs = show; @@ -1087,6 +1139,7 @@ void MapView::setBackgroundColor(const QColor &color) _cursorCoordinates->setBackgroundColor(color); _positionCoordinates->setBackgroundColor(color); _motionInfo->setBackgroundColor(color); + _legend->setBackgroundColor(color); for (int i = 0; i < _tracks.size(); i++) _tracks.at(i)->setMarkerBackgroundColor(color); @@ -1153,6 +1206,10 @@ void MapView::paintEvent(QPaintEvent *event) if (_motionInfo->pos() != coordinatesScenePos) _motionInfo->setPos(coordinatesScenePos); } + + QPointF legendPos = mapToScene(rect().topRight() + QPoint( + -(LEGEND_OFFSET + _legend->boundingRect().width()), LEGEND_OFFSET)); + _legend->setPos(legendPos); } QGraphicsView::paintEvent(event); @@ -1401,6 +1458,7 @@ void MapView::setInfoColor(const QColor &color) _cursorCoordinates->setColor(color); _positionCoordinates->setColor(color); _motionInfo->setColor(color); + _legend->setColor(color); } void MapView::drawInfoBackground(bool draw) @@ -1410,6 +1468,7 @@ void MapView::drawInfoBackground(bool draw) _cursorCoordinates->drawBackground(draw); _positionCoordinates->drawBackground(draw); _motionInfo->drawBackground(draw); + _legend->drawBackground(draw); for (int i = 0; i < _tracks.size(); i++) _tracks.at(i)->drawMarkerBackground(draw); diff --git a/src/GUI/mapview.h b/src/GUI/mapview.h index 4eaa467f..357f706f 100644 --- a/src/GUI/mapview.h +++ b/src/GUI/mapview.h @@ -13,6 +13,7 @@ #include "units.h" #include "format.h" #include "markerinfoitem.h" +#include "legenditem.h" #include "palette.h" #include "graphicsscene.h" @@ -134,6 +135,7 @@ public slots: void setMarkerPosition(qreal pos); void followPosition(bool follow); void showMotionInfo(bool show); + void showLegend(bool show); void useStyles(bool use); void drawHillShading(bool draw); void selectLayers(MapView::Layers layers); @@ -166,6 +168,8 @@ private: void pinchGesture(QPinchGesture *gesture); void skipColor() {_palette.nextColor();} void setHidpi(bool hidpi); + void addLegendEntry(const PathItem *path); + void updateLegend(); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); @@ -185,6 +189,7 @@ private: CoordinatesItem *_cursorCoordinates, *_positionCoordinates; CrosshairItem *_crosshair; MotionInfoItem *_motionInfo; + LegendItem *_legend; QList _tracks; QList _routes; QList _waypoints; diff --git a/src/GUI/pathitem.h b/src/GUI/pathitem.h index 728af6db..09eef7ca 100644 --- a/src/GUI/pathitem.h +++ b/src/GUI/pathitem.h @@ -4,6 +4,7 @@ #include #include #include "data/path.h" +#include "data/link.h" #include "graphicsscene.h" #include "markerinfoitem.h" #include "format.h" @@ -27,9 +28,11 @@ public: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - virtual QDateTime date() const = 0; - + const QDateTime &date() const {return _date;} + const QString &file() const {return _file;} + const QString &name() const {return _name;} const Path &path() const {return _path;} + const QColor &color() const; void addGraph(GraphItem *graph); @@ -67,6 +70,13 @@ protected: void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); void mousePressEvent(QGraphicsSceneMouseEvent *event); + QDateTime _date; + QString _name; + QString _file; + QString _desc; + QString _comment; + QVector _links; + static Units _units; static QTimeZone _timeZone; @@ -81,7 +91,6 @@ private: void updateWidth(); void updatePenStyle(); qreal width() const; - const QColor &color() const; Qt::PenStyle penStyle() const; qreal xInM() const; diff --git a/src/GUI/routeitem.h b/src/GUI/routeitem.h index 2859f1a2..620b7cc5 100644 --- a/src/GUI/routeitem.h +++ b/src/GUI/routeitem.h @@ -23,15 +23,9 @@ public: void showWaypointIcons(bool show); ToolTip info(bool extended) const; - QDateTime date() const {return QDateTime();} private: - QString _name; - QString _desc; - QString _comment; - QVector _links; QVector _waypoints; - QString _file; }; #endif // ROUTEITEM_H diff --git a/src/GUI/settings.cpp b/src/GUI/settings.cpp index a367ca85..eeb6d98c 100644 --- a/src/GUI/settings.cpp +++ b/src/GUI/settings.cpp @@ -173,6 +173,7 @@ SETTING(routeWaypoints, "routeWaypoints", true ); SETTING(waypointIcons, "waypointIcons", false ); SETTING(waypointLabels, "waypointLabels", true ); SETTING(pathTicks, "pathTicks", false ); +SETTING(legend, "legend", false ); SETTING(positionMarkers, "positionMarkers", true ); SETTING(markerInfo, "markerInfo", MarkerInfoItem::None ); SETTING(useStyles, "styles", true ); diff --git a/src/GUI/settings.h b/src/GUI/settings.h index 10433693..ea2b46de 100644 --- a/src/GUI/settings.h +++ b/src/GUI/settings.h @@ -122,6 +122,7 @@ public: static const Setting waypointIcons; static const Setting waypointLabels; static const Setting pathTicks; + static const Setting legend; static const Setting positionMarkers; static const Setting markerInfo; static const Setting useStyles; diff --git a/src/GUI/trackitem.h b/src/GUI/trackitem.h index eaf6fe1f..fb8532fd 100644 --- a/src/GUI/trackitem.h +++ b/src/GUI/trackitem.h @@ -2,7 +2,6 @@ #define TRACKITEM_H #include -#include "data/link.h" #include "pathitem.h" class Map; @@ -16,17 +15,10 @@ public: TrackItem(const Track &track, Map *map, QGraphicsItem *parent = 0); ToolTip info(bool extended) const; - QDateTime date() const {return _date;} private: - QString _name; - QString _desc; - QString _comment; - QVector _links; - QDateTime _date; qreal _time; qreal _movingTime; - QString _file; }; #endif // TRACKITEM_H