PageRenderTime 35ms CodeModel.GetById 16ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/guilib/GUILabel.cpp

http://github.com/xbmc/xbmc
C++ | 238 lines | 188 code | 34 blank | 16 comment | 38 complexity | 067819fc92da0c3710baa77e529b90a2 MD5 | raw file
  1/*
  2 *  Copyright (C) 2005-2018 Team Kodi
  3 *  This file is part of Kodi - https://kodi.tv
  4 *
  5 *  SPDX-License-Identifier: GPL-2.0-or-later
  6 *  See LICENSES/README.md for more information.
  7 */
  8
  9#include "GUILabel.h"
 10
 11#include <limits>
 12
 13CGUILabel::CGUILabel(float posX, float posY, float width, float height, const CLabelInfo& labelInfo, CGUILabel::OVER_FLOW overflow)
 14    : m_label(labelInfo)
 15    , m_textLayout(labelInfo.font, overflow == OVER_FLOW_WRAP, height)
 16    , m_scrolling(overflow == OVER_FLOW_SCROLL)
 17    , m_overflowType(overflow)
 18    , m_scrollInfo(50, 0, labelInfo.scrollSpeed, labelInfo.scrollSuffix)
 19    , m_renderRect()
 20    , m_maxRect(posX, posY, posX + width, posY + height)
 21    , m_invalid(true)
 22    , m_color(COLOR_TEXT)
 23{
 24}
 25
 26CGUILabel::~CGUILabel(void) = default;
 27
 28bool CGUILabel::SetScrolling(bool scrolling)
 29{
 30  bool changed = m_scrolling != scrolling;
 31
 32  m_scrolling = scrolling;
 33  if (changed)
 34    m_scrollInfo.Reset();
 35
 36  return changed;
 37}
 38
 39bool CGUILabel::SetOverflow(OVER_FLOW overflow)
 40{
 41  bool changed = m_overflowType != overflow;
 42
 43  m_overflowType = overflow;
 44
 45  return changed;
 46}
 47
 48bool CGUILabel::SetColor(CGUILabel::COLOR color)
 49{
 50  bool changed = m_color != color;
 51
 52  m_color = color;
 53
 54  return changed;
 55}
 56
 57UTILS::Color CGUILabel::GetColor() const
 58{
 59  switch (m_color)
 60  {
 61    case COLOR_SELECTED:
 62      return m_label.selectedColor;
 63    case COLOR_DISABLED:
 64      return m_label.disabledColor;
 65    case COLOR_FOCUSED:
 66      return m_label.focusedColor ? m_label.focusedColor : m_label.textColor;
 67    case COLOR_INVALID:
 68      return m_label.invalidColor ? m_label.invalidColor : m_label.textColor;
 69    default:
 70      break;
 71  }
 72  return m_label.textColor;
 73}
 74
 75bool CGUILabel::Process(unsigned int currentTime)
 76{
 77  //! @todo Add the correct processing
 78
 79  bool overFlows = (m_renderRect.Width() + 0.5f < m_textLayout.GetTextWidth()); // 0.5f to deal with floating point rounding issues
 80  bool renderSolid = (m_color == COLOR_DISABLED);
 81
 82  if (overFlows && m_scrolling && !renderSolid)
 83  {
 84    if (m_maxScrollLoops < m_scrollInfo.m_loopCount)
 85      SetScrolling(false);
 86    else
 87      return m_textLayout.UpdateScrollinfo(m_scrollInfo);
 88  }
 89
 90  return false;
 91}
 92
 93void CGUILabel::Render()
 94{
 95  UTILS::Color color = GetColor();
 96  bool renderSolid = (m_color == COLOR_DISABLED);
 97  bool overFlows = (m_renderRect.Width() + 0.5f < m_textLayout.GetTextWidth()); // 0.5f to deal with floating point rounding issues
 98  if (overFlows && m_scrolling && !renderSolid)
 99    m_textLayout.RenderScrolling(m_renderRect.x1, m_renderRect.y1, m_label.angle, color, m_label.shadowColor, 0, m_renderRect.Width(), m_scrollInfo);
100  else
101  {
102    float posX = m_renderRect.x1;
103    float posY = m_renderRect.y1;
104    uint32_t align = 0;
105    if (!overFlows)
106    { // hack for right and centered multiline text, as GUITextLayout::Render() treats posX as the right hand
107      // or center edge of the text (see GUIFontTTF::DrawTextInternal), and this has already been taken care of
108      // in UpdateRenderRect(), but we wish to still pass the horizontal alignment info through (so that multiline text
109      // is aligned correctly), so we must undo the UpdateRenderRect() changes for horizontal alignment.
110      if (m_label.align & XBFONT_RIGHT)
111        posX += m_renderRect.Width();
112      else if (m_label.align & XBFONT_CENTER_X)
113        posX += m_renderRect.Width() * 0.5f;
114      if (m_label.align & XBFONT_CENTER_Y) // need to pass a centered Y so that <angle> will rotate around the correct point.
115        posY += m_renderRect.Height() * 0.5f;
116      align = m_label.align;
117    }
118    else
119      align |= XBFONT_TRUNCATED;
120    m_textLayout.Render(posX, posY, m_label.angle, color, m_label.shadowColor, align, m_overflowType == OVER_FLOW_CLIP ? m_textLayout.GetTextWidth() : m_renderRect.Width(), renderSolid);
121  }
122}
123
124void CGUILabel::SetInvalid()
125{
126  m_invalid = true;
127}
128
129bool CGUILabel::UpdateColors()
130{
131  return m_label.UpdateColors();
132}
133
134bool CGUILabel::SetMaxRect(float x, float y, float w, float h)
135{
136  CRect oldRect = m_maxRect;
137
138  m_maxRect.SetRect(x, y, x + w, y + h);
139  UpdateRenderRect();
140
141  return oldRect != m_maxRect;
142}
143
144bool CGUILabel::SetAlign(uint32_t align)
145{
146  bool changed = m_label.align != align;
147
148  m_label.align = align;
149  UpdateRenderRect();
150
151  return changed;
152}
153
154bool CGUILabel::SetStyledText(const vecText &text, const std::vector<UTILS::Color> &colors)
155{
156  m_textLayout.UpdateStyled(text, colors, m_maxRect.Width());
157  m_invalid = false;
158  return true;
159}
160
161bool CGUILabel::SetText(const std::string &label)
162{
163  if (m_textLayout.Update(label, m_maxRect.Width(), m_invalid))
164  { // needed an update - reset scrolling and update our text layout
165    m_scrollInfo.Reset();
166    UpdateRenderRect();
167    m_invalid = false;
168    return true;
169  }
170  else
171    return false;
172}
173
174bool CGUILabel::SetTextW(const std::wstring &label)
175{
176  if (m_textLayout.UpdateW(label, m_maxRect.Width(), m_invalid))
177  {
178    m_scrollInfo.Reset();
179    UpdateRenderRect();
180    m_invalid = false;
181    return true;
182  }
183  else
184    return false;
185}
186
187void CGUILabel::UpdateRenderRect()
188{
189  // recalculate our text layout
190  float width, height;
191  m_textLayout.GetTextExtent(width, height);
192  width = std::min(width, GetMaxWidth());
193  if (m_label.align & XBFONT_CENTER_Y)
194    m_renderRect.y1 = m_maxRect.y1 + (m_maxRect.Height() - height) * 0.5f;
195  else
196    m_renderRect.y1 = m_maxRect.y1 + m_label.offsetY;
197  if (m_label.align & XBFONT_RIGHT)
198    m_renderRect.x1 = m_maxRect.x2 - width - m_label.offsetX;
199  else if (m_label.align & XBFONT_CENTER_X)
200    m_renderRect.x1 = m_maxRect.x1 + (m_maxRect.Width() - width) * 0.5f;
201  else
202    m_renderRect.x1 = m_maxRect.x1 + m_label.offsetX;
203  m_renderRect.x2 = m_renderRect.x1 + width;
204  m_renderRect.y2 = m_renderRect.y1 + height;
205}
206
207float CGUILabel::GetMaxWidth() const
208{
209  if (m_label.width) return m_label.width;
210  return m_maxRect.Width() - 2*m_label.offsetX;
211}
212
213bool CGUILabel::CheckAndCorrectOverlap(CGUILabel &label1, CGUILabel &label2)
214{
215  CRect rect(label1.m_renderRect);
216  if (rect.Intersect(label2.m_renderRect).IsEmpty())
217    return false; // nothing to do (though it could potentially encroach on the min_space requirement)
218
219  // overlap vertically and horizontally - check alignment
220  CGUILabel &left = label1.m_renderRect.x1 <= label2.m_renderRect.x1 ? label1 : label2;
221  CGUILabel &right = label1.m_renderRect.x1 <= label2.m_renderRect.x1 ? label2 : label1;
222  if ((left.m_label.align & 3) == 0 && right.m_label.align & XBFONT_RIGHT)
223  {
224    static const float min_space = 10;
225    float chopPoint = (left.m_maxRect.x1 + left.GetMaxWidth() + right.m_maxRect.x2 - right.GetMaxWidth()) * 0.5f;
226    // [1       [2...[2  1].|..........1]         2]
227    // [1       [2.....[2   |      1]..1]         2]
228    // [1       [2..........|.[2   1]..1]         2]
229    if (right.m_renderRect.x1 > chopPoint)
230      chopPoint = right.m_renderRect.x1 - min_space;
231    else if (left.m_renderRect.x2 < chopPoint)
232      chopPoint = left.m_renderRect.x2 + min_space;
233    left.m_renderRect.x2 = chopPoint - min_space;
234    right.m_renderRect.x1 = chopPoint + min_space;
235    return true;
236  }
237  return false;
238}