Merge remote branch 'origin/trunk' into trac-8658
[xbmc:xbmc-antiquated.git] / guilib / GUILabelControl.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "GUILabelControl.h"
23 #include "utils/CharsetConverter.h"
24
25 using namespace std;
26
27 CGUILabelControl::CGUILabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool wrapMultiLine, bool bHasPath)
28     : CGUIControl(parentID, controlID, posX, posY, width, height)
29     , m_label(posX, posY, width, height, labelInfo, wrapMultiLine ? CGUILabel::OVER_FLOW_WRAP : CGUILabel::OVER_FLOW_TRUNCATE)
30 {
31   m_bHasPath = bHasPath;
32   m_iCursorPos = 0;
33   m_bShowCursor = false;
34   m_dwCounter = 0;
35   ControlType = GUICONTROL_LABEL;
36   m_startHighlight = m_endHighlight = 0;
37   m_minWidth = 0;
38   if ((labelInfo.align & XBFONT_RIGHT) && m_width)
39     m_posX -= m_width;
40 }
41
42 CGUILabelControl::~CGUILabelControl(void)
43 {
44 }
45
46 void CGUILabelControl::ShowCursor(bool bShow)
47 {
48   m_bShowCursor = bShow;
49 }
50
51 void CGUILabelControl::SetCursorPos(int iPos)
52 {
53   CStdString label = m_infoLabel.GetLabel(m_parentID);
54   if (iPos > (int)label.length()) iPos = label.length();
55   if (iPos < 0) iPos = 0;
56   m_iCursorPos = iPos;
57 }
58
59 void CGUILabelControl::SetInfo(const CGUIInfoLabel &infoLabel)
60 {
61   m_infoLabel = infoLabel;
62 }
63
64 void CGUILabelControl::UpdateColors()
65 {
66   m_label.UpdateColors();
67   CGUIControl::UpdateColors();
68 }
69
70 void CGUILabelControl::UpdateInfo(const CGUIListItem *item)
71 {
72   CStdString label(m_infoLabel.GetLabel(m_parentID));
73
74   if (m_bShowCursor)
75   { // cursor location assumes utf16 text, so deal with that (inefficient, but it's not as if it's a high-use area
76     // virtual keyboard only)
77     CStdStringW utf16;
78     g_charsetConverter.utf8ToW(label, utf16);
79     CStdStringW col;
80     if ((++m_dwCounter % 50) > 25)
81       col = L"|";
82     else
83       col = L"[COLOR 00FFFFFF]|[/COLOR]";
84     utf16.Insert(m_iCursorPos, col);
85     g_charsetConverter.wToUTF8(utf16, label);
86   }
87   else if (m_startHighlight || m_endHighlight)
88   { // this is only used for times/dates, so working in ascii (utf8) is fine
89     CStdString colorLabel;
90     colorLabel.Format("[COLOR %x]%s[/COLOR]%s[COLOR %x]%s[/COLOR]", (color_t)m_label.GetLabelInfo().disabledColor, label.Left(m_startHighlight),
91                  label.Mid(m_startHighlight, m_endHighlight - m_startHighlight), (color_t)m_label.GetLabelInfo().disabledColor, label.Mid(m_endHighlight));
92     label = colorLabel;
93   }
94   else if (m_bHasPath)
95     label = ShortenPath(label);
96
97   m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
98   m_label.SetText(label);
99 }
100
101 void CGUILabelControl::Render()
102 {
103   m_label.SetColor(IsDisabled() ? CGUILabel::COLOR_DISABLED : CGUILabel::COLOR_TEXT);
104   m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
105   m_label.Render();
106   CGUIControl::Render();
107 }
108
109
110 bool CGUILabelControl::CanFocus() const
111 {
112   return false;
113 }
114
115 void CGUILabelControl::SetLabel(const string &strLabel)
116 {
117   m_infoLabel.SetLabel(strLabel, "");
118   if (m_iCursorPos > (int)strLabel.size())
119     m_iCursorPos = strLabel.size();
120 }
121
122 void CGUILabelControl::SetWidthControl(float minWidth, bool bScroll)
123 {
124   m_minWidth = minWidth;
125   m_label.SetScrolling(bScroll);
126 }
127
128 void CGUILabelControl::SetAlignment(uint32_t align)
129 {
130   m_label.GetLabelInfo().align = align;
131 }
132
133 #define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
134
135 float CGUILabelControl::GetWidth() const
136 {
137   if (m_minWidth && m_minWidth != m_width)
138     return CLAMP(m_label.GetTextWidth(), m_minWidth, m_width);
139   return m_width;
140 }
141
142 bool CGUILabelControl::OnMessage(CGUIMessage& message)
143 {
144   if ( message.GetControlId() == GetID() )
145   {
146     if (message.GetMessage() == GUI_MSG_LABEL_SET)
147     {
148       SetLabel(message.GetLabel());
149       return true;
150     }
151   }
152
153   return CGUIControl::OnMessage(message);
154 }
155
156 CStdString CGUILabelControl::ShortenPath(const CStdString &path)
157 {
158   if (m_width == 0 || path.IsEmpty())
159     return path;
160
161   char cDelim = '\0';
162   size_t nPos;
163
164   nPos = path.find_last_of( '\\' );
165   if ( nPos != std::string::npos )
166     cDelim = '\\';
167   else
168   {
169     nPos = path.find_last_of( '/' );
170     if ( nPos != std::string::npos )
171       cDelim = '/';
172   }
173   if ( cDelim == '\0' )
174     return path;
175
176   CStdString workPath(path);
177   // remove trailing slashes
178   if (workPath.size() > 3)
179     if (workPath.Right(3).Compare("://") != 0 && workPath.Right(2).Compare(":\\") != 0)
180       if (nPos == workPath.size() - 1)
181       {
182         workPath.erase(workPath.size() - 1);
183         nPos = workPath.find_last_of( cDelim );
184       }
185
186   m_label.SetText(workPath);
187   float textWidth = m_label.GetTextWidth();
188
189   while ( textWidth > m_width )
190   {
191     size_t nGreaterDelim = workPath.find_last_of( cDelim, nPos );
192     if (nGreaterDelim == std::string::npos)
193       break;
194
195     nPos = workPath.find_last_of( cDelim, nGreaterDelim - 1 );
196     if ( nPos == std::string::npos )
197       break;
198
199     workPath.replace( nPos + 1, nGreaterDelim - nPos - 1, "..." );
200
201     m_label.SetText(workPath);
202     textWidth = m_label.GetTextWidth();
203   }
204   return workPath;
205 }
206
207 void CGUILabelControl::SetHighlight(unsigned int start, unsigned int end)
208 {
209   m_startHighlight = start;
210   m_endHighlight = end;
211 }
212
213 CStdString CGUILabelControl::GetDescription() const
214 {
215   return m_infoLabel.GetLabel(m_parentID);
216 }