mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-27 21:24:47 +01:00
Added support for label shields
This commit is contained in:
parent
561fadb4f2
commit
537b1c3716
@ -180,7 +180,8 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/netfile.h \
|
||||
src/GUI/limitedcombobox.h \
|
||||
src/GUI/pathtickitem.h \
|
||||
src/map/IMG/textitem.h
|
||||
src/map/IMG/textitem.h \
|
||||
src/map/IMG/label.h
|
||||
SOURCES += src/main.cpp \
|
||||
src/common/coordinates.cpp \
|
||||
src/common/rectc.cpp \
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "common/rectc.h"
|
||||
#include "common/range.h"
|
||||
#include "style.h"
|
||||
#include "label.h"
|
||||
|
||||
class VectorTile;
|
||||
class SubFile;
|
||||
@ -23,7 +24,7 @@ public:
|
||||
ll2xy() the points in the IMG class as this can not be done in
|
||||
parallel. */
|
||||
QVector<QPointF> points;
|
||||
QString label;
|
||||
Label label;
|
||||
quint32 type;
|
||||
|
||||
bool operator<(const Poly &other) const
|
||||
@ -34,7 +35,7 @@ public:
|
||||
Point() : id(0) {}
|
||||
|
||||
Coordinates coordinates;
|
||||
QString label;
|
||||
Label label;
|
||||
quint32 type;
|
||||
bool poi;
|
||||
quint64 id;
|
||||
|
74
src/map/IMG/label.h
Normal file
74
src/map/IMG/label.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef LABEL_H
|
||||
#define LABEL_H
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
class Label {
|
||||
public:
|
||||
class Shield
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
None,
|
||||
USInterstate,
|
||||
USShield,
|
||||
USRound,
|
||||
Hbox,
|
||||
Box,
|
||||
Oval
|
||||
};
|
||||
|
||||
Shield() : _type(None) {}
|
||||
Shield(Type type, const QString &name) : _type(type), _text(name) {}
|
||||
|
||||
Type type() const {return _type;}
|
||||
const QString &text() const {return _text;}
|
||||
bool isValid() const {return _type > None && !_text.isEmpty();}
|
||||
|
||||
bool operator==(const Shield &other) const
|
||||
{return _type == other._type && _text == other._text;}
|
||||
|
||||
private:
|
||||
Type _type;
|
||||
QString _text;
|
||||
};
|
||||
|
||||
Label() {}
|
||||
Label(const QString &text, const Shield &shield = Shield())
|
||||
: _text(text), _shield(shield) {}
|
||||
|
||||
const Shield &shield() const {return _shield;}
|
||||
const QString &text() const {return _text;}
|
||||
bool isValid() const {return _shield.isValid() || !_text.isEmpty();}
|
||||
|
||||
void setText(const QString &text) {_text = text;}
|
||||
|
||||
private:
|
||||
QString _text;
|
||||
Shield _shield;
|
||||
};
|
||||
|
||||
inline uint qHash(const Label::Shield &shield)
|
||||
{
|
||||
return qHash(shield.text()) ^ shield.type();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
inline QDebug operator<<(QDebug dbg, const Label::Shield &shield)
|
||||
{
|
||||
dbg.nospace() << "Shield(" << shield.type() << ", " << shield.text() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug dbg, const Label &label)
|
||||
{
|
||||
dbg.nospace() << "Label(";
|
||||
if (label.shield().isValid())
|
||||
dbg << label.shield() << ", ";
|
||||
dbg << label.text() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // LABEL_H
|
@ -7,7 +7,7 @@ static quint8 NORMAL_CHARS[] = {
|
||||
' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', '~', '~', '~', '~', '~',
|
||||
'X', 'Y', 'Z', '~', '~', '~', ' ', ' ',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '~', '~', '~', '~', '~', '~'
|
||||
};
|
||||
@ -48,6 +48,7 @@ static QString capitalize(const QString &str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool LBLFile::init()
|
||||
{
|
||||
Handle hdl;
|
||||
@ -73,45 +74,48 @@ bool LBLFile::init()
|
||||
return true;
|
||||
}
|
||||
|
||||
QString LBLFile::label6b(Handle &hdl, quint32 offset) const
|
||||
Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
||||
{
|
||||
QByteArray result;
|
||||
Label::Shield::Type shieldType = Label::Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
QByteArray *bap = &label;
|
||||
Charset curCharSet = Normal;
|
||||
quint8 b1, b2, b3;
|
||||
|
||||
if (!seek(hdl, offset))
|
||||
return QString();
|
||||
return Label();
|
||||
|
||||
while (true) {
|
||||
if (!(readByte(hdl, b1) && readByte(hdl, b2) && readByte(hdl, b3)))
|
||||
return QString();
|
||||
return Label();
|
||||
|
||||
int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F};
|
||||
|
||||
for (int cpt = 0; cpt < 4; cpt++) {
|
||||
if (c[cpt] > 0x2F)
|
||||
return QString::fromLatin1(result);
|
||||
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d))
|
||||
return Label(capitalize(QString::fromLatin1(label)),
|
||||
Label::Shield(shieldType, shieldLabel));
|
||||
switch (curCharSet) {
|
||||
case Normal:
|
||||
if (c[cpt] == 0x1c)
|
||||
curCharSet = Symbol;
|
||||
else if (c[cpt] == 0x1b)
|
||||
curCharSet = Special;
|
||||
else if(c[cpt] == 0x1d)
|
||||
result.append('|');
|
||||
else if (c[cpt] == 0x1f)
|
||||
result.append(' ');
|
||||
else if (c[cpt] == 0x1e)
|
||||
result.append(' ');
|
||||
else if (c[cpt] >= 0x2a && c[cpt] <= 0x2f) {
|
||||
shieldType = (Label::Shield::Type)(c[cpt] - 0x29);
|
||||
bap = &shieldLabel;
|
||||
} else if (bap == &shieldLabel
|
||||
&& NORMAL_CHARS[c[cpt]] == ' ')
|
||||
bap = &label;
|
||||
else
|
||||
result.append(NORMAL_CHARS[c[cpt]]);
|
||||
bap->append(NORMAL_CHARS[c[cpt]]);
|
||||
break;
|
||||
case Symbol:
|
||||
result.append(SYMBOL_CHARS[c[cpt]]);
|
||||
bap->append(SYMBOL_CHARS[c[cpt]]);
|
||||
curCharSet = Normal;
|
||||
break;
|
||||
case Special:
|
||||
result.append(SPECIAL_CHARS[c[cpt]]);
|
||||
bap->append(SPECIAL_CHARS[c[cpt]]);
|
||||
curCharSet = Normal;
|
||||
break;
|
||||
}
|
||||
@ -119,30 +123,39 @@ QString LBLFile::label6b(Handle &hdl, quint32 offset) const
|
||||
}
|
||||
}
|
||||
|
||||
QString LBLFile::label8b(Handle &hdl, quint32 offset) const
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
||||
{
|
||||
QByteArray result;
|
||||
Label::Shield::Type shieldType = Label::Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
QByteArray *bap = &label;
|
||||
quint8 c;
|
||||
|
||||
if (!seek(hdl, offset))
|
||||
return QString();
|
||||
return Label();
|
||||
|
||||
while (true) {
|
||||
if (!readByte(hdl, c))
|
||||
return QString();
|
||||
if (!c)
|
||||
return Label();
|
||||
if (!c || c == 0x1d)
|
||||
break;
|
||||
|
||||
if (c >= 0x1B && c <= 0x1F)
|
||||
result.append(' ');
|
||||
else if (c > 0x07)
|
||||
result.append(c);
|
||||
if ((c >= 0x1e && c <= 0x1f))
|
||||
bap->append(' ');
|
||||
else if (c <= 0x07) {
|
||||
shieldType = (Label::Shield::Type)c;
|
||||
bap = &shieldLabel;
|
||||
} else if (bap == &shieldLabel && QChar(c).isSpace()) {
|
||||
bap = &label;
|
||||
} else
|
||||
bap->append(c);
|
||||
}
|
||||
|
||||
return _codec ? _codec->toUnicode(result) : QString::fromLatin1(result);
|
||||
return Label(capitalize(_codec ? _codec->toUnicode(label)
|
||||
: QString::fromLatin1(label)), Label::Shield(shieldType, _codec
|
||||
? _codec->toUnicode(shieldLabel) : QString::fromLatin1(shieldLabel)));
|
||||
}
|
||||
|
||||
QString LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
||||
{
|
||||
if (!_init) {
|
||||
if (!(_init = init()))
|
||||
@ -163,11 +176,11 @@ QString LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
||||
|
||||
switch (_encoding) {
|
||||
case 6:
|
||||
return capitalize(label6b(hdl, labelOffset));
|
||||
return label6b(hdl, labelOffset);
|
||||
case 9:
|
||||
case 10:
|
||||
return capitalize(label8b(hdl, labelOffset));
|
||||
return label8b(hdl, labelOffset);
|
||||
default:
|
||||
return QString();
|
||||
return Label();
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define LBLFILE_H
|
||||
|
||||
#include "subfile.h"
|
||||
#include "label.h"
|
||||
|
||||
class QTextCodec;
|
||||
|
||||
@ -10,13 +11,13 @@ class LBLFile : public SubFile
|
||||
public:
|
||||
LBLFile(IMG *img, quint32 size) : SubFile(img, size), _init(false) {}
|
||||
|
||||
QString label(Handle &hdl, quint32 offset, bool poi = false);
|
||||
Label label(Handle &hdl, quint32 offset, bool poi = false);
|
||||
|
||||
private:
|
||||
bool init();
|
||||
|
||||
QString label6b(Handle &hdl, quint32 offset) const;
|
||||
QString label8b(Handle &hdl, quint32 offset) const;
|
||||
Label label6b(Handle &hdl, quint32 offset) const;
|
||||
Label label8b(Handle &hdl, quint32 offset) const;
|
||||
|
||||
quint32 _offset;
|
||||
quint32 _size;
|
||||
|
@ -980,6 +980,11 @@ bool Style::isSummit(quint32 type)
|
||||
return (type == 0x6616);
|
||||
}
|
||||
|
||||
bool Style::isMajorRoad(quint32 type)
|
||||
{
|
||||
return (type <= TYPE(0x04));
|
||||
}
|
||||
|
||||
Style::POIClass Style::poiClass(quint32 type)
|
||||
{
|
||||
if ((type >= 0x2a00 && type < 0x2b00) || type == 0x2c0a || type == 0x2d02)
|
||||
|
@ -106,6 +106,7 @@ public:
|
||||
static bool isContourLine(quint32 type);
|
||||
static bool isSpot(quint32 type);
|
||||
static bool isSummit(quint32 type);
|
||||
static bool isMajorRoad(quint32 type);
|
||||
static POIClass poiClass(quint32 type);
|
||||
|
||||
private:
|
||||
|
@ -7,29 +7,48 @@
|
||||
|
||||
#define FLAGS (Qt::AlignCenter | Qt::TextWordWrap | Qt::TextDontClip)
|
||||
#define MAX_TEXT_WIDTH 8
|
||||
#define MIN_BOX_WIDTH 2
|
||||
|
||||
|
||||
static void expand(QRect &rect, int width)
|
||||
{
|
||||
rect.adjust(-(width/2 - rect.width()/2), 0, width/2 - rect.width()/2, 0);
|
||||
}
|
||||
|
||||
TextPointItem::TextPointItem(const QPoint &point, const QString *text,
|
||||
const QFont *font, const QImage *img, const QColor *color)
|
||||
: _text(text), _font(font), _img(img), _color(color)
|
||||
const QFont *font, const QImage *img, const QColor *color,
|
||||
const QColor *bgColor) : _text(text), _font(font), _img(img), _color(color),
|
||||
_bgColor(bgColor)
|
||||
{
|
||||
QRect iconRect;
|
||||
|
||||
if (text) {
|
||||
QFontMetrics fm(*font);
|
||||
int limit = font->pixelSize() * MAX_TEXT_WIDTH;
|
||||
_textRect = fm.boundingRect(QRect(0, 0, limit, 0), FLAGS, *text);
|
||||
_textRect.adjust(0, 0, 1, 1);
|
||||
}
|
||||
if (img) {
|
||||
iconRect = QRect(QPoint(point.x() - img->width()/2, point.y()
|
||||
- img->height()/2), img->size());
|
||||
_textRect.moveTopLeft(QPoint(point.x() + img->width(), point.y()
|
||||
|
||||
if (_bgColor && _textRect.width() < font->pixelSize() * MIN_BOX_WIDTH)
|
||||
expand(_textRect, font->pixelSize() * MIN_BOX_WIDTH);
|
||||
|
||||
setPos(point);
|
||||
}
|
||||
|
||||
void TextPointItem::setPos(const QPoint &point)
|
||||
{
|
||||
QPainterPath shape;
|
||||
QRect iconRect;
|
||||
|
||||
if (_img) {
|
||||
iconRect = QRect(QPoint(point.x() - _img->width()/2, point.y()
|
||||
- _img->height()/2), _img->size());
|
||||
_textRect.moveTopLeft(QPoint(point.x() + _img->width(), point.y()
|
||||
- _textRect.height()/2));
|
||||
} else
|
||||
_textRect.moveCenter(point);
|
||||
|
||||
_rect = _textRect | iconRect;
|
||||
_shape.addRect(_rect);
|
||||
shape.addRect(_rect);
|
||||
_shape = shape;
|
||||
}
|
||||
|
||||
void TextPointItem::paint(QPainter *painter) const
|
||||
@ -54,6 +73,13 @@ void TextPointItem::paint(QPainter *painter) const
|
||||
painter->drawImage(_textRect.x() - 1, _textRect.y(), img);
|
||||
painter->drawImage(_textRect.x() + 1, _textRect.y(), img);
|
||||
|
||||
|
||||
if (_bgColor) {
|
||||
painter->setPen(*_color);
|
||||
painter->setBrush(*_bgColor);
|
||||
painter->drawRect(_textRect);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
}
|
||||
if (_color) {
|
||||
painter->setFont(*_font);
|
||||
painter->setPen(*_color);
|
||||
|
@ -16,7 +16,7 @@ class TextPointItem : public TextItem
|
||||
public:
|
||||
TextPointItem() : _text(0), _font(0), _img(0) {}
|
||||
TextPointItem(const QPoint &point, const QString *text, const QFont *font,
|
||||
const QImage *img, const QColor *color);
|
||||
const QImage *img, const QColor *color, const QColor *bgColor = 0);
|
||||
|
||||
bool isValid() const {return !_rect.isEmpty();}
|
||||
|
||||
@ -24,11 +24,13 @@ public:
|
||||
QPainterPath shape() const {return _shape;}
|
||||
void paint(QPainter *painter) const;
|
||||
|
||||
void setPos(const QPoint &point);
|
||||
|
||||
private:
|
||||
const QString *_text;
|
||||
const QFont *_font;
|
||||
const QImage *_img;
|
||||
const QColor *_color;
|
||||
const QColor *_color, *_bgColor;
|
||||
QRect _rect, _textRect;
|
||||
QPainterPath _shape;
|
||||
};
|
||||
|
@ -73,12 +73,18 @@ private:
|
||||
QList<IMG::Point> _points;
|
||||
};
|
||||
|
||||
static void convertUnits(QString &str)
|
||||
|
||||
static QColor shieldColor(Qt::white);
|
||||
static QColor shieldBgColor1("#dd3e3e");
|
||||
static QColor shieldBgColor2("#379947");
|
||||
static QColor shieldBgColor3("#4a7fc1");
|
||||
|
||||
|
||||
static QString convertUnits(const QString &str)
|
||||
{
|
||||
bool ok;
|
||||
int number = str.toInt(&ok);
|
||||
if (ok)
|
||||
str = QString::number(qRound(number * 0.3048));
|
||||
return ok ? QString::number(qRound(number * 0.3048)) : str;
|
||||
}
|
||||
|
||||
static int minPOIZoom(Style::POIClass cl)
|
||||
@ -123,6 +129,40 @@ FONT(normalFont, NORMAL_FONT_SIZE)
|
||||
FONT(smallFont, SMALL_FONT_SIZE)
|
||||
FONT(poiFont, POI_FONT_SIZE)
|
||||
|
||||
static const QColor *shieldBgColor(Label::Shield::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Label::Shield::USInterstate:
|
||||
case Label::Shield::Hbox:
|
||||
return &shieldBgColor1;
|
||||
case Label::Shield::USShield:
|
||||
case Label::Shield::Box:
|
||||
return &shieldBgColor2;
|
||||
case Label::Shield::USRound:
|
||||
case Label::Shield::Oval:
|
||||
return &shieldBgColor3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int minShieldZoom(Label::Shield::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Label::Shield::USInterstate:
|
||||
case Label::Shield::Hbox:
|
||||
return 18;
|
||||
case Label::Shield::USShield:
|
||||
case Label::Shield::Box:
|
||||
return 19;
|
||||
case Label::Shield::USRound:
|
||||
case Label::Shield::Oval:
|
||||
return 20;
|
||||
default:
|
||||
return INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IMGMap::IMGMap(const QString &fileName, QObject *parent)
|
||||
: Map(parent), _fileName(fileName), _img(fileName),
|
||||
@ -278,6 +318,8 @@ void IMGMap::processPolygons(QList<IMG::Poly> &polygons)
|
||||
void IMGMap::processLines(QList<IMG::Poly> &lines, const QPoint &tile,
|
||||
QList<TextItem*> &textItems)
|
||||
{
|
||||
QRect tileRect(tile, QSize(TILE_SIZE, TILE_SIZE));
|
||||
|
||||
qStableSort(lines);
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
@ -288,20 +330,19 @@ void IMGMap::processLines(QList<IMG::Poly> &lines, const QPoint &tile,
|
||||
}
|
||||
}
|
||||
|
||||
if (_zoom < LINE_TEXT_MIN_ZOOM)
|
||||
return;
|
||||
|
||||
if (_zoom >= LINE_TEXT_MIN_ZOOM) {
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
IMG::Poly &poly = lines[i];
|
||||
const Style::Line &style = _img.style().line(poly.type);
|
||||
|
||||
if (style.img().isNull() && style.foreground() == Qt::NoPen)
|
||||
continue;
|
||||
if (poly.label.isEmpty() || style.textFontSize() == Style::None)
|
||||
if (poly.label.text().isEmpty()
|
||||
|| style.textFontSize() == Style::None)
|
||||
continue;
|
||||
|
||||
if (Style::isContourLine(poly.type))
|
||||
convertUnits(poly.label);
|
||||
poly.label.setText(convertUnits(poly.label.text()));
|
||||
|
||||
const QFont *font;
|
||||
switch (style.textFontSize()) {
|
||||
@ -317,13 +358,60 @@ void IMGMap::processLines(QList<IMG::Poly> &lines, const QPoint &tile,
|
||||
const QColor *color = style.textColor().isValid()
|
||||
? &style.textColor() : 0;
|
||||
|
||||
TextPathItem *item = new TextPathItem(poly.points, &poly.label,
|
||||
QRect(tile, QSize(TILE_SIZE, TILE_SIZE)), font, color);
|
||||
TextPathItem *item = new TextPathItem(poly.points,
|
||||
&poly.label.text(), tileRect, font, color);
|
||||
if (item->isValid() && !item->collides(textItems))
|
||||
textItems.append(item);
|
||||
else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int type = 1; type < 7; type++) {
|
||||
if (minShieldZoom((Label::Shield::Type)type) > _zoom)
|
||||
continue;
|
||||
|
||||
QSet<Label::Shield> shields;
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
const IMG::Poly &poly = lines.at(i);
|
||||
const Label::Shield &shield = poly.label.shield();
|
||||
if (shield.type() != type || !Style::isMajorRoad(poly.type))
|
||||
continue;
|
||||
|
||||
if (poly.label.shield().isValid() && !shields.contains(shield)) {
|
||||
bool valid = false;
|
||||
int idx = poly.points.size()/2, inc = 0, sign = 1;
|
||||
|
||||
TextPointItem *item = new TextPointItem(
|
||||
poly.points.at(idx).toPoint(), &shield.text(), normalFont(),
|
||||
0, &shieldColor, shieldBgColor(shield.type()));
|
||||
|
||||
while (1) {
|
||||
if (!item->collides(textItems)
|
||||
&& tileRect.contains(item->boundingRect().toRect())) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
inc++;
|
||||
sign = (sign < 0) ? 1 : -1;
|
||||
idx += inc * sign;
|
||||
|
||||
if (!(idx >= 0 && idx < poly.points.size()))
|
||||
break;
|
||||
|
||||
item->setPos(poly.points.at(idx).toPoint());
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
textItems.append(item);
|
||||
shields.insert(shield);
|
||||
} else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IMGMap::processPoints(QList<IMG::Point> &points,
|
||||
@ -339,7 +427,8 @@ void IMGMap::processPoints(QList<IMG::Point> &points,
|
||||
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
|
||||
continue;
|
||||
|
||||
const QString *label = point.label.isEmpty() ? 0 : &(point.label);
|
||||
const QString *label = point.label.text().isEmpty()
|
||||
? 0 : &(point.label.text());
|
||||
const QImage *img = style.img().isNull() ? 0 : &style.img();
|
||||
const QFont *font = 0;
|
||||
if (point.poi) {
|
||||
@ -369,10 +458,10 @@ void IMGMap::processPoints(QList<IMG::Point> &points,
|
||||
continue;
|
||||
|
||||
if (Style::isSpot(point.type))
|
||||
convertUnits(point.label);
|
||||
if (Style::isSummit(point.type) && !point.label.isEmpty()) {
|
||||
QStringList list = point.label.split(" ");
|
||||
convertUnits(list.last());
|
||||
point.label.setText(convertUnits(point.label.text()));
|
||||
if (Style::isSummit(point.type) && !point.label.text().isEmpty()) {
|
||||
QStringList list = point.label.text().split(" ");
|
||||
list.last() = convertUnits(list.last());
|
||||
point.label = list.join(" ");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user