diff --git a/specter/CMakeLists.txt b/specter/CMakeLists.txt index 5e5631e1e..f9455427c 100644 --- a/specter/CMakeLists.txt +++ b/specter/CMakeLists.txt @@ -35,6 +35,7 @@ list(APPEND SPECTER_HEADERS include/Specter/DeferredWindowEvents.hpp include/Specter/View.hpp include/Specter/RootView.hpp + include/Specter/Tooltip.hpp include/Specter/SplitView.hpp include/Specter/ScrollView.hpp include/Specter/TextView.hpp @@ -61,6 +62,7 @@ list(APPEND SPECTER_SOURCES lib/ViewResources.cpp lib/View.cpp lib/RootView.cpp + lib/Tooltip.cpp lib/SplitView.cpp lib/ScrollView.cpp lib/TextView.cpp diff --git a/specter/include/Specter/FontCache.hpp b/specter/include/Specter/FontCache.hpp index 2f6ac8fa6..44db21570 100644 --- a/specter/include/Specter/FontCache.hpp +++ b/specter/include/Specter/FontCache.hpp @@ -174,6 +174,7 @@ class FontCache } m_fontLib; FreeTypeGZipMemFace m_regFace; FreeTypeGZipMemFace m_monoFace; + FreeTypeGZipMemFace m_curvesFace; std::unordered_map> m_cachedAtlases; public: @@ -193,7 +194,11 @@ public: bool subpixel=false, float points=10.0, uint32_t dpi=72) {return prepCustomFont(gf, "bmonofont", m_monoFace, filter, subpixel, points, dpi);} - void closeBuiltinFonts() {m_regFace.close(); m_monoFace.close();} + FontTag prepCurvesFont(boo::IGraphicsDataFactory* gf, FCharFilter filter=AllCharFilter, + bool subpixel=false, float points=10.0, uint32_t dpi=72) + {return prepCustomFont(gf, "spectercurves", m_curvesFace, filter, subpixel, points, dpi);} + + void closeBuiltinFonts() {m_regFace.close(); m_monoFace.close(); m_curvesFace.close();} const FontAtlas& lookupAtlas(FontTag tag) const; }; diff --git a/specter/include/Specter/MultiLineTextView.hpp b/specter/include/Specter/MultiLineTextView.hpp index 760eaf9dc..d46548cfb 100644 --- a/specter/include/Specter/MultiLineTextView.hpp +++ b/specter/include/Specter/MultiLineTextView.hpp @@ -15,17 +15,25 @@ class MultiLineTextView : public View const FontAtlas& m_fontAtlas; size_t m_lineCapacity; float m_lineHeight; + int m_width; + std::string LineWrap(const std::string& str, int wrap); + std::wstring LineWrap(const std::wstring& str, int wrap); public: MultiLineTextView(ViewResources& res, View& parentView, const FontAtlas& font, size_t lineCapacity=256, float lineHeight=1.0); MultiLineTextView(ViewResources& res, View& parentView, FontTag font, size_t lineCapacity=256, float lineHeight=1.0); void typesetGlyphs(const std::string& str, - const Zeus::CColor& defaultColor=Zeus::CColor::skWhite); + const Zeus::CColor& defaultColor=Zeus::CColor::skWhite, + unsigned wrap=0); void typesetGlyphs(const std::wstring& str, - const Zeus::CColor& defaultColor=Zeus::CColor::skWhite); + const Zeus::CColor& defaultColor=Zeus::CColor::skWhite, + unsigned wrap=0); - void resized(const boo::SWindowRect& rootView, const boo::SWindowRect& sub); + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); void draw(boo::IGraphicsCommandQueue* gfxQ); + + int nominalWidth() const {return m_width;} + int nominalHeight() const {return (int(m_lineHeight * m_fontAtlas.FT_LineHeight()) >> 6) * m_lines.size();} }; } diff --git a/specter/include/Specter/RootView.hpp b/specter/include/Specter/RootView.hpp index 84e259192..b5d274056 100644 --- a/specter/include/Specter/RootView.hpp +++ b/specter/include/Specter/RootView.hpp @@ -5,6 +5,7 @@ #include "ViewResources.hpp" #include "MultiLineTextView.hpp" #include "SplitView.hpp" +#include "Tooltip.hpp" #include "FontCache.hpp" #include "DeferredWindowEvents.hpp" #include @@ -69,6 +70,7 @@ public: private: std::unique_ptr m_view; + std::unique_ptr m_tooltip; }; } diff --git a/specter/include/Specter/TextView.hpp b/specter/include/Specter/TextView.hpp index aac8c4afd..502f2e03b 100644 --- a/specter/include/Specter/TextView.hpp +++ b/specter/include/Specter/TextView.hpp @@ -22,6 +22,9 @@ class TextView : public View bool m_valid = false; int m_width = 0; + friend class MultiLineTextView; + static int DoKern(FT_Pos val, const FontAtlas& atlas); + public: class Resources { diff --git a/specter/include/Specter/Toolbar.hpp b/specter/include/Specter/Toolbar.hpp index b1fc1cf24..cf581f0bd 100644 --- a/specter/include/Specter/Toolbar.hpp +++ b/specter/include/Specter/Toolbar.hpp @@ -2,7 +2,6 @@ #define SPECTER_TOOLBAR_HPP #include "Specter/View.hpp" -#include namespace Specter { diff --git a/specter/include/Specter/Tooltip.hpp b/specter/include/Specter/Tooltip.hpp new file mode 100644 index 000000000..3f4ec25e1 --- /dev/null +++ b/specter/include/Specter/Tooltip.hpp @@ -0,0 +1,44 @@ +#ifndef SPECTER_TOOLTIP_HPP +#define SPECTER_TOOLTIP_HPP + +#include "Specter/View.hpp" +#include "Specter/MultiLineTextView.hpp" + +namespace Specter +{ + +class Tooltip : public View +{ + ViewBlock m_ttBlock; + boo::IGraphicsBufferD* m_ttBlockBuf; + SolidShaderVert m_ttVerts[16]; + int m_nomWidth = 25; + int m_nomHeight = 25; + + void setVerts(int width, int height, float pf); + + boo::IGraphicsBufferD* m_ttVertsBuf; + boo::IVertexFormat* m_ttVtxFmt; /* OpenGL only */ + boo::IShaderDataBinding* m_ttShaderBinding; + + std::string m_titleStr; + std::unique_ptr m_title; + std::string m_messageStr; + std::unique_ptr m_message; + + std::unique_ptr m_cornersOutline[4]; + std::unique_ptr m_cornersFilled[4]; +public: + Tooltip(ViewResources& res, View& parentView, const std::string& title, + const std::string& message); + void resized(const boo::SWindowRect& rootView, const boo::SWindowRect& sub); + void resetResources(ViewResources& res); + void draw(boo::IGraphicsCommandQueue* gfxQ); + + int nominalWidth() const {return m_nomWidth;} + int nominalHeight() const {return m_nomHeight;} +}; + +} + +#endif // SPECTER_TOOLTIP_HPP diff --git a/specter/include/Specter/View.hpp b/specter/include/Specter/View.hpp index 7986cc4b1..0272527b3 100644 --- a/specter/include/Specter/View.hpp +++ b/specter/include/Specter/View.hpp @@ -124,7 +124,7 @@ public: virtual void mouseMove(const boo::SWindowCoord&) {} virtual void mouseEnter(const boo::SWindowCoord&) {} virtual void mouseLeave(const boo::SWindowCoord&) {} - virtual void resized(const boo::SWindowRect &rootView, const boo::SWindowRect& sub); + virtual void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); virtual void resetResources(ViewResources& res) {} virtual void draw(boo::IGraphicsCommandQueue* gfxQ); }; diff --git a/specter/include/Specter/ViewResources.hpp b/specter/include/Specter/ViewResources.hpp index 8acafa9b6..f21aa88fd 100644 --- a/specter/include/Specter/ViewResources.hpp +++ b/specter/include/Specter/ViewResources.hpp @@ -21,6 +21,7 @@ class ThemeData Zeus::CColor m_button2Press = {0.2823, 0.2823, 0.2823, 1.0}; Zeus::CColor m_button1Disabled = {0.2823, 0.2823, 0.2823, 0.5}; Zeus::CColor m_button2Disabled = {0.1725, 0.1725, 0.1725, 0.5}; + Zeus::CColor m_tooltipBg = {0.0, 0.0, 0.0, 0.5}; public: virtual const Zeus::CColor& viewportBackground() const {return m_vpBg;} virtual const Zeus::CColor& toolbarBackground() const {return m_tbBg;} @@ -33,6 +34,7 @@ public: virtual const Zeus::CColor& button2Press() const {return m_button2Press;} virtual const Zeus::CColor& button1Disabled() const {return m_button1Disabled;} virtual const Zeus::CColor& button2Disabled() const {return m_button2Disabled;} + virtual const Zeus::CColor& tooltipBackground() const {return m_tooltipBg;} }; class ViewResources @@ -64,6 +66,8 @@ public: Specter::FontTag m_heading14; Specter::FontTag m_heading18; + Specter::FontTag m_curveFont; + ViewResources() = default; ViewResources(const ViewResources& other) = delete; ViewResources(ViewResources&& other) = default; diff --git a/specter/lib/FontCache.cpp b/specter/lib/FontCache.cpp index f24674adc..b37a32c92 100644 --- a/specter/lib/FontCache.cpp +++ b/specter/lib/FontCache.cpp @@ -21,6 +21,9 @@ extern "C" size_t DROIDSANS_PERMISSIVE_SZ; extern "C" const uint8_t BMONOFONT[]; extern "C" size_t BMONOFONT_SZ; +extern "C" const uint8_t SPECTERCURVES[]; +extern "C" size_t SPECTERCURVES_SZ; + extern "C" const FT_Driver_ClassRec tt_driver_class; namespace Specter @@ -284,6 +287,8 @@ FontAtlas::FontAtlas(boo::IGraphicsDataFactory* gf, FT_Face face, uint32_t dpi, curLineWidth += width + 1; charcode = FT_Get_Next_Char(face, charcode, &gindex); } + if (curLineHeight) + totalHeight += curLineHeight + 1; m_glyphs.reserve(glyphCount); m_glyphLookup.reserve(glyphCount); @@ -672,7 +677,8 @@ FontCache::FontCache(const HECL::Runtime::FileStoreManager& fileMgr) : m_fileMgr(fileMgr), m_cacheRoot(m_fileMgr.getStoreRoot() + _S("/fontcache")), m_regFace(m_fontLib, DROIDSANS_PERMISSIVE, DROIDSANS_PERMISSIVE_SZ), - m_monoFace(m_fontLib, BMONOFONT, BMONOFONT_SZ) + m_monoFace(m_fontLib, BMONOFONT, BMONOFONT_SZ), + m_curvesFace(m_fontLib, SPECTERCURVES, SPECTERCURVES_SZ) {HECL::MakeDir(m_cacheRoot.c_str());} FontTag FontCache::prepCustomFont(boo::IGraphicsDataFactory* gf, const std::string& name, FT_Face face, diff --git a/specter/lib/MultiLineTextView.cpp b/specter/lib/MultiLineTextView.cpp index 23f834782..40ae51f74 100644 --- a/specter/lib/MultiLineTextView.cpp +++ b/specter/lib/MultiLineTextView.cpp @@ -5,6 +5,127 @@ namespace Specter { static LogVisor::LogModule Log("Specter::MultiLineTextView"); +std::string MultiLineTextView::LineWrap(const std::string& str, int wrap) +{ + size_t rem = str.size(); + const utf8proc_uint8_t* it = reinterpret_cast(str.data()); + uint32_t lCh = -1; + int adv = 0; + + std::string ret; + ret.reserve(str.size()); + size_t lastSpaceRem; + const utf8proc_uint8_t* lastSpaceIt = nullptr; + size_t rollbackPos; + while (rem) + { + utf8proc_int32_t ch; + utf8proc_ssize_t sz = utf8proc_iterate(it, -1, &ch); + if (sz < 0) + Log.report(LogVisor::FatalError, "invalid UTF-8 char"); + if (ch == '\n') + { + ret += '\n'; + lCh = -1; + rem -= sz; + it += sz; + lastSpaceIt = nullptr; + adv = 0; + continue; + } + + const FontAtlas::Glyph* glyph = m_fontAtlas.lookupGlyph(ch); + if (!glyph) + { + rem -= sz; + it += sz; + continue; + } + + if (lCh != -1) + adv += TextView::DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas); + adv += glyph->m_advance; + + if (adv > wrap && lastSpaceIt) + { + ret.assign(ret.cbegin(), ret.cbegin() + rollbackPos); + ret += '\n'; + lCh = -1; + rem = lastSpaceRem; + it = lastSpaceIt; + lastSpaceIt = nullptr; + adv = 0; + continue; + } + + if (sz == 1 && (it[0] == ' ' || it[0] == '-')) + { + lastSpaceIt = it + 1; + lastSpaceRem = rem - 1; + rollbackPos = ret.size() + 1; + } + for (size_t i=0 ; im_glyphIdx; + rem -= sz; + it += sz; + } + + return ret; +} + +std::wstring MultiLineTextView::LineWrap(const std::wstring& str, int wrap) +{ + uint32_t lCh = -1; + int adv = 0; + + std::wstring ret; + ret.reserve(str.size()); + std::wstring::const_iterator lastSpaceIt = str.cend(); + size_t rollbackPos; + for (std::wstring::const_iterator it = str.cbegin() ; it != str.cend() ; ++it) + { + wchar_t ch = *it; + if (ch == L'\n') + { + ret += L'\n'; + lCh = -1; + lastSpaceIt = str.cend(); + adv = 0; + continue; + } + + const FontAtlas::Glyph* glyph = m_fontAtlas.lookupGlyph(ch); + if (!glyph) + continue; + + if (lCh != -1) + adv += TextView::DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas); + adv += glyph->m_advance; + + if (adv > wrap && lastSpaceIt != str.cend()) + { + ret.assign(ret.cbegin(), ret.cbegin() + rollbackPos); + ret += L'\n'; + lCh = -1; + it = lastSpaceIt; + lastSpaceIt = str.cend(); + adv = 0; + continue; + } + + if (ch == L' ' || ch == L'-') + { + lastSpaceIt = it + 1; + rollbackPos = ret.size() + 1; + } + ret += ch; + lCh = glyph->m_glyphIdx; + } + + return ret; +} + MultiLineTextView::MultiLineTextView(ViewResources& res, View& parentView, const FontAtlas& font, @@ -31,8 +152,16 @@ MultiLineTextView::MultiLineTextView(ViewResources& res, lineHeight) {} void MultiLineTextView::typesetGlyphs(const std::string& str, - const Zeus::CColor& defaultColor) + const Zeus::CColor& defaultColor, + unsigned wrap) { + if (wrap) + { + typesetGlyphs(LineWrap(str, wrap), defaultColor); + return; + } + + m_width = 0; m_lines.clear(); size_t rem = str.size() + 1; const utf8proc_uint8_t* it = reinterpret_cast(str.data()); @@ -63,6 +192,7 @@ void MultiLineTextView::typesetGlyphs(const std::string& str, { m_lines.emplace_back(new TextView(m_viewSystem, *this, m_fontAtlas, m_lineCapacity)); m_lines.back()->typesetGlyphs(std::string((char*)beginIt, it - beginIt), defaultColor); + m_width = std::max(m_width, m_lines.back()->nominalWidth()); beginIt = it + 1; } rem -= sz; @@ -73,8 +203,16 @@ void MultiLineTextView::typesetGlyphs(const std::string& str, } void MultiLineTextView::typesetGlyphs(const std::wstring& str, - const Zeus::CColor& defaultColor) + const Zeus::CColor& defaultColor, + unsigned wrap) { + if (wrap) + { + typesetGlyphs(LineWrap(str, wrap), defaultColor); + return; + } + + m_width = 0; m_lines.clear(); size_t rem = str.size() + 1; auto it = str.cbegin(); @@ -99,6 +237,7 @@ void MultiLineTextView::typesetGlyphs(const std::wstring& str, { m_lines.emplace_back(new TextView(m_viewSystem, *this, m_fontAtlas, m_lineCapacity)); m_lines.back()->typesetGlyphs(std::wstring(beginIt, it), defaultColor); + m_width = std::max(m_width, m_lines.back()->nominalWidth()); beginIt = it + 1; } --rem; diff --git a/specter/lib/RootView.cpp b/specter/lib/RootView.cpp index bb62a9caa..a09ffd37e 100644 --- a/specter/lib/RootView.cpp +++ b/specter/lib/RootView.cpp @@ -14,6 +14,8 @@ RootView::RootView(IViewManager& viewMan, ViewResources& res, boo::IWindow* wind m_renderTex = res.m_factory->newRenderTexture(rect.size[0], rect.size[1], 1); commitResources(res); resized(rect, rect); + + m_tooltip.reset(new Tooltip(res, *this, "Test", "Testing")); } void RootView::destroyed() @@ -30,6 +32,8 @@ void RootView::resized(const boo::SWindowRect& root, const boo::SWindowRect&) View::resized(m_rootRect, m_rootRect); if (m_view) m_view->resized(m_rootRect, m_rootRect); + if (m_tooltip) + m_tooltip->resized(m_rootRect, m_rootRect); if (old != m_rootRect) m_resizeRTDirty = true; } @@ -50,6 +54,18 @@ void RootView::mouseMove(const boo::SWindowCoord& coord) { if (m_view) m_view->mouseMove(coord); + + boo::SWindowRect ttrect = m_rootRect; + ttrect.location[0] = coord.pixel[0]; + ttrect.location[1] = coord.pixel[1]; + if (m_tooltip) + { + if (coord.pixel[0] + m_tooltip->nominalWidth() > m_rootRect.size[0]) + ttrect.location[0] -= m_tooltip->nominalWidth(); + if (coord.pixel[1] + m_tooltip->nominalHeight() > m_rootRect.size[1]) + ttrect.location[1] -= m_tooltip->nominalHeight(); + m_tooltip->resized(m_rootRect, ttrect); + } } void RootView::mouseEnter(const boo::SWindowCoord& coord) @@ -111,6 +127,8 @@ void RootView::resetResources(ViewResources& res) m_viewRes = &res; if (m_view) m_view->resetResources(res); + if (m_tooltip) + m_tooltip->resetResources(res); } void RootView::setContentView(std::unique_ptr&& view) @@ -136,6 +154,8 @@ void RootView::draw(boo::IGraphicsCommandQueue* gfxQ) View::draw(gfxQ); if (m_view) m_view->draw(gfxQ); + if (m_tooltip) + m_tooltip->draw(gfxQ); gfxQ->resolveDisplay(m_renderTex); } diff --git a/specter/lib/TextView.cpp b/specter/lib/TextView.cpp index 4c9ac5679..3cd85a7a6 100644 --- a/specter/lib/TextView.cpp +++ b/specter/lib/TextView.cpp @@ -46,7 +46,7 @@ void TextView::Resources::init(boo::GLDataFactory* factory, FontCache* fcache) "void main()\n" "{\n" " colorOut = vtf.color;\n" - " colorOut.a = texture(fontTex, vtf.uv).r;\n" + " colorOut.a *= texture(fontTex, vtf.uv).r;\n" "}\n"; static const char* FSSubpixel = @@ -63,7 +63,7 @@ void TextView::Resources::init(boo::GLDataFactory* factory, FontCache* fcache) "void main()\n" "{\n" " colorOut = vtf.color;\n" - " blendOut = texture(fontTex, vtf.uv);\n" + " blendOut = colorOut.a * texture(fontTex, vtf.uv);\n" "}\n"; static const char* BlockNames[] = {"SpecterViewBlock"}; @@ -121,7 +121,7 @@ void TextView::Resources::init(boo::ID3DDataFactory* factory, FontCache* fcache) "float4 main(in VertToFrag vtf) : SV_Target0\n" "{\n" " float4 colorOut = vtf.color;\n" - " colorOut.a = fontTex.Sample(samp, vtf.uv).r;\n" + " colorOut.a *= fontTex.Sample(samp, vtf.uv).r;\n" " return colorOut;\n" "}\n"; @@ -143,7 +143,7 @@ void TextView::Resources::init(boo::ID3DDataFactory* factory, FontCache* fcache) "{\n" " BlendOut ret;\n" " ret.colorOut = vtf.color;\n" - " ret.blendOut = fontTex.Sample(samp, vtf.uv);\n" + " ret.blendOut = ret.colorOut.a * fontTex.Sample(samp, vtf.uv);\n" " return ret;\n" "}\n"; @@ -229,7 +229,7 @@ void TextView::Resources::init(boo::MetalDataFactory* factory, FontCache* fcache "fragment float4 fmain(VertToFrag vtf [[ stage_in ]], texture2d_array fontTex [[ texture(0) ]])\n" "{\n" " float4 colorOut = vtf.color;\n" - " colorOut.a = fontTex.sample(samp, vtf.uv.xy, vtf.uv.z).r;\n" + " colorOut.a *= fontTex.sample(samp, vtf.uv.xy, vtf.uv.z).r;\n" " return colorOut;\n" "}\n"; @@ -329,7 +329,7 @@ TextView::RenderGlyph::RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, cons adv += glyph.m_advance; } -static int DoKern(FT_Pos val, const FontAtlas& atlas) +int TextView::DoKern(FT_Pos val, const FontAtlas& atlas) { if (!val) return 0; val = FT_MulFix(val, atlas.FT_Xscale()); @@ -387,6 +387,7 @@ void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& default m_valid = false; updateSize(); } + void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaultColor) { uint32_t lCh = -1; diff --git a/specter/lib/Tooltip.cpp b/specter/lib/Tooltip.cpp new file mode 100644 index 000000000..67fda0337 --- /dev/null +++ b/specter/lib/Tooltip.cpp @@ -0,0 +1,147 @@ +#include "Specter/Tooltip.hpp" +#include "Specter/ViewResources.hpp" +#include "Specter/RootView.hpp" + +namespace Specter +{ + +#define TOOLTIP_MAX_WIDTH 316 +#define TOOLTIP_MARGIN 8 + +Tooltip::Tooltip(ViewResources& res, View& parentView, const std::string& title, + const std::string& message) +: View(res, parentView), m_titleStr(title), m_messageStr(message) +{ + m_ttBlockBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, sizeof(ViewBlock), 1); + m_ttVertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SolidShaderVert), 16); + + if (!res.m_viewRes.m_solidVtxFmt) + { + boo::VertexElementDescriptor vdescs[] = + { + {m_ttVertsBuf, nullptr, boo::VertexSemantic::Position4}, + {m_ttVertsBuf, nullptr, boo::VertexSemantic::Color} + }; + m_ttVtxFmt = res.m_factory->newVertexFormat(2, vdescs); + boo::IGraphicsBuffer* bufs[] = {m_ttBlockBuf}; + m_ttShaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, + m_ttVtxFmt, m_ttVertsBuf, nullptr, + nullptr, 1, bufs, 0, nullptr); + } + else + { + boo::IGraphicsBuffer* bufs[] = {m_ttBlockBuf}; + m_ttShaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, + res.m_viewRes.m_solidVtxFmt, + m_ttVertsBuf, nullptr, + nullptr, 1, bufs, 0, nullptr); + } + + for (int i=0 ; i<16 ; ++i) + m_ttVerts[i].m_color = res.themeData().tooltipBackground(); + + commitResources(res); + resetResources(res); +} + +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); + + m_ttVerts[0].m_pos.assign(0, height-margin, 0); + m_ttVerts[1].m_pos.assign(0, margin, 0); + m_ttVerts[2].m_pos.assign(width, height-margin, 0); + m_ttVerts[3].m_pos.assign(width, margin, 0); + m_ttVerts[4].m_pos.assign(width, margin, 0); + + m_ttVerts[5].m_pos.assign(margin, height, 0); + m_ttVerts[6].m_pos.assign(margin, height, 0); + m_ttVerts[7].m_pos.assign(margin, height-margin, 0); + m_ttVerts[8].m_pos.assign(width-margin, height, 0); + m_ttVerts[9].m_pos.assign(width-margin, height-margin, 0); + m_ttVerts[10].m_pos.assign(width-margin, height-margin, 0); + + m_ttVerts[11].m_pos.assign(margin, margin, 0); + m_ttVerts[12].m_pos.assign(margin, margin, 0); + m_ttVerts[13].m_pos.assign(margin, 0, 0); + m_ttVerts[14].m_pos.assign(width-margin, margin, 0); + m_ttVerts[15].m_pos.assign(width-margin, 0, 0); + + m_ttVertsBuf->load(m_ttVerts, sizeof(SolidShaderVert) * 16); +} + +void Tooltip::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ + View::resized(root, sub); + float pf = rootView().viewRes().pixelFactor(); + setVerts(m_nomWidth, m_nomHeight, pf); + m_ttBlock.setViewRect(root, sub); + m_ttBlockBuf->load(&m_ttBlock, sizeof(ViewBlock)); + + boo::SWindowRect textRect = sub; + textRect.location[0] += TOOLTIP_MARGIN * pf; + textRect.location[1] += TOOLTIP_MARGIN * 1.5 * pf; + m_message->resized(root, textRect); + + textRect.location[1] += m_message->nominalHeight() + TOOLTIP_MARGIN * pf; + m_title->resized(root, textRect); + + boo::SWindowRect cornerRect = sub; + cornerRect.location[1] += m_nomHeight - TOOLTIP_MARGIN * pf; + m_cornersOutline[0]->resized(root, cornerRect); + m_cornersFilled[0]->resized(root, cornerRect); + cornerRect.location[0] += m_nomWidth - TOOLTIP_MARGIN * pf; + m_cornersOutline[1]->resized(root, cornerRect); + m_cornersFilled[1]->resized(root, cornerRect); + cornerRect.location[1] = sub.location[1]; + m_cornersOutline[2]->resized(root, cornerRect); + m_cornersFilled[2]->resized(root, cornerRect); + cornerRect.location[0] = sub.location[0]; + m_cornersOutline[3]->resized(root, cornerRect); + m_cornersFilled[3]->resized(root, cornerRect); +} + +void Tooltip::resetResources(ViewResources& res) +{ + for (int i=0 ; i<4 ; ++i) + { + m_cornersOutline[i].reset(new TextView(res, *this, res.m_curveFont, 1)); + m_cornersFilled[i].reset(new TextView(res, *this, res.m_curveFont, 1)); + } + m_cornersOutline[0]->typesetGlyphs(L"\xF4F0"); + m_cornersFilled[0]->typesetGlyphs(L"\xF4F1", res.themeData().tooltipBackground()); + m_cornersOutline[1]->typesetGlyphs(L"\xF4F2"); + m_cornersFilled[1]->typesetGlyphs(L"\xF4F3", res.themeData().tooltipBackground()); + m_cornersOutline[2]->typesetGlyphs(L"\xF4F4"); + m_cornersFilled[2]->typesetGlyphs(L"\xF4F5", res.themeData().tooltipBackground()); + m_cornersOutline[3]->typesetGlyphs(L"\xF4F6"); + m_cornersFilled[3]->typesetGlyphs(L"\xF4F7", res.themeData().tooltipBackground()); + + m_title.reset(new TextView(res, *this, res.m_heading14)); + 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_WIDTH * rootView().viewRes().pixelFactor())); + + float pf = res.pixelFactor(); + 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; +} + +void Tooltip::draw(boo::IGraphicsCommandQueue* gfxQ) +{ + gfxQ->setShaderDataBinding(m_ttShaderBinding); + gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); + gfxQ->draw(0, 16); + + for (int i=0 ; i<4 ; ++i) + m_cornersFilled[i]->draw(gfxQ); + + m_title->draw(gfxQ); + m_message->draw(gfxQ); +} + +} diff --git a/specter/lib/ViewResources.cpp b/specter/lib/ViewResources.cpp index 317d21c29..9f5d9f8a5 100644 --- a/specter/lib/ViewResources.cpp +++ b/specter/lib/ViewResources.cpp @@ -15,6 +15,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_fontData = factory->commit(); switch (factory->platform()) { @@ -45,6 +46,7 @@ void ViewResources::resetDPI(unsigned 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); m_heading18 = m_fcache->prepMainFont(m_factory, LatinAndJapaneseCharFilter, false, 18.f, dpi); + m_curveFont = m_fcache->prepCurvesFont(m_factory, AllCharFilter, false, 11.f, dpi); m_fontData = m_factory->commit(); m_fcache->closeBuiltinFonts(); } diff --git a/specter/resources/fonts/CMakeLists.txt b/specter/resources/fonts/CMakeLists.txt index e3a6508bf..925b90bfe 100644 --- a/specter/resources/fonts/CMakeLists.txt +++ b/specter/resources/fonts/CMakeLists.txt @@ -1,3 +1,4 @@ bintoc(droidsans-permissive.c droidsans-permissive.ttf.gz DROIDSANS_PERMISSIVE) bintoc(bmonofont-i18n.c bmonofont-i18n.ttf.gz BMONOFONT) -add_library(SpecterFonts droidsans-permissive.c bmonofont-i18n.c) +bintoc(SpecterCurveGlyphs.c SpecterCurveGlyphs.ttf.gz SPECTERCURVES) +add_library(SpecterFonts droidsans-permissive.c bmonofont-i18n.c SpecterCurveGlyphs.c) diff --git a/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz b/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz new file mode 100644 index 000000000..6b7590570 Binary files /dev/null and b/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz differ