aboutsummaryrefslogtreecommitdiff
path: root/guilib/GUIFont.cpp
diff options
context:
space:
mode:
authorAlTheKiller <AlTheKiller@svn>2009-09-23 01:49:50 +0000
committerAlTheKiller <AlTheKiller@svn>2009-09-23 01:49:50 +0000
commit45285e8a9300cd754a760560640b75b09f98035e (patch)
treead9f093885ad5c98e9dd4156674e7691c22ed0a2 /guilib/GUIFont.cpp
step 3/4: Move linuxport to trunk. How'd I get roped into this?
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@23097 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'guilib/GUIFont.cpp')
-rw-r--r--guilib/GUIFont.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/guilib/GUIFont.cpp b/guilib/GUIFont.cpp
new file mode 100644
index 0000000000..d80e3ab39d
--- /dev/null
+++ b/guilib/GUIFont.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFont.h"
+#include "GUIFontTTF.h"
+#include "GraphicContext.h"
+
+#include "utils/SingleLock.h"
+#include "MathUtils.h"
+
+#define ROUND(x) (float)(MathUtils::round_int(x))
+
+float CScrollInfo::GetPixelsPerFrame()
+{
+ static const float alphaEMA = 0.05f;
+
+ if (0 == pixelSpeed)
+ return 0; // not scrolling
+ DWORD currentTime = timeGetTime();
+ float delta = m_lastFrameTime ? (float)(currentTime - m_lastFrameTime) : m_averageFrameTime;
+ if (delta > 100)
+ delta = 100; // assume a minimum of 10 fps
+ m_lastFrameTime = currentTime;
+ // do an exponential moving average of the frame time
+ m_averageFrameTime = m_averageFrameTime + (delta - m_averageFrameTime) * alphaEMA;
+ // and multiply by pixel speed (per ms) to get number of pixels to move this frame
+ return pixelSpeed * m_averageFrameTime;
+}
+
+CGUIFont::CGUIFont(const CStdString& strFontName, uint32_t style, color_t textColor, color_t shadowColor, float lineSpacing, CGUIFontTTFBase *font)
+{
+ m_strFontName = strFontName;
+ m_style = style & 3;
+ m_textColor = textColor;
+ m_shadowColor = shadowColor;
+ m_lineSpacing = lineSpacing;
+ m_font = font;
+
+ if (m_font)
+ m_font->AddReference();
+}
+
+CGUIFont::~CGUIFont()
+{
+ if (m_font)
+ m_font->RemoveReference();
+}
+
+CStdString& CGUIFont::GetFontName()
+{
+ return m_strFontName;
+}
+
+void CGUIFont::DrawText( float x, float y, const vecColors &colors, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxPixelWidth)
+{
+ if (!m_font) return;
+
+ bool clip = maxPixelWidth > 0;
+ if (clip && ClippedRegionIsEmpty(x, y, maxPixelWidth, alignment))
+ return;
+
+ maxPixelWidth = ROUND(maxPixelWidth / g_graphicsContext.GetGUIScaleX());
+ vecColors renderColors;
+ for (unsigned int i = 0; i < colors.size(); i++)
+ renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));
+ if (!shadowColor) shadowColor = m_shadowColor;
+ if (shadowColor)
+ m_font->DrawTextInternal(x + 1, y + 1, g_graphicsContext.MergeAlpha(shadowColor), text, alignment, maxPixelWidth, false);
+ m_font->DrawTextInternal( x, y, renderColors, text, alignment, maxPixelWidth, false);
+
+ if (clip)
+ g_graphicsContext.RestoreClipRegion();
+}
+
+void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxWidth, CScrollInfo &scrollInfo)
+{
+ if (!m_font) return;
+ if (!shadowColor) shadowColor = m_shadowColor;
+
+ float spaceWidth = GetCharWidth(L' ');
+ // max chars on screen + extra margin chars
+ vecText::size_type maxChars =
+ std::min<vecText::size_type>(
+ (text.size() + (vecText::size_type)scrollInfo.suffix.size()),
+ (vecText::size_type)((maxWidth * 1.05f) / spaceWidth));
+
+ if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
+ return; // nothing to render
+
+ maxWidth = ROUND(maxWidth / g_graphicsContext.GetGUIScaleX());
+
+ // draw at our scroll position
+ // we handle the scrolling as follows:
+ // We scroll on a per-pixel basis up until we have scrolled the first character outside
+ // of our viewport, whereby we cycle the string around, and reset the scroll position.
+ //
+ // pixelPos is the amount in pixels to move the string by.
+ // characterPos is the amount in characters to rotate the string by.
+ //
+ float offset = scrollInfo.pixelPos;
+ if (!scrollInfo.waitTime)
+ {
+ // move along by the appropriate scroll amount
+ float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX());
+
+ if (scrollInfo.pixelSpeed > 0)
+ {
+ // we want to move scrollAmount, grab the next character
+ float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ if (scrollInfo.pixelPos + scrollAmount < charWidth)
+ scrollInfo.pixelPos += scrollAmount; // within the current character
+ else
+ { // past the current character, decrement scrollAmount by the charWidth and move to the next character
+ while (scrollInfo.pixelPos + scrollAmount >= charWidth)
+ {
+ scrollAmount -= (charWidth - scrollInfo.pixelPos);
+ scrollInfo.pixelPos = 0;
+ scrollInfo.characterPos++;
+ if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size())
+ {
+ scrollInfo.Reset();
+ break;
+ }
+ charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ }
+ }
+ offset = scrollInfo.pixelPos;
+ }
+ else if (scrollInfo.pixelSpeed < 0)
+ { // scrolling backwards
+ // we want to move scrollAmount, grab the next character
+ float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ if (scrollInfo.pixelPos + scrollAmount < charWidth)
+ scrollInfo.pixelPos += scrollAmount; // within the current character
+ else
+ { // past the current character, decrement scrollAmount by the charWidth and move to the next character
+ while (scrollInfo.pixelPos + scrollAmount >= charWidth)
+ {
+ scrollAmount -= (charWidth - scrollInfo.pixelPos);
+ scrollInfo.pixelPos = 0;
+ if (scrollInfo.characterPos == 0)
+ {
+ scrollInfo.Reset();
+ scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1;
+ break;
+ }
+ scrollInfo.characterPos--;
+ charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ }
+ }
+ offset = charWidth - scrollInfo.pixelPos;
+ }
+ }
+ else
+ scrollInfo.waitTime--;
+
+ // Now rotate our string as needed, only take a slightly larger then visible part of the text.
+ unsigned int pos = scrollInfo.characterPos;
+ vecText renderText;
+ renderText.reserve(maxChars);
+ for (vecText::size_type i = 0; i < maxChars; i++)
+ {
+ if (pos >= text.size() + scrollInfo.suffix.size())
+ pos = 0;
+ if (pos < text.size())
+ renderText.push_back(text[pos]);
+ else
+ renderText.push_back(scrollInfo.suffix[pos - text.size()]);
+ pos++;
+ }
+
+ vecColors renderColors;
+ for (unsigned int i = 0; i < colors.size(); i++)
+ renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));
+
+ bool scroll = !scrollInfo.waitTime && scrollInfo.pixelSpeed;
+ if (shadowColor)
+ m_font->DrawTextInternal(x - offset + 1, y + 1, g_graphicsContext.MergeAlpha(shadowColor), renderText, alignment, maxWidth + scrollInfo.pixelPos + m_font->GetLineHeight(2.0f), scroll);
+
+ m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + scrollInfo.pixelPos + m_font->GetLineHeight(2.0f), scroll);
+
+ g_graphicsContext.RestoreClipRegion();
+}
+
+// remaps unsupported font glpyhs to other suitable ones
+wchar_t CGUIFont::RemapGlyph(wchar_t letter)
+{
+ if (letter == 0x2019 || letter == 0x2018) return 0x0027; // single quotes
+ else if (letter == 0x201c || letter == 0x201d) return 0x0022;
+ return 0; // no decent character map
+}
+
+bool CGUIFont::ClippedRegionIsEmpty(float x, float y, float width, uint32_t alignment) const
+{
+ if (alignment & XBFONT_CENTER_X)
+ x -= width * 0.5f;
+ else if (alignment & XBFONT_RIGHT)
+ x -= width;
+ if (alignment & XBFONT_CENTER_Y)
+ y -= m_font->GetLineHeight(m_lineSpacing);
+
+ return !g_graphicsContext.SetClipRegion(x, y, width, m_font->GetLineHeight(2.0f) * g_graphicsContext.GetGUIScaleY());
+}
+
+float CGUIFont::GetTextWidth( const vecText &text )
+{
+ if (!m_font) return 0;
+ CSingleLock lock(g_graphicsContext);
+ return m_font->GetTextWidthInternal(text.begin(), text.end()) * g_graphicsContext.GetGUIScaleX();
+}
+
+float CGUIFont::GetCharWidth( character_t ch )
+{
+ if (!m_font) return 0;
+ CSingleLock lock(g_graphicsContext);
+ return m_font->GetCharWidthInternal(ch) * g_graphicsContext.GetGUIScaleX();
+}
+
+float CGUIFont::GetTextHeight(int numLines) const
+{
+ if (!m_font) return 0;
+ return m_font->GetTextHeight(m_lineSpacing, numLines) * g_graphicsContext.GetGUIScaleY();
+}
+
+float CGUIFont::GetLineHeight() const
+{
+ if (!m_font) return 0;
+ return m_font->GetLineHeight(m_lineSpacing) * g_graphicsContext.GetGUIScaleY();
+}
+
+void CGUIFont::Begin()
+{
+ if (!m_font) return;
+ m_font->Begin();
+}
+
+void CGUIFont::End()
+{
+ if (!m_font) return;
+ m_font->End();
+}
+
+void CGUIFont::SetFont(CGUIFontTTFBase *font)
+{
+ if (m_font == font)
+ return; // no need to update the font if we already have it
+ if (m_font)
+ m_font->RemoveReference();
+ m_font = font;
+ if (m_font)
+ m_font->AddReference();
+}