forked from organicmaps/organicmaps
added support for multi-line text with alignment.
This commit is contained in:
parent
e9efc658bd
commit
5113a86079
12 changed files with 493 additions and 269 deletions
|
@ -5,7 +5,7 @@
|
|||
#include "../yg/defines.hpp"
|
||||
#include "../yg/skin.hpp"
|
||||
#include "../yg/pen_info.hpp"
|
||||
#include "../yg/text_element.hpp"
|
||||
#include "../yg/straight_text_element.hpp"
|
||||
|
||||
#include "../version/version.hpp"
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ namespace yg
|
|||
return res;
|
||||
}
|
||||
|
||||
GlyphLayout::GlyphLayout()
|
||||
{}
|
||||
|
||||
GlyphLayout::GlyphLayout(GlyphLayout const & src, math::Matrix<double, 3, 3> const & m)
|
||||
: m_firstVisible(src.m_firstVisible),
|
||||
m_lastVisible(src.m_lastVisible),
|
||||
|
@ -118,8 +121,8 @@ namespace yg
|
|||
|
||||
limitRect.Inflate(2, 2);
|
||||
|
||||
m2::PointD ptOffs(-limitRect.SizeX() / 2,
|
||||
-limitRect.SizeY() / 2);
|
||||
m2::PointD ptOffs(-limitRect.SizeX() / 2 - limitRect.minX(),
|
||||
-limitRect.SizeY() / 2 - limitRect.minY());
|
||||
|
||||
/// adjusting according to position
|
||||
if (pos & EPosLeft)
|
||||
|
@ -128,10 +131,10 @@ namespace yg
|
|||
ptOffs += m2::PointD(limitRect.SizeX() / 2, 0);
|
||||
|
||||
if (pos & EPosAbove)
|
||||
ptOffs += m2::PointD(0, limitRect.SizeY() / 2);
|
||||
ptOffs += m2::PointD(0, -limitRect.SizeY() / 2);
|
||||
|
||||
if (pos & EPosUnder)
|
||||
ptOffs += m2::PointD(0, -limitRect.SizeY() / 2);
|
||||
ptOffs += m2::PointD(0, limitRect.SizeY() / 2);
|
||||
|
||||
m_limitRect = m2::AARectD(limitRect);
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ namespace yg
|
|||
|
||||
public:
|
||||
|
||||
GlyphLayout();
|
||||
|
||||
GlyphLayout(GlyphLayout const & layout, math::Matrix<double, 3, 3> const & m);
|
||||
|
||||
GlyphLayout(GlyphCache * glyphCache,
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include "overlay_renderer.hpp"
|
||||
#include "composite_overlay_element.hpp"
|
||||
#include "text_element.hpp"
|
||||
#include "straight_text_element.hpp"
|
||||
#include "path_text_element.hpp"
|
||||
#include "symbol_element.hpp"
|
||||
#include "render_state.hpp"
|
||||
#include "info_layer.hpp"
|
||||
|
@ -112,8 +113,6 @@ namespace yg
|
|||
params.m_glyphCache = glyphCache();
|
||||
params.m_logText = strings::MakeUniString(utf8Text);
|
||||
|
||||
StraightTextElement ste(params);
|
||||
|
||||
shared_ptr<OverlayElement> oe(new StraightTextElement(params));
|
||||
|
||||
math::Matrix<double, 3, 3> id = math::Identity<double, 3>();
|
||||
|
|
107
yg/path_text_element.cpp
Normal file
107
yg/path_text_element.cpp
Normal file
|
@ -0,0 +1,107 @@
|
|||
#include "../base/SRC_FIRST.hpp"
|
||||
#include "path_text_element.hpp"
|
||||
#include "overlay_renderer.hpp"
|
||||
|
||||
namespace yg
|
||||
{
|
||||
PathTextElement::PathTextElement(Params const & p)
|
||||
: TextElement(p),
|
||||
m_glyphLayout(p.m_glyphCache,
|
||||
p.m_fontDesc,
|
||||
p.m_pts,
|
||||
p.m_ptsCount,
|
||||
visText(),
|
||||
p.m_fullLength,
|
||||
p.m_pathOffset,
|
||||
p.m_position)
|
||||
{
|
||||
setPivot(m_glyphLayout.pivot());
|
||||
}
|
||||
|
||||
PathTextElement::PathTextElement(PathTextElement const & src, math::Matrix<double, 3, 3> const & m)
|
||||
: TextElement(src),
|
||||
m_glyphLayout(src.m_glyphLayout, m)
|
||||
{
|
||||
setPivot(m_glyphLayout.pivot());
|
||||
}
|
||||
|
||||
m2::AARectD const PathTextElement::boundRect() const
|
||||
{
|
||||
// return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(2, 2));
|
||||
return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(10, 2));
|
||||
// return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(40, 2)); //< to create more sparse street names structure
|
||||
}
|
||||
|
||||
vector<m2::AARectD> const & PathTextElement::boundRects() const
|
||||
{
|
||||
if (isDirtyRect())
|
||||
{
|
||||
m_boundRects.clear();
|
||||
m_boundRects.push_back(boundRect());
|
||||
setIsDirtyRect(false);
|
||||
}
|
||||
|
||||
return m_boundRects;
|
||||
}
|
||||
|
||||
void PathTextElement::draw(gl::OverlayRenderer * screen, math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
if (screen->isDebugging())
|
||||
{
|
||||
yg::Color c(255, 255, 255, 32);
|
||||
|
||||
if (isFrozen())
|
||||
c = yg::Color(0, 0, 255, 64);
|
||||
if (isNeedRedraw())
|
||||
c = yg::Color(255, 0, 0, 64);
|
||||
|
||||
screen->drawRectangle(roughBoundRect(), yg::Color(255, 255, 0, 64), yg::maxDepth - 3);
|
||||
|
||||
for (unsigned i = 0; i < boundRects().size(); ++i)
|
||||
screen->drawRectangle(boundRects()[i], c, yg::maxDepth - 3);
|
||||
}
|
||||
if (!isNeedRedraw())
|
||||
return;
|
||||
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
if ((m_glyphLayout.firstVisible() != 0) || (m_glyphLayout.lastVisible() != visText().size()))
|
||||
return;
|
||||
|
||||
drawTextImpl(m_glyphLayout, screen, m, m_fontDesc, yg::maxDepth);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
drawTextImpl(m_glyphLayout, screen, m, desc, yg::maxDepth);
|
||||
}
|
||||
|
||||
void PathTextElement::offset(m2::PointD const & offs)
|
||||
{
|
||||
TextElement::offset(offs);
|
||||
m_glyphLayout.setPivot(pivot());
|
||||
}
|
||||
|
||||
void PathTextElement::cache(StylesCache * stylesCache) const
|
||||
{
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
cacheTextImpl(m_glyphLayout, stylesCache, m_fontDesc);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
cacheTextImpl(m_glyphLayout, stylesCache, desc);
|
||||
}
|
||||
|
||||
int PathTextElement::visualRank() const
|
||||
{
|
||||
return 2000 + m_fontDesc.m_size;
|
||||
}
|
||||
|
||||
OverlayElement * PathTextElement::clone(math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
return new PathTextElement(*this, m);
|
||||
}
|
||||
}
|
38
yg/path_text_element.hpp
Normal file
38
yg/path_text_element.hpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "text_element.hpp"
|
||||
|
||||
namespace yg
|
||||
{
|
||||
class PathTextElement : public TextElement
|
||||
{
|
||||
private:
|
||||
|
||||
GlyphLayout m_glyphLayout;
|
||||
|
||||
m2::AARectD const boundRect() const;
|
||||
|
||||
public:
|
||||
|
||||
struct Params : TextElement::Params
|
||||
{
|
||||
m2::PointD const * m_pts;
|
||||
size_t m_ptsCount;
|
||||
double m_fullLength;
|
||||
double m_pathOffset;
|
||||
};
|
||||
|
||||
PathTextElement(Params const & p);
|
||||
PathTextElement(PathTextElement const & src, math::Matrix<double, 3, 3> const & m);
|
||||
|
||||
vector<m2::AARectD> const & boundRects() const;
|
||||
|
||||
void draw(gl::OverlayRenderer * r, math::Matrix<double, 3, 3> const & m) const;
|
||||
void cache(StylesCache * stylesCache) const;
|
||||
int visualRank() const;
|
||||
|
||||
void offset(m2::PointD const & offs);
|
||||
|
||||
OverlayElement * clone(math::Matrix<double, 3, 3> const & m) const;
|
||||
};
|
||||
}
|
228
yg/straight_text_element.cpp
Normal file
228
yg/straight_text_element.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
#include "../base/SRC_FIRST.hpp"
|
||||
#include "straight_text_element.hpp"
|
||||
#include "overlay_renderer.hpp"
|
||||
|
||||
namespace yg
|
||||
{
|
||||
void visSplit(strings::UniString const & visText, buffer_vector<strings::UniString, 3> & res)
|
||||
{
|
||||
if (visText.size() > 15)
|
||||
{
|
||||
/// split into two
|
||||
size_t rs = visText.size() / 2;
|
||||
size_t ls = visText.size() / 2;
|
||||
|
||||
size_t s;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (rs == visText.size() - 1)
|
||||
break;
|
||||
|
||||
if ((visText[rs] == strings::UniChar(' '))
|
||||
|| (visText[rs] == strings::UniChar('\t'))
|
||||
|| (visText[rs] == strings::UniChar('\n')))
|
||||
break;
|
||||
|
||||
++rs;
|
||||
}
|
||||
|
||||
if (rs == visText.size() - 1)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (ls == 0)
|
||||
break;
|
||||
|
||||
if ((visText[ls] == strings::UniChar(' '))
|
||||
|| (visText[rs] == strings::UniChar('\t'))
|
||||
|| (visText[rs] == strings::UniChar('\n')))
|
||||
break;
|
||||
|
||||
--ls;
|
||||
}
|
||||
|
||||
if (ls < 5)
|
||||
s = visText.size() - 1;
|
||||
else
|
||||
s = ls;
|
||||
}
|
||||
else
|
||||
s = rs;
|
||||
|
||||
res.push_back(strings::UniString());
|
||||
res.back().resize(s + 1);
|
||||
for (unsigned i = 0; i < s + 1; ++i)
|
||||
res.back()[i] = visText[i];
|
||||
|
||||
if (s != visText.size() - 1)
|
||||
{
|
||||
res.push_back(strings::UniString());
|
||||
res.back().resize(visText.size() - s - 1);
|
||||
for (unsigned i = s + 1; i < visText.size(); ++i)
|
||||
res.back()[i - s - 1] = visText[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
res.push_back(visText);
|
||||
}
|
||||
|
||||
StraightTextElement::StraightTextElement(Params const & p)
|
||||
: TextElement(p)
|
||||
{
|
||||
buffer_vector<strings::UniString, 3> res;
|
||||
if (p.m_doSplit)
|
||||
{
|
||||
res.clear();
|
||||
visSplit(visText(), res);
|
||||
}
|
||||
else
|
||||
res.push_back(visText());
|
||||
|
||||
double allElemWidth = 0;
|
||||
double allElemHeight = 0;
|
||||
double elemShift = 0;
|
||||
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
{
|
||||
m_glyphLayouts.push_back(GlyphLayout(p.m_glyphCache, p.m_fontDesc, m2::PointD(0, 0), res[i], yg::EPosCenter));
|
||||
m2::RectD r = m_glyphLayouts.back().limitRect().GetGlobalRect();
|
||||
allElemWidth = max(r.SizeX(), allElemWidth);
|
||||
allElemHeight += r.SizeY();
|
||||
}
|
||||
|
||||
double curShift = allElemHeight / 2;
|
||||
|
||||
/// performing aligning of glyphLayouts as for the center position
|
||||
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
{
|
||||
double elemSize = m_glyphLayouts[i].limitRect().GetGlobalRect().SizeY();
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, -curShift + elemSize / 2));
|
||||
curShift -= elemSize;
|
||||
}
|
||||
|
||||
if (position() & yg::EPosLeft)
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(-allElemWidth / 2, 0));
|
||||
|
||||
if (position() & yg::EPosRight)
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(allElemWidth / 2, 0));
|
||||
|
||||
if (position() & yg::EPosAbove)
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, -allElemHeight / 2));
|
||||
|
||||
if (position() & yg::EPosUnder)
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, allElemHeight / 2));
|
||||
|
||||
for (unsigned i = 0; i < res.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + pivot());
|
||||
}
|
||||
|
||||
StraightTextElement::Params::Params()
|
||||
: m_minWordsInRow(2),
|
||||
m_maxWordsInRow(4),
|
||||
m_minSymInRow(10),
|
||||
m_maxSymInRow(20),
|
||||
m_doSplit(false)
|
||||
{}
|
||||
|
||||
StraightTextElement::StraightTextElement(StraightTextElement const & src, math::Matrix<double, 3, 3> const & m)
|
||||
: TextElement(src),
|
||||
m_glyphLayouts(src.m_glyphLayouts)
|
||||
{
|
||||
static vector<m2::PointD> offsets;
|
||||
offsets.clear();
|
||||
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
offsets.push_back(m2::PointD(m_glyphLayouts[i].pivot() - pivot()));
|
||||
|
||||
setPivot(pivot() * m);
|
||||
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(pivot() + offsets[i]);
|
||||
}
|
||||
|
||||
vector<m2::AARectD> const & StraightTextElement::boundRects() const
|
||||
{
|
||||
if (isDirtyRect())
|
||||
{
|
||||
m_boundRects.clear();
|
||||
|
||||
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
m_boundRects.push_back(m_glyphLayouts[i].limitRect());
|
||||
|
||||
setIsDirtyRect(false);
|
||||
}
|
||||
return m_boundRects;
|
||||
}
|
||||
|
||||
void StraightTextElement::draw(gl::OverlayRenderer * screen, math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
if (screen->isDebugging())
|
||||
{
|
||||
yg::Color c(255, 255, 255, 32);
|
||||
|
||||
if (isFrozen())
|
||||
c = yg::Color(0, 0, 255, 64);
|
||||
if (isNeedRedraw())
|
||||
c = yg::Color(255, 0, 0, 64);
|
||||
|
||||
screen->drawRectangle(roughBoundRect(), yg::Color(255, 255, 0, 64), yg::maxDepth - 3);
|
||||
|
||||
for (unsigned i = 0 ; i < boundRects().size(); ++i)
|
||||
screen->drawRectangle(boundRects()[i], c, yg::maxDepth - 3);
|
||||
}
|
||||
else
|
||||
if (!isNeedRedraw())
|
||||
return;
|
||||
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
drawTextImpl(m_glyphLayouts[i], screen, m, m_fontDesc, yg::maxDepth);
|
||||
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
drawTextImpl(m_glyphLayouts[i], screen, m, desc, yg::maxDepth);
|
||||
}
|
||||
|
||||
void StraightTextElement::offset(m2::PointD const & offs)
|
||||
{
|
||||
TextElement::offset(offs);
|
||||
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + offs);
|
||||
}
|
||||
|
||||
void StraightTextElement::cache(StylesCache * stylesCache) const
|
||||
{
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
cacheTextImpl(m_glyphLayouts[i], stylesCache, m_fontDesc);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
|
||||
cacheTextImpl(m_glyphLayouts[i], stylesCache, desc);
|
||||
}
|
||||
|
||||
int StraightTextElement::visualRank() const
|
||||
{
|
||||
return 0000 + m_fontDesc.m_size;
|
||||
}
|
||||
|
||||
OverlayElement * StraightTextElement::clone(math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
return new StraightTextElement(*this, m);
|
||||
}
|
||||
}
|
39
yg/straight_text_element.hpp
Normal file
39
yg/straight_text_element.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "text_element.hpp"
|
||||
|
||||
namespace yg
|
||||
{
|
||||
class StraightTextElement : public TextElement
|
||||
{
|
||||
private:
|
||||
|
||||
/// glyph layout of the text parts.
|
||||
vector<GlyphLayout> m_glyphLayouts;
|
||||
|
||||
public:
|
||||
|
||||
struct Params : TextElement::Params
|
||||
{
|
||||
unsigned m_minWordsInRow;
|
||||
unsigned m_maxWordsInRow;
|
||||
unsigned m_minSymInRow;
|
||||
unsigned m_maxSymInRow;
|
||||
bool m_doSplit;
|
||||
Params();
|
||||
};
|
||||
|
||||
StraightTextElement(Params const & p);
|
||||
StraightTextElement(StraightTextElement const & src, math::Matrix<double, 3, 3> const & m);
|
||||
|
||||
vector<m2::AARectD> const & boundRects() const;
|
||||
|
||||
void draw(gl::OverlayRenderer * r, math::Matrix<double, 3, 3> const & m) const;
|
||||
void cache(StylesCache * stylesCache) const;
|
||||
int visualRank() const;
|
||||
|
||||
void offset(m2::PointD const & offs);
|
||||
|
||||
OverlayElement * clone(math::Matrix<double, 3, 3> const & m) const;
|
||||
};
|
||||
}
|
|
@ -41,10 +41,7 @@ namespace yg
|
|||
|
||||
void TextElement::drawTextImpl(GlyphLayout const & layout, gl::OverlayRenderer * screen, math::Matrix<double, 3, 3> const & m, FontDesc const & fontDesc, double depth) const
|
||||
{
|
||||
if ((layout.firstVisible() != 0) || (layout.lastVisible() != visText().size()))
|
||||
return;
|
||||
|
||||
m2::PointD pv = pivot() * m;
|
||||
m2::PointD pv = layout.pivot() * m;
|
||||
|
||||
for (unsigned i = layout.firstVisible(); i < layout.lastVisible(); ++i)
|
||||
{
|
||||
|
@ -96,195 +93,4 @@ namespace yg
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
StraightTextElement::StraightTextElement(Params const & p)
|
||||
: TextElement(p),
|
||||
m_glyphLayout(p.m_glyphCache,
|
||||
p.m_fontDesc,
|
||||
p.m_pivot,
|
||||
visText(),
|
||||
p.m_position)
|
||||
{
|
||||
setPivot(m_glyphLayout.pivot());
|
||||
}
|
||||
|
||||
StraightTextElement::StraightTextElement(StraightTextElement const & src, math::Matrix<double, 3, 3> const & m)
|
||||
: TextElement(src),
|
||||
m_glyphLayout(src.m_glyphLayout)
|
||||
{
|
||||
m_glyphLayout.setPivot(m_glyphLayout.pivot() * m);
|
||||
setPivot(m_glyphLayout.pivot());
|
||||
}
|
||||
|
||||
m2::AARectD const StraightTextElement::boundRect() const
|
||||
{
|
||||
return m_glyphLayout.limitRect();
|
||||
}
|
||||
|
||||
vector<m2::AARectD> const & StraightTextElement::boundRects() const
|
||||
{
|
||||
if (isDirtyRect())
|
||||
{
|
||||
m_boundRects.clear();
|
||||
m_boundRects.push_back(boundRect());
|
||||
setIsDirtyRect(false);
|
||||
}
|
||||
return m_boundRects;
|
||||
}
|
||||
|
||||
void StraightTextElement::draw(gl::OverlayRenderer * screen, math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
if (screen->isDebugging())
|
||||
{
|
||||
yg::Color c(255, 255, 255, 32);
|
||||
|
||||
if (isFrozen())
|
||||
c = yg::Color(0, 0, 255, 64);
|
||||
if (isNeedRedraw())
|
||||
c = yg::Color(255, 0, 0, 64);
|
||||
|
||||
screen->drawRectangle(roughBoundRect(), yg::Color(255, 255, 0, 64), yg::maxDepth - 3);
|
||||
|
||||
for (unsigned i = 0 ; i < boundRects().size(); ++i)
|
||||
screen->drawRectangle(boundRects()[i], c, yg::maxDepth - 3);
|
||||
}
|
||||
else
|
||||
if (!isNeedRedraw())
|
||||
return;
|
||||
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
drawTextImpl(m_glyphLayout, screen, m, m_fontDesc, yg::maxDepth);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
drawTextImpl(m_glyphLayout, screen, m, desc, yg::maxDepth);
|
||||
}
|
||||
|
||||
void StraightTextElement::offset(m2::PointD const & offs)
|
||||
{
|
||||
TextElement::offset(offs);
|
||||
m_glyphLayout.setPivot(pivot());
|
||||
}
|
||||
|
||||
void StraightTextElement::cache(StylesCache * stylesCache) const
|
||||
{
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
cacheTextImpl(m_glyphLayout, stylesCache, m_fontDesc);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
cacheTextImpl(m_glyphLayout, stylesCache, desc);
|
||||
}
|
||||
|
||||
int StraightTextElement::visualRank() const
|
||||
{
|
||||
return 0000 + m_fontDesc.m_size;
|
||||
}
|
||||
|
||||
OverlayElement * StraightTextElement::clone(math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
return new StraightTextElement(*this, m);
|
||||
}
|
||||
|
||||
PathTextElement::PathTextElement(Params const & p)
|
||||
: TextElement(p),
|
||||
m_glyphLayout(p.m_glyphCache,
|
||||
p.m_fontDesc,
|
||||
p.m_pts,
|
||||
p.m_ptsCount,
|
||||
visText(),
|
||||
p.m_fullLength,
|
||||
p.m_pathOffset,
|
||||
p.m_position)
|
||||
{
|
||||
setPivot(m_glyphLayout.pivot());
|
||||
}
|
||||
|
||||
PathTextElement::PathTextElement(PathTextElement const & src, math::Matrix<double, 3, 3> const & m)
|
||||
: TextElement(src),
|
||||
m_glyphLayout(src.m_glyphLayout, m)
|
||||
{
|
||||
setPivot(m_glyphLayout.pivot());
|
||||
}
|
||||
|
||||
m2::AARectD const PathTextElement::boundRect() const
|
||||
{
|
||||
// return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(2, 2));
|
||||
return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(10, 2));
|
||||
// return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(40, 2)); //< to create more sparse street names structure
|
||||
}
|
||||
|
||||
vector<m2::AARectD> const & PathTextElement::boundRects() const
|
||||
{
|
||||
if (isDirtyRect())
|
||||
{
|
||||
m_boundRects.clear();
|
||||
m_boundRects.push_back(boundRect());
|
||||
setIsDirtyRect(false);
|
||||
}
|
||||
|
||||
return m_boundRects;
|
||||
}
|
||||
|
||||
void PathTextElement::draw(gl::OverlayRenderer * screen, math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
if (screen->isDebugging())
|
||||
{
|
||||
yg::Color c(255, 255, 255, 32);
|
||||
|
||||
if (isFrozen())
|
||||
c = yg::Color(0, 0, 255, 64);
|
||||
if (isNeedRedraw())
|
||||
c = yg::Color(255, 0, 0, 64);
|
||||
|
||||
screen->drawRectangle(roughBoundRect(), yg::Color(255, 255, 0, 64), yg::maxDepth - 3);
|
||||
|
||||
for (unsigned i = 0; i < boundRects().size(); ++i)
|
||||
screen->drawRectangle(boundRects()[i], c, yg::maxDepth - 3);
|
||||
}
|
||||
if (!isNeedRedraw())
|
||||
return;
|
||||
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
drawTextImpl(m_glyphLayout, screen, m, m_fontDesc, yg::maxDepth);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
drawTextImpl(m_glyphLayout, screen, m, desc, yg::maxDepth);
|
||||
}
|
||||
|
||||
void PathTextElement::offset(m2::PointD const & offs)
|
||||
{
|
||||
TextElement::offset(offs);
|
||||
m_glyphLayout.setPivot(pivot());
|
||||
}
|
||||
|
||||
void PathTextElement::cache(StylesCache * stylesCache) const
|
||||
{
|
||||
yg::FontDesc desc = m_fontDesc;
|
||||
|
||||
if (m_fontDesc.m_isMasked)
|
||||
{
|
||||
cacheTextImpl(m_glyphLayout, stylesCache, m_fontDesc);
|
||||
desc.m_isMasked = false;
|
||||
}
|
||||
|
||||
cacheTextImpl(m_glyphLayout, stylesCache, desc);
|
||||
}
|
||||
|
||||
int PathTextElement::visualRank() const
|
||||
{
|
||||
return 2000 + m_fontDesc.m_size;
|
||||
}
|
||||
|
||||
OverlayElement * PathTextElement::clone(math::Matrix<double, 3, 3> const & m) const
|
||||
{
|
||||
return new PathTextElement(*this, m);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,66 +61,4 @@ namespace yg
|
|||
strings::UniString const & visText() const;
|
||||
FontDesc const & fontDesc() const;
|
||||
};
|
||||
|
||||
class StraightTextElement : public TextElement
|
||||
{
|
||||
private:
|
||||
|
||||
/// glyph layout aligned to pivot point
|
||||
GlyphLayout m_glyphLayout;
|
||||
|
||||
protected:
|
||||
|
||||
m2::AARectD const boundRect() const;
|
||||
|
||||
public:
|
||||
|
||||
struct Params : TextElement::Params
|
||||
{};
|
||||
|
||||
StraightTextElement(Params const & p);
|
||||
StraightTextElement(StraightTextElement const & src, math::Matrix<double, 3, 3> const & m);
|
||||
|
||||
vector<m2::AARectD> const & boundRects() const;
|
||||
|
||||
void draw(gl::OverlayRenderer * r, math::Matrix<double, 3, 3> const & m) const;
|
||||
void cache(StylesCache * stylesCache) const;
|
||||
int visualRank() const;
|
||||
|
||||
void offset(m2::PointD const & offs);
|
||||
|
||||
OverlayElement * clone(math::Matrix<double, 3, 3> const & m) const;
|
||||
};
|
||||
|
||||
class PathTextElement : public TextElement
|
||||
{
|
||||
private:
|
||||
|
||||
GlyphLayout m_glyphLayout;
|
||||
|
||||
m2::AARectD const boundRect() const;
|
||||
|
||||
public:
|
||||
|
||||
struct Params : TextElement::Params
|
||||
{
|
||||
m2::PointD const * m_pts;
|
||||
size_t m_ptsCount;
|
||||
double m_fullLength;
|
||||
double m_pathOffset;
|
||||
};
|
||||
|
||||
PathTextElement(Params const & p);
|
||||
PathTextElement(PathTextElement const & src, math::Matrix<double, 3, 3> const & m);
|
||||
|
||||
vector<m2::AARectD> const & boundRects() const;
|
||||
|
||||
void draw(gl::OverlayRenderer * r, math::Matrix<double, 3, 3> const & m) const;
|
||||
void cache(StylesCache * stylesCache) const;
|
||||
int visualRank() const;
|
||||
|
||||
void offset(m2::PointD const & offs);
|
||||
|
||||
OverlayElement * clone(math::Matrix<double, 3, 3> const & m) const;
|
||||
};
|
||||
}
|
||||
|
|
12
yg/yg.pro
12
yg/yg.pro
|
@ -58,7 +58,9 @@ SOURCES += \
|
|||
overlay_renderer.cpp \
|
||||
render_state_updater.cpp \
|
||||
styles_cache.cpp \
|
||||
composite_overlay_element.cpp
|
||||
composite_overlay_element.cpp \
|
||||
path_text_element.cpp \
|
||||
straight_text_element.cpp
|
||||
|
||||
HEADERS += \
|
||||
internal/opengl.hpp \
|
||||
|
@ -109,7 +111,9 @@ HEADERS += \
|
|||
overlay_renderer.hpp \
|
||||
render_state_updater.hpp \
|
||||
styles_cache.hpp \
|
||||
composite_overlay_element.hpp
|
||||
composite_overlay_element.hpp \
|
||||
path_text_element.hpp \
|
||||
straight_text_element.hpp
|
||||
|
||||
win32 {
|
||||
HEADERS += internal/opengl_win32.hpp
|
||||
|
@ -119,3 +123,7 @@ win32 {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "../../yg/pen_info.hpp"
|
||||
#include "../../yg/circle_info.hpp"
|
||||
#include "../../yg/text_element.hpp"
|
||||
#include "../../yg/straight_text_element.hpp"
|
||||
#include "../../yg/path_text_element.hpp"
|
||||
|
||||
#include "../../qt_tstfrm/macros.hpp"
|
||||
|
||||
|
@ -662,12 +664,65 @@ namespace
|
|||
}
|
||||
};
|
||||
|
||||
struct TestDrawMultiLineStringWithPosition
|
||||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
yg::FontDesc fontDesc(14, yg::Color(0, 0, 0, 0), true, yg::Color(255, 255, 255, 255));
|
||||
|
||||
m2::PointD pt = m2::PointD(50, 150);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosAboveRight, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(50, 300);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosRight, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(50, 450);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosUnderRight, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(400, 150);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosAbove, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(400, 300);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosCenter, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(400, 450);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosUnder, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(750, 150);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosAboveLeft, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(750, 300);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosLeft, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
|
||||
pt = m2::PointD(750, 450);
|
||||
|
||||
p->drawText(fontDesc, pt, yg::EPosUnderLeft, "Simplicity is the ultimate sophistication", yg::maxDepth, true);
|
||||
p->drawRectangle(m2::Inflate(m2::RectD(pt, pt), m2::PointD(2, 2)), yg::Color(0, 0, 0, 255), yg::maxDepth);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestDrawString
|
||||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
yg::FontDesc fontDesc(20, yg::Color(0, 0, 0, 0), true, yg::Color(255, 255, 255, 255));
|
||||
p->drawText(fontDesc, m2::PointD(40, 50), yg::EPosAboveRight, "Simplicity is the ultimate sophistication", 0, true);
|
||||
p->drawText(fontDesc, m2::PointD(40, 150), yg::EPosAboveRight, "Simplicity is the ultimate sophistication", 0, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1267,6 +1322,7 @@ namespace
|
|||
// UNIT_TEST_GL(TestDrawSingleSymbol);
|
||||
// UNIT_TEST_GL(TestDrawEmptySymbol);
|
||||
// UNIT_TEST_GL(TestDrawSingleSymbolAndSolidPath);
|
||||
UNIT_TEST_GL(TestDrawMultiLineStringWithPosition);
|
||||
// UNIT_TEST_GL(TestDrawString);
|
||||
// UNIT_TEST_GL(TestDrawStringWithFixedFont);
|
||||
// UNIT_TEST_GL(TestDrawStringWithColor);
|
||||
|
@ -1293,7 +1349,7 @@ namespace
|
|||
// UNIT_TEST_GL(TestDrawPathSolid1PX);
|
||||
// UNIT_TEST_GL(TestDrawPathSolid2PX);
|
||||
// UNIT_TEST_GL(TestDrawPathSolid);
|
||||
UNIT_TEST_GL(TestDrawOverlappedSymbolWithText);
|
||||
// UNIT_TEST_GL(TestDrawOverlappedSymbolWithText);
|
||||
// UNIT_TEST_GL(TestDrawAARect);
|
||||
// UNIT_TEST_GL(TestDrawSector);
|
||||
// UNIT_TEST_GL(TestDrawPathSolidDiffWidth);
|
||||
|
|
Loading…
Add table
Reference in a new issue