Formspec textlist: Black Irrlicht magic to detect fake doubleclicks

This commit is contained in:
Kahrl 2013-08-15 21:46:55 +02:00
parent 7921fe2cd1
commit d8337034b5
2 changed files with 66 additions and 10 deletions

@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h" #include "util/string.h"
#include "util/numeric.h" #include "util/numeric.h"
#include "filesys.h" #include "filesys.h"
#include "gettime.h"
#include "gettext.h" #include "gettext.h"
@ -81,6 +82,10 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
m_selected_item(NULL), m_selected_item(NULL),
m_selected_amount(0), m_selected_amount(0),
m_selected_dragging(false), m_selected_dragging(false),
m_listbox_click_fname(),
m_listbox_click_index(-1),
m_listbox_click_time(0),
m_listbox_doubleclick(false),
m_tooltip_element(NULL), m_tooltip_element(NULL),
m_allowclose(true), m_allowclose(true),
m_use_gettext(false), m_use_gettext(false),
@ -143,6 +148,42 @@ int GUIFormSpecMenu::getListboxIndex(std::string listboxname) {
return -1; return -1;
} }
bool GUIFormSpecMenu::checkListboxClick(std::wstring wlistboxname,
int eventtype)
{
// WARNING: BLACK IRRLICHT MAGIC
// Used to fix Irrlicht's subpar reporting of single clicks and double
// clicks in listboxes (gui::EGET_LISTBOX_CHANGED,
// gui::EGET_LISTBOX_SELECTED_AGAIN):
// 1. IGUIListBox::setSelected() is counted as a click.
// Including the initial setSelected() done by parseTextList().
// 2. Clicking on a the selected item and then dragging for less
// than 500ms is counted as a doubleclick, no matter when the
// item was previously selected (e.g. more than 500ms ago)
// So when Irrlicht reports a doubleclick, we need to check
// for ourselves if really was a doubleclick. Or just a fake.
for(unsigned int i=0; i < m_listboxes.size(); i++) {
std::wstring name(m_listboxes[i].first.fname.c_str());
int selected = m_listboxes[i].second->getSelected();
if (name == wlistboxname && selected >= 0) {
u32 now = getTimeMs();
bool doubleclick =
(eventtype == gui::EGET_LISTBOX_SELECTED_AGAIN)
&& (name == m_listbox_click_fname)
&& (selected == m_listbox_click_index)
&& (m_listbox_click_time >= now - 500);
m_listbox_click_fname = name;
m_listbox_click_index = selected;
m_listbox_click_time = now;
m_listbox_doubleclick = doubleclick;
return true;
}
}
return false;
}
std::vector<std::string> split(const std::string &s, char delim) { std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> tokens; std::vector<std::string> tokens;
@ -1920,7 +1961,7 @@ ItemStack GUIFormSpecMenu::verifySelectedItem()
return ItemStack(); return ItemStack();
} }
void GUIFormSpecMenu::acceptInput(int eventtype) void GUIFormSpecMenu::acceptInput()
{ {
if(m_text_dst) if(m_text_dst)
{ {
@ -1957,11 +1998,12 @@ void GUIFormSpecMenu::acceptInput(int eventtype)
} }
else if(s.ftype == f_ListBox) { else if(s.ftype == f_ListBox) {
std::stringstream ss; std::stringstream ss;
if (eventtype == gui::EGET_LISTBOX_CHANGED) {
ss << "CHG:"; if (m_listbox_doubleclick) {
ss << "DCL:";
} }
else { else {
ss << "DCL:"; ss << "CHG:";
} }
ss << (getListboxIndex(wide_to_narrow(s.fname.c_str()))+1); ss << (getListboxIndex(wide_to_narrow(s.fname.c_str()))+1);
fields[wide_to_narrow(s.fname.c_str())] = ss.str(); fields[wide_to_narrow(s.fname.c_str())] = ss.str();
@ -2459,12 +2501,16 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
for(u32 i=0; i<m_fields.size(); i++) for(u32 i=0; i<m_fields.size(); i++)
{ {
FieldSpec &s = m_fields[i]; FieldSpec &s = m_fields[i];
// if its a button, set the send field so // if its a listbox, set the send field so
// lua knows which button was pressed // lua knows which listbox was changed
if ((s.ftype == f_ListBox) && (s.fid == current_id)) // checkListboxClick() is black magic
// for properly handling double clicks
if ((s.ftype == f_ListBox) && (s.fid == current_id)
&& checkListboxClick(s.fname,
event.GUIEvent.EventType))
{ {
s.send = true; s.send = true;
acceptInput(event.GUIEvent.EventType); acceptInput();
s.send=false; s.send=false;
// Restore focus to the full form // Restore focus to the full form
Environment->setFocus(this); Environment->setFocus(this);

@ -228,7 +228,7 @@ public:
void updateSelectedItem(); void updateSelectedItem();
ItemStack verifySelectedItem(); ItemStack verifySelectedItem();
void acceptInput(int evttype=-1); void acceptInput();
bool OnEvent(const SEvent& event); bool OnEvent(const SEvent& event);
int getListboxIndex(std::string listboxname); int getListboxIndex(std::string listboxname);
@ -272,6 +272,12 @@ protected:
ItemStack m_selected_content_guess; ItemStack m_selected_content_guess;
InventoryLocation m_selected_content_guess_inventory; InventoryLocation m_selected_content_guess_inventory;
// WARNING: BLACK IRRLICHT MAGIC, see checkListboxClick()
std::wstring m_listbox_click_fname;
int m_listbox_click_index;
u32 m_listbox_click_time;
bool m_listbox_doubleclick;
v2s32 m_pointer; v2s32 m_pointer;
gui::IGUIStaticText *m_tooltip_element; gui::IGUIStaticText *m_tooltip_element;
@ -301,6 +307,10 @@ private:
fs_key_pendig current_keys_pending; fs_key_pendig current_keys_pending;
// Determine whether listbox click was double click
// (Using some black Irrlicht magic)
bool checkListboxClick(std::wstring wlistboxname, int eventtype);
void parseElement(parserData* data,std::string element); void parseElement(parserData* data,std::string element);
void parseSize(parserData* data,std::string element); void parseSize(parserData* data,std::string element);