From d923e9eeddd63d34ae3de2c6f00b02d4e6179fc3 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 7 Dec 2015 15:44:46 -1000 Subject: [PATCH] Better tooltip rendering; floating-point pixel factor --- specter/include/Specter/TextView.hpp | 3 + specter/include/Specter/ViewResources.hpp | 4 +- specter/lib/Button.cpp | 4 +- specter/lib/TextView.cpp | 16 +++++ specter/lib/Tooltip.cpp | 64 +++++++++--------- specter/lib/ViewResources.cpp | 12 ++-- .../resources/fonts/SpecterCurveGlyphs.ttf.gz | Bin 1142 -> 1141 bytes 7 files changed, 62 insertions(+), 41 deletions(-) diff --git a/specter/include/Specter/TextView.hpp b/specter/include/Specter/TextView.hpp index 502f2e03b..03b77be7b 100644 --- a/specter/include/Specter/TextView.hpp +++ b/specter/include/Specter/TextView.hpp @@ -74,8 +74,11 @@ public: int nominalWidth() const {return m_width;} int nominalHeight() const {return m_fontAtlas.FT_LineHeight() >> 6;} + std::pair queryGlyphDimensions(size_t pos) const; + private: std::vector m_glyphs; + std::vector> m_glyphDims; }; } diff --git a/specter/include/Specter/ViewResources.hpp b/specter/include/Specter/ViewResources.hpp index 35d374e4e..08a87784b 100644 --- a/specter/include/Specter/ViewResources.hpp +++ b/specter/include/Specter/ViewResources.hpp @@ -74,8 +74,8 @@ public: ViewResources& operator=(const ViewResources& other) = delete; ViewResources& operator=(ViewResources&& other) = default; - void init(boo::IGraphicsDataFactory* factory, FontCache* fcache, const ThemeData& theme, unsigned dpi); - void resetDPI(unsigned dpi); + void init(boo::IGraphicsDataFactory* factory, FontCache* fcache, const ThemeData& theme, float pixelFactor); + void resetPixelFactor(float pixelFactor); void resetTheme(const ThemeData& theme); void resetLanguage(const ThemeData& theme); diff --git a/specter/lib/Button.cpp b/specter/lib/Button.cpp index 0b6cef0e8..c72e34c6e 100644 --- a/specter/lib/Button.cpp +++ b/specter/lib/Button.cpp @@ -49,7 +49,7 @@ void Button::setText(const std::string& text) m_textStr = text; m_text->typesetGlyphs(text, rootView().themeData().uiText()); - float pf = rootView().window()->getVirtualPixelFactor(); + float pf = rootView().viewRes().pixelFactor(); float width = m_text->nominalWidth() + 10 * pf; float height = 20 * pf; m_verts[0].m_pos.assign(1, height+1, 0); @@ -186,7 +186,7 @@ void Button::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) boo::SWindowRect textRect = sub; m_bBlock.setViewRect(root, sub); m_bBlockBuf->load(&m_bBlock, sizeof(ViewBlock)); - float pf = rootView().window()->getVirtualPixelFactor(); + float pf = rootView().viewRes().pixelFactor(); textRect.location[0] += 5 * pf; textRect.location[1] += 8 * pf; m_text->resized(root, textRect); diff --git a/specter/lib/TextView.cpp b/specter/lib/TextView.cpp index 3cd85a7a6..66cc14aa8 100644 --- a/specter/lib/TextView.cpp +++ b/specter/lib/TextView.cpp @@ -352,6 +352,8 @@ void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& default uint32_t lCh = -1; m_glyphs.clear(); m_glyphs.reserve(str.size()); + m_glyphDims.clear(); + m_glyphDims.reserve(str.size()); int adv = 0; while (rem) @@ -374,6 +376,7 @@ void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& default if (lCh != -1) adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas); m_glyphs.emplace_back(adv, *glyph, defaultColor); + m_glyphDims.emplace_back(glyph->m_width, glyph->m_height); lCh = glyph->m_glyphIdx; rem -= sz; @@ -393,6 +396,8 @@ void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaul uint32_t lCh = -1; m_glyphs.clear(); m_glyphs.reserve(str.size()); + m_glyphDims.clear(); + m_glyphDims.reserve(str.size()); int adv = 0; for (wchar_t ch : str) @@ -407,6 +412,7 @@ void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaul if (lCh != -1) adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas); m_glyphs.emplace_back(adv, *glyph, defaultColor); + m_glyphDims.emplace_back(glyph->m_width, glyph->m_height); lCh = glyph->m_glyphIdx; @@ -453,5 +459,15 @@ void TextView::draw(boo::IGraphicsCommandQueue* gfxQ) } } +std::pair TextView::queryGlyphDimensions(size_t pos) const +{ + if (pos >= m_glyphDims.size()) + Log.report(LogVisor::FatalError, + "TextView::queryGlyphWidth(%" PRISize ") out of bounds: %" PRISize, + pos, m_glyphDims.size()); + + return m_glyphDims[pos]; +} + } diff --git a/specter/lib/Tooltip.cpp b/specter/lib/Tooltip.cpp index 29617fbd8..648954b0c 100644 --- a/specter/lib/Tooltip.cpp +++ b/specter/lib/Tooltip.cpp @@ -7,7 +7,6 @@ namespace Specter #define TOOLTIP_MAX_WIDTH 316 #define TOOLTIP_MAX_TEXT_WIDTH 300 -#define TOOLTIP_MARGIN 8 Tooltip::Tooltip(ViewResources& res, View& parentView, const std::string& title, const std::string& message) @@ -45,32 +44,30 @@ Tooltip::Tooltip(ViewResources& res, View& parentView, const std::string& title, resetResources(res); } -#define EDGE_EPSILON 0.25 - void Tooltip::setVerts(int width, int height, float pf) { - int margin = TOOLTIP_MARGIN * pf; - width = std::max(width, margin*2); - height = std::max(height, margin*2); + std::pair margin = m_cornersFilled[0]->queryGlyphDimensions(0); + width = std::max(width, margin.first*2); + height = std::max(height, margin.second*2); - m_ttVerts[0].m_pos.assign(0, height-margin-EDGE_EPSILON, 0); - m_ttVerts[1].m_pos.assign(0, margin+EDGE_EPSILON, 0); - m_ttVerts[2].m_pos.assign(width, height-margin-EDGE_EPSILON, 0); - m_ttVerts[3].m_pos.assign(width, margin+EDGE_EPSILON, 0); - m_ttVerts[4].m_pos.assign(width, margin+EDGE_EPSILON, 0); + m_ttVerts[0].m_pos.assign(0, height-margin.second, 0); + m_ttVerts[1].m_pos.assign(0, margin.second, 0); + m_ttVerts[2].m_pos.assign(width, height-margin.second, 0); + m_ttVerts[3].m_pos.assign(width, margin.second, 0); + m_ttVerts[4].m_pos.assign(width, margin.second, 0); - m_ttVerts[5].m_pos.assign(margin+EDGE_EPSILON, height, 0); - m_ttVerts[6].m_pos.assign(margin+EDGE_EPSILON, height, 0); - m_ttVerts[7].m_pos.assign(margin+EDGE_EPSILON, height-margin+EDGE_EPSILON, 0); - m_ttVerts[8].m_pos.assign(width-margin-EDGE_EPSILON, height, 0); - m_ttVerts[9].m_pos.assign(width-margin-EDGE_EPSILON, height-margin+EDGE_EPSILON, 0); - m_ttVerts[10].m_pos.assign(width-margin-EDGE_EPSILON, height-margin+EDGE_EPSILON, 0); + m_ttVerts[5].m_pos.assign(margin.first, height, 0); + m_ttVerts[6].m_pos.assign(margin.first, height, 0); + m_ttVerts[7].m_pos.assign(margin.first, height-margin.second, 0); + m_ttVerts[8].m_pos.assign(width-margin.first, height, 0); + m_ttVerts[9].m_pos.assign(width-margin.first, height-margin.second, 0); + m_ttVerts[10].m_pos.assign(width-margin.first, height-margin.second, 0); - m_ttVerts[11].m_pos.assign(margin+EDGE_EPSILON, margin-EDGE_EPSILON, 0); - m_ttVerts[12].m_pos.assign(margin+EDGE_EPSILON, margin-EDGE_EPSILON, 0); - m_ttVerts[13].m_pos.assign(margin+EDGE_EPSILON, 0, 0); - m_ttVerts[14].m_pos.assign(width-margin-EDGE_EPSILON, margin-EDGE_EPSILON, 0); - m_ttVerts[15].m_pos.assign(width-margin-EDGE_EPSILON, 0, 0); + m_ttVerts[11].m_pos.assign(margin.first, margin.second, 0); + m_ttVerts[12].m_pos.assign(margin.first, margin.second, 0); + m_ttVerts[13].m_pos.assign(margin.first, 0, 0); + m_ttVerts[14].m_pos.assign(width-margin.first, margin.second, 0); + m_ttVerts[15].m_pos.assign(width-margin.first, 0, 0); m_ttVertsBuf->load(m_ttVerts, sizeof(SolidShaderVert) * 16); } @@ -83,25 +80,27 @@ void Tooltip::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) m_ttBlock.setViewRect(root, sub); m_ttBlockBuf->load(&m_ttBlock, sizeof(ViewBlock)); + std::pair margin = m_cornersFilled[0]->queryGlyphDimensions(0); + boo::SWindowRect textRect = sub; - textRect.location[0] += TOOLTIP_MARGIN * pf; - textRect.location[1] += TOOLTIP_MARGIN * 1.5 * pf; + textRect.location[0] += margin.first; + textRect.location[1] += margin.second * 1.5; m_message->resized(root, textRect); - textRect.location[1] += m_message->nominalHeight() + TOOLTIP_MARGIN * pf; + textRect.location[1] += m_message->nominalHeight() + margin.second; m_title->resized(root, textRect); boo::SWindowRect cornerRect = sub; - cornerRect.location[1] += m_nomHeight - TOOLTIP_MARGIN * pf; + cornerRect.location[1] += m_nomHeight - margin.second; // Upper left m_cornersOutline[0]->resized(root, cornerRect); m_cornersFilled[0]->resized(root, cornerRect); - cornerRect.location[0] += m_nomWidth - TOOLTIP_MARGIN * pf; + cornerRect.location[0] += m_nomWidth - margin.first; // Upper right m_cornersOutline[1]->resized(root, cornerRect); m_cornersFilled[1]->resized(root, cornerRect); - cornerRect.location[1] = sub.location[1]; + cornerRect.location[1] = sub.location[1]; // Lower right m_cornersOutline[2]->resized(root, cornerRect); m_cornersFilled[2]->resized(root, cornerRect); - cornerRect.location[0] = sub.location[0]; + cornerRect.location[0] = sub.location[0]; // Lower left m_cornersOutline[3]->resized(root, cornerRect); m_cornersFilled[3]->resized(root, cornerRect); } @@ -126,12 +125,13 @@ void Tooltip::resetResources(ViewResources& res) m_title->typesetGlyphs(m_titleStr); m_message.reset(new MultiLineTextView(res, *this, res.m_mainFont)); m_message->typesetGlyphs(m_messageStr, Zeus::CColor::skWhite, - int(TOOLTIP_MAX_TEXT_WIDTH * rootView().viewRes().pixelFactor())); + int(TOOLTIP_MAX_TEXT_WIDTH * res.pixelFactor())); float pf = res.pixelFactor(); + std::pair margin = m_cornersOutline[0]->queryGlyphDimensions(0); m_nomWidth = std::min(int(TOOLTIP_MAX_WIDTH * pf), - int(std::max(m_title->nominalWidth(), m_message->nominalWidth()) + TOOLTIP_MARGIN * 2 * pf)); - m_nomHeight = m_title->nominalHeight() + m_message->nominalHeight() + TOOLTIP_MARGIN * 3 * pf; + int(std::max(m_title->nominalWidth(), m_message->nominalWidth()) + margin.first * 2)); + m_nomHeight = m_title->nominalHeight() + m_message->nominalHeight() + margin.second * 3; } void Tooltip::draw(boo::IGraphicsCommandQueue* gfxQ) diff --git a/specter/lib/ViewResources.cpp b/specter/lib/ViewResources.cpp index 9f5d9f8a5..6b81aa76f 100644 --- a/specter/lib/ViewResources.cpp +++ b/specter/lib/ViewResources.cpp @@ -5,9 +5,10 @@ namespace Specter static LogVisor::LogModule Log("Specter::ViewResources"); void ViewResources::init(boo::IGraphicsDataFactory* factory, FontCache* fcache, - const ThemeData& theme, unsigned dpi) + const ThemeData& theme, float pf) { - m_pixelFactor = dpi / 72.f; + m_pixelFactor = pf; + unsigned dpi = 72.f * pf; m_theme = theme; m_factory = factory; m_fcache = fcache; @@ -15,7 +16,7 @@ void ViewResources::init(boo::IGraphicsDataFactory* factory, FontCache* fcache, m_monoFont = fcache->prepMonoFont(factory, AllCharFilter, false, 10.f, dpi); m_heading14 = fcache->prepMainFont(factory, LatinAndJapaneseCharFilter, false, 14.f, dpi); m_heading18 = fcache->prepMainFont(factory, LatinAndJapaneseCharFilter, false, 18.f, dpi); - m_curveFont = fcache->prepCurvesFont(factory, AllCharFilter, false, 11.f, dpi); + m_curveFont = fcache->prepCurvesFont(factory, AllCharFilter, false, 8.f, dpi); m_fontData = factory->commit(); switch (factory->platform()) { @@ -39,9 +40,10 @@ void ViewResources::init(boo::IGraphicsDataFactory* factory, FontCache* fcache, m_resData = factory->commit(); } -void ViewResources::resetDPI(unsigned dpi) +void ViewResources::resetPixelFactor(float pf) { - m_pixelFactor = dpi / 72.f; + m_pixelFactor = pf; + unsigned dpi = 72.f * pf; m_mainFont = m_fcache->prepMainFont(m_factory, AllCharFilter, false, 10.f, dpi); m_monoFont = m_fcache->prepMonoFont(m_factory, AllCharFilter, false, 10.f, dpi); m_heading14 = m_fcache->prepMainFont(m_factory, LatinAndJapaneseCharFilter, false, 14.f, dpi); diff --git a/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz b/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz index 6b759057080620c8591214075a33360744ded170..e9d3a7c913c0fd016427bc3f9ecf587c6eb74b5d 100644 GIT binary patch delta 1128 zcmV-u1eg2v2=xdDABzYGb2Mg=2OfVMRTTctotd4DiETEPidtm0rr2n*nQS(VjVY9N zyAib-nzj_QnsqbTO|!|a`;#_`RtgfdFMSYfUmAT7MN4ZU*eDo85PeXzRq&{?wsH6oO93pSrC9*@e&mDCK7vhAKvxB%Rn&3+6{k?_q9e- z#qu$L4zS#x8cF7_F5dPv%a?dQoEj?`h-)E0+01q|oh;^Emm?wA%yKZD9UnZ`f3LJZ z#Qs+^R&t=OWBre8V?4HGSW$nzW|D2|SZ>UWl#blqia5(NEN{%_Qc2;6GmMw^#%OZH$~_o54`_cTAdcp9#nL-}J^K`(zt8sPAlJro&BR^1pI+Pj8)}1) zb`tGlvZ2vi119n+bbQx&@xY5CARO&$L#7~!F$ZaX5LMy(m96YK}AUE?Tp zcZDiHU{EwjfTmoJChC`k?j77U!297Y{1F&*1~KDRf)y1QATcld#L$0tW#K@j(i?{2 z&ka64&JuaD3b|(iro_c?Hdp3x7k+VFSFK&Ql#c>S$w~NYT|QR#=6^Jle|M=4@0_FA z|2>Ll@FGs&3_itWEI@XJ_d^V5`#7kM$P}Tqdstag}dcrMun8qs~!EXqoZCdDVr9j^KYJ>ME& z6Q@BqWDujBMrW(D)gD$xM6cKp6i4X-eMjHh=j_>)IW(E0g1LW2iX{$+9lC43&2CFR z9Gj}4Lu{S4Pc42ZUZXGR3*B8jZO__o(Pa*QLA-is4dMYPj4bEOa z^LHTT^MnSJd|rR>33%P-6@CwFpI6a9dwgC)Jx%z0fc3NTW~$s9L_L(`35|Hn=LP4T z@OcGKV$$bTG*YwAYcR<2`2g!rVkdIQV;ltxA&m@IXz;yHp^0e}Cfd-!r`fppvWzjt1&pgtRUi1xf1NR z3dNz^s9{)|Z4uKnjho0-eSO{7KfF_Q-dPm*m;@=Ll12g2`Ms#o%cDbySiWMapT!(pCdJc0>!G$!j$@>~nsZHaW@=+170*e#Mk0A#&@!P zUpjI$i(x#%^AEAD&qUI(^uvGd4*=N;h!?Y&eBsQW&pr*f-s1V^p?c%@^W)c!AGxdl zH#F2ijf=+?O53F@%XL*R1gyar(^IN{!!bB6Y7 z&S(=^#ir56G(^KRW(*laxTz+S+rn&iSNi)6eU;Pn zB|UcPZMklITKTqY4AB@3FVU$VxAU(-+rrA#s~ZX?*No39-!Xt^t+=w4!=uv!!tH5k z-pQSoE3X?*T)s-lGpA{gu2Au^*hT*DjqxSpY>odCw++TX&+3I&ED-r_344WRS%?a!4YM1Xrl@9gm`eWdJ_-(Z?rO#}p#$ zo#to^WU}+QWIR#O_e4ANfY0C8sZT|s(>yi8TrrL-@Hcy)U^X`w+n<`xCfIj?gW?>X;xsunWAWKkgq1KSoMAd8a~u&f%kpwzI`;DWUlLl8 zL3D950shw7LO3&12xoHfm>%%@^u7A6g|Rc(