GUIFormSpecMenu focus fixes
authorKahrl <kahrl@gmx.net>
Mon, 19 Aug 2013 09:26:51 +0000 (11:26 +0200)
committerKahrl <kahrl@gmx.net>
Mon, 19 Aug 2013 13:49:36 +0000 (15:49 +0200)
builtin/modmgr.lua
src/guiFormSpecMenu.cpp
src/guiFormSpecMenu.h
src/main.cpp
src/mainmenumanager.h
src/modalMenu.h

index 9f5e687b2bc4d38fe381524bed4ef18ef9559f50..81ac94c0ea2fed5d7cb8c173b135351f4dc80bf0 100644 (file)
@@ -329,6 +329,8 @@ function modmgr.render_modlist(render_list)
                if retval ~= "" then
                        retval = retval ..","
                end
+
+               local color = ""
                
                if v.is_modpack then
                        local rawlist = filterlist.get_raw_list(render_list)
@@ -343,19 +345,21 @@ function modmgr.render_modlist(render_list)
                        end
                        
                        if all_enabled == false then
-                               retval = retval .. mt_color_grey
+                               color = mt_color_grey
                        else
-                               retval = retval .. mt_color_dark_green
+                               color = mt_color_dark_green
                        end
                end
                
                if v.typ == "game_mod" then
-                       retval = retval .. mt_color_blue
+                       color = mt_color_blue
                else
                        if v.enabled then
-                               retval = retval .. mt_color_green
+                               color = mt_color_green
                        end
                end
+
+               retval = retval .. color
                if v.modpack  ~= nil then
                        retval = retval .. "    "
                end
@@ -401,7 +405,7 @@ function modmgr.dialog_configure_world()
                "button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
                "button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
        
-       if mod ~= nil and mod.name ~= "" then
+       if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
                if mod.is_modpack then
                        local rawlist = filterlist.get_raw_list(modmgr.modlist)
                        
@@ -662,57 +666,23 @@ function modmgr.handle_configure_world_buttons(fields)
                modmgr.world_config_selected_mod = event.index
 
                if event.typ == "DCL" then
-                       local mod = filterlist.get_list(modmgr.modlist)[event.index]
-                       
-                       if mod.typ == "game_mod" then
-                               return nil
-                       end
-                       
-                       if not mod.is_modpack then
-                               mod.enabled = not mod.enabled
-                       else
-                               local list = filterlist.get_raw_list(modmgr.modlist)
-                               local toset = nil
-                               
-                               for i=1,#list,1 do
-                                       if list[i].modpack == mod.name then
-                                               if toset == nil then
-                                                       toset = not list[i].enabled
-                                               end
-                                               
-                                               list[i].enabled = toset
-                                       end
-                               end
-                       end
+                       modmgr.world_config_enable_mod(nil)
                end
        end
        
+       if fields["key_enter"] ~= nil then
+               modmgr.world_config_enable_mod(nil)
+       end
+       
        if fields["cb_mod_enable"] ~= nil then
-               local mod = filterlist.get_list(modmgr.modlist)
-                       [engine.get_textlist_index("world_config_modlist")]
-               if fields["cb_mod_enable"] == "true" then
-                       mod.enabled = true
-               else
-                       mod.enabled = false
-               end
+               local toset = (fields["cb_mod_enable"] == "true")
+               modmgr.world_config_enable_mod(toset)
        end
        
        if fields["btn_mp_enable"] ~= nil or
                fields["btn_mp_disable"] then
-               local mod = filterlist.get_list(modmgr.modlist)
-                       [engine.get_textlist_index("world_config_modlist")]
-               
-               local toset=false
-               if fields["btn_mp_enable"] ~= nil then
-                       toset = true
-               end
-               local list = filterlist.get_raw_list(modmgr.modlist)
-               
-               for i=1,#list,1 do
-                       if list[i].modpack == mod.name then
-                               list[i].enabled = toset
-                       end
-               end
+               local toset = (fields["btn_mp_enable"] ~= nil)
+               modmgr.world_config_enable_mod(toset)
        end
        
        if fields["cb_hide_gamemods"] ~= nil then
@@ -818,6 +788,31 @@ function modmgr.handle_configure_world_buttons(fields)
        return nil
 end
 --------------------------------------------------------------------------------
