2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUILabelControl.h"
22 #include "utils/CharsetConverter.h"
26 CGUILabelControl::CGUILabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool wrapMultiLine, bool bHasPath)
27 : CGUIControl(parentID, controlID, posX, posY, width, height)
28 , m_label(posX, posY, width, height, labelInfo, wrapMultiLine ? CGUILabel::OVER_FLOW_WRAP : CGUILabel::OVER_FLOW_TRUNCATE)
30 m_bHasPath = bHasPath;
32 m_bShowCursor = false;
34 ControlType = GUICONTROL_LABEL;
35 m_startHighlight = m_endHighlight = 0;
36 m_startSelection = m_endSelection = 0;
40 CGUILabelControl::~CGUILabelControl(void)
44 void CGUILabelControl::ShowCursor(bool bShow)
46 m_bShowCursor = bShow;
49 void CGUILabelControl::SetCursorPos(int iPos)
51 CStdString labelUTF8 = m_infoLabel.GetLabel(m_parentID);
53 g_charsetConverter.utf8ToW(labelUTF8, label);
54 if (iPos > (int)label.length()) iPos = label.length();
55 if (iPos < 0) iPos = 0;
57 if (m_iCursorPos != iPos)
63 void CGUILabelControl::SetInfo(const CGUIInfoLabel &infoLabel)
65 m_infoLabel = infoLabel;
68 bool CGUILabelControl::UpdateColors()
70 bool changed = CGUIControl::UpdateColors();
71 changed |= m_label.UpdateColors();
76 typedef struct InsertPointInfo
85 bool operator < (const InsertPointInfo& info) const
91 // TAIL always ahead HEAD at same pos.
98 // HEADs in same pos, larger block's HEAD ahead
99 if (blockLength > info.blockLength)
101 if (blockLength < info.blockLength)
103 // same pos, type, blocklength, then lower priority HEAD ahead.
104 // then the higher priority block will nested in the lower priority one.
105 return priority < info.priority;
107 else if (type == TAIL)
109 // TAILs in same pos, smaill block's TAIL ahead
110 if (blockLength < info.blockLength)
112 if (blockLength > info.blockLength)
114 // same pos, type, blocklength, then higher priority TAIL ahead.
115 return priority > info.priority;
118 // order type HEAD_AND_TAIL by priority, higher ahead.
119 return priority > info.priority;
125 int priority; // only used when same pos, same type, same blocklength
129 void CGUILabelControl::UpdateInfo(const CGUIListItem *item)
131 CStdString label(m_infoLabel.GetLabel(m_parentID));
133 bool changed = false;
134 if (m_startHighlight < m_endHighlight || m_startSelection < m_endSelection || m_bShowCursor)
137 g_charsetConverter.utf8ToW(label, utf16);
138 vecText text; text.reserve(utf16.size()+1);
140 colors.push_back(m_label.GetLabelInfo().textColor);
141 colors.push_back(m_label.GetLabelInfo().disabledColor);
142 color_t select = m_label.GetLabelInfo().selectedColor;
145 colors.push_back(select);
146 colors.push_back(0xFF000000);
147 for (unsigned int i = 0; i < utf16.size(); i++)
149 unsigned int ch = utf16[i];
150 if ((m_startSelection < m_endSelection) && (m_startSelection <= i && i < m_endSelection))
152 else if ((m_startHighlight < m_endHighlight) && (i < m_startHighlight || i >= m_endHighlight))
156 if (m_bShowCursor && m_iCursorPos >= 0 && (unsigned int)m_iCursorPos <= utf16.size())
158 unsigned int ch = L'|';
159 if ((++m_dwCounter % 50) <= 25)
161 text.insert(text.begin() + m_iCursorPos, ch);
163 changed |= m_label.SetMaxRect(m_posX, m_posY, GetWidth(), m_height);
164 changed |= m_label.SetStyledText(text, colors);
169 label = ShortenPath(label);
171 changed |= m_label.SetMaxRect(m_posX, m_posY, GetWidth(), m_height);
172 changed |= m_label.SetText(label);
178 void CGUILabelControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
180 bool changed = false;
182 changed |= m_label.SetColor(IsDisabled() ? CGUILabel::COLOR_DISABLED : CGUILabel::COLOR_TEXT);
183 changed |= m_label.SetMaxRect(m_posX, m_posY, GetWidth(), m_height);
184 changed |= m_label.Process(currentTime);
189 CGUIControl::Process(currentTime, dirtyregions);
192 CRect CGUILabelControl::CalcRenderRegion() const
194 return m_label.GetRenderRect();
197 void CGUILabelControl::Render()
200 CGUIControl::Render();
204 bool CGUILabelControl::CanFocus() const
209 void CGUILabelControl::SetLabel(const string &strLabel)
211 // NOTE: this optimization handles fixed labels only (i.e. not info labels).
212 // One way it might be extended to all labels would be for GUIInfoLabel ( or here )
213 // to store the label prior to parsing, and then compare that against what you're setting.
214 if (m_infoLabel.GetLabel(GetParentID(), false) != strLabel)
216 m_infoLabel.SetLabel(strLabel, "", GetParentID());
217 if (m_iCursorPos > (int)strLabel.size())
218 m_iCursorPos = strLabel.size();
224 void CGUILabelControl::SetWidthControl(float minWidth, bool bScroll)
226 if (m_label.SetScrolling(bScroll) || m_minWidth != minWidth)
229 m_minWidth = minWidth;
232 void CGUILabelControl::SetAlignment(uint32_t align)
234 if (m_label.GetLabelInfo().align != align)
237 m_label.GetLabelInfo().align = align;
241 #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
243 float CGUILabelControl::GetWidth() const
245 if (m_minWidth && m_minWidth != m_width)
247 float maxWidth = m_width ? m_width : m_label.GetTextWidth();
248 return CLAMP(m_label.GetTextWidth(), m_minWidth, maxWidth);
253 void CGUILabelControl::SetWidth(float width)
256 m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
257 CGUIControl::SetWidth(m_width);
260 bool CGUILabelControl::OnMessage(CGUIMessage& message)
262 if ( message.GetControlId() == GetID() )
264 if (message.GetMessage() == GUI_MSG_LABEL_SET)
266 SetLabel(message.GetLabel());
271 return CGUIControl::OnMessage(message);
274 CStdString CGUILabelControl::ShortenPath(const CStdString &path)
276 if (m_width == 0 || path.IsEmpty())
282 nPos = path.find_last_of( '\\' );
283 if ( nPos != std::string::npos )
287 nPos = path.find_last_of( '/' );
288 if ( nPos != std::string::npos )
291 if ( cDelim == '\0' )
294 CStdString workPath(path);
295 // remove trailing slashes
296 if (workPath.size() > 3)
297 if (workPath.Right(3).Compare("://") != 0 && workPath.Right(2).Compare(":\\") != 0)
298 if (nPos == workPath.size() - 1)
300 workPath.erase(workPath.size() - 1);
301 nPos = workPath.find_last_of( cDelim );
304 if (m_label.SetText(workPath))
307 float textWidth = m_label.GetTextWidth();
309 while ( textWidth > m_width )
311 size_t nGreaterDelim = workPath.find_last_of( cDelim, nPos );
312 if (nGreaterDelim == std::string::npos)
315 nPos = workPath.find_last_of( cDelim, nGreaterDelim - 1 );
316 if ( nPos == std::string::npos )
319 workPath.replace( nPos + 1, nGreaterDelim - nPos - 1, "..." );
321 if (m_label.SetText(workPath))
324 textWidth = m_label.GetTextWidth();
329 void CGUILabelControl::SetHighlight(unsigned int start, unsigned int end)
331 m_startHighlight = start;
332 m_endHighlight = end;
335 void CGUILabelControl::SetSelection(unsigned int start, unsigned int end)
337 m_startSelection = start;
338 m_endSelection = end;
341 CStdString CGUILabelControl::GetDescription() const
343 return m_infoLabel.GetLabel(m_parentID);