Merge pull request #22816 from CastagnaIT/fix_tx3g
[xbmc.git] / xbmc / guilib / GUIEditControl.cpp
blob325a703152b9f2ae28107d73d6b805301a3b06e2
1 /*
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.
7 */
9 #include "GUIEditControl.h"
11 #include "GUIFont.h"
12 #include "GUIKeyboardFactory.h"
13 #include "GUIUserMessages.h"
14 #include "GUIWindowManager.h"
15 #include "LocalizeStrings.h"
16 #include "ServiceBroker.h"
17 #include "XBDateTime.h"
18 #include "dialogs/GUIDialogNumeric.h"
19 #include "input/Key.h"
20 #include "input/XBMC_vkeys.h"
21 #include "utils/CharsetConverter.h"
22 #include "utils/ColorUtils.h"
23 #include "utils/Digest.h"
24 #include "utils/Variant.h"
25 #include "windowing/WinSystem.h"
27 using namespace KODI::GUILIB;
29 using KODI::UTILITY::CDigest;
31 const char* CGUIEditControl::smsLetters[10] = { " !@#$%^&*()[]{}<>/\\|0", ".,;:\'\"-+_=?`~1", "abc2ABC", "def3DEF", "ghi4GHI", "jkl5JKL", "mno6MNO", "pqrs7PQRS", "tuv8TUV", "wxyz9WXYZ" };
32 const unsigned int CGUIEditControl::smsDelay = 1000;
34 #ifdef TARGET_WINDOWS
35 extern HWND g_hWnd;
36 #endif
38 CGUIEditControl::CGUIEditControl(int parentID, int controlID, float posX, float posY,
39 float width, float height, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus,
40 const CLabelInfo& labelInfo, const std::string &text)
41 : CGUIButtonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
43 DefaultConstructor();
44 SetLabel(text);
47 void CGUIEditControl::DefaultConstructor()
49 ControlType = GUICONTROL_EDIT;
50 m_textOffset = 0;
51 m_textWidth = GetWidth();
52 m_cursorPos = 0;
53 m_cursorBlink = 0;
54 m_inputHeading = g_localizeStrings.Get(16028);
55 m_inputType = INPUT_TYPE_TEXT;
56 m_smsLastKey = 0;
57 m_smsKeyIndex = 0;
58 m_label.SetAlign(m_label.GetLabelInfo().align & XBFONT_CENTER_Y); // left align
59 m_label2.GetLabelInfo().offsetX = 0;
60 m_isMD5 = false;
61 m_invalidInput = false;
62 m_inputValidator = NULL;
63 m_inputValidatorData = NULL;
64 m_editLength = 0;
65 m_editOffset = 0;
68 CGUIEditControl::CGUIEditControl(const CGUIButtonControl &button)
69 : CGUIButtonControl(button)
71 DefaultConstructor();
74 CGUIEditControl::~CGUIEditControl(void) = default;
76 bool CGUIEditControl::OnMessage(CGUIMessage &message)
78 if (message.GetMessage() == GUI_MSG_SET_TYPE)
80 SetInputType((INPUT_TYPE)message.GetParam1(), message.GetParam2());
81 return true;
83 else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
85 message.SetLabel(GetLabel2());
86 return true;
88 else if (message.GetMessage() == GUI_MSG_SET_TEXT &&
89 ((message.GetControlId() <= 0 && HasFocus()) || (message.GetControlId() == GetID())))
91 SetLabel2(message.GetLabel());
92 UpdateText();
94 return CGUIButtonControl::OnMessage(message);
97 bool CGUIEditControl::OnAction(const CAction &action)
99 ValidateCursor();
101 if (m_inputType != INPUT_TYPE_READONLY)
103 if (action.GetID() == ACTION_BACKSPACE)
105 // backspace
106 if (m_cursorPos)
108 if (!ClearMD5())
109 m_text2.erase(--m_cursorPos, 1);
110 UpdateText();
112 return true;
114 else if (action.GetID() == ACTION_MOVE_LEFT ||
115 action.GetID() == ACTION_CURSOR_LEFT)
117 if (m_cursorPos > 0)
119 m_cursorPos--;
120 UpdateText(false);
121 return true;
124 else if (action.GetID() == ACTION_MOVE_RIGHT ||
125 action.GetID() == ACTION_CURSOR_RIGHT)
127 if (m_cursorPos < m_text2.size())
129 m_cursorPos++;
130 UpdateText(false);
131 return true;
134 else if (action.GetID() == ACTION_PASTE)
136 ClearMD5();
137 OnPasteClipboard();
138 return true;
140 else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_UNICODE && m_edit.empty())
142 // input from the keyboard (vkey, not ascii)
143 unsigned char b = action.GetID() & 0xFF;
144 if (b == XBMCVK_HOME)
146 m_cursorPos = 0;
147 UpdateText(false);
148 return true;
150 else if (b == XBMCVK_END)
152 m_cursorPos = m_text2.length();
153 UpdateText(false);
154 return true;
156 if (b == XBMCVK_LEFT && m_cursorPos > 0)
158 m_cursorPos--;
159 UpdateText(false);
160 return true;
162 if (b == XBMCVK_RIGHT && m_cursorPos < m_text2.length())
164 m_cursorPos++;
165 UpdateText(false);
166 return true;
168 if (b == XBMCVK_DELETE)
170 if (m_cursorPos < m_text2.length())
172 if (!ClearMD5())
173 m_text2.erase(m_cursorPos, 1);
174 UpdateText();
175 return true;
178 if (b == XBMCVK_BACK)
180 if (m_cursorPos > 0)
182 if (!ClearMD5())
183 m_text2.erase(--m_cursorPos, 1);
184 UpdateText();
186 return true;
188 else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
190 // enter - send click message, but otherwise ignore
191 SEND_CLICK_MESSAGE(GetID(), GetParentID(), 1);
192 return true;
194 else if (b == XBMCVK_ESCAPE)
195 { // escape - fallthrough to default action
196 return CGUIButtonControl::OnAction(action);
199 else if (action.GetID() == KEY_UNICODE)
201 // input from the keyboard
202 int ch = action.GetUnicode();
203 // ignore non-printing characters
204 if ( !((0 <= ch && ch < 0x8) || (0xE <= ch && ch < 0x1B) || (0x1C <= ch && ch < 0x20)) )
206 switch (ch)
208 case 9: // tab, ignore
209 case 11: // Non-printing character, ignore
210 case 12: // Non-printing character, ignore
211 break;
212 case 10:
213 case 13:
215 // enter - send click message, but otherwise ignore
216 SEND_CLICK_MESSAGE(GetID(), GetParentID(), 1);
217 return true;
219 case 27:
220 { // escape - fallthrough to default action
221 return CGUIButtonControl::OnAction(action);
223 case 8:
225 // backspace
226 if (m_cursorPos)
228 if (!ClearMD5())
229 m_text2.erase(--m_cursorPos, 1);
231 break;
233 case 127:
234 { // delete
235 if (m_cursorPos < m_text2.length())
237 if (!ClearMD5())
238 m_text2.erase(m_cursorPos, 1);
240 break;
242 default:
244 ClearMD5();
245 m_edit.clear();
246 m_text2.insert(m_text2.begin() + m_cursorPos++, action.GetUnicode());
247 break;
250 UpdateText();
251 return true;
254 else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
255 { // input from the remote
256 ClearMD5();
257 m_edit.clear();
258 OnSMSCharacter(action.GetID() - REMOTE_0);
259 return true;
261 else if (action.GetID() == ACTION_INPUT_TEXT)
263 m_edit.clear();
264 std::wstring str;
265 g_charsetConverter.utf8ToW(action.GetText(), str, false);
266 m_text2.insert(m_cursorPos, str);
267 m_cursorPos += str.size();
268 UpdateText();
269 return true;
272 return CGUIButtonControl::OnAction(action);
275 void CGUIEditControl::OnClick()
277 // we received a click - it's not from the keyboard, so pop up the virtual keyboard, unless
278 // that is where we reside!
279 if (GetParentID() == WINDOW_DIALOG_KEYBOARD)
280 return;
282 std::string utf8;
283 g_charsetConverter.wToUTF8(m_text2, utf8);
284 bool textChanged = false;
285 switch (m_inputType)
287 case INPUT_TYPE_READONLY:
288 textChanged = false;
289 break;
290 case INPUT_TYPE_NUMBER:
291 textChanged = CGUIDialogNumeric::ShowAndGetNumber(utf8, m_inputHeading);
292 break;
293 case INPUT_TYPE_SECONDS:
294 textChanged = CGUIDialogNumeric::ShowAndGetSeconds(utf8, g_localizeStrings.Get(21420));
295 break;
296 case INPUT_TYPE_TIME:
298 CDateTime dateTime;
299 dateTime.SetFromDBTime(utf8);
300 KODI::TIME::SystemTime time;
301 dateTime.GetAsSystemTime(time);
302 if (CGUIDialogNumeric::ShowAndGetTime(time, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
304 dateTime = CDateTime(time);
305 utf8 = dateTime.GetAsLocalizedTime("", false);
306 textChanged = true;
308 break;
310 case INPUT_TYPE_DATE:
312 CDateTime dateTime;
313 dateTime.SetFromDBDate(utf8);
314 if (dateTime < CDateTime(2000,1, 1, 0, 0, 0))
315 dateTime = CDateTime(2000, 1, 1, 0, 0, 0);
316 KODI::TIME::SystemTime date;
317 dateTime.GetAsSystemTime(date);
318 if (CGUIDialogNumeric::ShowAndGetDate(date, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
320 dateTime = CDateTime(date);
321 utf8 = dateTime.GetAsDBDate();
322 textChanged = true;
324 break;
326 case INPUT_TYPE_IPADDRESS:
327 textChanged = CGUIDialogNumeric::ShowAndGetIPAddress(utf8, m_inputHeading);
328 break;
329 case INPUT_TYPE_SEARCH:
330 textChanged = CGUIKeyboardFactory::ShowAndGetFilter(utf8, true);
331 break;
332 case INPUT_TYPE_FILTER:
333 textChanged = CGUIKeyboardFactory::ShowAndGetFilter(utf8, false);
334 break;
335 case INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW:
336 textChanged = CGUIDialogNumeric::ShowAndVerifyNewPassword(utf8);
337 break;
338 case INPUT_TYPE_PASSWORD_MD5:
339 utf8 = ""; //! @todo Ideally we'd send this to the keyboard and tell the keyboard we have this type of input
340 // fallthrough
341 [[fallthrough]];
342 case INPUT_TYPE_TEXT:
343 default:
344 textChanged = CGUIKeyboardFactory::ShowAndGetInput(utf8, m_inputHeading, true, m_inputType == INPUT_TYPE_PASSWORD || m_inputType == INPUT_TYPE_PASSWORD_MD5);
345 break;
347 if (textChanged)
349 ClearMD5();
350 m_edit.clear();
351 g_charsetConverter.utf8ToW(utf8, m_text2, false);
352 m_cursorPos = m_text2.size();
353 UpdateText();
354 m_cursorPos = m_text2.size();
358 void CGUIEditControl::UpdateText(bool sendUpdate)
360 m_smsTimer.Stop();
361 if (sendUpdate)
363 ValidateInput();
365 SEND_CLICK_MESSAGE(GetID(), GetParentID(), 0);
367 m_textChangeActions.ExecuteActions(GetID(), GetParentID());
369 SetInvalid();
372 void CGUIEditControl::SetInputType(CGUIEditControl::INPUT_TYPE type, const CVariant& heading)
374 m_inputType = type;
375 if (heading.isString())
376 m_inputHeading = heading.asString();
377 else if (heading.isInteger() && heading.asInteger())
378 m_inputHeading = g_localizeStrings.Get(static_cast<uint32_t>(heading.asInteger()));
379 //! @todo Verify the current input string?
382 void CGUIEditControl::RecalcLabelPosition()
384 // ensure that our cursor is within our width
385 ValidateCursor();
387 std::wstring text = GetDisplayedText();
388 m_textWidth = m_label.CalcTextWidth(text + L'|');
389 float beforeCursorWidth = m_label.CalcTextWidth(text.substr(0, m_cursorPos));
390 float afterCursorWidth = m_label.CalcTextWidth(text.substr(0, m_cursorPos) + L'|');
391 float leftTextWidth = m_label.GetRenderRect().Width();
392 float maxTextWidth = m_label.GetMaxWidth();
393 if (leftTextWidth > 0)
394 maxTextWidth -= leftTextWidth + spaceWidth;
396 // if skinner forgot to set height :p
397 if (m_height == 0 && m_label.GetLabelInfo().font)
398 m_height = m_label.GetLabelInfo().font->GetTextHeight(1);
400 if (m_textWidth > maxTextWidth)
401 { // we render taking up the full width, so make sure our cursor position is
402 // within the render window
403 if (m_textOffset + afterCursorWidth > maxTextWidth)
405 // move the position to the left (outside of the viewport)
406 m_textOffset = maxTextWidth - afterCursorWidth;
408 else if (m_textOffset + beforeCursorWidth < 0) // offscreen to the left
410 // otherwise use original position
411 m_textOffset = -beforeCursorWidth;
413 else if (m_textOffset + m_textWidth < maxTextWidth)
414 { // we have more text than we're allowed, but we aren't filling all the space
415 m_textOffset = maxTextWidth - m_textWidth;
418 else
419 m_textOffset = 0;
422 void CGUIEditControl::ProcessText(unsigned int currentTime)
424 if (m_smsTimer.IsRunning() && m_smsTimer.GetElapsedMilliseconds() > smsDelay)
425 UpdateText();
427 if (m_bInvalidated)
429 m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
430 m_label.SetText(m_info.GetLabel(GetParentID()));
431 RecalcLabelPosition();
434 bool changed = false;
436 m_clipRect.x1 = m_label.GetRenderRect().x1;
437 m_clipRect.x2 = m_clipRect.x1 + m_label.GetMaxWidth();
438 m_clipRect.y1 = m_posY;
439 m_clipRect.y2 = m_posY + m_height;
441 // start by rendering the normal text
442 float leftTextWidth = m_label.GetRenderRect().Width();
443 if (leftTextWidth > 0)
445 // render the text on the left
446 changed |= m_label.SetColor(GetTextColor());
447 changed |= m_label.Process(currentTime);
449 m_clipRect.x1 += leftTextWidth + spaceWidth;
452 if (CServiceBroker::GetWinSystem()->GetGfxContext().SetClipRegion(m_clipRect.x1, m_clipRect.y1, m_clipRect.Width(), m_clipRect.Height()))
454 uint32_t align = m_label.GetLabelInfo().align & XBFONT_CENTER_Y; // start aligned left
455 if (m_label2.GetTextWidth() < m_clipRect.Width())
456 { // align text as our text fits
457 if (leftTextWidth > 0)
458 { // right align as we have 2 labels
459 align |= XBFONT_RIGHT;
461 else
462 { // align by whatever the skinner requests
463 align |= (m_label2.GetLabelInfo().align & 3);
466 changed |= m_label2.SetMaxRect(m_clipRect.x1 + m_textOffset, m_posY, m_clipRect.Width() - m_textOffset, m_height);
468 std::wstring text = GetDisplayedText();
469 std::string hint = m_hintInfo.GetLabel(GetParentID());
471 if (!HasFocus() && text.empty() && !hint.empty())
473 changed |= m_label2.SetText(hint);
475 else if ((HasFocus() || GetParentID() == WINDOW_DIALOG_KEYBOARD) &&
476 m_inputType != INPUT_TYPE_READONLY)
478 changed |= SetStyledText(text);
480 else
481 changed |= m_label2.SetTextW(text);
483 changed |= m_label2.SetAlign(align);
484 changed |= m_label2.SetColor(GetTextColor());
485 changed |= m_label2.SetOverflow(CGUILabel::OVER_FLOW_CLIP);
486 changed |= m_label2.Process(currentTime);
487 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreClipRegion();
489 if (changed)
490 MarkDirtyRegion();
493 void CGUIEditControl::RenderText()
495 m_label.Render();
497 if (CServiceBroker::GetWinSystem()->GetGfxContext().SetClipRegion(m_clipRect.x1, m_clipRect.y1, m_clipRect.Width(), m_clipRect.Height()))
499 m_label2.Render();
500 CServiceBroker::GetWinSystem()->GetGfxContext().RestoreClipRegion();
504 CGUILabel::COLOR CGUIEditControl::GetTextColor() const
506 CGUILabel::COLOR color = CGUIButtonControl::GetTextColor();
507 if (color != CGUILabel::COLOR_DISABLED && HasInvalidInput())
508 return CGUILabel::COLOR_INVALID;
510 return color;
513 void CGUIEditControl::SetHint(const GUIINFO::CGUIInfoLabel& hint)
515 m_hintInfo = hint;
518 std::wstring CGUIEditControl::GetDisplayedText() const
520 std::wstring text(m_text2);
521 if (m_inputType == INPUT_TYPE_PASSWORD || m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW)
523 text.clear();
524 if (m_smsTimer.IsRunning())
525 { // using the remove to input, so display the last key input
526 text.append(m_cursorPos - 1, L'*');
527 text.append(1, m_text2[m_cursorPos - 1]);
528 text.append(m_text2.size() - m_cursorPos, L'*');
530 else
531 text.append(m_text2.size(), L'*');
533 else if (!m_edit.empty())
534 text.insert(m_editOffset, m_edit);
535 return text;
538 bool CGUIEditControl::SetStyledText(const std::wstring &text)
540 vecText styled;
541 styled.reserve(text.size() + 1);
543 std::vector<UTILS::COLOR::Color> colors;
544 colors.push_back(m_label.GetLabelInfo().textColor);
545 colors.push_back(m_label.GetLabelInfo().disabledColor);
546 UTILS::COLOR::Color select = m_label.GetLabelInfo().selectedColor;
547 if (!select)
548 select = 0xFFFF0000;
549 colors.push_back(select);
550 colors.push_back(0x00FFFFFF);
552 unsigned int startHighlight = m_cursorPos;
553 unsigned int endHighlight = m_cursorPos + m_edit.size();
554 unsigned int startSelection = m_cursorPos + m_editOffset;
555 unsigned int endSelection = m_cursorPos + m_editOffset + m_editLength;
557 CGUIFont* font = m_label2.GetLabelInfo().font;
558 uint32_t style = (font ? font->GetStyle() : (FONT_STYLE_NORMAL & FONT_STYLE_MASK)) << 24;
560 for (unsigned int i = 0; i < text.size(); i++)
562 uint32_t ch = text[i] | style;
563 if (m_editLength > 0 && startSelection <= i && i < endSelection)
564 ch |= (2 << 16); // highlight the letters we're playing with
565 else if (!m_edit.empty() && (i < startHighlight || i >= endHighlight))
566 ch |= (1 << 16); // dim the bits we're not editing
567 styled.push_back(ch);
570 // show the cursor
571 uint32_t ch = L'|' | style;
572 if ((++m_cursorBlink % 64) > 32)
573 ch |= (3 << 16);
574 styled.insert(styled.begin() + m_cursorPos, ch);
576 return m_label2.SetStyledText(styled, colors);
579 void CGUIEditControl::ValidateCursor()
581 if (m_cursorPos > m_text2.size())
582 m_cursorPos = m_text2.size();
585 void CGUIEditControl::SetLabel(const std::string &text)
587 CGUIButtonControl::SetLabel(text);
588 SetInvalid();
591 void CGUIEditControl::SetLabel2(const std::string &text)
593 m_edit.clear();
594 std::wstring newText;
595 g_charsetConverter.utf8ToW(text, newText, false);
596 if (newText != m_text2)
598 m_isMD5 = (m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW);
599 m_text2 = newText;
600 m_cursorPos = m_text2.size();
601 ValidateInput();
602 SetInvalid();
606 std::string CGUIEditControl::GetLabel2() const
608 std::string text;
609 g_charsetConverter.wToUTF8(m_text2, text);
610 if (m_inputType == INPUT_TYPE_PASSWORD_MD5 && !m_isMD5)
611 return CDigest::Calculate(CDigest::Type::MD5, text);
612 return text;
615 bool CGUIEditControl::ClearMD5()
617 if (!(m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW) || !m_isMD5)
618 return false;
620 m_text2.clear();
621 m_cursorPos = 0;
622 if (m_inputType != INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW)
623 m_isMD5 = false;
624 return true;
627 unsigned int CGUIEditControl::GetCursorPosition() const
629 return m_cursorPos;
632 void CGUIEditControl::SetCursorPosition(unsigned int iPosition)
634 m_cursorPos = iPosition;
637 void CGUIEditControl::OnSMSCharacter(unsigned int key)
639 assert(key < 10);
640 if (m_smsTimer.IsRunning())
642 // we're already entering an SMS character
643 if (key != m_smsLastKey || m_smsTimer.GetElapsedMilliseconds() > smsDelay)
644 { // a different key was clicked than last time, or we have timed out
645 m_smsLastKey = key;
646 m_smsKeyIndex = 0;
648 else
649 { // same key as last time within the appropriate time period
650 m_smsKeyIndex++;
651 if (m_cursorPos)
652 m_text2.erase(--m_cursorPos, 1);
655 else
656 { // key is pressed for the first time
657 m_smsLastKey = key;
658 m_smsKeyIndex = 0;
661 m_smsKeyIndex = m_smsKeyIndex % strlen(smsLetters[key]);
663 m_text2.insert(m_text2.begin() + m_cursorPos++, smsLetters[key][m_smsKeyIndex]);
664 UpdateText();
665 m_smsTimer.StartZero();
668 void CGUIEditControl::OnPasteClipboard()
670 std::wstring unicode_text;
671 std::string utf8_text;
673 // Get text from the clipboard
674 utf8_text = CServiceBroker::GetWinSystem()->GetClipboardText();
675 g_charsetConverter.utf8ToW(utf8_text, unicode_text, false);
677 // Insert the pasted text at the current cursor position.
678 if (unicode_text.length() > 0)
680 std::wstring left_end = m_text2.substr(0, m_cursorPos);
681 std::wstring right_end = m_text2.substr(m_cursorPos);
683 m_text2 = left_end;
684 m_text2.append(unicode_text);
685 m_text2.append(right_end);
686 m_cursorPos += unicode_text.length();
687 UpdateText();
691 void CGUIEditControl::SetInputValidation(StringValidation::Validator inputValidator, void *data /* = NULL */)
693 if (m_inputValidator == inputValidator)
694 return;
696 m_inputValidator = inputValidator;
697 m_inputValidatorData = data;
698 // the input validator has changed, so re-validate the current data
699 ValidateInput();
702 bool CGUIEditControl::ValidateInput(const std::wstring &data) const
704 if (m_inputValidator == NULL)
705 return true;
707 return m_inputValidator(GetLabel2(), m_inputValidatorData != NULL ? m_inputValidatorData : const_cast<void*>((const void*)this));
710 void CGUIEditControl::ValidateInput()
712 // validate the input
713 bool invalid = !ValidateInput(m_text2);
714 // nothing to do if still valid/invalid
715 if (invalid != m_invalidInput)
717 // the validity state has changed so we need to update the control
718 m_invalidInput = invalid;
720 // let the window/dialog know that the validity has changed
721 CGUIMessage msg(GUI_MSG_VALIDITY_CHANGED, GetID(), GetID(), m_invalidInput ? 0 : 1);
722 SendWindowMessage(msg);
724 SetInvalid();
728 void CGUIEditControl::SetFocus(bool focus)
730 m_smsTimer.Stop();
731 CGUIControl::SetFocus(focus);
732 SetInvalid();
735 std::string CGUIEditControl::GetDescriptionByIndex(int index) const
737 if (index == 0)
738 return GetDescription();
739 else if(index == 1)
740 return GetLabel2();
742 return "";