+function modmgr.world_config_enable_mod(toset)
+       local mod = filterlist.get_list(modmgr.modlist)
+               [engine.get_textlist_index("world_config_modlist")]
+
+       if mod.typ == "game_mod" then
+               -- game mods can't be enabled or disabled
+       elseif not mod.is_modpack then
+               if toset == nil then
+                       mod.enabled = not mod.enabled
+               else
+                       mod.enabled = toset
+               end
+       else
+               local list = filterlist.get_raw_list(modmgr.modlist)
+               for i=1,#list,1 do
+                       if list[i].modpack == mod.name then
+                               if toset == nil then
+                                       toset = not list[i].enabled
+                               end
+                               list[i].enabled = toset
+                       end
+               end
+       end
+end
+--------------------------------------------------------------------------------
 function modmgr.handle_delete_mod_buttons(fields)
        local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
        
index b0cfa38c20783cbc05d87d79190df55bd2a72f2e..1da923cd17686df84fa061cb1f293b60e132eede 100644 (file)
@@ -131,6 +131,81 @@ void GUIFormSpecMenu::removeChildren()
        }
 }
 
+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) {
 
        std::wstring wlistboxname = narrow_to_wide(listboxname.c_str());
@@ -387,6 +462,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;
@@ -503,7 +583,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;
        }
@@ -582,9 +668,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")
@@ -670,10 +755,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());
@@ -732,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)
                {
@@ -811,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;
@@ -894,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")
                {
@@ -1091,6 +1184,11 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std:
                        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);
@@ -1146,6 +1244,10 @@ 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++) {
@@ -1213,6 +1315,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);
@@ -1400,6 +1507,21 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                }
        }
 
+       //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
        removeChildren();
 
@@ -1485,6 +1607,13 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
                m_tooltip_element->setWordWrap(false);
        }
+
+       //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
@@ -2041,6 +2170,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)
@@ -2391,8 +2555,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;
                                }
                        }
@@ -2442,8 +2604,6 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                                                return true;
                                        }else{
                                                s.send = false;
-                                               // Restore focus to the full form
-                                               Environment->setFocus(this);
                                                return true;
                                        }
                                }
@@ -2488,8 +2648,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;
index 640c35c0a407139ca2ac705ea3f06bd0e5e9397e..73c21b72decab7f2ebb3fac5043272746bfc43ab 100644 (file)
@@ -212,6 +212,7 @@ public:
        }
 
        void removeChildren();
+       void setInitialFocus();
        /*
                Remove and re-add (or reposition) stuff
        */
@@ -225,6 +226,7 @@ public:
        ItemStack verifySelectedItem();
 
        void acceptInput();
+       bool preprocessEvent(const SEvent& event);
        bool OnEvent(const SEvent& event);
 
        int getListboxIndex(std::string listboxname);
@@ -288,6 +290,7 @@ private:
                v2s32 basepos;
                int bp_set;
                v2u32 screensize;
+               std::wstring focused_fieldname;
                std::map<std::wstring,int> listbox_selections;
                std::map<std::wstring,int> listbox_scroll;
        } parserData;
index 7450593d326d380b6fc4d63e661dbaf671da0646..05a7dd1630e1f4ebc1d3b1fbd708c14006a19fc2 100644 (file)
@@ -244,7 +244,7 @@ public:
                */
                if(noMenuActive() == false)
                {
-                       return false;
+                       return g_menumgr.preprocessEvent(event);
                }
 
                // Remember whether each key is down or up
index a3133686bb69e32735f6d336288785f45a0710cc..d151cf48d663b33958e8be9defacb316b9f81e0a 100644 (file)
@@ -77,6 +77,15 @@ public:
                        m_stack.back()->setVisible(true);
        }
 
+       // Returns true to prevent further processing
+       virtual bool preprocessEvent(const SEvent& event)
+       {
+               if(m_stack.size() != 0)
+                       return m_stack.back()->preprocessEvent(event);
+               else
+                       return false;
+       }
+
        u32 menuCount()
        {
                return m_stack.size();
index 62bfabc06b7c9818bc4b6538b3d1db253c58631c..c8b45a247a8cb233de94e1eb0b790deecb9190f4 100644 (file)
@@ -122,6 +122,7 @@ public:
 
        virtual void regenerateGui(v2u32 screensize) = 0;
        virtual void drawMenu() = 0;
+       virtual bool preprocessEvent(const SEvent& event) { return false; };
        virtual bool OnEvent(const SEvent& event) { return false; };
 
 protected: