2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUILabelControl.h"
12 #include "GUIMessage.h"
13 #include "utils/CharsetConverter.h"
14 #include "utils/ColorUtils.h"
15 #include "utils/StringUtils.h"
17 using namespace KODI::GUILIB
;
19 CGUILabelControl::CGUILabelControl(int parentID
, int controlID
, float posX
, float posY
, float width
, float height
, const CLabelInfo
& labelInfo
, bool wrapMultiLine
, bool bHasPath
)
20 : CGUIControl(parentID
, controlID
, posX
, posY
, width
, height
)
21 , m_label(posX
, posY
, width
, height
, labelInfo
, wrapMultiLine
? CGUILabel::OVER_FLOW_WRAP
: CGUILabel::OVER_FLOW_TRUNCATE
)
23 m_bHasPath
= bHasPath
;
25 m_bShowCursor
= false;
27 ControlType
= GUICONTROL_LABEL
;
28 m_startHighlight
= m_endHighlight
= 0;
29 m_startSelection
= m_endSelection
= 0;
31 m_label
.SetScrollLoopCount(2);
34 CGUILabelControl::~CGUILabelControl(void) = default;
36 void CGUILabelControl::ShowCursor(bool bShow
)
38 m_bShowCursor
= bShow
;
41 void CGUILabelControl::SetCursorPos(int iPos
)
43 std::string labelUTF8
= m_infoLabel
.GetLabel(m_parentID
);
45 g_charsetConverter
.utf8ToW(labelUTF8
, label
);
46 if (iPos
> (int)label
.length()) iPos
= label
.length();
47 if (iPos
< 0) iPos
= 0;
49 if (m_iCursorPos
!= iPos
)
55 void CGUILabelControl::SetInfo(const GUIINFO::CGUIInfoLabel
&infoLabel
)
57 m_infoLabel
= infoLabel
;
60 bool CGUILabelControl::UpdateColors(const CGUIListItem
* item
)
62 bool changed
= CGUIControl::UpdateColors(nullptr);
63 changed
|= m_label
.UpdateColors();
68 void CGUILabelControl::UpdateInfo(const CGUIListItem
*item
)
70 std::string
label(m_infoLabel
.GetLabel(m_parentID
));
73 if (m_startHighlight
< m_endHighlight
|| m_startSelection
< m_endSelection
|| m_bShowCursor
)
76 g_charsetConverter
.utf8ToW(label
, utf16
);
77 vecText text
; text
.reserve(utf16
.size()+1);
78 std::vector
<KODI::UTILS::COLOR::Color
> colors
;
79 colors
.push_back(m_label
.GetLabelInfo().textColor
);
80 colors
.push_back(m_label
.GetLabelInfo().disabledColor
);
81 KODI::UTILS::COLOR::Color select
= m_label
.GetLabelInfo().selectedColor
;
84 colors
.push_back(select
);
85 colors
.push_back(0xFF000000);
87 CGUIFont
* font
= m_label
.GetLabelInfo().font
;
88 uint32_t style
= (font
? font
->GetStyle() : (FONT_STYLE_NORMAL
& FONT_STYLE_MASK
)) << 24;
90 for (unsigned int i
= 0; i
< utf16
.size(); i
++)
92 uint32_t ch
= utf16
[i
] | style
;
93 if ((m_startSelection
< m_endSelection
) && (m_startSelection
<= i
&& i
< m_endSelection
))
95 else if ((m_startHighlight
< m_endHighlight
) && (i
< m_startHighlight
|| i
>= m_endHighlight
))
99 if (m_bShowCursor
&& m_iCursorPos
>= 0 && (unsigned int)m_iCursorPos
<= utf16
.size())
101 uint32_t ch
= L
'|' | style
;
102 if ((++m_dwCounter
% 50) <= 25)
104 text
.insert(text
.begin() + m_iCursorPos
, ch
);
106 changed
|= m_label
.SetMaxRect(m_posX
, m_posY
, GetMaxWidth(), m_height
);
107 changed
|= m_label
.SetStyledText(text
, colors
);
112 label
= ShortenPath(label
);
114 changed
|= m_label
.SetMaxRect(m_posX
, m_posY
, GetMaxWidth(), m_height
);
115 changed
|= m_label
.SetText(label
);
121 void CGUILabelControl::Process(unsigned int currentTime
, CDirtyRegionList
&dirtyregions
)
123 bool changed
= false;
125 changed
|= m_label
.SetColor(IsDisabled() ? CGUILabel::COLOR_DISABLED
: CGUILabel::COLOR_TEXT
);
126 changed
|= m_label
.SetMaxRect(m_posX
, m_posY
, GetMaxWidth(), m_height
);
127 changed
|= m_label
.Process(currentTime
);
132 CGUIControl::Process(currentTime
, dirtyregions
);
135 CRect
CGUILabelControl::CalcRenderRegion() const
137 return m_label
.GetRenderRect();
140 void CGUILabelControl::Render()
142 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetRenderOrder() ==
143 RENDER_ORDER_FRONT_TO_BACK
)
146 CGUIControl::Render();
150 bool CGUILabelControl::CanFocus() const
155 void CGUILabelControl::SetLabel(const std::string
&strLabel
)
157 // NOTE: this optimization handles fixed labels only (i.e. not info labels).
158 // One way it might be extended to all labels would be for GUIInfoLabel ( or here )
159 // to store the label prior to parsing, and then compare that against what you're setting.
160 if (m_infoLabel
.GetLabel(GetParentID(), false) != strLabel
)
162 m_infoLabel
.SetLabel(strLabel
, "", GetParentID());
163 if (m_iCursorPos
> (int)strLabel
.size())
164 m_iCursorPos
= strLabel
.size();
170 void CGUILabelControl::SetWidthControl(float minWidth
, bool bScroll
)
172 if (m_label
.SetScrolling(bScroll
) || m_minWidth
!= minWidth
)
175 m_minWidth
= minWidth
;
178 void CGUILabelControl::SetAlignment(uint32_t align
)
180 if (m_label
.GetLabelInfo().align
!= align
)
183 m_label
.GetLabelInfo().align
= align
;
187 #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
189 float CGUILabelControl::GetWidth() const
191 if (m_minWidth
&& m_minWidth
!= m_width
)
192 return CLAMP(m_label
.GetTextWidth(), m_minWidth
, GetMaxWidth());
196 void CGUILabelControl::SetWidth(float width
)
199 m_label
.SetMaxRect(m_posX
, m_posY
, m_width
, m_height
);
200 CGUIControl::SetWidth(m_width
);
203 bool CGUILabelControl::OnMessage(CGUIMessage
& message
)
205 if (message
.GetControlId() == GetID())
207 if (message
.GetMessage() == GUI_MSG_LABEL_SET
)
209 SetLabel(message
.GetLabel());
213 if (message
.GetMessage() == GUI_MSG_REFRESH_TIMER
&& IsVisible())
217 else if (message
.GetMessage() == GUI_MSG_WINDOW_RESIZE
&& IsVisible())
219 m_label
.SetInvalid();
222 return CGUIControl::OnMessage(message
);
225 std::string
CGUILabelControl::ShortenPath(const std::string
&path
)
227 if (m_width
== 0 || path
.empty())
233 nPos
= path
.find_last_of( '\\' );
234 if ( nPos
!= std::string::npos
)
238 nPos
= path
.find_last_of( '/' );
239 if ( nPos
!= std::string::npos
)
242 if ( cDelim
== '\0' )
245 std::string
workPath(path
);
246 // remove trailing slashes
247 if (workPath
.size() > 3)
248 if (!StringUtils::EndsWith(workPath
, "://") &&
249 !StringUtils::EndsWith(workPath
, ":\\"))
250 if (nPos
== workPath
.size() - 1)
252 workPath
.erase(workPath
.size() - 1);
253 nPos
= workPath
.find_last_of( cDelim
);
256 if (m_label
.SetText(workPath
))
259 float textWidth
= m_label
.GetTextWidth();
261 while ( textWidth
> m_width
)
263 size_t nGreaterDelim
= workPath
.find_last_of( cDelim
, nPos
);
264 if (nGreaterDelim
== std::string::npos
)
267 nPos
= workPath
.find_last_of( cDelim
, nGreaterDelim
- 1 );
268 if ( nPos
== std::string::npos
)
271 workPath
.replace( nPos
+ 1, nGreaterDelim
- nPos
- 1, "..." );
273 if (m_label
.SetText(workPath
))
276 textWidth
= m_label
.GetTextWidth();
281 void CGUILabelControl::SetHighlight(unsigned int start
, unsigned int end
)
283 m_startHighlight
= start
;
284 m_endHighlight
= end
;
287 void CGUILabelControl::SetSelection(unsigned int start
, unsigned int end
)
289 m_startSelection
= start
;
290 m_endSelection
= end
;
293 std::string
CGUILabelControl::GetDescription() const
295 return m_infoLabel
.GetLabel(m_parentID
);