From 141226b509aad48ae036af4dfa567af15f1e8afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Sat, 19 Dec 2015 20:23:07 +0100 Subject: [PATCH] Added support for imperial units --- gpxsee.nsi | 2 +- gpxsee.pro | 3 +- lang/gpxsee_cs.ts | 149 ++++++++++++++++++++++++++--------------- src/config.h | 2 +- src/elevationgraph.cpp | 46 ++++++++++--- src/elevationgraph.h | 4 ++ src/graph.cpp | 31 ++++++++- src/graph.h | 7 +- src/gui.cpp | 77 +++++++++++++++++---- src/gui.h | 6 ++ src/slideritem.cpp | 6 ++ src/slideritem.h | 2 + src/speedgraph.cpp | 41 +++++++++--- src/speedgraph.h | 4 ++ src/units.h | 15 +++++ 15 files changed, 298 insertions(+), 97 deletions(-) create mode 100644 src/units.h diff --git a/gpxsee.nsi b/gpxsee.nsi index 94080a3f..8fe322cc 100644 --- a/gpxsee.nsi +++ b/gpxsee.nsi @@ -63,7 +63,7 @@ Section "GPXSee (required)" SEC_APP ; Write the uninstall keys for Windows WriteRegStr HKCU "${REGENTRY}" "DisplayName" "GPXSee" WriteRegStr HKCU "${REGENTRY}" "Publisher" "Martin Tuma" - WriteRegStr HKCU "${REGENTRY}" "DisplayVersion" "2.4" + WriteRegStr HKCU "${REGENTRY}" "DisplayVersion" "2.5" WriteRegStr HKCU "${REGENTRY}" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegDWORD HKCU "${REGENTRY}" "NoModify" 1 WriteRegDWORD HKCU "${REGENTRY}" "NoRepair" 1 diff --git a/gpxsee.pro b/gpxsee.pro index 043e755e..122d5ff5 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -27,7 +27,8 @@ HEADERS += src/config.h \ src/filebrowser.h \ src/map.h \ src/maplist.h \ - src/downloader.h + src/downloader.h \ + src/units.h SOURCES += src/main.cpp \ src/gui.cpp \ src/gpx.cpp \ diff --git a/lang/gpxsee_cs.ts b/lang/gpxsee_cs.ts index d2c5f07e..691ec3c6 100644 --- a/lang/gpxsee_cs.ts +++ b/lang/gpxsee_cs.ts @@ -15,31 +15,43 @@ + km km + m m - + Ascent Stoupání - + Descent Klesání - + Minimum Minimum - + + mi + mi + + + + ft + ft + + + Maximum Maximum @@ -52,12 +64,12 @@ O Qt - + GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at Program GPXSee je distribuován pod podmínkami licence GNU General Public License verze 3. Pro více informací navštivte stránky programu na adrese - + Open file Otevřít soubor @@ -67,7 +79,7 @@ Uložit jako - + Open POI file Otevřít POI soubor @@ -83,8 +95,8 @@ - - + + Keyboard controls Ovládací klávesy @@ -104,20 +116,20 @@ Znovu načíst - + Show Zobrazit - - + + File Soubor - - + + Data sources Zdroje dat @@ -148,190 +160,205 @@ + Metric + Metrické + + + + Imperial + Imperiální + + + Next Následující - + Previous Předchozí - + Last Poslední - + First První - + Map Mapa - + POI POI - + Settings Nastavení - + + Units + Jednotky + + + Help Nápověda - + Elevation Výška - + Speed Rychlost - + Next file Následující soubor - + Previous file Předchozí soubor - + First file První soubor - + Last file Poslední soubor - + Append modifier Modifikátor nahradit/přidat - + Map (tiles) source URLs are read on program startup from the following file: URL mapových zdrojů (dlaždic) jsou načteny při startu programu z následujícího souboru: - + The file format is one map entry per line, consisting of the map name and tiles URL delimited by a TAB character. The tile X and Y coordinates are replaced with $x and $y in the URL and the zoom level is replaced with $z. An example map file could look like: Formát souboru je jeden mapový záznam na řádku, kde mapový záznam sestává ze jména mapy a URL dlaždic navzájem oddělených tabulátorem. Souřadnice dlaždice jsou v URL nahrazeny řetězci $x a $y, úroven přiblížení (zoom) pak řetězcem $z. Příklad: - + To make GPXSee load a POI file automatically on startup, add the file to the following directory: POI soubory, které se mají automaticky nahrát při startu programu jsou načítány z následujícího adresáře: - - + + Line: %1 Řádka: %1 - + Maximum Maximum - + Minimum Minimum - + About GPXSee O aplikaci GPXSee - + Navigation Navigace - + GPX viewer and analyzer Prohlížeč a analyzátor GPX - + Map sources Mapové zdroje - + POIs POI body - + Distance Vzdálenost - + Time Čas - + Ascent Stoupání - - - - + + + + m m - + Descent Klesání - + %1 tracks Počet tras: %1 - - + + km km - - + + Error Chyba - + Error loading GPX file: %1 Soubor GPX nelze otevřít: %1 - + Error loading POI file: %1 Soubor POI nelze otevřít: @@ -352,11 +379,13 @@ + km + km/h km/h @@ -370,5 +399,15 @@ Maximum Maximum + + + mi + mi + + + + mi/h + mi/h + diff --git a/src/config.h b/src/config.h index a91ed59a..2ea923bd 100644 --- a/src/config.h +++ b/src/config.h @@ -3,7 +3,7 @@ #define APP_NAME "GPXSee" #define APP_HOMEPAGE "http://tumic.wz.cz/gpxsee" -#define APP_VERSION "2.4" +#define APP_VERSION "2.5" #define FONT_FAMILY "Arial" #define FONT_SIZE 12 diff --git a/src/elevationgraph.cpp b/src/elevationgraph.cpp index 136ee379..cfee6301 100644 --- a/src/elevationgraph.cpp +++ b/src/elevationgraph.cpp @@ -14,7 +14,19 @@ ElevationGraph::ElevationGraph(QWidget *parent) : Graph(parent) Graph::setYLabel(tr("Elevation")); Graph::setXUnits(tr("km")); Graph::setYUnits(tr("m")); - Graph::setXScale(0.001); + Graph::setXScale(M2KM); +} + +void ElevationGraph::addInfo() +{ + Graph::addInfo(tr("Ascent"), QString::number(_ascent * _yScale, 'f', 0) + + THIN_SPACE + _yUnits); + Graph::addInfo(tr("Descent"), QString::number(_descent * _yScale, 'f', 0) + + THIN_SPACE + _yUnits); + Graph::addInfo(tr("Maximum"), QString::number(_max * _yScale, 'f', 0) + + THIN_SPACE + _yUnits); + Graph::addInfo(tr("Minimum"), QString::number(_min * _yScale, 'f', 0) + + THIN_SPACE + _yUnits); } void ElevationGraph::loadGPX(const GPX &gpx) @@ -49,16 +61,8 @@ void ElevationGraph::loadGPX(const GPX &gpx) _max = qMax(_max, max); _min = qMin(_min, min); - addInfo(tr("Ascent"), QString::number(_ascent, 'f', 0) - + THIN_SPACE + _yUnits); - addInfo(tr("Descent"), QString::number(_descent, 'f', 0) - + THIN_SPACE + _yUnits); - addInfo(tr("Maximum"), QString::number(_max, 'f', 0) - + THIN_SPACE + _yUnits); - addInfo(tr("Minimum"), QString::number(_min, 'f', 0) - + THIN_SPACE + _yUnits); - - Graph::loadData(data); + addInfo(); + loadData(data); } void ElevationGraph::clear() @@ -70,3 +74,23 @@ void ElevationGraph::clear() Graph::clear(); } + +void ElevationGraph::setUnits(enum Units units) +{ + if (units == Metric) { + Graph::setXUnits(tr("km")); + Graph::setYUnits(tr("m")); + Graph::setXScale(M2KM); + Graph::setYScale(1); + } else { + Graph::setXUnits(tr("mi")); + Graph::setYUnits(tr("ft")); + Graph::setXScale(M2MI); + Graph::setYScale(M2FT); + } + + clearInfo(); + addInfo(); + + redraw(); +} diff --git a/src/elevationgraph.h b/src/elevationgraph.h index 66fbce78..5e8ad24b 100644 --- a/src/elevationgraph.h +++ b/src/elevationgraph.h @@ -3,6 +3,7 @@ #include "graph.h" #include "gpx.h" +#include "units.h" class ElevationGraph : public Graph { @@ -13,6 +14,7 @@ public: void loadGPX(const GPX &gpx); void clear(); + void setUnits(enum Units units); qreal ascent() const {return _ascent;} qreal descent() const {return _descent;} @@ -20,6 +22,8 @@ public: qreal min() const {return _min;} private: + void addInfo(); + qreal _ascent, _descent; qreal _max, _min; }; diff --git a/src/graph.cpp b/src/graph.cpp index 83cf6ab8..c1755e4e 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -116,6 +116,16 @@ void Graph::setYUnits(const QString &units) createYLabel(); } +void Graph::setXScale(qreal scale) +{ + _xScale = scale; +} + +void Graph::setYScale(qreal scale) +{ + _yScale = scale; +} + void Graph::loadData(const QVector &data) { QPainterPath path; @@ -143,7 +153,13 @@ void Graph::loadData(const QVector &data) if (_graphs.size() > 1) _sliderInfo->hide(); - resize(viewport()->size() - QSizeF(MARGIN, MARGIN)); + redraw(); +} + +void Graph::redraw() +{ + if (!_graphs.isEmpty()) + resize(viewport()->size() - QSizeF(MARGIN, MARGIN)); } void Graph::resize(const QSizeF &size) @@ -187,8 +203,11 @@ void Graph::resize(const QSizeF &size) _scene->addItem(_xAxis); _scene->addItem(_yAxis); + qreal sp = (_slider->pos().x() == _slider->area().left()) + ? 0 : (_slider->pos().x() - _slider->area().left()) + / _slider->area().width(); _slider->setArea(r); - _slider->setPos(r.bottomLeft()); + _slider->setPos(QPointF(sp * r.width(), r.bottom())); _scene->addItem(_slider); r = _scene->itemsBoundingRect(); @@ -202,7 +221,7 @@ void Graph::resize(const QSizeF &size) void Graph::resizeEvent(QResizeEvent *) { if (!_graphs.empty()) - resize(viewport()->size() - QSizeF(MARGIN, MARGIN)); + redraw(); } void Graph::plot(QPainter *painter, const QRectF &target) @@ -234,6 +253,7 @@ void Graph::clear() _scene->removeItem(_info); _sliderInfo->show(); + _slider->clear(); _info->clear(); _scene->clear(); _graphs.clear(); @@ -285,3 +305,8 @@ void Graph::addInfo(const QString &key, const QString &value) { _info->insert(key, value); } + +void Graph::clearInfo() +{ + _info->clear(); +} diff --git a/src/graph.h b/src/graph.h index c351b06d..62a10af1 100644 --- a/src/graph.h +++ b/src/graph.h @@ -41,10 +41,12 @@ public: void setYLabel(const QString &label); void setXUnits(const QString &units); void setYUnits(const QString &units); - void setXScale(qreal scale) {_xScale = scale;} - void setYScale(qreal scale) {_yScale = scale;} + void setXScale(qreal scale); + void setYScale(qreal scale); void setPrecision(int p) {_precision = p;} + void redraw(); + void plot(QPainter *painter, const QRectF &target); void clear(); @@ -52,6 +54,7 @@ public: void setSliderPosition(qreal pos); void addInfo(const QString &key, const QString &value); + void clearInfo(); signals: void sliderPositionChanged(qreal); diff --git a/src/gui.cpp b/src/gui.cpp index 379a607b..c522749c 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -31,7 +31,7 @@ static QString timeSpan(qreal time) s = time - (h * 3600) - (m * 60); return QString("%1:%2:%3").arg(h).arg(m, 2, 10, QChar('0')) - .arg(s,2, 10, QChar('0')); + .arg(s, 2, 10, QChar('0')); } @@ -193,6 +193,19 @@ void GUI::createActions() _showToolbarsAction->setChecked(true); connect(_showToolbarsAction, SIGNAL(triggered(bool)), this, SLOT(showToolbars(bool))); + QActionGroup *ag = new QActionGroup(this); + ag->setExclusive(true); + _metricUnitsAction = new QAction(tr("Metric"), this); + _metricUnitsAction->setCheckable(true); + _metricUnitsAction->setActionGroup(ag); + _metricUnitsAction->setChecked(true); + connect(_metricUnitsAction, SIGNAL(triggered()), this, + SLOT(setMetricUnits())); + _imperialUnitsAction = new QAction(tr("Imperial"), this); + _imperialUnitsAction->setCheckable(true); + _imperialUnitsAction->setActionGroup(ag); + connect(_imperialUnitsAction, SIGNAL(triggered()), this, + SLOT(setImperialUnits())); // Navigation actions _nextAction = new QAction(QIcon(QPixmap(NEXT_FILE_ICON)), tr("Next"), this); @@ -237,6 +250,10 @@ void GUI::createMenus() _poiMenu->addAction(_showPOIAction); _settingsMenu = menuBar()->addMenu(tr("Settings")); + _unitsMenu = _settingsMenu->addMenu(tr("Units")); + _unitsMenu->addAction(_metricUnitsAction); + _unitsMenu->addAction(_imperialUnitsAction); + _settingsMenu->addSeparator(); _settingsMenu->addAction(_showToolbarsAction); _settingsMenu->addAction(_showGraphsAction); @@ -487,17 +504,31 @@ void GUI::saveFile(const QString &fileName) QGraphicsScene scene; InfoItem info; - info.insert(tr("Distance"), QString::number(_distance / 1000, 'f', 1) - + THIN_SPACE + tr("km")); - info.insert(tr("Time"), timeSpan(_time)); - info.insert(tr("Ascent"), QString::number(_elevationGraph->ascent(), 'f', 0) - + THIN_SPACE + tr("m")); - info.insert(tr("Descent"), QString::number(_elevationGraph->descent(), 'f', - 0) + THIN_SPACE + tr("m")); - info.insert(tr("Maximum"), QString::number(_elevationGraph->max(), 'f', 0) - + THIN_SPACE + tr("m")); - info.insert(tr("Minimum"), QString::number(_elevationGraph->min(), 'f', 0) - + THIN_SPACE + tr("m")); + if (_imperialUnitsAction->isChecked()) { + info.insert(tr("Distance"), QString::number(_distance * M2MI, 'f', 1) + + THIN_SPACE + tr("mi")); + info.insert(tr("Time"), timeSpan(_time)); + info.insert(tr("Ascent"), QString::number(_elevationGraph->ascent() + * M2FT, 'f', 0) + THIN_SPACE + tr("ft")); + info.insert(tr("Descent"), QString::number(_elevationGraph->descent() + * M2FT, 'f', 0) + THIN_SPACE + tr("ft")); + info.insert(tr("Maximum"), QString::number(_elevationGraph->max() + * M2FT, 'f', 0) + THIN_SPACE + tr("ft")); + info.insert(tr("Minimum"), QString::number(_elevationGraph->min() + * M2FT, 'f', 0) + THIN_SPACE + tr("ft")); + } else { + info.insert(tr("Distance"), QString::number(_distance * M2KM, 'f', 1) + + THIN_SPACE + tr("km")); + info.insert(tr("Time"), timeSpan(_time)); + info.insert(tr("Ascent"), QString::number(_elevationGraph->ascent(), + 'f', 0) + THIN_SPACE + tr("m")); + info.insert(tr("Descent"), QString::number(_elevationGraph->descent(), + 'f', 0) + THIN_SPACE + tr("m")); + info.insert(tr("Maximum"), QString::number(_elevationGraph->max(), 'f', + 0) + THIN_SPACE + tr("m")); + info.insert(tr("Minimum"), QString::number(_elevationGraph->min(), 'f', + 0) + THIN_SPACE + tr("m")); + } scene.addItem(&info); scene.render(&p, QRectF(0, 0, printer.width(), 200)); @@ -593,8 +624,12 @@ void GUI::updateStatusBarInfo() else _fileNameLabel->setText(tr("%1 tracks").arg(_files.size())); - _distanceLabel->setText(QString::number(_distance / 1000, 'f', 1) - + " " + tr("km")); + if (_imperialUnitsAction->isChecked()) + _distanceLabel->setText(QString::number(_distance * M2MI, 'f', 1) + + " " + tr("mi")); + else + _distanceLabel->setText(QString::number(_distance * M2KM, 'f', 1) + + " " + tr("km")); _timeLabel->setText(timeSpan(_time)); } @@ -633,6 +668,20 @@ void GUI::updateNavigationActions() } } +void GUI::setMetricUnits() +{ + _elevationGraph->setUnits(Metric); + _speedGraph->setUnits(Metric); + updateStatusBarInfo(); +} + +void GUI::setImperialUnits() +{ + _elevationGraph->setUnits(Imperial); + _speedGraph->setUnits(Imperial); + updateStatusBarInfo(); +} + void GUI::next() { QString file = _browser->next(); diff --git a/src/gui.h b/src/gui.h index 049bb5c4..ec98b094 100644 --- a/src/gui.h +++ b/src/gui.h @@ -50,6 +50,9 @@ private slots: void last(); void first(); + void setMetricUnits(); + void setImperialUnits(); + private: void loadFiles(); @@ -73,6 +76,7 @@ private: QMenu *_poiMenu; QMenu *_mapMenu; QMenu *_settingsMenu; + QMenu *_unitsMenu; QToolBar *_fileToolBar; QToolBar *_showToolBar; @@ -100,6 +104,8 @@ private: QAction *_prevAction; QAction *_lastAction; QAction *_firstAction; + QAction *_metricUnitsAction; + QAction *_imperialUnitsAction; QList _mapActions; QLabel *_fileNameLabel; diff --git a/src/slideritem.cpp b/src/slideritem.cpp index 104066ec..5d2192fe 100644 --- a/src/slideritem.cpp +++ b/src/slideritem.cpp @@ -46,3 +46,9 @@ QVariant SliderItem::itemChange(GraphicsItemChange change, const QVariant &value return QGraphicsItem::itemChange(change, value); } + +void SliderItem::clear() +{ + _area = QRectF(); + setPos(QPointF()); +} diff --git a/src/slideritem.h b/src/slideritem.h index be8c6921..047f46e0 100644 --- a/src/slideritem.h +++ b/src/slideritem.h @@ -17,6 +17,8 @@ public: QRectF area() {return _area;} void setArea(const QRectF &area) {_area = area;} + void clear(); + signals: void positionChanged(const QPointF&); diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp index b2488108..22d50280 100644 --- a/src/speedgraph.cpp +++ b/src/speedgraph.cpp @@ -10,11 +10,19 @@ SpeedGraph::SpeedGraph(QWidget *parent) : Graph(parent) Graph::setYLabel(tr("Speed")); Graph::setXUnits(tr("km")); Graph::setYUnits(tr("km/h")); - Graph::setXScale(0.001); - Graph::setYScale(3.6); + Graph::setXScale(M2KM); + Graph::setYScale(MS2KMH); Graph::setPrecision(1); } +void SpeedGraph::addInfo() +{ + Graph::addInfo(tr("Average"), QString::number(avg() * _yScale, 'f', 1) + + THIN_SPACE + _yUnits); + Graph::addInfo(tr("Maximum"), QString::number(_max * _yScale, 'f', 1) + + THIN_SPACE + _yUnits); +} + void SpeedGraph::loadGPX(const GPX &gpx) { QVector data; @@ -31,13 +39,8 @@ void SpeedGraph::loadGPX(const GPX &gpx) max = qMax(max, data.at(i).y()); _max = qMax(_max, max); - - addInfo(tr("Average"), QString::number(avg() * _yScale, 'f', 1) - + THIN_SPACE + _yUnits); - addInfo(tr("Maximum"), QString::number(_max * _yScale, 'f', 1) - + THIN_SPACE + _yUnits); - - Graph::loadData(data); + addInfo(); + loadData(data); } qreal SpeedGraph::avg() const @@ -60,3 +63,23 @@ void SpeedGraph::clear() Graph::clear(); } + +void SpeedGraph::setUnits(enum Units units) +{ + if (units == Metric) { + Graph::setXUnits(tr("km")); + Graph::setYUnits(tr("km/h")); + Graph::setXScale(M2KM); + Graph::setYScale(MS2KMH); + } else { + Graph::setXUnits(tr("mi")); + Graph::setYUnits(tr("mi/h")); + Graph::setXScale(M2MI); + Graph::setYScale(MS2MIH); + } + + clearInfo(); + addInfo(); + + redraw(); +} diff --git a/src/speedgraph.h b/src/speedgraph.h index c9dc6e8c..9acf0087 100644 --- a/src/speedgraph.h +++ b/src/speedgraph.h @@ -4,6 +4,7 @@ #include #include "graph.h" #include "gpx.h" +#include "units.h" class SpeedGraph : public Graph { @@ -14,11 +15,14 @@ public: void loadGPX(const GPX &gpx); void clear(); + void setUnits(enum Units units); qreal avg() const; qreal max() const {return _max;} private: + void addInfo(); + qreal _max; QList _avg; }; diff --git a/src/units.h b/src/units.h new file mode 100644 index 00000000..59f68dd4 --- /dev/null +++ b/src/units.h @@ -0,0 +1,15 @@ +#ifndef UNITS_H +#define UNITS_H + +enum Units { + Metric, + Imperial +}; + +#define M2KM 0.001000000000 // m -> km +#define M2MI 0.000621371192 // m -> mi +#define M2FT 3.280839900000 // m -> ft +#define MS2KMH 3.600000000000 // m/s -> km/h +#define MS2MIH 2.236936290000 // m/s -> mi/h + +#endif // UNITS_H