From 8548bb75b66f871d1b6941ca9b79012e88274799 Mon Sep 17 00:00:00 2001 From: Kahrl Date: Mon, 19 Aug 2013 11:26:51 +0200 Subject: GUIFormSpecMenu focus fixes --- src/guiFormSpecMenu.cpp | 192 +++++++++++++++++++++++++++++++++++++++++++----- src/guiFormSpecMenu.h | 3 + src/main.cpp | 2 +- src/mainmenumanager.h | 9 +++ src/modalMenu.h | 1 + 5 files changed, 189 insertions(+), 18 deletions(-) (limited to 'src') 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: -- cgit v1.2.3