From 1466de5ddf642b5ccf9ec7ddc05762d7b36daae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Sun, 1 Jun 2025 10:33:16 +0200 Subject: [PATCH] Make the legend interactive --- gpxsee.pro | 2 ++ src/GUI/legendentryitem.cpp | 72 +++++++++++++++++++++++++++++++++++++ src/GUI/legendentryitem.h | 34 ++++++++++++++++++ src/GUI/legenditem.cpp | 65 ++++++++++++++++++--------------- src/GUI/legenditem.h | 23 +++++------- src/GUI/mapview.cpp | 26 ++++---------- src/GUI/mapview.h | 2 -- src/GUI/pathitem.cpp | 10 ++++-- src/GUI/pathitem.h | 3 +- 9 files changed, 170 insertions(+), 67 deletions(-) create mode 100644 src/GUI/legendentryitem.cpp create mode 100644 src/GUI/legendentryitem.h diff --git a/gpxsee.pro b/gpxsee.pro index 2df63d0b..1725a55d 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/legendentryitem.h \ src/GUI/legenditem.h \ src/common/garmin.h \ src/common/coordinates.h \ @@ -277,6 +278,7 @@ HEADERS += src/common/config.h \ src/data/geojsonparser.h SOURCES += src/main.cpp \ + src/GUI/legendentryitem.cpp \ src/GUI/legenditem.cpp \ src/common/coordinates.cpp \ src/common/rectc.cpp \ diff --git a/src/GUI/legendentryitem.cpp b/src/GUI/legendentryitem.cpp new file mode 100644 index 00000000..3b5b4290 --- /dev/null +++ b/src/GUI/legendentryitem.cpp @@ -0,0 +1,72 @@ +#include +#include +#include "font.h" +#include "legendentryitem.h" + +#define PADDING 2 + +LegendEntryItem::LegendEntryItem(const QColor &color, const QString &text, + QGraphicsItem *parent) : QGraphicsItem(parent), _color(color), _text(text) +{ + _textColor = Qt::black; + _font.setPixelSize(FONT_SIZE); + _font.setFamily(FONT_FAMILY); + + QFontMetrics fm(_font); + _boundingRect = QRectF(0, 0, FONT_SIZE * 2 + PADDING * 2 + + fm.tightBoundingRect(text).width() + PADDING * 2, + FONT_SIZE + PADDING * 2); + + setCursor(Qt::ArrowCursor); + setAcceptHoverEvents(true); +} + +void LegendEntryItem::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + QFontMetrics fm(_font); + + painter->setRenderHint(QPainter::Antialiasing, false); + + painter->setFont(_font); + painter->setBrush(_color); + painter->setPen(QPen(Qt::black)); + painter->drawRect(PADDING, PADDING, FONT_SIZE * 2, FONT_SIZE); + painter->setPen(QPen(_textColor)); + painter->drawText(FONT_SIZE * 2 + PADDING * 2 + PADDING, + PADDING + fm.ascent(), _text); + + //painter->setPen(Qt::red); + //painter->setBrush(Qt::NoBrush); + //painter->drawRect(boundingRect()); +} + +void LegendEntryItem::setTextColor(const QColor &color) +{ + _textColor = color; + update(); +} + +void LegendEntryItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + Q_UNUSED(event); + + _font.setBold(true); + setZValue(zValue() + 1.0); + update(); + + emit selected(true); +} + +void LegendEntryItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + Q_UNUSED(event); + + _font.setBold(false); + setZValue(zValue() - 1.0); + update(); + + emit selected(false); +} diff --git a/src/GUI/legendentryitem.h b/src/GUI/legendentryitem.h new file mode 100644 index 00000000..518b9223 --- /dev/null +++ b/src/GUI/legendentryitem.h @@ -0,0 +1,34 @@ +#ifndef LEGENDENTRYITEM_H +#define LEGENDENTRYITEM_H + +#include +#include + +class LegendEntryItem : public QObject, public QGraphicsItem +{ + Q_OBJECT + +public: + LegendEntryItem(const QColor &color, const QString &text, + QGraphicsItem *parent = 0); + + QRectF boundingRect() const {return _boundingRect;} + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + + void setTextColor(const QColor &color); + +signals: + void selected(bool); + +private: + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + + QRectF _boundingRect; + QColor _color, _textColor; + QString _text; + QFont _font; +}; + +#endif // LEGENDENTRYITEM_H diff --git a/src/GUI/legenditem.cpp b/src/GUI/legenditem.cpp index e69b5a33..0bd7e89b 100644 --- a/src/GUI/legenditem.cpp +++ b/src/GUI/legenditem.cpp @@ -1,17 +1,17 @@ #include #include +#include #include "font.h" +#include "pathitem.h" +#include "graphitem.h" +#include "planeitem.h" +#include "legendentryitem.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, @@ -28,21 +28,6 @@ void LegendItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option 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); @@ -50,23 +35,43 @@ void LegendItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option //painter->drawRect(boundingRect()); } -void LegendItem::addItem(const QColor &color, const QString &text) +void LegendItem::addItem(PathItem *item) { prepareGeometryChange(); - _items.append(Item(color, text)); + LegendEntryItem *li = new LegendEntryItem(item->color(), + item->name().isEmpty() ? QFileInfo(item->file()).fileName() : item->name(), + this); + li->setPos(0, _items.size() * li->boundingRect().height()); - 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)); + _items.append(li); + + _boundingRect = QRectF(0, 0, qMax(_boundingRect.width(), + li->boundingRect().width()), _items.size() * li->boundingRect().height()); + + QObject::connect(li, &LegendEntryItem::selected, item, &PathItem::hoverAll); +} + +void LegendItem::addItem(PlaneItem *item) +{ + if (item->name().isEmpty()) + return; + + prepareGeometryChange(); + + LegendEntryItem *li = new LegendEntryItem(item->color(), item->name(), this); + li->setPos(0, _items.size() * li->boundingRect().height()); + + _items.append(li); + + _boundingRect = QRectF(0, 0, qMax(_boundingRect.width(), + li->boundingRect().width()), _items.size() * li->boundingRect().height()); } void LegendItem::setColor(const QColor &color) { - _color = color; - update(); + for (int i = 0; i < _items.size(); i++) + _items.at(i)->setTextColor(color); } void LegendItem::setBackgroundColor(const QColor &color) @@ -84,6 +89,8 @@ void LegendItem::drawBackground(bool draw) void LegendItem::clear() { prepareGeometryChange(); + + qDeleteAll(_items); _items.clear(); _boundingRect = QRectF(); } diff --git a/src/GUI/legenditem.h b/src/GUI/legenditem.h index 1c7daa9c..8dbce3b5 100644 --- a/src/GUI/legenditem.h +++ b/src/GUI/legenditem.h @@ -3,7 +3,11 @@ #include -class LegendItem : public QGraphicsItem +class LegendEntryItem; +class PathItem; +class PlaneItem; + +class LegendItem : public QGraphicsItem { public: LegendItem(QGraphicsItem *parent = 0); @@ -12,27 +16,18 @@ public: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void addItem(PathItem *item); + void addItem(PlaneItem *item); 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; + QList _items; QRectF _boundingRect; - QColor _color, _bgColor; - QFont _font; + QColor _bgColor; bool _drawBackground; }; diff --git a/src/GUI/mapview.cpp b/src/GUI/mapview.cpp index 32094abe..f2e3b7c8 100644 --- a/src/GUI/mapview.cpp +++ b/src/GUI/mapview.cpp @@ -153,30 +153,18 @@ void MapView::updateLegend() if (_showTracks) { for (int i = 0; i < _tracks.size(); i++) - addLegendEntry(_tracks.at(i)); + _legend->addItem(_tracks.at(i)); } if (_showRoutes) { for (int i = 0; i < _routes.size(); i++) - addLegendEntry(_routes.at(i)); + _legend->addItem(_routes.at(i)); } if (_showAreas) { for (int i = 0; i < _areas.size(); i++) - addLegendEntry(_areas.at(i)); + _legend->addItem(_areas.at(i)); } } -void MapView::addLegendEntry(const PathItem *ti) -{ - _legend->addItem(ti->color(), ti->name().isEmpty() - ? QFileInfo(ti->file()).fileName() : ti->name()); -} - -void MapView::addLegendEntry(const PlaneItem *plane) -{ - if (!plane->name().isEmpty()) - _legend->addItem(plane->color(), plane->name()); -} - PathItem *MapView::addTrack(const Track &track) { if (!track.isValid()) { @@ -204,7 +192,7 @@ PathItem *MapView::addTrack(const Track &track) if (_showTracks) { addPOI(_poi->points(ti->path())); - addLegendEntry(ti); + _legend->addItem(ti); } return ti; @@ -238,7 +226,7 @@ PathItem *MapView::addRoute(const Route &route) if (_showRoutes) { addPOI(_poi->points(ri->path())); - addLegendEntry(ri); + _legend->addItem(ri); } return ri; @@ -266,7 +254,7 @@ void MapView::addArea(const Area &area) if (_showAreas) { addPOI(_poi->points(ai->bounds())); - addLegendEntry(ai); + _legend->addItem(ai); } } @@ -309,7 +297,7 @@ MapItem *MapView::addMap(MapAction *map) if (_showAreas) { addPOI(_poi->points(mi->bounds())); - addLegendEntry(mi); + _legend->addItem(mi); } return mi; diff --git a/src/GUI/mapview.h b/src/GUI/mapview.h index 36a35905..c4180961 100644 --- a/src/GUI/mapview.h +++ b/src/GUI/mapview.h @@ -168,8 +168,6 @@ private: void pinchGesture(QPinchGesture *gesture); void skipColor() {_palette.nextColor();} void setHidpi(bool hidpi); - void addLegendEntry(const PathItem *path); - void addLegendEntry(const PlaneItem *plane); void updateLegend(); void mouseMoveEvent(QMouseEvent *event); diff --git a/src/GUI/pathitem.cpp b/src/GUI/pathitem.cpp index 646ca6a5..e7174e8e 100644 --- a/src/GUI/pathitem.cpp +++ b/src/GUI/pathitem.cpp @@ -388,9 +388,9 @@ void PathItem::drawMarkerBackground(bool draw) _markerInfo->drawBackground(draw); } -void PathItem::hover(bool hover) +void PathItem::hover(bool hvr) { - if (hover) { + if (hvr) { _pen.setWidth((width() + 1) * pow(2, -_digitalZoom)); setZValue(zValue() + 1.0); } else { @@ -401,6 +401,12 @@ void PathItem::hover(bool hover) update(); } +void PathItem::hoverAll(bool hvr) +{ + hover(hvr); + emit selected(hvr); +} + void PathItem::showMarker(bool show) { if (_showMarker == show) diff --git a/src/GUI/pathitem.h b/src/GUI/pathitem.h index 09eef7ca..72fbd3a4 100644 --- a/src/GUI/pathitem.h +++ b/src/GUI/pathitem.h @@ -60,7 +60,8 @@ public: static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;} public slots: - void hover(bool hover); + void hover(bool hvr); + void hoverAll(bool hvr); signals: void selected(bool);