aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjmarshallnz <jcmarsha@gmail.com>2014-08-09 13:10:16 +1200
committerjmarshallnz <jcmarsha@gmail.com>2014-08-09 13:10:16 +1200
commitba51182916400f9e999ea8f27524b958829248a9 (patch)
tree61cda5ffbca247eff5a374b85bc60ea3306136c5
parent63b41ad9da29928edb7ee08fbdf6d952a60b8619 (diff)
parentfe2428df350a426e5f7d6a80d4a82be70a58dc3d (diff)
Merge pull request #5008 from jmarshallnz/edit_keyboard
Use an edit control in the keyboard dialog
-rw-r--r--system/settings/settings.xml5
-rw-r--r--xbmc/Application.cpp46
-rw-r--r--xbmc/dialogs/GUIDialogKeyboardGeneric.cpp439
-rw-r--r--xbmc/dialogs/GUIDialogKeyboardGeneric.h31
-rw-r--r--xbmc/guilib/GUIEditControl.cpp160
-rw-r--r--xbmc/guilib/GUIEditControl.h9
6 files changed, 262 insertions, 428 deletions
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index cc331b7280..32ff1d9213 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2551,11 +2551,6 @@
</setting>
</group>
<group id="2">
- <setting id="input.remoteaskeyboard" type="boolean" label="21449" help="36376">
- <level>1</level>
- <default>false</default>
- <control type="toggle" />
- </setting>
<setting id="input.enablemouse" type="boolean" label="21369" help="36377">
<level>0</level>
<control type="toggle" />
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index a2e4fe8317..2093886a4a 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -2461,35 +2461,31 @@ bool CApplication::OnKey(const CKey& key)
}
if (useKeyboard)
{
- action = CAction(0); // reset our action
- if (CSettings::Get().GetBool("input.remoteaskeyboard"))
+ // use the virtualkeyboard section of the keymap, and send keyboard-specific or navigation
+ // actions through if that's what they are
+ CAction action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key);
+ if (!(action.GetID() == ACTION_MOVE_LEFT ||
+ action.GetID() == ACTION_MOVE_RIGHT ||
+ action.GetID() == ACTION_MOVE_UP ||
+ action.GetID() == ACTION_MOVE_DOWN ||
+ action.GetID() == ACTION_SELECT_ITEM ||
+ action.GetID() == ACTION_ENTER ||
+ action.GetID() == ACTION_PREVIOUS_MENU ||
+ action.GetID() == ACTION_NAV_BACK))
{
- // users remote is executing keyboard commands, so use the virtualkeyboard section of keymap.xml
- // and send those rather than actual keyboard presses. Only for navigation-type commands though
- action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key);
- if (!(action.GetID() == ACTION_MOVE_LEFT ||
- action.GetID() == ACTION_MOVE_RIGHT ||
- action.GetID() == ACTION_MOVE_UP ||
- action.GetID() == ACTION_MOVE_DOWN ||
- action.GetID() == ACTION_SELECT_ITEM ||
- action.GetID() == ACTION_ENTER ||
- action.GetID() == ACTION_PREVIOUS_MENU ||
- action.GetID() == ACTION_NAV_BACK))
- {
- // the action isn't plain navigation - check for a keyboard-specific keymap
- action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key, false);
- if (!(action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9) ||
- action.GetID() == ACTION_BACKSPACE ||
- action.GetID() == ACTION_SHIFT ||
- action.GetID() == ACTION_SYMBOLS ||
- action.GetID() == ACTION_CURSOR_LEFT ||
- action.GetID() == ACTION_CURSOR_RIGHT)
- action = CAction(0); // don't bother with this action
- }
+ // the action isn't plain navigation - check for a keyboard-specific keymap
+ action = CButtonTranslator::GetInstance().GetAction(WINDOW_DIALOG_KEYBOARD, key, false);
+ if (!(action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9) ||
+ action.GetID() == ACTION_BACKSPACE ||
+ action.GetID() == ACTION_SHIFT ||
+ action.GetID() == ACTION_SYMBOLS ||
+ action.GetID() == ACTION_CURSOR_LEFT ||
+ action.GetID() == ACTION_CURSOR_RIGHT)
+ action = CAction(0); // don't bother with this action
}
+ // else pass the keys through directly
if (!action.GetID())
{
- // keyboard entry - pass the keys through directly
if (key.GetFromService())
action = CAction(key.GetButtonCode() != KEY_INVALID ? key.GetButtonCode() : 0, key.GetUnicode());
else
diff --git a/xbmc/dialogs/GUIDialogKeyboardGeneric.cpp b/xbmc/dialogs/GUIDialogKeyboardGeneric.cpp
index f8cd48ddc8..2a7902a73f 100644
--- a/xbmc/dialogs/GUIDialogKeyboardGeneric.cpp
+++ b/xbmc/dialogs/GUIDialogKeyboardGeneric.cpp
@@ -20,7 +20,8 @@
#include "interfaces/AnnouncementManager.h"
#include "input/XBMC_vkeys.h"
-#include "guilib/GUILabelControl.h"
+#include "guilib/GUIEditControl.h"
+#include "guilib/GUILabelControl.h" // for backward compatibility
#include "guilib/GUIWindowManager.h"
#include "guilib/Key.h"
#include "guilib/LocalizeStrings.h"
@@ -28,15 +29,9 @@
#include "GUIDialogNumeric.h"
#include "GUIDialogOK.h"
#include "GUIDialogKeyboardGeneric.h"
-#include "utils/TimeUtils.h"
#include "utils/RegExp.h"
#include "ApplicationMessenger.h"
-#include "windowing/WindowingFactory.h"
-#include "utils/CharsetConverter.h"
-
-#if defined(TARGET_DARWIN)
-#include "osx/CocoaInterface.h"
-#endif
+#include "addons/Skin.h" // for backward compatibility
// Symbol mapping (based on MS virtual keyboard - may need improving)
static char symbol_map[37] = ")!@#$%^&*([]{}-_=+;:\'\",.<>/?\\|`~ ";
@@ -51,8 +46,9 @@ static char symbol_map[37] = ")!@#$%^&*([]{}-_=+;:\'\",.<>/?\\|`~ ";
#define CTL_BUTTON_IP_ADDRESS 307
#define CTL_BUTTON_CLEAR 308
-#define CTL_LABEL_EDIT 310
+#define CTL_LABEL_EDIT 310 // backward compatibility
#define CTL_LABEL_HEADING 311
+#define CTL_EDIT 312
#define CTL_BUTTON_BACKSPACE 8
@@ -60,7 +56,6 @@ static char symbolButtons[] = "._-@/\\";
#define NUM_SYMBOLS sizeof(symbolButtons) - 1
#define SEARCH_DELAY 1000
-#define REMOTE_SMS_DELAY 1000
CGUIDialogKeyboardGeneric::CGUIDialogKeyboardGeneric()
: CGUIDialog(WINDOW_DIALOG_KEYBOARD, "DialogKeyboard.xml")
@@ -72,12 +67,34 @@ CGUIDialogKeyboardGeneric::CGUIDialogKeyboardGeneric()
m_hiddenInput = false;
m_keyType = LOWER;
m_strHeading = "";
- m_iCursorPos = 0;
- m_iEditingOffset = 0;
- m_lastRemoteClickTime = 0;
m_loadType = KEEP_IN_MEMORY;
}
+void CGUIDialogKeyboardGeneric::OnWindowLoaded()
+{
+ CGUIEditControl *edit = (CGUIEditControl *)GetControl(CTL_EDIT);
+ if (!edit && g_SkinInfo && g_SkinInfo->APIVersion() < ADDON::AddonVersion("5.2.0"))
+ {
+ // backward compatibility: convert label to edit control
+ CGUILabelControl *label = (CGUILabelControl *)GetControl(CTL_LABEL_EDIT);
+ if (label && label->GetControlType() == CGUIControl::GUICONTROL_LABEL)
+ {
+ // create a new edit control positioned in the same spot
+ edit = new CGUIEditControl(label->GetParentID(), CTL_EDIT, label->GetXPosition(), label->GetYPosition(),
+ label->GetWidth(), label->GetHeight(), CTextureInfo(), CTextureInfo(),
+ label->GetLabelInfo(), "");
+ AddControl(edit);
+ m_defaultControl = CTL_EDIT;
+ m_defaultAlways = true;
+ }
+ }
+ // show the cursor always
+ if (edit)
+ edit->SetShowCursorAlways(true);
+
+ CGUIDialog::OnWindowLoaded();
+}
+
void CGUIDialogKeyboardGeneric::OnInitWindow()
{
CGUIDialog::OnInitWindow();
@@ -87,12 +104,6 @@ void CGUIDialogKeyboardGeneric::OnInitWindow()
// set alphabetic (capitals)
UpdateButtons();
- CGUILabelControl* pEdit = dynamic_cast<CGUILabelControl*>(GetControl(CTL_LABEL_EDIT));
- if (pEdit)
- {
- pEdit->ShowCursor();
- }
-
// set heading
if (!m_strHeading.empty())
{
@@ -103,7 +114,12 @@ void CGUIDialogKeyboardGeneric::OnInitWindow()
{
SET_CONTROL_HIDDEN(CTL_LABEL_HEADING);
}
- g_Windowing.EnableTextInput(true);
+ // set type
+ {
+ CGUIMessage msg(GUI_MSG_SET_TYPE, GetID(), CTL_EDIT, m_hiddenInput ? CGUIEditControl::INPUT_TYPE_PASSWORD : CGUIEditControl::INPUT_TYPE_TEXT);
+ OnMessage(msg);
+ }
+ SetEditText(m_text);
CVariant data;
data["title"] = m_strHeading;
@@ -129,12 +145,7 @@ bool CGUIDialogKeyboardGeneric::OnAction(const CAction &action)
}
else if (action.GetID() == ACTION_CURSOR_RIGHT)
{
- if (m_strEditing.empty() && (unsigned int) GetCursorPos() == m_strEdit.size() && (m_strEdit.size() == 0 || m_strEdit[m_strEdit.size() - 1] != ' '))
- { // add a space
- Character(L' ');
- }
- else
- MoveCursor(1);
+ MoveCursor(1);
}
else if (action.GetID() == ACTION_SHIFT)
{
@@ -144,104 +155,20 @@ bool CGUIDialogKeyboardGeneric::OnAction(const CAction &action)
{
OnSymbols();
}
- else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
- {
- OnRemoteNumberClick(action.GetID());
- }
- else if (action.GetID() == ACTION_PASTE)
- {
- OnPasteClipboard();
- }
- else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_ASCII)
- { // input from the keyboard (vkey, not ascii)
- if (!m_strEditing.empty())
- return handled;
- uint8_t b = action.GetID() & 0xFF;
- if (b == XBMCVK_HOME)
- {
- SetCursorPos(0);
- }
- else if (b == XBMCVK_END)
- {
- SetCursorPos(m_strEdit.size());
- }
- else if (b == XBMCVK_LEFT)
- {
- MoveCursor( -1);
- }
- else if (b == XBMCVK_RIGHT)
- {
- MoveCursor(1);
- }
- else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
- {
- OnOK();
- }
- else if (b == XBMCVK_DELETE)
- {
- if (GetCursorPos() < (int)m_strEdit.size())
- {
- MoveCursor(1);
- Backspace();
- }
- }
- else if (b == XBMCVK_BACK) Backspace();
- else if (b == XBMCVK_ESCAPE) Close();
- }
else if (action.GetID() >= KEY_ASCII)
- { // input from the keyboard
- //char ch = action.GetID() & 0xFF;
- int ch = action.GetUnicode();
-
- // Ignore non-printing characters
- if ( !((0 <= ch && ch < 0x8) || (0xE <= ch && ch < 0x1B) || (0x1C <= ch && ch < 0x20)) )
- {
- switch (ch)
- {
- case 0x8: // backspace
- Backspace();
- break;
- case 0x9: // Tab (do nothing)
- case 0xB: // Non-printing character, ignore
- case 0xC: // Non-printing character, ignore
- break;
- case 0xA: // enter
- case 0xD: // enter
- OnOK();
- break;
- case 0x1B: // escape
- Close();
- break;
- case 0x7F: // Delete
- if (GetCursorPos() < (int)m_strEdit.size())
- {
- MoveCursor(1);
- Backspace();
- }
- break;
- default: //use character input
- // When we support text input method, we only accept text by gui text message.
- if (!g_Windowing.IsTextInputEnabled())
- Character(action.GetUnicode());
- break;
- }
- }
+ { // send action to the edit control
+ CGUIControl *edit = GetControl(CTL_EDIT);
+ if (edit)
+ edit->OnAction(action);
}
else // unhandled by us - let's see if the baseclass wants it
handled = CGUIDialog::OnAction(action);
- if (handled && m_pCharCallback)
- { // we did _something_, so make sure our search message filter is reset
- m_pCharCallback(this, GetText());
- }
return handled;
}
bool CGUIDialogKeyboardGeneric::OnMessage(CGUIMessage& message)
{
- CGUIDialog::OnMessage(message);
-
-
switch ( message.GetMessage() )
{
case GUI_MSG_CLICKED:
@@ -279,10 +206,21 @@ bool CGUIDialogKeyboardGeneric::OnMessage(CGUIMessage& message)
OnIPAddress();
break;
case CTL_BUTTON_CLEAR:
- SetText("");
+ SetEditText("");
break;
+ case CTL_EDIT:
+ {
+ CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CTL_EDIT);
+ OnMessage(msg);
+ // update callback I guess?
+ if (m_pCharCallback)
+ { // we did _something_, so make sure our search message filter is reset
+ m_pCharCallback(this, msg.GetLabel());
+ }
+ m_text = msg.GetLabel();
+ return true;
+ }
default:
- m_lastRemoteKeyClicked = 0;
OnClickButton(iControl);
break;
}
@@ -290,145 +228,62 @@ bool CGUIDialogKeyboardGeneric::OnMessage(CGUIMessage& message)
break;
case GUI_MSG_SET_TEXT:
- SetText(message.GetLabel());
-
- // close the dialog if requested
- if (message.GetParam1() > 0)
- OnOK();
- break;
-
case GUI_MSG_INPUT_TEXT:
- InputText(message.GetLabel());
- break;
-
case GUI_MSG_INPUT_TEXT_EDIT:
- InputTextEditing(message.GetLabel(), message.GetParam1(), message.GetParam2());
- break;
+ {
+ // ensure this goes to the edit control
+ CGUIControl *edit = GetControl(CTL_EDIT);
+ if (edit)
+ edit->OnMessage(message);
+
+ // close the dialog if requested
+ if (message.GetMessage() == GUI_MSG_SET_TEXT && message.GetParam1() > 0)
+ OnOK();
+ return true;
+ }
}
- return true;
+ return CGUIDialog::OnMessage(message);
}
-void CGUIDialogKeyboardGeneric::SetText(const std::string& aTextString)
+void CGUIDialogKeyboardGeneric::SetEditText(const std::string &text)
{
- m_strEdit.clear();
- m_strEditing.clear();
- m_iEditingOffset = 0;
- g_charsetConverter.utf8ToW(aTextString, m_strEdit);
- UpdateLabel();
- SetCursorPos(m_strEdit.size());
+ CGUIMessage msg(GUI_MSG_SET_TEXT, GetID(), CTL_EDIT);
+ msg.SetLabel(text);
+ OnMessage(msg);
}
-void CGUIDialogKeyboardGeneric::InputText(const std::string& aTextString)
+void CGUIDialogKeyboardGeneric::SetText(const std::string& text)
{
- std::wstring newStr;
- g_charsetConverter.utf8ToW(aTextString, newStr);
- if (!newStr.empty())
- {
- m_strEditing.clear();
- m_iEditingOffset = 0;
- m_strEdit.insert(GetCursorPos(), newStr);
- UpdateLabel();
- MoveCursor(newStr.size());
- }
+ m_text = text;
}
-void CGUIDialogKeyboardGeneric::InputTextEditing(const std::string& aTextString, int start, int length)
+const std::string &CGUIDialogKeyboardGeneric::GetText() const
{
- m_strEditing.clear();
- m_iEditingOffset = start;
- m_iEditingLength = length;
- g_charsetConverter.utf8ToW(aTextString, m_strEditing);
-// CLog::Log(LOGDEBUG, "CGUIDialogKeyboardGeneric::InputTextEditing len %lu range(%d, %d) -> range len %d", m_strEditing.size(), m_iEditingOffset, length, m_iEditingLength);
- UpdateLabel();
- SetCursorPos(GetCursorPos());
+ return m_text;
}
-std::string CGUIDialogKeyboardGeneric::GetText() const
-{
- std::string utf8String;
- g_charsetConverter.wToUTF8(m_strEdit, utf8String);
- return utf8String;
-}
-
-void CGUIDialogKeyboardGeneric::Character(WCHAR ch)
+void CGUIDialogKeyboardGeneric::Character(char ch)
{
if (!ch) return;
- m_strEditing.clear();
- m_iEditingOffset = 0;
- // TODO: May have to make this routine take a WCHAR for the symbols?
- m_strEdit.insert(GetCursorPos(), 1, ch);
- UpdateLabel();
- MoveCursor(1);
-}
-
-void CGUIDialogKeyboardGeneric::FrameMove()
-{
- // reset the hide state of the label when the remote
- // sms style input times out
- if (m_lastRemoteClickTime && m_lastRemoteClickTime + REMOTE_SMS_DELAY < CTimeUtils::GetFrameTime())
- {
- // finished inputting a sms style character - turn off our shift and symbol states
- ResetShiftAndSymbols();
- }
- CGUIDialog::FrameMove();
-}
-void CGUIDialogKeyboardGeneric::UpdateLabel() // FIXME seems to be called twice for one USB SDL keyboard action/character
-{
- CGUILabelControl* pEdit = dynamic_cast<CGUILabelControl*>(GetControl(CTL_LABEL_EDIT));
- if (pEdit)
+ std::string character(1, ch);
+ // send text to edit control
+ CGUIControl *edit = GetControl(CTL_EDIT);
+ if (edit)
{
- std::wstring edit = m_strEdit;
- pEdit->SetHighlight(0, 0);
- pEdit->SetSelection(0, 0);
- if (m_hiddenInput)
- { // convert to *'s
- edit.clear();
- if (m_lastRemoteClickTime + REMOTE_SMS_DELAY > CTimeUtils::GetFrameTime() && m_iCursorPos > 0)
- { // using the remove to input, so display the last key input
- edit.append(m_iCursorPos - 1, L'*');
- edit.append(1, m_strEdit[m_iCursorPos - 1]);
- }
- else
- edit.append(m_strEdit.size(), L'*');
- }
- else if (!m_strEditing.empty())
- {
- edit.insert(m_iCursorPos, m_strEditing);
- pEdit->SetHighlight(m_iCursorPos, m_iCursorPos + m_strEditing.size());
- if (m_iEditingLength > 0)
- pEdit->SetSelection(m_iCursorPos + m_iEditingOffset, m_iCursorPos + m_iEditingOffset + m_iEditingLength);
- }
- // convert back to utf8
- std::string utf8Edit;
- g_charsetConverter.wToUTF8(edit, utf8Edit);
- pEdit->SetLabel(utf8Edit);
- // Send off a search message
- unsigned int now = CTimeUtils::GetFrameTime();
- // don't send until the REMOTE_SMS_DELAY has passed
- if (m_lastRemoteClickTime && m_lastRemoteClickTime + REMOTE_SMS_DELAY >= now)
- return;
-
- if (m_pCharCallback)
- {
- // do not send editing text comes from system input method
- if (!m_hiddenInput && !m_strEditing.empty())
- g_charsetConverter.wToUTF8(m_strEdit, utf8Edit);
- m_pCharCallback(this, utf8Edit);
- }
+ CGUIMessage msg(GUI_MSG_INPUT_TEXT, GetID(), CTL_EDIT);
+ msg.SetLabel(character);
+ edit->OnMessage(msg);
}
}
void CGUIDialogKeyboardGeneric::Backspace()
{
- int iPos = GetCursorPos();
- if (iPos > 0)
- {
- m_strEdit.erase(iPos - 1, 1);
- MoveCursor(-1);
- UpdateLabel();
- }
+ // send action to edit control
+ CGUIControl *edit = GetControl(CTL_EDIT);
+ if (edit)
+ edit->OnAction(CAction(ACTION_BACKSPACE));
}
void CGUIDialogKeyboardGeneric::OnClickButton(int iButtonControl)
@@ -441,48 +296,6 @@ void CGUIDialogKeyboardGeneric::OnClickButton(int iButtonControl)
Character(GetCharacter(iButtonControl));
}
-void CGUIDialogKeyboardGeneric::OnRemoteNumberClick(int key)
-{
- unsigned int now = CTimeUtils::GetFrameTime();
-
- if (m_lastRemoteClickTime)
- { // a remote key has been pressed
- if (key != m_lastRemoteKeyClicked || m_lastRemoteClickTime + REMOTE_SMS_DELAY < now)
- { // a different key was clicked than last time, or we have timed out
- m_lastRemoteKeyClicked = key;
- m_indexInSeries = 0;
- // reset our shift and symbol states, and update our label to ensure the search filter is sent
- ResetShiftAndSymbols();
- UpdateLabel();
- }
- else
- { // same key as last time within the appropriate time period
- m_indexInSeries++;
- Backspace();
- }
- }
- else
- { // key is pressed for the first time
- m_lastRemoteKeyClicked = key;
- m_indexInSeries = 0;
- }
-
- int arrayIndex = key - REMOTE_0;
- m_indexInSeries = m_indexInSeries % strlen(s_charsSeries[arrayIndex]);
- m_lastRemoteClickTime = now;
-
- // Select the character that will be pressed
- const char* characterPressed = s_charsSeries[arrayIndex];
- characterPressed += m_indexInSeries;
-
- // use caps where appropriate
- char ch = *characterPressed;
- bool caps = (m_keyType == CAPS && !m_bShift) || (m_keyType == LOWER && m_bShift);
- if (!caps && *characterPressed >= 'A' && *characterPressed <= 'Z')
- ch += 32;
- Character(ch);
-}
-
char CGUIDialogKeyboardGeneric::GetCharacter(int iButton)
{
// First the numbers
@@ -579,34 +392,14 @@ void CGUIDialogKeyboardGeneric::OnDeinitWindow(int nextWindowID)
// reset the heading (we don't always have this)
m_strHeading = "";
- g_Windowing.EnableTextInput(false);
ANNOUNCEMENT::CAnnouncementManager::Get().Announce(ANNOUNCEMENT::Input, "xbmc", "OnInputFinished");
}
void CGUIDialogKeyboardGeneric::MoveCursor(int iAmount)
{
- if (!m_strEditing.empty())
- return;
- SetCursorPos(GetCursorPos() + iAmount);
-}
-
-void CGUIDialogKeyboardGeneric::SetCursorPos(int iPos)
-{
- if (iPos < 0)
- iPos = 0;
- else if (iPos > (int)m_strEdit.size())
- iPos = (int)m_strEdit.size();
- m_iCursorPos = iPos;
- CGUILabelControl* pEdit = dynamic_cast<CGUILabelControl*>(GetControl(CTL_LABEL_EDIT));
- if (pEdit)
- {
- pEdit->SetCursorPos(m_iCursorPos + (m_hiddenInput ? 0 : m_iEditingOffset));
- }
-}
-
-int CGUIDialogKeyboardGeneric::GetCursorPos() const
-{
- return m_iCursorPos;
+ CGUIControl *edit = GetControl(CTL_EDIT);
+ if (edit)
+ edit->OnAction(CAction(iAmount < 0 ? ACTION_CURSOR_LEFT : ACTION_CURSOR_RIGHT));
}
void CGUIDialogKeyboardGeneric::OnSymbols()
@@ -628,40 +421,23 @@ void CGUIDialogKeyboardGeneric::OnIPAddress()
{
// find any IP address in the current string if there is any
// We match to #.#.#.#
- std::string utf8String;
- g_charsetConverter.wToUTF8(m_strEdit, utf8String);
+ std::string text = GetText();
std::string ip;
CRegExp reg;
reg.RegComp("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
- int start = reg.RegFind(utf8String.c_str());
+ int start = reg.RegFind(text.c_str());
int length = 0;
if (start > -1)
{
length = reg.GetSubLength(0);
- ip = utf8String.substr(start, length);
+ ip = text.substr(start, length);
}
else
- start = utf8String.size();
+ start = text.size();
if (CGUIDialogNumeric::ShowAndGetIPAddress(ip, g_localizeStrings.Get(14068)))
- {
- utf8String = utf8String.substr(0, start) + ip.c_str() + utf8String.substr(start + length);
- g_charsetConverter.utf8ToW(utf8String, m_strEdit);
- UpdateLabel();
- CGUILabelControl* pEdit = dynamic_cast<CGUILabelControl*>(GetControl(CTL_LABEL_EDIT));
- if (pEdit)
- pEdit->SetCursorPos(m_strEdit.size());
- }
+ SetEditText(text.substr(0, start) + ip.c_str() + text.substr(start + length));
}
-void CGUIDialogKeyboardGeneric::ResetShiftAndSymbols()
-{
- if (m_bShift) OnShift();
- if (m_keyType == SYMBOLS) OnSymbols();
- m_lastRemoteClickTime = 0;
-}
-
-const char* CGUIDialogKeyboardGeneric::s_charsSeries[10] = { " 0!@#$%^&*()[]{}<>/\\|", ".,1;:\'\"-+_=?`~", "ABC2", "DEF3", "GHI4", "JKL5", "MNO6", "PQRS7", "TUV8", "WXYZ9" };
-
void CGUIDialogKeyboardGeneric::SetControlLabel(int id, const std::string &label)
{ // find all controls with this id, and set all their labels
CGUIMessage message(GUI_MSG_LABEL_SET, GetID(), id);
@@ -721,30 +497,3 @@ bool CGUIDialogKeyboardGeneric::ShowAndGetInput(char_callback_t pCallback, const
}
else return false;
}
-
-void CGUIDialogKeyboardGeneric::OnPasteClipboard(void)
-{
- std::wstring unicode_text;
- std::string utf8_text;
-
-// Get text from the clipboard
- utf8_text = g_Windowing.GetClipboardText();
-
- // Insert the pasted text at the current cursor position.
- if (utf8_text.length() > 0)
- {
- g_charsetConverter.utf8ToW(utf8_text, unicode_text);
-
- size_t i = GetCursorPos();
- if (i > m_strEdit.size())
- i = m_strEdit.size();
- std::wstring left_end = m_strEdit.substr(0, i);
- std::wstring right_end = m_strEdit.substr(i);
-
- m_strEdit = left_end;
- m_strEdit.append(unicode_text);
- m_strEdit.append(right_end);
- UpdateLabel();
- MoveCursor(unicode_text.length());
- }
-}
diff --git a/xbmc/dialogs/GUIDialogKeyboardGeneric.h b/xbmc/dialogs/GUIDialogKeyboardGeneric.h
index f3236b9d7e..260eeb52b0 100644
--- a/xbmc/dialogs/GUIDialogKeyboardGeneric.h
+++ b/xbmc/dialogs/GUIDialogKeyboardGeneric.h
@@ -36,19 +36,14 @@ class CGUIDialogKeyboardGeneric : public CGUIDialog, public CGUIKeyboard
virtual void Cancel();
virtual int GetWindowId() const;
- //CGUIDialog Interface
- virtual void FrameMove();
void SetHeading(const std::string& heading);
- void SetText(const std::string& aTextString);
- void InputText(const std::string& aTextString);
- void InputTextEditing(const std::string& aTextString, int start, int length);
- std::string GetText() const;
+ void SetText(const std::string& text);
+ const std::string &GetText() const;
bool IsConfirmed() { return m_bIsConfirmed; };
void SetHiddenInput(bool hiddenInput) { m_hiddenInput = hiddenInput; };
- void Character(WCHAR wch);
- void OnPasteClipboard(void);
protected:
+ virtual void OnWindowLoaded();
virtual void OnInitWindow();
virtual bool OnAction(const CAction &action);
virtual bool OnMessage(CGUIMessage& message);
@@ -56,41 +51,27 @@ class CGUIDialogKeyboardGeneric : public CGUIDialog, public CGUIKeyboard
void SetControlLabel(int id, const std::string &label);
void OnShift();
void MoveCursor(int iAmount);
- void SetCursorPos(int iPos);
- int GetCursorPos() const;
void OnSymbols();
void OnIPAddress();
void OnOK();
private:
void OnClickButton(int iButtonControl);
- void OnRemoteNumberClick(int key);
void UpdateButtons();
char GetCharacter(int iButton);
- void UpdateLabel();
- void ResetShiftAndSymbols();
+ void Character(char ch);
void Backspace();
+ void SetEditText(const std::string& text);
void SendSearchMessage();
- std::wstring m_strEdit;
- int m_iCursorPos;
-
- // holds the spelling region of keystrokes/text generated from 'input method'
- std::wstring m_strEditing;
- int m_iEditingOffset;
- int m_iEditingLength;
-
bool m_bIsConfirmed;
KEYBOARD m_keyType;
int m_iMode;
bool m_bShift;
bool m_hiddenInput;
- unsigned int m_lastRemoteClickTime;
- WORD m_lastRemoteKeyClicked;
- int m_indexInSeries;
std::string m_strHeading;
- static const char* s_charsSeries[10];
+ std::string m_text; ///< current text
char_callback_t m_pCharCallback;
diff --git a/xbmc/guilib/GUIEditControl.cpp b/xbmc/guilib/GUIEditControl.cpp
index f422d71a2e..76f7f54983 100644
--- a/xbmc/guilib/GUIEditControl.cpp
+++ b/xbmc/guilib/GUIEditControl.cpp
@@ -29,6 +29,7 @@
#include "XBDateTime.h"
#include "windowing/WindowingFactory.h"
#include "utils/md5.h"
+#include "GUIUserMessages.h"
#if defined(TARGET_DARWIN)
#include "osx/CocoaInterface.h"
@@ -59,6 +60,7 @@ void CGUIEditControl::DefaultConstructor()
m_textWidth = GetWidth();
m_cursorPos = 0;
m_cursorBlink = 0;
+ m_cursorShowAlways = false;
m_inputHeading = 0;
m_inputType = INPUT_TYPE_TEXT;
m_smsLastKey = 0;
@@ -69,6 +71,8 @@ void CGUIEditControl::DefaultConstructor()
m_invalidInput = false;
m_inputValidator = NULL;
m_inputValidatorData = NULL;
+ m_editLength = 0;
+ m_editOffset = 0;
}
CGUIEditControl::CGUIEditControl(const CGUIButtonControl &button)
@@ -93,17 +97,31 @@ bool CGUIEditControl::OnMessage(CGUIMessage &message)
message.SetLabel(GetLabel2());
return true;
}
- else if (message.GetMessage() == GUI_MSG_SETFOCUS ||
- message.GetMessage() == GUI_MSG_LOSTFOCUS)
- {
- m_smsTimer.Stop();
- }
else if (message.GetMessage() == GUI_MSG_SET_TEXT &&
((message.GetControlId() <= 0 && HasFocus()) || (message.GetControlId() == GetID())))
{
SetLabel2(message.GetLabel());
UpdateText();
}
+ else if (message.GetMessage() == GUI_MSG_INPUT_TEXT && !message.GetLabel().empty()
+ && (HasFocus() || message.GetControlId() == GetID()))
+ {
+ m_edit.clear();
+ std::wstring str;
+ g_charsetConverter.utf8ToW(message.GetLabel(), str);
+ m_text2.insert(m_cursorPos, str);
+ m_cursorPos += str.size();
+ UpdateText();
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_INPUT_TEXT_EDIT && HasFocus())
+ {
+ g_charsetConverter.utf8ToW(message.GetLabel(), m_edit);
+ m_editOffset = message.GetParam1();
+ m_editLength = message.GetParam2();
+ UpdateText(false);
+ return true;
+ }
return CGUIButtonControl::OnMessage(message);
}
@@ -124,7 +142,8 @@ bool CGUIEditControl::OnAction(const CAction &action)
}
return true;
}
- else if (action.GetID() == ACTION_MOVE_LEFT)
+ else if (action.GetID() == ACTION_MOVE_LEFT ||
+ action.GetID() == ACTION_CURSOR_LEFT)
{
if (m_cursorPos > 0)
{
@@ -133,7 +152,8 @@ bool CGUIEditControl::OnAction(const CAction &action)
return true;
}
}
- else if (action.GetID() == ACTION_MOVE_RIGHT)
+ else if (action.GetID() == ACTION_MOVE_RIGHT ||
+ action.GetID() == ACTION_CURSOR_RIGHT)
{
if ((unsigned int) m_cursorPos < m_text2.size())
{
@@ -148,7 +168,7 @@ bool CGUIEditControl::OnAction(const CAction &action)
OnPasteClipboard();
return true;
}
- else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_ASCII)
+ else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_ASCII && !m_edit.empty())
{
// input from the keyboard (vkey, not ascii)
BYTE b = action.GetID() & 0xFF;
@@ -196,13 +216,29 @@ bool CGUIEditControl::OnAction(const CAction &action)
}
return true;
}
+ else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
+ {
+ // enter - send click message, but otherwise ignore
+ SEND_CLICK_MESSAGE(GetID(), GetParentID(), 1);
+ return true;
+ }
+ else if (b == XBMCVK_ESCAPE)
+ { // escape - fallthrough to default action
+ return CGUIButtonControl::OnAction(action);
+ }
}
else if (action.GetID() >= KEY_ASCII)
{
// input from the keyboard
- switch (action.GetUnicode())
+ int ch = action.GetUnicode();
+ // ignore non-printing characters
+ if ( !((0 <= ch && ch < 0x8) || (0xE <= ch && ch < 0x1B) || (0x1C <= ch && ch < 0x20)) )
+ {
+ switch (ch)
{
- case '\t':
+ case 9: // tab, ignore
+ case 11: // Non-printing character, ignore
+ case 12: // Non-printing character, ignore
break;
case 10:
case 13:
@@ -225,19 +261,34 @@ bool CGUIEditControl::OnAction(const CAction &action)
}
break;
}
+ case 127:
+ { // delete
+ if (m_cursorPos < m_text2.length())
+ {
+ if (!ClearMD5())
+ m_text2.erase(m_cursorPos, 1);
+ }
+ break;
+ }
default:
{
- ClearMD5();
- m_text2.insert(m_text2.begin() + m_cursorPos++, (WCHAR)action.GetUnicode());
+ if (!g_Windowing.IsTextInputEnabled())
+ {
+ ClearMD5();
+ m_edit.clear();
+ m_text2.insert(m_text2.begin() + m_cursorPos++, (WCHAR)action.GetUnicode());
+ }
break;
}
}
UpdateText();
return true;
+ }
}
else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
{ // input from the remote
ClearMD5();
+ m_edit.clear();
if (m_inputType == INPUT_TYPE_FILTER)
{ // filtering - use single number presses
m_text2.insert(m_text2.begin() + m_cursorPos++, L'0' + (action.GetID() - REMOTE_0));
@@ -326,6 +377,7 @@ void CGUIEditControl::OnClick()
if (textChanged)
{
ClearMD5();
+ m_edit.clear();
g_charsetConverter.utf8ToW(utf8, m_text2);
m_cursorPos = m_text2.size();
UpdateText();
@@ -438,23 +490,20 @@ void CGUIEditControl::ProcessText(unsigned int currentTime)
align |= (m_label2.GetLabelInfo().align & 3);
}
}
+ changed |= m_label2.SetMaxRect(m_clipRect.x1 + m_textOffset, m_posY, m_clipRect.Width() - m_textOffset, m_height);
+
CStdStringW text = GetDisplayedText();
- // add the cursor if we're focused
- if (HasFocus() && m_inputType != INPUT_TYPE_READONLY)
+ // add the cursor and highlighting if we're focused
+ if ((HasFocus() || m_cursorShowAlways) && m_inputType != INPUT_TYPE_READONLY)
+ changed |= SetStyledText(text);
+ else
{
- CStdStringW col;
- if ((m_focusCounter % 64) > 32)
- col = L"|";
+ if (text.empty())
+ changed |= m_label2.SetText(m_hintInfo.GetLabel(GetParentID()));
else
- col = L"[COLOR 00FFFFFF]|[/COLOR]";
- text.insert(m_cursorPos, col);
+ changed |= m_label2.SetTextW(text);
}
- changed |= m_label2.SetMaxRect(m_clipRect.x1 + m_textOffset, m_posY, m_clipRect.Width() - m_textOffset, m_height);
- if (text.empty())
- changed |= m_label2.SetText(m_hintInfo.GetLabel(GetParentID()));
- else
- changed |= m_label2.SetTextW(text);
changed |= m_label2.SetAlign(align);
changed |= m_label2.SetColor(GetTextColor());
changed |= m_label2.SetOverflow(CGUILabel::OVER_FLOW_CLIP);
@@ -492,13 +541,60 @@ void CGUIEditControl::SetHint(const CGUIInfoLabel& hint)
CStdStringW CGUIEditControl::GetDisplayedText() const
{
+ CStdStringW text(m_text2);
if (m_inputType == INPUT_TYPE_PASSWORD || m_inputType == INPUT_TYPE_PASSWORD_MD5 || m_inputType == INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW)
{
- CStdStringW text;
- text.append(m_text2.size(), L'*');
- return text;
+ text.clear();
+ if (m_smsTimer.IsRunning())
+ { // using the remove to input, so display the last key input
+ text.append(m_cursorPos - 1, L'*');
+ text.append(1, m_text2[m_cursorPos - 1]);
+ text.append(m_text2.size() - m_cursorPos, L'*');
+ }
+ else
+ text.append(m_text2.size(), L'*');;
+ }
+ else if (!m_edit.empty())
+ text.insert(m_editOffset, m_edit);
+ return text;
+}
+
+bool CGUIEditControl::SetStyledText(const CStdStringW &text)
+{
+ vecText styled;
+ styled.reserve(text.size() + 1);
+
+ vecColors colors;
+ colors.push_back(m_label.GetLabelInfo().textColor);
+ colors.push_back(m_label.GetLabelInfo().disabledColor);
+ color_t select = m_label.GetLabelInfo().selectedColor;
+ if (!select)
+ select = 0xFFFF0000;
+ colors.push_back(select);
+ colors.push_back(0x00FFFFFF);
+
+ unsigned int startHighlight = m_cursorPos;
+ unsigned int endHighlight = m_cursorPos + m_edit.size();
+ unsigned int startSelection = m_cursorPos + m_editOffset;
+ unsigned int endSelection = m_cursorPos + m_editOffset + m_editLength;
+
+ for (unsigned int i = 0; i < text.size(); i++)
+ {
+ unsigned int ch = text[i];
+ if (m_editLength > 0 && startSelection <= i && i < endSelection)
+ ch |= (2 << 16); // highlight the letters we're playing with
+ else if (!m_edit.empty() && (i < startHighlight || i >= endHighlight))
+ ch |= (1 << 16); // dim the bits we're not editing
+ styled.push_back(ch);
}
- return m_text2;
+
+ // show the cursor
+ unsigned int ch = L'|';
+ if ((++m_cursorBlink % 64) > 32)
+ ch |= (3 << 16);
+ styled.insert(styled.begin() + m_cursorPos, ch);
+
+ return m_label2.SetStyledText(styled, colors);
}
void CGUIEditControl::ValidateCursor()
@@ -515,6 +611,7 @@ void CGUIEditControl::SetLabel(const std::string &text)
void CGUIEditControl::SetLabel2(const std::string &text)
{
+ m_edit.clear();
CStdStringW newText;
g_charsetConverter.utf8ToW(text, newText);
if (newText != m_text2)
@@ -650,3 +747,10 @@ void CGUIEditControl::ValidateInput()
SetInvalid();
}
}
+
+void CGUIEditControl::SetFocus(bool focus)
+{
+ m_smsTimer.Stop();
+ g_Windowing.EnableTextInput(focus);
+ CGUIControl::SetFocus(focus);
+}
diff --git a/xbmc/guilib/GUIEditControl.h b/xbmc/guilib/GUIEditControl.h
index f32652ec4d..b10dadd4ab 100644
--- a/xbmc/guilib/GUIEditControl.h
+++ b/xbmc/guilib/GUIEditControl.h
@@ -72,6 +72,8 @@ public:
virtual CStdString GetLabel2() const;
+ void SetShowCursorAlways(bool always) { m_cursorShowAlways = always; }
+
unsigned int GetCursorPosition() const;
void SetCursorPosition(unsigned int iPosition);
@@ -85,10 +87,12 @@ public:
virtual void SetInputValidation(StringValidation::Validator inputValidator, void *data = NULL);
protected:
+ virtual void SetFocus(bool focus);
virtual void ProcessText(unsigned int currentTime);
virtual void RenderText();
virtual CGUILabel::COLOR GetTextColor() const;
CStdStringW GetDisplayedText() const;
+ bool SetStyledText(const CStdStringW &text);
void RecalcLabelPosition();
void ValidateCursor();
void UpdateText(bool sendUpdate = true);
@@ -115,6 +119,7 @@ protected:
unsigned int m_cursorPos;
unsigned int m_cursorBlink;
+ bool m_cursorShowAlways;
int m_inputHeading;
INPUT_TYPE m_inputType;
@@ -130,6 +135,10 @@ protected:
unsigned int m_smsLastKey;
CStopWatch m_smsTimer;
+ std::wstring m_edit;
+ int m_editOffset;
+ int m_editLength;
+
static const char* smsLetters[10];
static const unsigned int smsDelay;
};