]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/guiFormSpecMenu.cpp
Add curl, freetype and luaJIT to CMAKE_BUILD_INFO
[dragonfireclient.git] / src / guiFormSpecMenu.cpp
index 79497dca1814ff35d59d4aab0504962fd2af1332..28cb6740e3d8a2dee8ff44252cb3bb19d2062e98 100644 (file)
@@ -44,10 +44,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/numeric.h"
 #include "filesys.h"
 #include "gettime.h"
-
 #include "gettext.h"
 
-
 #define MY_CHECKPOS(a,b)                                                                                                       \
        if (v_pos.size() != 2) {                                                                                                \
                errorstream<< "Invalid pos for element " << a << "specified: \""        \
@@ -71,12 +69,14 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
                gui::IGUIElement* parent, s32 id,
                IMenuManager *menumgr,
                InventoryManager *invmgr,
-               IGameDef *gamedef
+               IGameDef *gamedef,
+               ISimpleTextureSource *tsrc
 ):
        GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr),
        m_device(dev),
        m_invmgr(invmgr),
        m_gamedef(gamedef),
+       m_tsrc(tsrc),
        m_form_src(NULL),
        m_text_dst(NULL),
        m_selected_item(NULL),
@@ -88,7 +88,6 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
        m_listbox_doubleclick(false),
        m_tooltip_element(NULL),
        m_allowclose(true),
-       m_use_gettext(false),
        m_lock(false)
 {
        current_keys_pending.key_down = false;
@@ -127,11 +126,89 @@ void GUIFormSpecMenu::removeChildren()
                if(e != NULL)
                        e->remove();
        }*/
+
        if(m_tooltip_element)
        {
                m_tooltip_element->remove();
+               m_tooltip_element->drop();
                m_tooltip_element = NULL;
        }
