add support for selection and deletion of entire words in text controls (ctrl+backspace/delete/left/right) based on patch by Chakakhan/kenny (thanks!)
also refactored wclipboard closes #511 This was SVN commit r9646.
This commit is contained in:
parent
889f4698f2
commit
492e49da38
@ -129,6 +129,7 @@ hotkey.camera.down = S, DownArrow ; Scroll or rotate dow
|
||||
hotkey.console.toggle = BackQuote, F9 ; Open/close console
|
||||
hotkey.console.copy = "Ctrl+C" ; Copy from console to clipboard
|
||||
hotkey.console.paste = "Ctrl+V" ; Paste clipboard to console
|
||||
hotkey.console.cut = "Ctrl+X" ; Cut the selected text and copy it to the clipboard
|
||||
|
||||
; > ENTITY SELECTION
|
||||
hotkey.selection.add = Shift ; Add units to selection
|
||||
@ -186,6 +187,12 @@ hotkey.menu.toggle = "F10" ; Toggle in-game menu
|
||||
; > HOTKEYS ONLY
|
||||
hotkey.chat = Return ; Toggle chat window
|
||||
|
||||
; > GUI TEXTBOX HOTKEYS
|
||||
hotkey.text.delete.word.left = "Ctrl+Backspace" ; Used in text input boxes to delete word to the left of cursor
|
||||
hotkey.text.delete.word.right = "Ctrl+Del" ; Used in text input boxes to delete word to the right of cursor
|
||||
hotkey.text.move.word.left = "Ctrl+LeftArrow" ; Move cursor to start of word to the left of cursor
|
||||
hotkey.text.move.word.right = "Ctrl+RightArrow" ; Move cursor to start of word to the left of cursor
|
||||
|
||||
; > PROFILER
|
||||
hotkey.profile.toggle = "F11" ; Enable/disable real-time profiler
|
||||
hotkey.profile.save = "Shift+F11" ; Save current profiler data to logs/profile.txt
|
||||
|
@ -34,6 +34,7 @@ CInput
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Globals.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
@ -70,49 +71,30 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
{
|
||||
ENSURE(m_iBufferPos != -1);
|
||||
|
||||
// Since the GUI framework doesn't handle to set settings
|
||||
// in Unicode (CStrW), we'll simply retrieve the actual
|
||||
// pointer and edit that.
|
||||
CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
|
||||
|
||||
if (ev->ev.type == SDL_HOTKEYDOWN)
|
||||
{
|
||||
std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
|
||||
if (hotkey == "console.paste")
|
||||
{
|
||||
wchar_t* text = sys_clipboard_get();
|
||||
if (text)
|
||||
{
|
||||
if (m_iBufferPos == (int)pCaption->length())
|
||||
*pCaption += text;
|
||||
else
|
||||
*pCaption = pCaption->Left(m_iBufferPos) + text +
|
||||
pCaption->Right((long) pCaption->length()-m_iBufferPos);
|
||||
|
||||
UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
|
||||
|
||||
m_iBufferPos += (int)wcslen(text);
|
||||
|
||||
sys_clipboard_free(text);
|
||||
}
|
||||
|
||||
return IN_HANDLED;
|
||||
}
|
||||
return(ManuallyHandleHotkeyEvent(ev));
|
||||
}
|
||||
else if (ev->ev.type == SDL_KEYDOWN)
|
||||
{
|
||||
// Since the GUI framework doesn't handle to set settings
|
||||
// in Unicode (CStrW), we'll simply retrieve the actual
|
||||
// pointer and edit that.
|
||||
CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
|
||||
bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
|
||||
|
||||
int szChar = ev->ev.key.keysym.sym;
|
||||
wchar_t cooked = (wchar_t)ev->ev.key.keysym.unicode;
|
||||
|
||||
switch (szChar)
|
||||
{
|
||||
case '\t':
|
||||
case SDLK_TAB: // '\t'
|
||||
/* Auto Complete */
|
||||
// TODO Gee: (2004-09-07) What to do with tab?
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
m_WantedX=0.f;
|
||||
case SDLK_BACKSPACE: // '\b'
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (SelectingText())
|
||||
DeleteCurSelection();
|
||||
@ -120,26 +102,29 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
{
|
||||
m_iBufferPos_Tail = -1;
|
||||
|
||||
if (pCaption->empty() ||
|
||||
m_iBufferPos == 0)
|
||||
if (pCaption->empty() || m_iBufferPos == 0)
|
||||
{
|
||||
break;
|
||||
|
||||
if (m_iBufferPos == (int)pCaption->length())
|
||||
*pCaption = pCaption->Left( (long) pCaption->length()-1);
|
||||
}
|
||||
else
|
||||
*pCaption = pCaption->Left( m_iBufferPos-1 ) +
|
||||
pCaption->Right( (long) pCaption->length()-m_iBufferPos );
|
||||
{
|
||||
if (m_iBufferPos == (int)pCaption->length())
|
||||
*pCaption = pCaption->Left( (long) pCaption->length()-1);
|
||||
else
|
||||
*pCaption = pCaption->Left( m_iBufferPos-1 ) +
|
||||
pCaption->Right( (long) pCaption->length()-m_iBufferPos );
|
||||
|
||||
--m_iBufferPos;
|
||||
--m_iBufferPos;
|
||||
|
||||
UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
|
||||
UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAutoScroll();
|
||||
break;
|
||||
|
||||
case SDLK_DELETE:
|
||||
m_WantedX=0.f;
|
||||
m_WantedX=0.0f;
|
||||
// If selection:
|
||||
if (SelectingText())
|
||||
{
|
||||
@ -147,14 +132,17 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pCaption->empty() ||
|
||||
m_iBufferPos == (int)pCaption->length())
|
||||
if (pCaption->empty() || m_iBufferPos == (int)pCaption->length())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pCaption = pCaption->Left( m_iBufferPos ) +
|
||||
pCaption->Right( (long) pCaption->length()-(m_iBufferPos+1) );
|
||||
|
||||
*pCaption = pCaption->Left( m_iBufferPos ) +
|
||||
pCaption->Right( (long) pCaption->length()-(m_iBufferPos+1) );
|
||||
|
||||
UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
|
||||
UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAutoScroll();
|
||||
@ -162,7 +150,7 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
|
||||
case SDLK_HOME:
|
||||
// If there's not a selection, we should create one now
|
||||
if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
// Make sure a selection isn't created.
|
||||
m_iBufferPos_Tail = -1;
|
||||
@ -174,14 +162,14 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
}
|
||||
|
||||
m_iBufferPos = 0;
|
||||
m_WantedX=0.f;
|
||||
m_WantedX=0.0f;
|
||||
|
||||
UpdateAutoScroll();
|
||||
break;
|
||||
|
||||
case SDLK_END:
|
||||
// If there's not a selection, we should create one now
|
||||
if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
// Make sure a selection isn't created.
|
||||
m_iBufferPos_Tail = -1;
|
||||
@ -193,7 +181,7 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
}
|
||||
|
||||
m_iBufferPos = (long) pCaption->length();
|
||||
m_WantedX=0.f;
|
||||
m_WantedX=0.0f;
|
||||
|
||||
UpdateAutoScroll();
|
||||
break;
|
||||
@ -221,25 +209,20 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
|
||||
**/
|
||||
case SDLK_LEFT:
|
||||
// reset m_WantedX, very important
|
||||
m_WantedX=0.f;
|
||||
|
||||
if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT] ||
|
||||
!SelectingText())
|
||||
if (shiftKeyPressed || !SelectingText())
|
||||
{
|
||||
// If there's not a selection, we should create one now
|
||||
if (!SelectingText() && !g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
// Make sure a selection isn't created.
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
else if (!SelectingText())
|
||||
{
|
||||
// Place tail at the current point:
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
}
|
||||
|
||||
if (m_iBufferPos)
|
||||
if (m_iBufferPos > 0)
|
||||
--m_iBufferPos;
|
||||
}
|
||||
else
|
||||
@ -254,25 +237,20 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
break;
|
||||
|
||||
case SDLK_RIGHT:
|
||||
m_WantedX=0.f;
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT] ||
|
||||
!SelectingText())
|
||||
if (shiftKeyPressed || !SelectingText())
|
||||
{
|
||||
// If there's not a selection, we should create one now
|
||||
if (!SelectingText() && !g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
// Make sure a selection isn't created.
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
else if (!SelectingText())
|
||||
{
|
||||
// Place tail at the current point:
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
}
|
||||
|
||||
|
||||
if (m_iBufferPos != (int)pCaption->length())
|
||||
if (m_iBufferPos < (int)pCaption->length())
|
||||
++m_iBufferPos;
|
||||
}
|
||||
else
|
||||
@ -308,15 +286,12 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
**/
|
||||
case SDLK_UP:
|
||||
{
|
||||
// If there's not a selection, we should create one now
|
||||
if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
// Make sure a selection isn't created.
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
else if (!SelectingText())
|
||||
{
|
||||
// Place tail at the current point:
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
}
|
||||
|
||||
@ -356,15 +331,12 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
|
||||
case SDLK_DOWN:
|
||||
{
|
||||
// If there's not a selection, we should create one now
|
||||
if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
// Make sure a selection isn't created.
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
else if (!SelectingText())
|
||||
{
|
||||
// Place tail at the current point:
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
}
|
||||
|
||||
@ -428,7 +400,6 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
}
|
||||
default: //Insert a character
|
||||
{
|
||||
// If there's a selection, delete if first.
|
||||
if (cooked == 0)
|
||||
return IN_PASS; // Important, because we didn't use any key
|
||||
|
||||
@ -438,7 +409,7 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
if (max_length != 0 && (int)pCaption->length() >= max_length)
|
||||
break;
|
||||
|
||||
m_WantedX=0.f;
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (SelectingText())
|
||||
DeleteCurSelection();
|
||||
@ -465,6 +436,251 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev)
|
||||
return IN_PASS;
|
||||
}
|
||||
|
||||
|
||||
InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
|
||||
{
|
||||
CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
|
||||
bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
|
||||
|
||||
std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
|
||||
if (hotkey == "console.paste")
|
||||
{
|
||||
m_WantedX=0.0f;
|
||||
|
||||
wchar_t* text = sys_clipboard_get();
|
||||
if (text)
|
||||
{
|
||||
if (m_iBufferPos == (int)pCaption->length())
|
||||
*pCaption += text;
|
||||
else
|
||||
*pCaption = pCaption->Left(m_iBufferPos) + text +
|
||||
pCaption->Right((long) pCaption->length()-m_iBufferPos);
|
||||
|
||||
UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
|
||||
|
||||
m_iBufferPos += (int)wcslen(text);
|
||||
|
||||
sys_clipboard_free(text);
|
||||
}
|
||||
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "console.copy" || hotkey == "console.cut")
|
||||
{
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (SelectingText())
|
||||
{
|
||||
int virtualFrom;
|
||||
int virtualTo;
|
||||
|
||||
if (m_iBufferPos_Tail >= m_iBufferPos)
|
||||
{
|
||||
virtualFrom = m_iBufferPos;
|
||||
virtualTo = m_iBufferPos_Tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
virtualFrom = m_iBufferPos_Tail;
|
||||
virtualTo = m_iBufferPos;
|
||||
}
|
||||
|
||||
CStrW text = (pCaption->Left(virtualTo)).Right(virtualTo - virtualFrom);
|
||||
|
||||
sys_clipboard_set(&text[0]);
|
||||
|
||||
if (hotkey == "console.cut")
|
||||
{
|
||||
DeleteCurSelection();
|
||||
}
|
||||
}
|
||||
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "text.delete.word.left")
|
||||
{
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (SelectingText())
|
||||
{
|
||||
DeleteCurSelection();
|
||||
}
|
||||
if (!pCaption->empty() && !m_iBufferPos == 0)
|
||||
{
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
CStrW searchString = pCaption->Left( m_iBufferPos );
|
||||
|
||||
// If we are starting in whitespace, adjust position until we get a non whitespace
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (!iswspace(searchString[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
}
|
||||
|
||||
// If we end up on a puctuation char we just delete it (treat punct like a word)
|
||||
if (iswpunct(searchString[m_iBufferPos - 1]))
|
||||
m_iBufferPos--;
|
||||
else
|
||||
{
|
||||
// Now we are on a non white space character, adjust position to char after next whitespace char is found
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
}
|
||||
}
|
||||
|
||||
DeleteCurSelection();
|
||||
}
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "text.delete.word.right")
|
||||
{
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (SelectingText())
|
||||
{
|
||||
DeleteCurSelection();
|
||||
}
|
||||
if (!pCaption->empty() && m_iBufferPos < (int)pCaption->length())
|
||||
{
|
||||
// Delete the word to the right of the cursor
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
|
||||
// Delete chars to the right unit we hit whitespace
|
||||
while (++m_iBufferPos < (int)pCaption->length())
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos]) || iswpunct((*pCaption)[m_iBufferPos]))
|
||||
break;
|
||||
}
|
||||
|
||||
// Eliminate any whitespace behind the word we just deleted
|
||||
while (m_iBufferPos < (int)pCaption->length())
|
||||
{
|
||||
if (!iswspace((*pCaption)[m_iBufferPos]))
|
||||
break;
|
||||
|
||||
m_iBufferPos++;
|
||||
}
|
||||
DeleteCurSelection();
|
||||
}
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "text.move.word.left")
|
||||
{
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (shiftKeyPressed || !SelectingText())
|
||||
{
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
else if (!SelectingText())
|
||||
{
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
}
|
||||
|
||||
if (!pCaption->empty() && !m_iBufferPos == 0)
|
||||
{
|
||||
CStrW searchString = pCaption->Left( m_iBufferPos );
|
||||
|
||||
// If we are starting in whitespace, adjust position until we get a non whitespace
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (!iswspace(searchString[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
}
|
||||
|
||||
// If we end up on a puctuation char we just select it (treat punct like a word)
|
||||
if (iswpunct(searchString[m_iBufferPos - 1]))
|
||||
m_iBufferPos--;
|
||||
else
|
||||
{
|
||||
// Now we are on a non white space character, adjust position to char after next whitespace char is found
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_iBufferPos_Tail < m_iBufferPos)
|
||||
m_iBufferPos = m_iBufferPos_Tail;
|
||||
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
|
||||
UpdateAutoScroll();
|
||||
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "text.move.word.right")
|
||||
{
|
||||
m_WantedX=0.0f;
|
||||
|
||||
if (shiftKeyPressed || !SelectingText())
|
||||
{
|
||||
if (!shiftKeyPressed)
|
||||
{
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
else if (!SelectingText())
|
||||
{
|
||||
m_iBufferPos_Tail = m_iBufferPos;
|
||||
}
|
||||
|
||||
if (!pCaption->empty() && m_iBufferPos < (int)pCaption->length())
|
||||
{
|
||||
CStrW searchString = *pCaption;
|
||||
|
||||
// Select chars to the right until we hit whitespace
|
||||
while (++m_iBufferPos < (int)pCaption->length())
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos]) || iswpunct((*pCaption)[m_iBufferPos]))
|
||||
break;
|
||||
}
|
||||
|
||||
// Also select any whitespace following the word we just selected
|
||||
while (m_iBufferPos < (int)pCaption->length())
|
||||
{
|
||||
if (!iswspace((*pCaption)[m_iBufferPos]))
|
||||
break;
|
||||
|
||||
m_iBufferPos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_iBufferPos_Tail > m_iBufferPos)
|
||||
m_iBufferPos = m_iBufferPos_Tail;
|
||||
|
||||
m_iBufferPos_Tail = -1;
|
||||
}
|
||||
|
||||
UpdateAutoScroll();
|
||||
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IN_PASS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CInput::HandleMessage(SGUIMessage &Message)
|
||||
{
|
||||
// TODO Gee:
|
||||
@ -480,7 +696,7 @@ void CInput::HandleMessage(SGUIMessage &Message)
|
||||
// Update scroll-bar
|
||||
// TODO Gee: (2004-09-01) Is this really updated each time it should?
|
||||
if (scrollbar &&
|
||||
(Message.value == CStr("size") ||
|
||||
(Message.value == CStr("size") ||
|
||||
Message.value == CStr("z") ||
|
||||
Message.value == CStr("absolute")))
|
||||
{
|
||||
@ -565,6 +781,101 @@ void CInput::HandleMessage(SGUIMessage &Message)
|
||||
|
||||
}break;
|
||||
|
||||
case GUIM_MOUSE_DBLCLICK_LEFT:
|
||||
{
|
||||
CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
|
||||
m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition();
|
||||
|
||||
// See if we are clicking over whitespace
|
||||
if (iswspace((*pCaption)[m_iBufferPos]))
|
||||
{
|
||||
// see if we are in a section of whitespace greater than one character
|
||||
if ((m_iBufferPos + 1 < (int) pCaption->length() && iswspace((*pCaption)[m_iBufferPos + 1])) ||
|
||||
(m_iBufferPos - 1 > 0 && iswspace((*pCaption)[m_iBufferPos - 1])))
|
||||
{
|
||||
//
|
||||
// We are clicking in an area with more than one whitespace character
|
||||
// so we select both the word to the left and then the word to the right
|
||||
//
|
||||
// [1] First the left
|
||||
// skip the whitespace
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (!iswspace((*pCaption)[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
}
|
||||
// now go until we hit white space or punctuation
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
|
||||
if (iswpunct((*pCaption)[m_iBufferPos]))
|
||||
break;
|
||||
}
|
||||
|
||||
// [2] Then the right
|
||||
// go right until we are not in whitespace
|
||||
while (++m_iBufferPos_Tail < (int)pCaption->length())
|
||||
{
|
||||
if (!iswspace((*pCaption)[m_iBufferPos_Tail]))
|
||||
break;
|
||||
}
|
||||
// now go to the right until we hit whitespace or punctuation
|
||||
while (++m_iBufferPos_Tail < (int)pCaption->length())
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos_Tail]) || iswpunct((*pCaption)[m_iBufferPos_Tail]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// single whitespace so select word to the right
|
||||
while (++m_iBufferPos_Tail < (int)pCaption->length())
|
||||
{
|
||||
if (!iswspace((*pCaption)[m_iBufferPos_Tail]))
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't include the leading whitespace
|
||||
m_iBufferPos = m_iBufferPos_Tail;
|
||||
|
||||
// now go to the right until we hit whitespace or punctuation
|
||||
while (++m_iBufferPos_Tail < (int)pCaption->length())
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos_Tail]) || iswpunct((*pCaption)[m_iBufferPos_Tail]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// clicked on non-whitespace so select current word
|
||||
// go until we hit white space or punctuation
|
||||
while (m_iBufferPos > 0)
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos - 1]))
|
||||
break;
|
||||
|
||||
m_iBufferPos--;
|
||||
|
||||
if (iswpunct((*pCaption)[m_iBufferPos]))
|
||||
break;
|
||||
}
|
||||
// go to the right until we hit whitespace or punctuation
|
||||
while (++m_iBufferPos_Tail < (int)pCaption->length())
|
||||
{
|
||||
if (iswspace((*pCaption)[m_iBufferPos_Tail]) || iswpunct((*pCaption)[m_iBufferPos_Tail]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_RELEASE_LEFT:
|
||||
if (m_SelectingText)
|
||||
{
|
||||
@ -921,7 +1232,7 @@ void CInput::Draw()
|
||||
}
|
||||
|
||||
if (i < (int)it->m_ListOfX.size())
|
||||
x_pointer += (float)font.GetCharacterWidth((*pCaption)[it->m_ListStart + i]);
|
||||
x_pointer += (float)font.GetCharacterWidth((*pCaption)[it->m_ListStart + i]);
|
||||
}
|
||||
|
||||
if (done)
|
||||
@ -953,7 +1264,7 @@ void CInput::Draw()
|
||||
{
|
||||
if (multiline)
|
||||
{
|
||||
if (buffered_y + buffer_zone > m_CachedActualSize.GetHeight())
|
||||
if (buffered_y + buffer_zone > m_CachedActualSize.GetHeight())
|
||||
break;
|
||||
}
|
||||
|
||||
@ -961,7 +1272,7 @@ void CInput::Draw()
|
||||
|
||||
// Text must always be drawn in integer values. So we have to convert scroll
|
||||
if (multiline)
|
||||
glTranslatef(0.f, -(float)(int)scroll, 0.f);
|
||||
glTranslatef(0.f, -(float)(int)scroll, 0.f);
|
||||
else
|
||||
glTranslatef(-(float)(int)m_HorizontalScroll, 0.f, 0.f);
|
||||
|
||||
@ -1169,7 +1480,7 @@ void CInput::UpdateText(int from, int to_before, int to_after)
|
||||
|
||||
if (destroy_row_to_used == false)
|
||||
{
|
||||
destroy_row_to = m_CharacterPositions.end();
|
||||
destroy_row_to = m_CharacterPositions.end();
|
||||
check_point_row_start = -1;
|
||||
|
||||
destroy_row_from_used = true;
|
||||
@ -1180,7 +1491,7 @@ void CInput::UpdateText(int from, int to_before, int to_after)
|
||||
from = destroy_row_from->m_ListStart;
|
||||
|
||||
if (destroy_row_to != m_CharacterPositions.end())
|
||||
to = destroy_row_to->m_ListStart; // notice it will iterate [from, to), so it will never reach to.
|
||||
to = destroy_row_to->m_ListStart; // notice it will iterate [from, to), so it will never reach to.
|
||||
else
|
||||
to = (int)caption.length();
|
||||
|
||||
@ -1428,7 +1739,7 @@ int CInput::GetMouseHoveringTextPosition()
|
||||
return 0;
|
||||
|
||||
// Return position
|
||||
int RetPosition;
|
||||
int retPosition;
|
||||
|
||||
float buffer_zone;
|
||||
bool multiline;
|
||||
@ -1493,20 +1804,19 @@ int CInput::GetMouseHoveringTextPosition()
|
||||
}
|
||||
|
||||
//m_iBufferPos = m_CharacterPositions.get.m_ListStart;
|
||||
RetPosition = current->m_ListStart;
|
||||
retPosition = current->m_ListStart;
|
||||
|
||||
// Okay, now loop through the glyphs to find the appropriate X position
|
||||
float dummy;
|
||||
RetPosition += GetXTextPosition(current, mouse.x, dummy);
|
||||
retPosition += GetXTextPosition(current, mouse.x, dummy);
|
||||
|
||||
return RetPosition;
|
||||
return retPosition;
|
||||
}
|
||||
|
||||
// Does not process horizontal scrolling, 'x' must be modified before inputted.
|
||||
int CInput::GetXTextPosition(const std::list<SRow>::iterator ¤t, const float &x, float &wanted)
|
||||
{
|
||||
int Ret=0;
|
||||
|
||||
int ret=0;
|
||||
float previous=0.f;
|
||||
int i=0;
|
||||
|
||||
@ -1517,9 +1827,9 @@ int CInput::GetXTextPosition(const std::list<SRow>::iterator ¤t, const flo
|
||||
if (*it >= x)
|
||||
{
|
||||
if (x - previous >= *it - x)
|
||||
Ret += i+1;
|
||||
ret += i+1;
|
||||
else
|
||||
Ret += i;
|
||||
ret += i;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1529,39 +1839,40 @@ int CInput::GetXTextPosition(const std::list<SRow>::iterator ¤t, const flo
|
||||
// character of that line.
|
||||
if (i == (int)current->m_ListOfX.size())
|
||||
{
|
||||
Ret += i;
|
||||
ret += i;
|
||||
wanted = x;
|
||||
}
|
||||
else wanted = 0.f;
|
||||
|
||||
return Ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CInput::DeleteCurSelection()
|
||||
{
|
||||
CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
|
||||
|
||||
int VirtualFrom, VirtualTo;
|
||||
int virtualFrom;
|
||||
int virtualTo;
|
||||
|
||||
if (m_iBufferPos_Tail >= m_iBufferPos)
|
||||
{
|
||||
VirtualFrom = m_iBufferPos;
|
||||
VirtualTo = m_iBufferPos_Tail;
|
||||
virtualFrom = m_iBufferPos;
|
||||
virtualTo = m_iBufferPos_Tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
VirtualFrom = m_iBufferPos_Tail;
|
||||
VirtualTo = m_iBufferPos;
|
||||
virtualFrom = m_iBufferPos_Tail;
|
||||
virtualTo = m_iBufferPos;
|
||||
}
|
||||
|
||||
*pCaption = pCaption->Left( VirtualFrom ) +
|
||||
pCaption->Right( (long) pCaption->length()-(VirtualTo) );
|
||||
*pCaption = pCaption->Left( virtualFrom ) +
|
||||
pCaption->Right( (long) pCaption->length() - (virtualTo) );
|
||||
|
||||
UpdateText(VirtualFrom, VirtualTo, VirtualFrom);
|
||||
UpdateText(virtualFrom, virtualTo, virtualFrom);
|
||||
|
||||
// Remove selection
|
||||
m_iBufferPos_Tail = -1;
|
||||
m_iBufferPos = VirtualFrom;
|
||||
m_iBufferPos = virtualFrom;
|
||||
}
|
||||
|
||||
bool CInput::SelectingText() const
|
||||
|
@ -96,6 +96,11 @@ protected:
|
||||
*/
|
||||
virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev);
|
||||
|
||||
/**
|
||||
* Handle hotkey events (called by ManuallyHandleEvent)
|
||||
*/
|
||||
virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev);
|
||||
|
||||
/**
|
||||
* @see IGUIObject#UpdateCachedSize()
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2010 Wildfire Games
|
||||
/* Copyright (c) 2011 Wildfire Games
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -20,15 +20,19 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SYSDEP_CLIPBOARD
|
||||
#define INCLUDED_SYSDEP_CLIPBOARD
|
||||
|
||||
// "copy" text into the clipboard. replaces previous contents.
|
||||
extern Status sys_clipboard_set(const wchar_t* text);
|
||||
|
||||
// allow "pasting" from clipboard. returns the current contents if they
|
||||
// can be represented as text, otherwise 0.
|
||||
// when it is no longer needed, the returned pointer must be freed via
|
||||
// sys_clipboard_free. (NB: not necessary if zero, but doesn't hurt)
|
||||
// allow "pasting" from clipboard.
|
||||
// @return current clipboard text or 0 if not representable as text.
|
||||
// callers are responsible for passing this pointer to sys_clipboard_free.
|
||||
extern wchar_t* sys_clipboard_get();
|
||||
|
||||
// frees memory used by <copy>, which must have been returned by
|
||||
// sys_clipboard_get. see note above.
|
||||
// free memory returned by sys_clipboard_get.
|
||||
// @param copy is ignored if 0.
|
||||
extern Status sys_clipboard_free(wchar_t* copy);
|
||||
|
||||
#endif // #ifndef INCLUDED_SYSDEP_CLIPBOARD
|
||||
|
@ -26,89 +26,98 @@
|
||||
#include "lib/sysdep/os/win/win.h"
|
||||
#include "lib/sysdep/os/win/wutil.h"
|
||||
|
||||
// caller is responsible for freeing *hMem.
|
||||
static Status SetClipboardText(const wchar_t* text, HGLOBAL* hMem)
|
||||
|
||||
// caller is responsible for freeing hMem.
|
||||
static Status SetClipboardText(const wchar_t* text, HGLOBAL& hMem)
|
||||
{
|
||||
const size_t numChars = wcslen(text);
|
||||
*hMem = GlobalAlloc(GMEM_MOVEABLE, (numChars+1) * sizeof(wchar_t));
|
||||
if(!*hMem)
|
||||
hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, (numChars + 1) * sizeof(wchar_t));
|
||||
if(!hMem)
|
||||
WARN_RETURN(ERR::NO_MEM);
|
||||
|
||||
wchar_t* lockedText = (wchar_t*)GlobalLock(*hMem);
|
||||
wchar_t* lockedText = (wchar_t*)GlobalLock(hMem);
|
||||
if(!lockedText)
|
||||
WARN_RETURN(ERR::NO_MEM);
|
||||
wcscpy_s(lockedText, numChars+1, text);
|
||||
GlobalUnlock(*hMem);
|
||||
GlobalUnlock(hMem);
|
||||
|
||||
HANDLE hData = SetClipboardData(CF_UNICODETEXT, *hMem);
|
||||
HANDLE hData = SetClipboardData(CF_UNICODETEXT, hMem);
|
||||
if(!hData) // failed
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
// "copy" text into the clipboard. replaces previous contents.
|
||||
Status sys_clipboard_set(const wchar_t* text)
|
||||
|
||||
// @return INFO::OK iff text has been assigned a pointer (which the
|
||||
// caller must free via sys_clipboard_free) to the clipboard text.
|
||||
static Status GetClipboardText(wchar_t*& text)
|
||||
{
|
||||
// note: MSDN claims that the window handle must not be 0;
|
||||
// that does actually work on WinXP, but we'll play it safe.
|
||||
if(!OpenClipboard(wutil_AppWindow()))
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
EmptyClipboard();
|
||||
// NB: Windows NT/2000+ auto convert CF_UNICODETEXT <-> CF_TEXT.
|
||||
|
||||
HGLOBAL hMem;
|
||||
Status ret = SetClipboardText(text, &hMem);
|
||||
if(!IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||
return INFO::CANNOT_HANDLE;
|
||||
|
||||
CloseClipboard();
|
||||
|
||||
// note: MSDN's SetClipboardData documentation says hMem must not be
|
||||
// freed until after CloseClipboard. however, GlobalFree still fails
|
||||
// after the successful completion of both. we'll leave it in to avoid
|
||||
// memory leaks, but ignore its return value.
|
||||
(void)GlobalFree(hMem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static wchar_t* CopyClipboardContents()
|
||||
{
|
||||
// Windows NT/2000+ auto convert UNICODETEXT <-> TEXT
|
||||
HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT);
|
||||
if(!hMem)
|
||||
return 0;
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
|
||||
const wchar_t* lockedText = (const wchar_t*)GlobalLock(hMem);
|
||||
if(!lockedText)
|
||||
return 0;
|
||||
WARN_RETURN(ERR::NO_MEM);
|
||||
|
||||
const size_t numChars = GlobalSize(hMem)/sizeof(wchar_t) - 1;
|
||||
wchar_t* text = new wchar_t[numChars+1];
|
||||
wcscpy_s(text, numChars+1, lockedText);
|
||||
const size_t size = GlobalSize(hMem);
|
||||
text = (wchar_t*)malloc(size);
|
||||
if(!text)
|
||||
WARN_RETURN(ERR::NO_MEM);
|
||||
wcscpy_s(text, size/sizeof(wchar_t), lockedText);
|
||||
|
||||
GlobalUnlock(hMem);
|
||||
(void)GlobalUnlock(hMem);
|
||||
|
||||
return text;
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
// allow "pasting" from clipboard. returns the current contents if they
|
||||
// can be represented as text, otherwise 0.
|
||||
// when it is no longer needed, the returned pointer must be freed via
|
||||
// sys_clipboard_free. (NB: not necessary if zero, but doesn't hurt)
|
||||
wchar_t* sys_clipboard_get()
|
||||
|
||||
// OpenClipboard parameter.
|
||||
// NB: using wutil_AppWindow() causes GlobalLock to fail.
|
||||
static const HWND hWndNewOwner = 0; // MSDN: associate with "current task"
|
||||
|
||||
Status sys_clipboard_set(const wchar_t* text)
|
||||
{
|
||||
if(!OpenClipboard(wutil_AppWindow()))
|
||||
return 0;
|
||||
wchar_t* const ret = CopyClipboardContents();
|
||||
CloseClipboard();
|
||||
if(!OpenClipboard(hWndNewOwner))
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
|
||||
WARN_IF_FALSE(EmptyClipboard());
|
||||
|
||||
// NB: to enable copy/pasting something other than text, add
|
||||
// message handlers for WM_RENDERFORMAT and WM_RENDERALLFORMATS.
|
||||
HGLOBAL hMem;
|
||||
Status ret = SetClipboardText(text, hMem);
|
||||
|
||||
WARN_IF_FALSE(CloseClipboard()); // must happen before GlobalFree
|
||||
|
||||
ENSURE(GlobalFree(hMem) == 0); // (0 indicates success)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// frees memory used by <copy>, which must have been returned by
|
||||
// sys_clipboard_get. see note above.
|
||||
wchar_t* sys_clipboard_get()
|
||||
{
|
||||
if(!OpenClipboard(hWndNewOwner))
|
||||
return 0;
|
||||
|
||||
wchar_t* text;
|
||||
Status ret = GetClipboardText(text);
|
||||
|
||||
WARN_IF_FALSE(CloseClipboard());
|
||||
|
||||
return (ret == INFO::OK)? text : 0;
|
||||
}
|
||||
|
||||
|
||||
Status sys_clipboard_free(wchar_t* text)
|
||||
{
|
||||
delete[] text;
|
||||
free(text);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user