From 8548bb75b66f871d1b6941ca9b79012e88274799 Mon Sep 17 00:00:00 2001 From: Kahrl Date: Mon, 19 Aug 2013 11:26:51 +0200 Subject: [PATCH] GUIFormSpecMenu focus fixes --- builtin/modmgr.lua | 91 +++++++++---------- src/guiFormSpecMenu.cpp | 192 ++++++++++++++++++++++++++++++++++++---- src/guiFormSpecMenu.h | 3 + src/main.cpp | 2 +- src/mainmenumanager.h | 9 ++ src/modalMenu.h | 1 + 6 files changed, 232 insertions(+), 66 deletions(-) diff --git a/builtin/modmgr.lua b/builtin/modmgr.lua index 9f5e687b2..81ac94c0e 100644 --- a/builtin/modmgr.lua +++ b/builtin/modmgr.lua @@ -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] diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index b0cfa38c2..1da923cd1 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -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 children = getChildren(); + + // in case "children" contains any NULL elements, remove them + for (core::list::Iterator it = children.begin(); + it != children.end();) { + if (*it) + ++it; + else + it = children.erase(it); + } + + // 1. first empty editbox + for (core::list::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::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::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::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::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(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 { 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& 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; isetTextAlignment(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(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; diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 640c35c0a..73c21b72d 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -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 listbox_selections; std::map listbox_scroll; } parserData; diff --git a/src/main.cpp b/src/main.cpp index 7450593d3..05a7dd163 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -244,7 +244,7 @@ public: */ if(noMenuActive() == false) { - return false; + return g_menumgr.preprocessEvent(event); } // Remember whether each key is down or up diff --git a/src/mainmenumanager.h b/src/mainmenumanager.h index a3133686b..d151cf48d 100644 --- a/src/mainmenumanager.h +++ b/src/mainmenumanager.h @@ -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(); diff --git a/src/modalMenu.h b/src/modalMenu.h index 62bfabc06..c8b45a247 100644 --- a/src/modalMenu.h +++ b/src/modalMenu.h @@ -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: