aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/guiFormSpecMenu.cpp50
-rw-r--r--src/guiFormSpecMenu.h3
2 files changed, 51 insertions, 2 deletions
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index 79497dca1..6c34ecc2c 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -184,6 +184,38 @@ bool GUIFormSpecMenu::checkListboxClick(std::wstring wlistboxname,
return false;
}
+gui::IGUIScrollBar* GUIFormSpecMenu::getListboxScrollbar(
+ gui::IGUIListBox *listbox)
+{
+ // WARNING: BLACK IRRLICHT MAGIC
+ // Ordinarily, due to how formspecs work (recreating the entire GUI
+ // when something changes), when you select an item in a textlist
+ // with more items than fit in the visible area, the newly selected
+ // item is scrolled to the bottom of the visible area. This is
+ // annoying and breaks GUI designs that use double clicks.
+
+ // This function helps fixing this problem by giving direct access
+ // to a listbox's scrollbar. This works because CGUIListBox doesn't
+ // cache the scrollbar position anywhere.
+
+ // If this stops working in a future irrlicht version, consider
+ // maintaining a local copy of irr::gui::CGUIListBox, possibly also
+ // fixing the other reasons why black irrlicht magic is needed.
+
+ core::list<gui::IGUIElement*> children = listbox->getChildren();
+ for(core::list<gui::IGUIElement*>::Iterator it = children.begin();
+ it != children.end(); ++it) {
+ gui::IGUIElement* child = *it;
+ if (child && child->getType() == gui::EGUIET_SCROLL_BAR) {
+ return static_cast<gui::IGUIScrollBar*>(child);
+ }
+ }
+
+ verbosestream<<"getListboxScrollbar: WARNING: "
+ <<"listbox has no scrollbar"<<std::endl;
+ return NULL;
+}
+
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> tokens;
@@ -616,6 +648,13 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) {
e->setSelected(data->listbox_selections[fname_w]);
}
+ if (data->listbox_scroll.find(fname_w) != data->listbox_scroll.end()) {
+ gui::IGUIScrollBar *scrollbar = getListboxScrollbar(e);
+ if (scrollbar) {
+ scrollbar->setPos(data->listbox_scroll[fname_w]);
+ }
+ }
+
if (str_initial_selection != "")
e->setSelected(stoi(str_initial_selection.c_str())-1);
@@ -1417,11 +1456,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
//preserve listboxes
for (unsigned int i = 0; i < m_listboxes.size(); i++) {
- int selection = m_listboxes[i].second->getSelected();
+ std::wstring listboxname = m_listboxes[i].first.fname;
+ gui::IGUIListBox *listbox = m_listboxes[i].second;
+
+ int selection = listbox->getSelected();
if (selection != -1) {
- std::wstring listboxname = m_listboxes[i].first.fname;
mydata.listbox_selections[listboxname] = selection;
}
+
+ gui::IGUIScrollBar *scrollbar = getListboxScrollbar(listbox);
+ if (scrollbar) {
+ mydata.listbox_scroll[listboxname] = scrollbar->getPos();
+ }
}
// Remove children
diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h
index 28f11d2e7..f8d7ff1fb 100644
--- a/src/guiFormSpecMenu.h
+++ b/src/guiFormSpecMenu.h
@@ -294,6 +294,7 @@ private:
int bp_set;
v2u32 screensize;
std::map<std::wstring,int> listbox_selections;
+ std::map<std::wstring,int> listbox_scroll;
} parserData;
typedef struct {
@@ -311,6 +312,8 @@ private:
// (Using some black Irrlicht magic)
bool checkListboxClick(std::wstring wlistboxname, int eventtype);
+ gui::IGUIScrollBar* getListboxScrollbar(gui::IGUIListBox *listbox);
+
void parseElement(parserData* data,std::string element);
void parseSize(parserData* data,std::string element);