+
+}
+
+void GUIFormSpecMenu::setInitialFocus()
+{
+       // Set initial focus according to following order of precedence:
+       // 1. first empty editbox
+       // 2. first editbox
+       // 3. first listbox
+       // 4. last button
+       // 5. first focusable (not statictext, not tabheader)
+       // 6. first child element
+
+       core::list<gui::IGUIElement*> children = getChildren();
+
+       // in case "children" contains any NULL elements, remove them
+       for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
+                       it != children.end();) {
+               if (*it)
+                       ++it;
+               else
+                       it = children.erase(it);
+       }
+
+       // 1. first empty editbox
+       for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
+                       it != children.end(); ++it) {
+               if ((*it)->getType() == gui::EGUIET_EDIT_BOX
+                               && (*it)->getText()[0] == 0) {
+                       Environment->setFocus(*it);
+                       return;
+               }
+       }
+
+       // 2. first editbox
+       for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
+                       it != children.end(); ++it) {
+               if ((*it)->getType() == gui::EGUIET_EDIT_BOX) {
+                       Environment->setFocus(*it);
+                       return;
+               }
+       }
+
+       // 3. first listbox
+       for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
+                       it != children.end(); ++it) {
+               if ((*it)->getType() == gui::EGUIET_LIST_BOX) {
+                       Environment->setFocus(*it);
+                       return;
+               }
+       }
+
+       // 4. last button
+       for (core::list<gui::IGUIElement*>::Iterator it = children.getLast();
+                       it != children.end(); --it) {
+               if ((*it)->getType() == gui::EGUIET_BUTTON) {
+                       Environment->setFocus(*it);
+                       return;
+               }
+       }
+
+       // 5. first focusable (not statictext, not tabheader)
+       for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
+                       it != children.end(); ++it) {
+               if ((*it)->getType() != gui::EGUIET_STATIC_TEXT &&
+                               (*it)->getType() != gui::EGUIET_TAB_CONTROL) {
+                       Environment->setFocus(*it);
+                       return;
+               }
+       }
+
+       // 6. first child element
+       if (children.empty())
+               Environment->setFocus(this);
+       else
+               Environment->setFocus(*(children.begin()));
 }
 
 int GUIFormSpecMenu::getListboxIndex(std::string listboxname) {
@@ -184,6 +261,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;
 
@@ -228,8 +337,6 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element) {
                invsize.X = stof(parts[0]);
                invsize.Y = stof(parts[1]);
 
-               infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
-
                if (m_lock) {
                        v2u32 current_screensize = m_device->getVideoDriver()->getScreenSize();
                        v2u32 delta = current_screensize - m_lockscreensize;
@@ -310,10 +417,6 @@ void GUIFormSpecMenu::parseList(parserData* data,std::string element) {
                v2s32 geom;
                geom.X = stoi(v_geom[0]);
                geom.Y = stoi(v_geom[1]);
-               infostream<<"list inv="<<location<<", listname="<<listname
-                               <<", pos=("<<pos.X<<","<<pos.Y<<")"
-                               <<", geom=("<<geom.X<<","<<geom.Y<<")"
-                               <<std::endl;
 
                s32 start_i = 0;
                if(startindex != "")
@@ -353,9 +456,6 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element) {
 
                std::wstring wlabel = narrow_to_wide(label.c_str());
 
-               if (m_use_gettext)
-                       wlabel = wstrgettext(label);
-
                FieldSpec spec = FieldSpec(
                                narrow_to_wide(name.c_str()),
                                L"",
@@ -367,6 +467,11 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element) {
                spec.flabel = wlabel; //Needed for displaying text on MSVC
                gui::IGUICheckBox* e = Environment->addCheckBox(fselected, rect, this,
                                        spec.fid, spec.flabel.c_str());
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
+
                m_checkboxes.push_back(std::pair<FieldSpec,gui::IGUICheckBox*>(spec,e));
                m_fields.push_back(spec);
                return;
@@ -380,7 +485,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) {
        if (parts.size() == 3) {
                std::vector<std::string> v_pos = split(parts[0],',');
                std::vector<std::string> v_geom = split(parts[1],',');
-               std::string name = parts[2];
+               std::string name = unescape_string(parts[2]);
 
                MY_CHECKPOS("image",0);
                MY_CHECKGEOM("image",1);
@@ -390,13 +495,9 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) {
                pos.Y += stof(v_pos[1]) * (float) spacing.Y;
 
                v2s32 geom;
-               geom.X = stoi(v_geom[0]) * (float)imgsize.X;
-               geom.Y = stoi(v_geom[1]) * (float)imgsize.Y;
+               geom.X = stof(v_geom[0]) * (float)imgsize.X;
+               geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
 
-               infostream<<"image name="<<name
-                               <<", pos=("<<pos.X<<","<<pos.Y<<")"
-                               <<", geom=("<<geom.X<<","<<geom.Y<<")"
-                               <<std::endl;
                if(data->bp_set != 2)
                        errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
                m_images.push_back(ImageDrawSpec(name, pos, geom));
@@ -405,7 +506,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) {
 
        if (parts.size() == 2) {
                std::vector<std::string> v_pos = split(parts[0],',');
-               std::string name = parts[1];
+               std::string name = unescape_string(parts[1]);
 
                MY_CHECKPOS("image",0);
 
@@ -413,9 +514,6 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) {
                pos.X += stof(v_pos[0]) * (float) spacing.X;
                pos.Y += stof(v_pos[1]) * (float) spacing.Y;
 
-               std::cout<<"image name="<<name
-                               <<", pos=("<<pos.X<<","<<pos.Y<<")"
-                               <<std::endl;
                if(data->bp_set != 2)
                        errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
                m_images.push_back(ImageDrawSpec(name, pos));
@@ -443,10 +541,6 @@ void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element) {
                geom.X = stoi(v_geom[0]) * (float)imgsize.X;
                geom.Y = stoi(v_geom[1]) * (float)imgsize.Y;
 
-               infostream<<"item name="<<name
-                               <<", pos=("<<pos.X<<","<<pos.Y<<")"
-                               <<", geom=("<<geom.X<<","<<geom.Y<<")"
-                               <<std::endl;
                if(data->bp_set != 2)
                        errorstream<<"WARNING: invalid use of item_image without a size[] element"<<std::endl;
                m_itemimages.push_back(ImageDrawSpec(name, pos, geom));
@@ -484,9 +578,6 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::stri
 
                std::wstring wlabel = narrow_to_wide(label.c_str());
 
-               if (m_use_gettext)
-                       wlabel = wstrgettext(label);
-
                FieldSpec spec = FieldSpec(
                        narrow_to_wide(name.c_str()),
                        wlabel,
@@ -497,7 +588,13 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::stri
                if(type == "button_exit")
                        spec.is_exit = true;
 
-               Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
+               gui::IGUIButton* e = Environment->addButton(rect, this, spec.fid,
+                               spec.flabel.c_str());
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
+
                m_fields.push_back(spec);
                return;
        }
@@ -510,7 +607,7 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) {
        if (parts.size() == 3) {
                std::vector<std::string> v_pos = split(parts[0],',');
                std::vector<std::string> v_geom = split(parts[1],',');
-               std::string name = parts[2];
+               std::string name = unescape_string(parts[2]);
 
                MY_CHECKPOS("background",0);
                MY_CHECKGEOM("background",1);
@@ -523,10 +620,6 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) {
                geom.X = stof(v_geom[0]) * (float)spacing.X;
                geom.Y = stof(v_geom[1]) * (float)spacing.Y;
 
-               infostream<<"image name="<<name
-                               <<", pos=("<<pos.X<<","<<pos.Y<<")"
-                               <<", geom=("<<geom.X<<","<<geom.Y<<")"
-                               <<std::endl;
                if(data->bp_set != 2)
                        errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
                m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
@@ -580,9 +673,8 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) {
                //now really show list
                gui::IGUIListBox *e = Environment->addListBox(rect, this,spec.fid);
 
-               //don't reset if we already have a user specified selection
-               if (data->listbox_selections.find(fname_w) == data->listbox_selections.end()) {
-                       e->setAutoScrollEnabled(false);
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
                }
 
                if (str_transparent == "false")
@@ -598,7 +690,6 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) {
                                        std::wstring toadd =
                                                narrow_to_wide(unescape_string(items[i]).c_str() + 7);
 
-
                                        e->addItem(toadd.c_str());
 
                                        irr::video::SColor toset;
@@ -616,6 +707,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);
 
@@ -662,10 +760,9 @@ void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) {
                //now really show list
                gui::IGUIComboBox *e = Environment->addComboBox(rect, this,spec.fid);
 
-               //don't reset if we already have a user specified selection
-               //if (data->combobox_selections.find(fname_w) == data->listbox_selections.end()) {
-               //      e->setAutoScrollEnabled(false);
-               //}
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
 
                for (unsigned int i=0; i < items.size(); i++) {
                        e->addItem(narrow_to_wide(items[i]).c_str());
@@ -674,11 +771,6 @@ void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) {
                if (str_initial_selection != "")
                        e->setSelected(stoi(str_initial_selection.c_str())-1);
 
-               //if (data->listbox_selections.find(fname_w) != data->listbox_selections.end()) {
-               //      e->setSelected(data->listbox_selections[fname_w]);
-               //}
-
-               //m_listboxes.push_back(std::pair<FieldSpec,gui::IGUIListBox*>(spec,e));
                m_fields.push_back(spec);
                return;
        }
@@ -715,13 +807,6 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) {
 
                std::wstring wlabel = narrow_to_wide(label.c_str());
 
-               if (m_use_gettext) {
-                       if (label.length() > 1)
-                               wlabel = wstrgettext(label);
-                       else
-                               wlabel = L"";
-               }
-
                FieldSpec spec = FieldSpec(
                        narrow_to_wide(name.c_str()),
                        wlabel,
@@ -731,7 +816,10 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) {
 
                spec.send = true;
                gui::IGUIEditBox * e = Environment->addEditBox(0, rect, true, this, spec.fid);
-               Environment->setFocus(e);
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
 
                if (label.length() > 1)
                {
@@ -794,13 +882,6 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,std::vector<std::string>
 
        std::wstring wlabel = narrow_to_wide(label.c_str());
 
-       if (m_use_gettext) {
-               if (label.length() > 1)
-                       wlabel = wstrgettext(label);
-               else
-                       wlabel = L"";
-       }
-
        FieldSpec spec = FieldSpec(
                narrow_to_wide(name.c_str()),
                wlabel,
@@ -817,7 +898,10 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,std::vector<std::string>
        {
                spec.send = true;
                gui::IGUIEditBox *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
-               Environment->setFocus(e);
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
 
                irr::SEvent evt;
                evt.EventType            = EET_KEY_INPUT_EVENT;
@@ -884,13 +968,6 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,std::vector<std::string>& p
 
        std::wstring wlabel = narrow_to_wide(label.c_str());
 
-       if (m_use_gettext) {
-               if (label.length() > 1)
-                       wlabel = wstrgettext(label);
-               else
-                       wlabel = L"";
-       }
-
        FieldSpec spec = FieldSpec(
                narrow_to_wide(name.c_str()),
                wlabel,
@@ -907,7 +984,10 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,std::vector<std::string>& p
        {
                spec.send = true;
                gui::IGUIEditBox *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
-               Environment->setFocus(e);
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
 
                if (type == "textarea")
                {
@@ -971,9 +1051,6 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) {
 
                std::wstring wlabel = narrow_to_wide(text.c_str());
 
-               if (m_use_gettext)
-                       wlabel = wstrgettext(text);
-
                FieldSpec spec = FieldSpec(
                        L"",
                        wlabel,
@@ -992,7 +1069,7 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) {
 
        if (parts.size() == 2) {
                std::vector<std::string> v_pos = split(parts[0],',');
-               std::string text = parts[1];
+               std::wstring text = narrow_to_wide(unescape_string(parts[1]));
 
                MY_CHECKPOS("vertlabel",1);
 
@@ -1005,23 +1082,16 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) {
                if(data->bp_set != 2)
                        errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
 
-               text = unescape_string(text);
-               std::string label = "";
-
-               if (m_use_gettext) {
-                       const char* toset = gettext(text.c_str());
-
-                       text = std::string(toset);
-               }
+               std::wstring label = L"";
 
                for (unsigned int i=0; i < text.length(); i++) {
-                       label += text.c_str()[i];
-                       label += "\n";
+                       label += text[i];
+                       label += L"\n";
                }
 
                FieldSpec spec = FieldSpec(
                        L"",
-                       narrow_to_wide(label.c_str()),
+                       label,
                        L"",
                        258+m_fields.size()
                );
@@ -1076,13 +1146,12 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std:
                if(data->bp_set != 2)
                        errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
 
+               image_name = unescape_string(image_name);
+               pressed_image_name = unescape_string(pressed_image_name);
                label = unescape_string(label);
 
                std::wstring wlabel = narrow_to_wide(label.c_str());
 
-               if (m_use_gettext)
-                       wlabel = wstrgettext(label);
-
                FieldSpec spec = FieldSpec(
                        narrow_to_wide(name.c_str()),
                        wlabel,
@@ -1095,27 +1164,18 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std:
 
                video::ITexture *texture = 0;
                video::ITexture *pressed_texture = 0;
-               //if there's no gamedef specified try to get direct
-               //TODO check for possible texture leak
-               if (m_gamedef != 0) {
-                       texture = m_gamedef->tsrc()->getTexture(image_name);
-                       if ((parts.size() == 8)) {
-                               pressed_texture = m_gamedef->tsrc()->getTexture(pressed_image_name);
-                       }
-               } else {
-                       if (fs::PathExists(image_name)) {
-                               texture = Environment->getVideoDriver()->getTexture(image_name.c_str());
-                               m_Textures.push_back(texture);
-                       }
-                       if (fs::PathExists(pressed_image_name)) {
-                               pressed_texture = Environment->getVideoDriver()->getTexture(pressed_image_name.c_str());
-                               m_Textures.push_back(pressed_texture);
-                       }
-               }
-               if (parts.size() < 8)
+               texture = m_tsrc->getTexture(image_name);
+               if (parts.size() == 8)
+                       pressed_texture = m_tsrc->getTexture(pressed_image_name);
+               else
                        pressed_texture = texture;
 
                gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
+
                e->setUseAlphaChannel(true);
                e->setImage(texture);
                e->setPressedImage(pressed_texture);
@@ -1171,20 +1231,19 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) {
 
                gui::IGUITabControl *e = Environment->addTabControl(rect,this,show_background,show_border,spec.fid);
 
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
+
                e->setNotClipped(true);
 
                for (unsigned int i=0; i< buttons.size(); i++) {
                        wchar_t* wbutton = 0;
 
-                       if (m_use_gettext)
-                               wbutton = wgettext(buttons[i].c_str());
-                       else
-                               wbutton = (wchar_t*) narrow_to_wide(buttons[i].c_str()).c_str();
+                       std::wstring wlabel = narrow_to_wide(buttons[i]); //Needed for displaying text on windows
+                       wbutton = (wchar_t*) wlabel.c_str();
 
                        e->addTab(wbutton,-1);
-
-                       if (m_use_gettext)
-                               delete[] wbutton;
                }
 
                if ((tab_index >= 0) &&
@@ -1244,6 +1303,11 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
                );
 
                gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
+
+               if (spec.fname == data->focused_fieldname) {
+                       Environment->setFocus(e);
+               }
+
                e->setUseAlphaChannel(true);
                e->setImage(texture);
                e->setPressedImage(texture);
@@ -1417,11 +1481,33 @@ 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();
+               }
+       }
+
+       //preserve focus
+       gui::IGUIElement *focused_element = Environment->getFocus();
+       if (focused_element && focused_element->getParent() == this) {
+               s32 focused_id = focused_element->getID();
+               if (focused_id > 257) {
+                       for (u32 i=0; i<m_fields.size(); i++) {
+                               if (m_fields[i].fid == focused_id) {
+                                       mydata.focused_fieldname =
+                                               m_fields[i].fname;
+                                       break;
+                               }
+                       }
+               }
        }
 
        // Remove children
@@ -1508,7 +1594,16 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
                m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
                m_tooltip_element->setWordWrap(false);
+               //we're not parent so no autograb for this one!
+               m_tooltip_element->grab();
        }
+
+       //set initial focus if parser didn't set it
+       focused_element = Environment->getFocus();
+       if (!focused_element
+                       || !isMyChild(focused_element)
+                       || focused_element->getType() == gui::EGUIET_TAB_CONTROL)
+               setInitialFocus();
 }
 
 GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
@@ -1687,15 +1782,7 @@ void GUIFormSpecMenu::drawMenu()
        for(u32 i=0; i<m_backgrounds.size(); i++)
        {
                const ImageDrawSpec &spec = m_backgrounds[i];
-               video::ITexture *texture = 0;
-
-               if (m_gamedef != 0)
-                       texture = m_gamedef->tsrc()->getTexture(spec.name);
-               else
-               {
-                       texture = driver->getTexture(spec.name.c_str());
-                       m_Textures.push_back(texture);
-               }
+               video::ITexture *texture = m_tsrc->getTexture(spec.name);
 
                if (texture != 0) {
                        // Image size on screen
@@ -1737,15 +1824,8 @@ void GUIFormSpecMenu::drawMenu()
        for(u32 i=0; i<m_images.size(); i++)
        {
                const ImageDrawSpec &spec = m_images[i];
-               video::ITexture *texture = 0;
+               video::ITexture *texture = m_tsrc->getTexture(spec.name);
 
-               if (m_gamedef != 0)
-                       texture = m_gamedef->tsrc()->getTexture(spec.name);
-               else
-               {
-                       texture = driver->getTexture(spec.name.c_str());
-                       m_Textures.push_back(texture);
-               }
                if (texture != 0) {
                        const core::dimension2d<u32>& img_origsize = texture->getOriginalSize();
                        // Image size on screen
@@ -2065,6 +2145,41 @@ void GUIFormSpecMenu::acceptInput()
        }
 }
 
+bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
+{
+       // Fix Esc/Return key being eaten by checkboxen and listboxen
+       if(event.EventType==EET_KEY_INPUT_EVENT)
+       {
+               KeyPress kp(event.KeyInput);
+               if (kp == EscapeKey || kp == getKeySetting("keymap_inventory")
+                               || event.KeyInput.Key==KEY_RETURN)
+               {
+                       gui::IGUIElement *focused = Environment->getFocus();
+                       if (focused && isMyChild(focused) &&
+                                       (focused->getType() == gui::EGUIET_LIST_BOX ||
+                                        focused->getType() == gui::EGUIET_CHECK_BOX)) {
+                               OnEvent(event);
+                               return true;
+                       }
+               }
+       }
+       // Mouse wheel events: send to hovered element instead of focused
+       if(event.EventType==EET_MOUSE_INPUT_EVENT
+                       && event.MouseInput.Event == EMIE_MOUSE_WHEEL)
+       {
+               s32 x = event.MouseInput.X;
+               s32 y = event.MouseInput.Y;
+               gui::IGUIElement *hovered =
+                       Environment->getRootGUIElement()->getElementFromPoint(
+                               core::position2d<s32>(x, y));
+               if (hovered && isMyChild(hovered)) {
+                       hovered->OnEvent(event);
+                       return true;
+               }
+       }
+       return false;
+}
+
 bool GUIFormSpecMenu::OnEvent(const SEvent& event)
 {
        if(event.EventType==EET_KEY_INPUT_EVENT)
@@ -2415,8 +2530,6 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                                        s.send = true;
                                        acceptInput();
                                        s.send = false;
-                                       // Restore focus to the full form
-                                       Environment->setFocus(this);
                                        return true;
                                }
                        }
@@ -2466,8 +2579,6 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                                                return true;
                                        }else{
                                                s.send = false;
-                                               // Restore focus to the full form
-                                               Environment->setFocus(this);
                                                return true;
                                        }
                                }
@@ -2512,8 +2623,6 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                                                s.send = true;
                                                acceptInput();
                                                s.send=false;
-                                               // Restore focus to the full form
-                                               Environment->setFocus(this);
                                        }
                                }
                                return true;