@@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
43
43
#include " util/string.h"
44
44
#include " util/numeric.h"
45
45
#include " filesys.h"
46
+ #include " gettime.h"
46
47
47
48
#include " gettext.h"
48
49
@@ -81,6 +82,10 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
81
82
m_selected_item(NULL ),
82
83
m_selected_amount(0 ),
83
84
m_selected_dragging(false ),
85
+ m_listbox_click_fname(),
86
+ m_listbox_click_index(-1 ),
87
+ m_listbox_click_time(0 ),
88
+ m_listbox_doubleclick(false ),
84
89
m_tooltip_element(NULL ),
85
90
m_allowclose(true ),
86
91
m_use_gettext(false ),
@@ -143,6 +148,42 @@ int GUIFormSpecMenu::getListboxIndex(std::string listboxname) {
143
148
return -1 ;
144
149
}
145
150
151
+ bool GUIFormSpecMenu::checkListboxClick (std::wstring wlistboxname,
152
+ int eventtype)
153
+ {
154
+ // WARNING: BLACK IRRLICHT MAGIC
155
+ // Used to fix Irrlicht's subpar reporting of single clicks and double
156
+ // clicks in listboxes (gui::EGET_LISTBOX_CHANGED,
157
+ // gui::EGET_LISTBOX_SELECTED_AGAIN):
158
+ // 1. IGUIListBox::setSelected() is counted as a click.
159
+ // Including the initial setSelected() done by parseTextList().
160
+ // 2. Clicking on a the selected item and then dragging for less
161
+ // than 500ms is counted as a doubleclick, no matter when the
162
+ // item was previously selected (e.g. more than 500ms ago)
163
+
164
+ // So when Irrlicht reports a doubleclick, we need to check
165
+ // for ourselves if really was a doubleclick. Or just a fake.
166
+
167
+ for (unsigned int i=0 ; i < m_listboxes.size (); i++) {
168
+ std::wstring name (m_listboxes[i].first .fname .c_str ());
169
+ int selected = m_listboxes[i].second ->getSelected ();
170
+ if (name == wlistboxname && selected >= 0 ) {
171
+ u32 now = getTimeMs ();
172
+ bool doubleclick =
173
+ (eventtype == gui::EGET_LISTBOX_SELECTED_AGAIN)
174
+ && (name == m_listbox_click_fname)
175
+ && (selected == m_listbox_click_index)
176
+ && (m_listbox_click_time >= now - 500 );
177
+ m_listbox_click_fname = name;
178
+ m_listbox_click_index = selected;
179
+ m_listbox_click_time = now;
180
+ m_listbox_doubleclick = doubleclick;
181
+ return true ;
182
+ }
183
+ }
184
+ return false ;
185
+ }
186
+
146
187
std::vector<std::string> split (const std::string &s, char delim) {
147
188
std::vector<std::string> tokens;
148
189
@@ -1920,7 +1961,7 @@ ItemStack GUIFormSpecMenu::verifySelectedItem()
1920
1961
return ItemStack ();
1921
1962
}
1922
1963
1923
- void GUIFormSpecMenu::acceptInput (int eventtype )
1964
+ void GUIFormSpecMenu::acceptInput ()
1924
1965
{
1925
1966
if (m_text_dst)
1926
1967
{
@@ -1957,11 +1998,12 @@ void GUIFormSpecMenu::acceptInput(int eventtype)
1957
1998
}
1958
1999
else if (s.ftype == f_ListBox) {
1959
2000
std::stringstream ss;
1960
- if (eventtype == gui::EGET_LISTBOX_CHANGED) {
1961
- ss << " CHG:" ;
2001
+
2002
+ if (m_listbox_doubleclick) {
2003
+ ss << " DCL:" ;
1962
2004
}
1963
2005
else {
1964
- ss << " DCL :" ;
2006
+ ss << " CHG :" ;
1965
2007
}
1966
2008
ss << (getListboxIndex (wide_to_narrow (s.fname .c_str ()))+1 );
1967
2009
fields[wide_to_narrow (s.fname .c_str ())] = ss.str ();
@@ -2459,12 +2501,16 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
2459
2501
for (u32 i=0 ; i<m_fields.size (); i++)
2460
2502
{
2461
2503
FieldSpec &s = m_fields[i];
2462
- // if its a button, set the send field so
2463
- // lua knows which button was pressed
2464
- if ((s.ftype == f_ListBox) && (s.fid == current_id))
2504
+ // if its a listbox, set the send field so
2505
+ // lua knows which listbox was changed
2506
+ // checkListboxClick() is black magic
2507
+ // for properly handling double clicks
2508
+ if ((s.ftype == f_ListBox) && (s.fid == current_id)
2509
+ && checkListboxClick (s.fname ,
2510
+ event.GUIEvent .EventType ))
2465
2511
{
2466
2512
s.send = true ;
2467
- acceptInput (event. GUIEvent . EventType );
2513
+ acceptInput ();
2468
2514
s.send =false ;
2469
2515
// Restore focus to the full form
2470
2516
Environment->setFocus (this );
0 commit comments