1
0
forked from 0ad/0ad

Fixes incorrect input handling in dropdowns and lists, they were manually handling all events, but should only handle certain key presses. Fixes #2885.

Fixes bug where lists/dropdowns could select an invalid index.

This was SVN commit r15909.
This commit is contained in:
historic_bruno 2014-10-27 04:37:06 +00:00
parent 570b0374f4
commit ff50b0b74c
2 changed files with 118 additions and 99 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2013 Wildfire Games.
/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -296,92 +296,100 @@ void CDropDown::HandleMessage(SGUIMessage &Message)
InReaction CDropDown::ManuallyHandleEvent(const SDL_Event_* ev)
{
int szChar = ev->ev.key.keysym.sym;
InReaction result = IN_PASS;
bool update_highlight = false;
switch (szChar)
if (ev->ev.type == SDL_KEYDOWN)
{
case '\r':
m_Open=false;
break;
int szChar = ev->ev.key.keysym.sym;
case SDLK_HOME:
case SDLK_END:
case SDLK_UP:
case SDLK_DOWN:
case SDLK_PAGEUP:
case SDLK_PAGEDOWN:
if (!m_Open)
return IN_PASS;
// Set current selected item to highlighted, before
// then really processing these in CList::ManuallyHandleEvent()
GUI<int>::SetSetting(this, "selected", m_ElementHighlight);
update_highlight = true;
break;
default:
// If we have inputed a character try to get the closest element to it.
// TODO: not too nice and doesn't deal with dashes.
if (m_Open && ((szChar >= SDLK_a && szChar <= SDLK_z) || szChar == SDLK_SPACE
|| (szChar >= SDLK_0 && szChar <= SDLK_9)
#if !SDL_VERSION_ATLEAST(2,0,0)
|| (szChar >= SDLK_KP0 && szChar <= SDLK_KP9)))
#else // SDL2
|| (szChar >= SDLK_KP_0 && szChar <= SDLK_KP_9)))
#endif
switch (szChar)
{
// arbitrary 1 second limit to add to string or start fresh.
// maximal amount of characters is 100, which imo is far more than enough.
if (timer_Time() - m_TimeOfLastInput > 1.0 || m_InputBuffer.length() >= 100)
m_InputBuffer = szChar;
else
m_InputBuffer += szChar;
case '\r':
m_Open = false;
result = IN_HANDLED;
break;
m_TimeOfLastInput = timer_Time();
case SDLK_HOME:
case SDLK_END:
case SDLK_UP:
case SDLK_DOWN:
case SDLK_PAGEUP:
case SDLK_PAGEDOWN:
if (!m_Open)
return IN_PASS;
// Set current selected item to highlighted, before
// then really processing these in CList::ManuallyHandleEvent()
GUI<int>::SetSetting(this, "selected", m_ElementHighlight);
update_highlight = true;
break;
CGUIList *pList;
GUI<CGUIList>::GetSettingPointer(this, "list", pList);
// let's look for the closest element
// basically it's alphabetic order and "as many letters as we can get".
int closest = -1;
int bestIndex = -1;
int difference = 1250;
for (int i=0; i<(int)pList->m_Items.size(); ++i)
default:
// If we have inputed a character try to get the closest element to it.
// TODO: not too nice and doesn't deal with dashes.
if (m_Open && ((szChar >= SDLK_a && szChar <= SDLK_z) || szChar == SDLK_SPACE
|| (szChar >= SDLK_0 && szChar <= SDLK_9)
#if !SDL_VERSION_ATLEAST(2,0,0)
|| (szChar >= SDLK_KP0 && szChar <= SDLK_KP9)))
#else // SDL2
|| (szChar >= SDLK_KP_0 && szChar <= SDLK_KP_9)))
#endif
{
int indexOfDifference = 0;
int diff = 0;
for (size_t j=0; j < m_InputBuffer.length(); ++j)
// arbitrary 1 second limit to add to string or start fresh.
// maximal amount of characters is 100, which imo is far more than enough.
if (timer_Time() - m_TimeOfLastInput > 1.0 || m_InputBuffer.length() >= 100)
m_InputBuffer = szChar;
else
m_InputBuffer += szChar;
m_TimeOfLastInput = timer_Time();
CGUIList *pList;
GUI<CGUIList>::GetSettingPointer(this, "list", pList);
// let's look for the closest element
// basically it's alphabetic order and "as many letters as we can get".
int closest = -1;
int bestIndex = -1;
int difference = 1250;
for (int i=0; i<(int)pList->m_Items.size(); ++i)
{
diff = abs(pList->m_Items[i].GetOriginalString().LowerCase()[j] - (int)m_InputBuffer[j]);
if (diff == 0)
indexOfDifference = j+1;
else
break;
int indexOfDifference = 0;
int diff = 0;
for (size_t j=0; j < m_InputBuffer.length(); ++j)
{
diff = abs(pList->m_Items[i].GetOriginalString().LowerCase()[j] - (int)m_InputBuffer[j]);
if (diff == 0)
indexOfDifference = j+1;
else
break;
}
if (indexOfDifference > bestIndex || (indexOfDifference >= bestIndex && diff < difference))
{
bestIndex = indexOfDifference;
closest = i;
difference = diff;
}
}
if (indexOfDifference > bestIndex || (indexOfDifference >= bestIndex && diff < difference))
// let's select the closest element. There should basically always be one.
if (closest != -1)
{
bestIndex = indexOfDifference;
closest = i;
difference = diff;
GUI<int>::SetSetting(this, "selected", closest);
update_highlight = true;
GetScrollBar(0).SetPos(m_ItemsYPositions[closest] - 60);
}
result = IN_HANDLED;
}
// let's select the closest element. There should basically always be one.
if (closest != -1)
{
GUI<int>::SetSetting(this, "selected", closest);
update_highlight = true;
GetScrollBar(0).SetPos(m_ItemsYPositions[closest] - 60);
}
break;
}
break;
}
CList::ManuallyHandleEvent(ev);
if (CList::ManuallyHandleEvent(ev) == IN_HANDLED)
result = IN_HANDLED;
if (update_highlight)
GUI<int>::GetSetting(this, "selected", m_ElementHighlight);
return IN_HANDLED;
return result;
}
void CDropDown::SetupListRect()

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2013 Wildfire Games.
/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -259,43 +259,54 @@ void CList::HandleMessage(SGUIMessage &Message)
InReaction CList::ManuallyHandleEvent(const SDL_Event_* ev)
{
int szChar = ev->ev.key.keysym.sym;
InReaction result = IN_PASS;
switch (szChar)
if (ev->ev.type == SDL_KEYDOWN)
{
case SDLK_HOME:
SelectFirstElement();
UpdateAutoScroll();
break;
int szChar = ev->ev.key.keysym.sym;
case SDLK_END:
SelectLastElement();
UpdateAutoScroll();
break;
switch (szChar)
{
case SDLK_HOME:
SelectFirstElement();
UpdateAutoScroll();
result = IN_HANDLED;
break;
case SDLK_UP:
SelectPrevElement();
UpdateAutoScroll();
break;
case SDLK_END:
SelectLastElement();
UpdateAutoScroll();
result = IN_HANDLED;
break;
case SDLK_DOWN:
SelectNextElement();
UpdateAutoScroll();
break;
case SDLK_UP:
SelectPrevElement();
UpdateAutoScroll();
result = IN_HANDLED;
break;
case SDLK_PAGEUP:
GetScrollBar(0).ScrollMinusPlenty();
break;
case SDLK_DOWN:
SelectNextElement();
UpdateAutoScroll();
result = IN_HANDLED;
break;
case SDLK_PAGEDOWN:
GetScrollBar(0).ScrollPlusPlenty();
break;
case SDLK_PAGEUP:
GetScrollBar(0).ScrollMinusPlenty();
result = IN_HANDLED;
break;
default: // Do nothing
return IN_PASS;
case SDLK_PAGEDOWN:
GetScrollBar(0).ScrollPlusPlenty();
result = IN_HANDLED;
break;
default: // Do nothing
result = IN_PASS;
}
}
return IN_HANDLED;
return result;
}
void CList::Draw()
@ -462,7 +473,7 @@ void CList::SelectPrevElement()
int selected;
GUI<int>::GetSetting(this, "selected", selected);
if (selected >= 0)
if (selected > 0)
{
--selected;
GUI<int>::SetSetting(this, "selected", selected);