From 6cc0074db7573147cfb1a9ad228ba6fd04a1c81e Mon Sep 17 00:00:00 2001 From: ExMix Date: Thu, 23 May 2013 15:31:39 +0300 Subject: [PATCH] support a max width property for drawable texts --- graphics/glyph_layout.cpp | 199 ++++++++++++++++++----------- graphics/glyph_layout.hpp | 21 +++ graphics/straight_text_element.cpp | 3 +- graphics/straight_text_element.hpp | 1 + gui/text_view.cpp | 9 +- gui/text_view.hpp | 2 + 6 files changed, 160 insertions(+), 75 deletions(-) diff --git a/graphics/glyph_layout.cpp b/graphics/glyph_layout.cpp index d48b852fac..fe1e546c09 100644 --- a/graphics/glyph_layout.cpp +++ b/graphics/glyph_layout.cpp @@ -79,80 +79,24 @@ namespace graphics m_textLength(0), m_textOffset(0) { - if (!m_fontDesc.IsValid()) - return; + initStraigthText(glyphCache, fontDesc, pt, visText, pos, numeric_limits::max()); + } - size_t const cnt = visText.size(); - ASSERT_GREATER(cnt, 0, ()); - - m_entries.resize(cnt); - m_metrics.resize(cnt); - - m2::RectD boundRect; - m2::PointD curPt(0, 0); - - bool isFirst = true; - - for (size_t i = 0; i < visText.size(); ++i) - { - GlyphKey glyphKey(visText[i], - fontDesc.m_size, - //fontDesc.m_isMasked, - false, //< calculating glyph positions using unmasked glyphs. - fontDesc.m_color); - - GlyphMetrics const m = glyphCache->getGlyphMetrics(glyphKey); - - m_textLength += m.m_xAdvance; - - if (isFirst) - { - boundRect = m2::RectD(m.m_xOffset, - -m.m_yOffset, - m.m_xOffset, - -m.m_yOffset); - isFirst = false; - } - else - boundRect.Add(m2::PointD(m.m_xOffset + curPt.x, -m.m_yOffset + curPt.y)); - - boundRect.Add(m2::PointD(m.m_xOffset + m.m_width, - -(m.m_yOffset + m.m_height)) + curPt); - - GlyphLayoutElem elem; - elem.m_sym = visText[i]; - elem.m_angle = 0; - elem.m_pt = curPt; - m_entries[i] = elem; - m_metrics[i] = m; - - curPt += m2::PointD(m.m_xAdvance, m.m_yAdvance); - } - - boundRect.Inflate(2, 2); - - m2::PointD ptOffs(-boundRect.SizeX() / 2 - boundRect.minX(), - -boundRect.SizeY() / 2 - boundRect.minY()); - - // adjusting according to position - if (pos & EPosLeft) - ptOffs += m2::PointD(-boundRect.SizeX() / 2, 0); - - if (pos & EPosRight) - ptOffs += m2::PointD(boundRect.SizeX() / 2, 0); - - if (pos & EPosAbove) - ptOffs += m2::PointD(0, -boundRect.SizeY() / 2); - - if (pos & EPosUnder) - ptOffs += m2::PointD(0, boundRect.SizeY() / 2); - - for (unsigned i = 0; i < m_entries.size(); ++i) - m_entries[i].m_pt += ptOffs; - - boundRect.Offset(ptOffs); - - m_boundRects.push_back(m2::AnyRectD(boundRect)); + GlyphLayout::GlyphLayout(GlyphCache * glyphCache, + FontDesc const & fontDesc, + m2::PointD const & pt, + strings::UniString const & visText, + graphics::EPosition pos, + unsigned maxWidth) + : m_firstVisible(0), + m_lastVisible(visText.size()), + m_fontDesc(fontDesc), + m_pivot(pt), + m_offset(0, 0), + m_textLength(0), + m_textOffset(0) + { + initStraigthText(glyphCache, fontDesc, pt, visText, pos, maxWidth); } GlyphLayout::GlyphLayout(GlyphLayout const & src, @@ -224,6 +168,115 @@ namespace graphics recalcAlongPath(); } + void GlyphLayout::addGlyph(GlyphCache * glyphCache, + GlyphKey const & key, + bool isFirst, + strings::UniChar symbol, + m2::RectD & boundRect, + m2::PointD & curPt) + { + GlyphMetrics const m = glyphCache->getGlyphMetrics(key); + + m_textLength += m.m_xAdvance; + + if (isFirst) + { + boundRect = m2::RectD(m.m_xOffset, + -m.m_yOffset, + m.m_xOffset, + -m.m_yOffset); + + } + else + boundRect.Add(m2::PointD(m.m_xOffset + curPt.x, -m.m_yOffset + curPt.y)); + + boundRect.Add(m2::PointD(m.m_xOffset + m.m_width, + -(m.m_yOffset + m.m_height)) + curPt); + + GlyphLayoutElem elem; + elem.m_sym = symbol; + elem.m_angle = 0; + elem.m_pt = curPt; + m_entries.push_back(elem); + m_metrics.push_back(m); + + curPt += m2::PointD(m.m_xAdvance, m.m_yAdvance); + } + + void GlyphLayout::initStraigthText(GlyphCache * glyphCache, + FontDesc const & fontDesc, + m2::PointD const & pt, + strings::UniString const & visText, + graphics::EPosition pos, + unsigned maxWidth) + { + if (!m_fontDesc.IsValid()) + return; + + size_t const cnt = visText.size(); + ASSERT_GREATER(cnt, 0, ()); + + m_entries.reserve(cnt + 2); + m_metrics.reserve(cnt + 2); + + m2::RectD boundRect; + m2::PointD curPt(0, 0); + + bool isFirst = true; + + strings::UniChar dotSymbol = strings::MakeUniString(".")[0]; + GlyphKey dotKey(dotSymbol, + fontDesc.m_size, + false, + fontDesc.m_color); + maxWidth -= glyphCache->getGlyphMetrics(dotKey).m_xAdvance; + + for (size_t i = 0; i < visText.size(); ++i) + { + if (m_textLength >= maxWidth) + { + addGlyph(glyphCache, dotKey, isFirst, dotSymbol, boundRect, curPt); + addGlyph(glyphCache, dotKey, isFirst, dotSymbol, boundRect, curPt); + addGlyph(glyphCache, dotKey, isFirst, dotSymbol, boundRect, curPt); + m_lastVisible = i + 3; + break; + } + + GlyphKey glyphKey(visText[i], + fontDesc.m_size, + false, //< calculating glyph positions using unmasked glyphs. + fontDesc.m_color); + + addGlyph(glyphCache, glyphKey, isFirst, visText[i], boundRect, curPt); + isFirst = false; + } + + boundRect.Inflate(2, 2); + + m2::PointD ptOffs(-boundRect.SizeX() / 2 - boundRect.minX(), + -boundRect.SizeY() / 2 - boundRect.minY()); + + // adjusting according to position + if (pos & EPosLeft) + ptOffs += m2::PointD(-boundRect.SizeX() / 2, 0); + + if (pos & EPosRight) + ptOffs += m2::PointD(boundRect.SizeX() / 2, 0); + + if (pos & EPosAbove) + ptOffs += m2::PointD(0, -boundRect.SizeY() / 2); + + if (pos & EPosUnder) + ptOffs += m2::PointD(0, boundRect.SizeY() / 2); + + for (unsigned i = 0; i < m_entries.size(); ++i) + m_entries[i].m_pt += ptOffs; + + boundRect.Offset(ptOffs); + + m_boundRects.push_back(m2::AnyRectD(boundRect)); + } + void GlyphLayout::recalcAlongPath() { size_t const count = m_visText.size(); diff --git a/graphics/glyph_layout.hpp b/graphics/glyph_layout.hpp index aa48cc5331..356b93d27a 100644 --- a/graphics/glyph_layout.hpp +++ b/graphics/glyph_layout.hpp @@ -64,6 +64,20 @@ namespace graphics void recalcPivot(); void recalcAlongPath(); + inline void addGlyph(GlyphCache * glyphCache, + GlyphKey const & key, + bool isFirst, + strings::UniChar symbol, + m2::RectD & boundRect, + m2::PointD & curPt); + + void initStraigthText(GlyphCache * glyphCache, + FontDesc const & font, + m2::PointD const & pt, + strings::UniString const & visText, + graphics::EPosition pos, + unsigned maxWidth); + public: GlyphLayout(); @@ -77,6 +91,13 @@ namespace graphics strings::UniString const & visText, graphics::EPosition pos); + GlyphLayout(GlyphCache * glyphCache, + FontDesc const & font, + m2::PointD const & pt, + strings::UniString const & visText, + graphics::EPosition pos, + unsigned maxWidth); + GlyphLayout(GlyphCache * glyphCache, FontDesc const & font, m2::PointD const * pts, diff --git a/graphics/straight_text_element.cpp b/graphics/straight_text_element.cpp index 5afadd2ccb..5cab7fc41a 100644 --- a/graphics/straight_text_element.cpp +++ b/graphics/straight_text_element.cpp @@ -97,7 +97,7 @@ namespace graphics 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], graphics::EPosCenter)); + m_glyphLayouts.push_back(GlyphLayout(p.m_glyphCache, p.m_fontDesc, m2::PointD(0, 0), res[i], graphics::EPosCenter, p.m_maxPixelWidth)); m2::RectD r = m_glyphLayouts.back().boundRects().back().GetGlobalRect(); allElemWidth = max(r.SizeX(), allElemWidth); allElemHeight += r.SizeY(); @@ -168,6 +168,7 @@ namespace graphics m_maxWordsInRow(4), m_minSymInRow(10), m_maxSymInRow(20), + m_maxPixelWidth(numeric_limits::max()), m_doSplit(false), m_useAllParts(true), m_offset(0, 0) diff --git a/graphics/straight_text_element.hpp b/graphics/straight_text_element.hpp index 9d42c095fa..c9f5ee6792 100644 --- a/graphics/straight_text_element.hpp +++ b/graphics/straight_text_element.hpp @@ -20,6 +20,7 @@ namespace graphics unsigned m_maxWordsInRow; unsigned m_minSymInRow; unsigned m_maxSymInRow; + unsigned m_maxPixelWidth; bool m_doSplit; bool m_useAllParts; m2::PointD m_offset; diff --git a/gui/text_view.cpp b/gui/text_view.cpp index 5f2a692c05..328012bed6 100644 --- a/gui/text_view.cpp +++ b/gui/text_view.cpp @@ -8,7 +8,7 @@ namespace gui { TextView::TextView(Params const & p) - : Element(p) + : Element(p), m_maxWidth(numeric_limits::max()) { setText(p.m_text); @@ -50,6 +50,7 @@ namespace gui params.m_doSplit = true; params.m_delimiters = "\n"; params.m_useAllParts = true; + params.m_maxPixelWidth = m_maxWidth; elem.reset(new graphics::StraightTextElement(params)); } @@ -136,6 +137,12 @@ namespace gui return m_boundRects; } + void TextView::setMaxWidth(unsigned width) + { + m_maxWidth = width; + setIsDirtyLayout(true); + } + bool TextView::onTapStarted(m2::PointD const & pt) { return false; diff --git a/gui/text_view.hpp b/gui/text_view.hpp index a485722ec0..7702d6b105 100644 --- a/gui/text_view.hpp +++ b/gui/text_view.hpp @@ -20,6 +20,7 @@ namespace gui map > m_elems; string m_text; + unsigned m_maxWidth; mutable vector m_boundRects; @@ -41,6 +42,7 @@ namespace gui void setText(string const & text); string const & text() const; + void setMaxWidth(unsigned width); vector const & boundRects() const; void draw(graphics::OverlayRenderer * r, math::Matrix const & m) const;