diff --git a/sources.cmake b/sources.cmake index ba4868d71..d4f28ae4d 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 37a09e850..8b448654f 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -420,13 +420,18 @@ namespace UserConfigParams &m_multitouch_group, "A parameter in range [0, 0.5] that determines the zone that is " "considered as max value in steering button.")); - + PARAM_PREFIX FloatUserConfigParam m_multitouch_scale PARAM_DEFAULT( FloatUserConfigParam(1.0f, "multitouch_scale", &m_multitouch_group, "A parameter in range [0.5, 1.5] that determines the scale of the " "multitouch interface.")); + PARAM_PREFIX BoolUserConfigParam m_screen_keyboard + PARAM_DEFAULT( BoolUserConfigParam(false, "screen_keyboard", + &m_multitouch_group, + "Enable screen keyboard.") ); + // ---- GP start order PARAM_PREFIX GroupUserConfigParam m_gp_start_order PARAM_DEFAULT( GroupUserConfigParam("GpStartOrder", @@ -491,7 +496,7 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_texture_compression PARAM_DEFAULT(BoolUserConfigParam(true, "enable_texture_compression", &m_video_group, "Enable Texture Compression")); - /** This is a bit flag: bit 0: enabled (1) or disabled(0). + /** This is a bit flag: bit 0: enabled (1) or disabled(0). * Bit 1: setting done by default(0), or by user choice (2). This allows * to e.g. disable h.d. textures on hd3000 as default, but still allow the * user to enable it. */ @@ -592,7 +597,7 @@ namespace UserConfigParams PARAM_PREFIX bool m_no_start_screen PARAM_DEFAULT( false ); PARAM_PREFIX bool m_race_now PARAM_DEFAULT( false ); - + PARAM_PREFIX bool m_enforce_current_player PARAM_DEFAULT( false ); /** True to test funky ambient/diffuse/specularity in RGB & @@ -910,7 +915,7 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_artist_debug_mode PARAM_DEFAULT( BoolUserConfigParam(false, "artist_debug_mode", "Whether to enable track debugging features") ); - + PARAM_PREFIX BoolUserConfigParam m_everything_unlocked PARAM_DEFAULT( BoolUserConfigParam(false, "everything_unlocked", "Enable all karts and tracks") ); diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 6f225b548..87e5c0d06 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -673,6 +673,7 @@ namespace GUIEngine #include "guiengine/message_queue.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" +#include "guiengine/screen_keyboard.hpp" #include "guiengine/skin.hpp" #include "guiengine/widget.hpp" #include "guiengine/dialog_queue.hpp" @@ -967,6 +968,7 @@ namespace GUIEngine g_current_screen = NULL; needsUpdate.clearWithoutDeleting(); + if (ScreenKeyboard::isActive()) ScreenKeyboard::dismiss(); if (ModalDialog::isADialogActive()) ModalDialog::dismiss(); //delete g_font; @@ -1345,12 +1347,19 @@ namespace GUIEngine Widget* getWidget(const char* name) { + if (ScreenKeyboard::isActive()) + { + Widget* widget = ScreenKeyboard::getCurrent()->getWidget(name); + if (widget != NULL) + return widget; + } + // if a modal dialog is shown, search within it too if (ModalDialog::isADialogActive()) { - Widget* widgetWithinDialog = - ModalDialog::getCurrent()->getWidget(name); - if (widgetWithinDialog != NULL) return widgetWithinDialog; + Widget* widget = ModalDialog::getCurrent()->getWidget(name); + if (widget != NULL) + return widget; } Screen* screen = getCurrentScreen(); @@ -1363,12 +1372,19 @@ namespace GUIEngine // ----------------------------------------------------------------------- Widget* getWidget(const int id) { + if (ScreenKeyboard::isActive()) + { + Widget* widget = ScreenKeyboard::getCurrent()->getWidget(id); + if (widget != NULL) + return widget; + } + // if a modal dialog is shown, search within it too if (ModalDialog::isADialogActive()) { - Widget* widgetWithinDialog = - ModalDialog::getCurrent()->getWidget(id); - if (widgetWithinDialog != NULL) return widgetWithinDialog; + Widget* widget = ModalDialog::getCurrent()->getWidget(id); + if (widget != NULL) + return widget; } Screen* screen = getCurrentScreen(); diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index 6f30906da..0f9fe440e 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -26,6 +26,7 @@ #include "guiengine/engine.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/screen.hpp" +#include "guiengine/screen_keyboard.hpp" #include "guiengine/widget.hpp" #include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" @@ -478,9 +479,15 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo } // don't allow navigating to any widget when a dialog is shown; only navigate to widgets in the dialog - if (ModalDialog::isADialogActive() && !ModalDialog::getCurrent()->isMyIrrChild(el)) + if (ScreenKeyboard::isActive()) { - el = NULL; + if (!ScreenKeyboard::getCurrent()->isMyIrrChild(el)) + el = NULL; + } + else if (ModalDialog::isADialogActive()) + { + if (!ModalDialog::getCurrent()->isMyIrrChild(el)) + el = NULL; } bool found = false; @@ -501,8 +508,16 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo if (playerID != PLAYER_ID_GAME_MASTER && !closestWidget->m_supports_multiplayer) return; // if a dialog is shown, restrict to items in the dialog - if (ModalDialog::isADialogActive() && !ModalDialog::getCurrent()->isMyChild(closestWidget)) - continue; + if (ScreenKeyboard::isActive()) + { + if (!ScreenKeyboard::getCurrent()->isMyChild(closestWidget)) + continue; + } + else if (ModalDialog::isADialogActive()) + { + if (!ModalDialog::getCurrent()->isMyChild(closestWidget)) + continue; + } if (NAVIGATION_DEBUG) { @@ -537,7 +552,12 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo // select the last/first widget Widget* wrapWidget = NULL; - if (ModalDialog::isADialogActive()) + if (ScreenKeyboard::isActive()) + { + wrapWidget = reverse ? ScreenKeyboard::getCurrent()->getLastWidget(): + ScreenKeyboard::getCurrent()->getFirstWidget(); + } + else if (ModalDialog::isADialogActive()) { wrapWidget = reverse ? ModalDialog::getCurrent()->getLastWidget() : ModalDialog::getCurrent()->getFirstWidget(); @@ -558,6 +578,14 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo void EventHandler::sendEventToUser(GUIEngine::Widget* widget, std::string& name, const int playerID) { + if (ScreenKeyboard::isActive()) + { + if (ScreenKeyboard::getCurrent()->processEvent(widget->m_properties[PROP_ID]) == EVENT_BLOCK) + { + return; + } + } + if (ModalDialog::isADialogActive()) { if (ModalDialog::getCurrent()->processEvent(widget->m_properties[PROP_ID]) == EVENT_BLOCK) @@ -579,6 +607,14 @@ EventPropagation EventHandler::onWidgetActivated(GUIEngine::Widget* w, const int Widget* parent = w->m_event_handler; + if (ScreenKeyboard::isActive()) + { + if (ScreenKeyboard::getCurrent()->processEvent(w->m_properties[PROP_ID]) == EVENT_BLOCK) + { + return EVENT_BLOCK; + } + } + if (ModalDialog::isADialogActive() && (parent == NULL || parent->m_type != GUIEngine::WTYPE_RIBBON)) { if (ModalDialog::getCurrent()->processEvent(w->m_properties[PROP_ID]) == EVENT_BLOCK) @@ -670,10 +706,23 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event) if (!w->isFocusable() || !w->isActivated()) return GUIEngine::EVENT_BLOCK; // When a modal dialog is shown, don't select widgets out of the dialog - if (ModalDialog::isADialogActive() && !ModalDialog::getCurrent()->isMyChild(w)) + if (ScreenKeyboard::isActive()) { // check for parents too before discarding event - if (w->m_event_handler != NULL) + if (!ScreenKeyboard::getCurrent()->isMyChild(w) && + w->m_event_handler != NULL) + { + if (!ScreenKeyboard::getCurrent()->isMyChild(w->m_event_handler)) + { + break; + } + } + } + else if (ModalDialog::isADialogActive()) + { + // check for parents too before discarding event + if (!ModalDialog::getCurrent()->isMyChild(w) && + w->m_event_handler != NULL) { if (!ModalDialog::getCurrent()->isMyChild(w->m_event_handler)) { @@ -771,7 +820,8 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event) { // currently, enter pressed in text ctrl events can only happen in dialogs. // FIXME : find a cleaner way to route the event to its proper location - if (ModalDialog::isADialogActive()) ModalDialog::onEnterPressed(); + if (!ScreenKeyboard::isActive() && ModalDialog::isADialogActive()) + ModalDialog::onEnterPressed(); break; } default: diff --git a/src/guiengine/screen_keyboard.cpp b/src/guiengine/screen_keyboard.cpp new file mode 100644 index 000000000..8edf826c8 --- /dev/null +++ b/src/guiengine/screen_keyboard.cpp @@ -0,0 +1,319 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License: or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" +#include "guiengine/engine.hpp" +#include "guiengine/screen_keyboard.hpp" +#include "guiengine/layout_manager.hpp" +#include "guiengine/widget.hpp" +#include "guiengine/widgets/button_widget.hpp" +#include "guiengine/widgets/CGUIEditBox.hpp" +#include "utils/log.hpp" + +#include + +using namespace GUIEngine; + +#define KEYBOARD_COLS_NUM 11 +#define KEYBOARD_ROWS_NUM 3 +typedef std::string KeyboardLayout[KEYBOARD_ROWS_NUM][KEYBOARD_COLS_NUM]; + +KeyboardLayout layout_lower = + {{"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "123" }, + {"a", "s", "d", "f", "g", "h", "j", "k", "l", "Back", "Shift"}, + {"z", "x", "c", "v", "b", "n", "m", ",", ".", "Space", "Enter"}}; + +KeyboardLayout layout_upper = + {{"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "123" }, + {"A", "S", "D", "F", "G", "H", "J", "K", "L", "Back", "Shift"}, + {"Z", "X", "C", "V", "B", "N", "M", ",", ".", "Space", "Enter"}}; + +KeyboardLayout layout_digits = + {{"1", "2", "3", "!", "@", "#", "$", "%", "^", "&", "Text" }, + {"4", "5", "6", "*", "(", ")", "-", "_", "=", "Back", "Shift"}, + {"7", "8", "9", "0", "+", "/", "?", ",", ".", "Space", "Enter"}}; + +KeyboardLayout layout_digits2 = + {{"1", "2", "3", "[", "]", "{", "}", ";", ":", "\\", "Text" }, + {"4", "5", "6", "|", "\'", "\"", "<", ">", "`", "Back", "Shift"}, + {"7", "8", "9", "0", "~", "/", "?", ",", ".", "Space", "Enter"}}; + +ScreenKeyboard* ScreenKeyboard::m_screen_keyboard = NULL; + +// ---------------------------------------------------------------------------- +/** The screen keyboard constructor + * \param percent_width A relative value in range of 0.0 to 1.0 that + * determines width of the screen that will be used by the keyboard. + * \param percent_height A relative value in range of 0.0 to 1.0 that + * determines height of the screen that will be used by the keyboard. + * \param edit_box The edit box that is assigned to the keyboard. + */ +ScreenKeyboard::ScreenKeyboard(float percent_width, float percent_height, + CGUIEditBox* edit_box) +{ + if (m_screen_keyboard != NULL) + { + delete m_screen_keyboard; + Log::warn("GUIEngine", "Showing a screen keyboard while the previous " + "one is still open. Destroying the previous keyboard."); + } + + m_screen_keyboard = this; + m_buttons_type = BUTTONS_NONE; + m_percent_width = std::min(std::max(percent_width, 0.0f), 1.0f); + m_percent_height = std::min(std::max(percent_height, 0.0f), 1.0f); + m_irrlicht_window = NULL; + m_edit_box = edit_box; + + init(); +} // ScreenKeyboard + +// ---------------------------------------------------------------------------- +/** The screen keyboard destructor + */ +ScreenKeyboard::~ScreenKeyboard() +{ + m_screen_keyboard = NULL; + + GUIEngine::getGUIEnv()->removeFocus(m_irrlicht_window); + m_irrlicht_window->remove(); + + input_manager->setMode(m_previous_mode); + + elementsWereDeleted(); +} // ~ScreenKeyboard + +// ---------------------------------------------------------------------------- +/** Internal function that makes whole screen keyboard initialization + */ +void ScreenKeyboard::init() +{ + const core::dimension2d& frame_size = irr_driver->getFrameSize(); + + int margin = 15; + int w = frame_size.Width * m_percent_width; + int h = frame_size.Height * m_percent_height; + int x = frame_size.Width/2 - w/2; + int y = frame_size.Height - h - margin; + + if (m_edit_box != NULL) + { + core::rect pos = m_edit_box->getAbsolutePosition(); + + if (pos.LowerRightCorner.Y + 5 > y) + { + y = margin; + } + } + + m_area = core::rect(x, y, x + w, y + h); + + m_irrlicht_window = GUIEngine::getGUIEnv()->addWindow(m_area, true); + m_irrlicht_window->setDrawTitlebar(false); + m_irrlicht_window->getCloseButton()->setVisible(false); + m_irrlicht_window->setDraggable(UserConfigParams::m_artist_debug_mode); + + m_previous_mode=input_manager->getMode(); + input_manager->setMode(InputManager::MENU); + + createButtons(); + assignButtons(BUTTONS_LOWER); +} // init + +// ---------------------------------------------------------------------------- +/** Creates all button widgets + */ +void ScreenKeyboard::createButtons() +{ + int pos_x = 1; + int pos_y = 10; + int width = (m_area.getWidth() - 2 * pos_x) / KEYBOARD_COLS_NUM; + int height = (m_area.getHeight() - 2 * pos_y) / KEYBOARD_ROWS_NUM; + + char width_str[100]; + sprintf(width_str, "%i", width); + char height_str[100]; + sprintf(height_str, "%i", height); + + for (int i = 0; i < KEYBOARD_ROWS_NUM; i++) + { + char tmp[100]; + sprintf(tmp, "%i", pos_y + height * i); + std::string pos_y_str = tmp; + + for (int j = 0; j < KEYBOARD_COLS_NUM; j++) + { + char tmp[100]; + sprintf(tmp, "%i", pos_x + width * j); + std::string pos_x_str = tmp; + + ButtonWidget* button = new ButtonWidget(); + button->setParent(m_irrlicht_window); + button->m_properties[PROP_WIDTH] = width_str; + button->m_properties[PROP_HEIGHT] = height_str; + button->m_properties[PROP_X] = pos_x_str; + button->m_properties[PROP_Y] = pos_y_str; + m_widgets.push_back(button); + m_buttons.push_back(button); + } + } + + LayoutManager::calculateLayout(m_widgets, this); + addWidgetsRecursively(m_widgets); +} // createButtons + +// ---------------------------------------------------------------------------- +/** A function that allows to select one of the available buttons layout + * \param buttons_type One of the available buttons type + */ +void ScreenKeyboard::assignButtons(ButtonsType buttons_type) +{ + m_buttons_type = buttons_type; + + KeyboardLayout* keys = NULL; + + switch (buttons_type) + { + case BUTTONS_LOWER: + keys = &layout_lower; + break; + case BUTTONS_UPPER: + keys = &layout_upper; + break; + case BUTTONS_DIGITS: + keys = &layout_digits; + break; + case BUTTONS_DIGITS2: + keys = &layout_digits2; + break; + default: + keys = NULL; + break; + }; + + for (int i = 0; i < KEYBOARD_ROWS_NUM; i++) + { + for (int j = 0; j < KEYBOARD_COLS_NUM; j++) + { + std::string key = keys != NULL ? (*keys)[i][j] : "?"; + + ButtonWidget* button = m_buttons[i * KEYBOARD_COLS_NUM + j]; + button->setText(key.c_str()); + button->m_properties[PROP_ID] = key; + } + } +} // assignButtons + +// ---------------------------------------------------------------------------- +/** A function that handles buttons events + * \param eventSource Button ID + * \return Block event if edit box is assigned + */ +EventPropagation ScreenKeyboard::processEvent(const std::string& eventSource) +{ + if (m_edit_box == NULL) + return EVENT_LET; + + SEvent event; + bool send_event = false; + + if (eventSource == "Shift") + { + switch (m_buttons_type) + { + case BUTTONS_UPPER: + assignButtons(BUTTONS_LOWER); + break; + case BUTTONS_LOWER: + assignButtons(BUTTONS_UPPER); + break; + case BUTTONS_DIGITS: + assignButtons(BUTTONS_DIGITS2); + break; + case BUTTONS_DIGITS2: + assignButtons(BUTTONS_DIGITS); + break; + default: + break; + } + } + else if (eventSource == "123") + { + assignButtons(BUTTONS_DIGITS); + } + else if (eventSource == "Text") + { + assignButtons(BUTTONS_LOWER); + } + else if (eventSource == "Enter") + { + dismiss(); + return EVENT_BLOCK; + } + else if (eventSource == "Back") + { + event.KeyInput.Key = KEY_BACK; + event.KeyInput.Char = 0; + send_event = true; + } + else if (eventSource == "Space") + { + event.KeyInput.Key = KEY_UNKNOWN; + event.KeyInput.Char = ' '; + send_event = true; + } + else if (eventSource.size() > 0) + { + event.KeyInput.Key = KEY_UNKNOWN; + event.KeyInput.Char = eventSource.at(0); + send_event = true; + } + + if (send_event) + { + event.EventType = EET_KEY_INPUT_EVENT; + event.KeyInput.PressedDown = true; + event.KeyInput.Control = false; + event.KeyInput.Shift = false; + + m_edit_box->OnEvent(event); + } + + return EVENT_BLOCK; +} // processEvent + +// ---------------------------------------------------------------------------- +/** A function that closes the keyboard + */ +void ScreenKeyboard::dismiss() +{ + delete m_screen_keyboard; + m_screen_keyboard = NULL; +} // dismiss + +// ---------------------------------------------------------------------------- +/** A function that handles escape pressed event + */ +bool ScreenKeyboard::onEscapePressed() +{ + dismiss(); + return true; +} // onEscapePressed + +// ---------------------------------------------------------------------------- diff --git a/src/guiengine/screen_keyboard.hpp b/src/guiengine/screen_keyboard.hpp new file mode 100644 index 000000000..04df28b43 --- /dev/null +++ b/src/guiengine/screen_keyboard.hpp @@ -0,0 +1,129 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License: or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_SCREEN_KEYBOARD_HPP +#define HEADER_SCREEN_KEYBOARD_HPP + +#include + +#include "guiengine/abstract_top_level_container.hpp" +#include "guiengine/skin.hpp" +#include "input/input_manager.hpp" +#include "utils/leak_check.hpp" + + +class CGUIEditBox; + +/** + * \ingroup guiengine + */ +namespace GUIEngine +{ + class ButtonWidget; + + /** + * \brief Class representing a screen keyboard. Only once instance at a + * time (if you create a 2nd the first will be destroyed). You can call + * static function 'dismiss' to simply close the keyboard (so you don't + * need to keep track of instances yourself) + * \ingroup guiengine + */ + class ScreenKeyboard : public SkinWidgetContainer, + public AbstractTopLevelContainer + { + private: + enum ButtonsType + { + BUTTONS_NONE, + BUTTONS_LOWER, + BUTTONS_UPPER, + BUTTONS_DIGITS, + BUTTONS_DIGITS2 + }; + + /** Global instance of the current screen keyboard */ + static ScreenKeyboard* m_screen_keyboard; + + /** A value in range of 0.0 to 1.0 that determines width of the screen + * that is used by the keyboard */ + float m_percent_width; + + /** A value in range of 0.0 to 1.0 that determines height of the screen + * that is used by the keyboard */ + float m_percent_height; + + /** The edit box that is assigned to the keyboard */ + CGUIEditBox* m_edit_box; + + /** Remembers currently selected button type */ + ButtonsType m_buttons_type; + + /** Irrlicht window used by the keyboard widget */ + irr::gui::IGUIWindow* m_irrlicht_window; + + /** Contains position and dimensions of the keyboard */ + irr::core::rect m_area; + + /** Contans the pointers to all button widgets */ + std::vector m_buttons; + + /** Remembered input mode that was used before keyboard creation */ + InputManager::InputDriverMode m_previous_mode; + + void init(); + void createButtons(); + void assignButtons(ButtonsType buttons_type); + + public: + LEAK_CHECK() + + ScreenKeyboard(float percent_width, float percent_height, + CGUIEditBox* edit_box); + ~ScreenKeyboard(); + + virtual EventPropagation processEvent(const std::string& eventSource); + + static void dismiss(); + static bool onEscapePressed(); + + /** Returns pointer to the created keyboard or NULL if keyboard was + * not created */ + static ScreenKeyboard* getCurrent() {return m_screen_keyboard;} + + /** Returns true if keyboard is created */ + static bool isActive() {return m_screen_keyboard != NULL;} + + /** Get irrlicht window used by the keyboard widget */ + irr::gui::IGUIWindow* getIrrlichtElement() {return m_irrlicht_window;} + + /** Checks if the screen keyboard is a parent of the selected item + * \param widget A widget that should be checked + * \return True if keyboard is the parent + */ + bool isMyIrrChild(irr::gui::IGUIElement* widget) const + {return m_irrlicht_window->isMyChild(widget);} + + /** Returns width of the screen keyboard */ + int getWidth() {return m_area.getWidth();} + + /** Returns height of the screen keyboard */ + int getHeight() {return m_area.getHeight();} + }; +} + +#endif diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 3475239bf..1ca7cabc4 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -29,6 +29,7 @@ #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" +#include "guiengine/screen_keyboard.hpp" #include "guiengine/widgets.hpp" #include "io/file_manager.hpp" #include "states_screens/state_manager.hpp" @@ -2299,32 +2300,41 @@ core::recti Skin::draw3DWindowBackground(IGUIElement *element, const core::recti *clip, core::recti* checkClientArea) { - if (ModalDialog::getCurrent() == NULL) return rect; - - if (ModalDialog::getCurrent()->fadeBackground()) - drawBGFadeColor(); - - // draw frame - if (m_dialog_size < 1.0f) + if (ScreenKeyboard::getCurrent() && + ScreenKeyboard::getCurrent()->getIrrlichtElement() == element) { - core::recti sized_rect = rect; - core::position2d center = sized_rect.getCenter(); - const int w = sized_rect.getWidth(); - const int h = sized_rect.getHeight(); - const float texture_size = sin(m_dialog_size*M_PI*0.5f); - sized_rect.UpperLeftCorner.X = (int)(center.X -(w/2.0f)*texture_size); - sized_rect.UpperLeftCorner.Y = (int)(center.Y -(h/2.0f)*texture_size); - sized_rect.LowerRightCorner.X = (int)(center.X +(w/2.0f)*texture_size); - sized_rect.LowerRightCorner.Y = (int)(center.Y +(h/2.0f)*texture_size); - drawBoxFromStretchableTexture( ModalDialog::getCurrent(), sized_rect, - SkinConfig::m_render_params["window::neutral"]); - - m_dialog_size += GUIEngine::getLatestDt()*5; + drawBoxFromStretchableTexture( ScreenKeyboard::getCurrent(), rect, + SkinConfig::m_render_params["window::neutral"]); } - else + else if (ModalDialog::getCurrent() && + ModalDialog::getCurrent()->getIrrlichtElement() == element) { - drawBoxFromStretchableTexture( ModalDialog::getCurrent(), rect, + if (ModalDialog::getCurrent()->fadeBackground()) + drawBGFadeColor(); + + // draw frame + if (m_dialog_size < 1.0f) + { + core::recti sized_rect = rect; + core::position2d center = sized_rect.getCenter(); + const int w = sized_rect.getWidth(); + const int h = sized_rect.getHeight(); + const float tex_size = sin(m_dialog_size*M_PI*0.5f); + sized_rect.UpperLeftCorner.X = (int)(center.X -(w/2.0f)*tex_size); + sized_rect.UpperLeftCorner.Y = (int)(center.Y -(h/2.0f)*tex_size); + sized_rect.LowerRightCorner.X = (int)(center.X +(w/2.0f)*tex_size); + sized_rect.LowerRightCorner.Y = (int)(center.Y +(h/2.0f)*tex_size); + + drawBoxFromStretchableTexture(ModalDialog::getCurrent(), sized_rect, SkinConfig::m_render_params["window::neutral"]); + + m_dialog_size += GUIEngine::getLatestDt()*5; + } + else + { + drawBoxFromStretchableTexture(ModalDialog::getCurrent(), rect, + SkinConfig::m_render_params["window::neutral"]); + } } return rect; diff --git a/src/guiengine/widgets/CGUIEditBox.cpp b/src/guiengine/widgets/CGUIEditBox.cpp index 53012e958..2b868cd99 100644 --- a/src/guiengine/widgets/CGUIEditBox.cpp +++ b/src/guiengine/widgets/CGUIEditBox.cpp @@ -12,8 +12,10 @@ //#include "os.h" #include "Keycodes.h" +#include "config/user_config.hpp" #include "graphics/2dutils.hpp" #include "graphics/irr_driver.hpp" +#include "guiengine/screen_keyboard.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" #include "utils/time.hpp" @@ -1236,6 +1238,7 @@ bool CGUIEditBox::processMouse(const SEvent& event) #endif setTextMarkers(CursorPos, CursorPos ); calculateScrollPos(); + return true; } else if (!m_rtl) @@ -1245,6 +1248,19 @@ bool CGUIEditBox::processMouse(const SEvent& event) { return false; } + else if (UserConfigParams::m_screen_keyboard) + { + CursorPos = Text.size(); + setTextMarkers(CursorPos, CursorPos); + calculateScrollPos(); + + if (GUIEngine::ScreenKeyboard::getCurrent() == NULL) + { + new GUIEngine::ScreenKeyboard(0.98, 0.30, this); + } + + return true; + } else { // move cursor @@ -1264,6 +1280,7 @@ bool CGUIEditBox::processMouse(const SEvent& event) MouseMarking = true; setTextMarkers( newMarkBegin, CursorPos); calculateScrollPos(); + return true; } } diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index bd9488fb8..cfb067e8b 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -25,6 +25,7 @@ #include "guiengine/event_handler.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/screen.hpp" +#include "guiengine/screen_keyboard.hpp" #include "input/device_manager.hpp" #include "input/gamepad_device.hpp" #include "input/keyboard_device.hpp" @@ -663,9 +664,13 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, } } - if (button == KEY_RETURN && GUIEngine::ModalDialog::isADialogActive()) + if (button == KEY_RETURN) { - GUIEngine::ModalDialog::onEnterPressed(); + if (GUIEngine::ModalDialog::isADialogActive() && + !GUIEngine::ScreenKeyboard::isActive()) + { + GUIEngine::ModalDialog::onEnterPressed(); + } } if (action != PA_BEFORE_FIRST) @@ -732,6 +737,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, // ... when in-game if (StateManager::get()->getGameState() == GUIEngine::GAME && !GUIEngine::ModalDialog::isADialogActive() && + !GUIEngine::ScreenKeyboard::isActive() && !race_manager->isWatchingReplay() ) { if (player == NULL) @@ -1171,6 +1177,7 @@ EventPropagation InputManager::input(const SEvent& event) if (getDeviceManager()->getAssignMode() != NO_ASSIGN && !GUIEngine::isWithinATextBox() && (!GUIEngine::ModalDialog::isADialogActive() && + !GUIEngine::ScreenKeyboard::isActive() && StateManager::get()->getGameState() == GUIEngine::GAME)) { return EVENT_BLOCK; diff --git a/src/input/multitouch_device.cpp b/src/input/multitouch_device.cpp index a27072170..fea305662 100644 --- a/src/input/multitouch_device.cpp +++ b/src/input/multitouch_device.cpp @@ -25,6 +25,7 @@ #include "karts/controller/controller.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/modaldialog.hpp" +#include "guiengine/screen_keyboard.hpp" // ---------------------------------------------------------------------------- /** The multitouch device constructor @@ -263,6 +264,7 @@ void MultitouchDevice::handleControls(MultitouchButton* button) // to use it for GUI navigation. if (StateManager::get()->getGameState() != GUIEngine::GAME || GUIEngine::ModalDialog::isADialogActive() || + GUIEngine::ScreenKeyboard::isActive() || race_manager->isWatchingReplay()) return; diff --git a/src/states_screens/state_manager.cpp b/src/states_screens/state_manager.cpp index 5b3dca40e..db58c644b 100644 --- a/src/states_screens/state_manager.cpp +++ b/src/states_screens/state_manager.cpp @@ -25,6 +25,7 @@ #include "guiengine/engine.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/screen.hpp" +#include "guiengine/screen_keyboard.hpp" #include "input/input_device.hpp" #include "input/input_manager.hpp" #include "main_loop.hpp" @@ -163,10 +164,17 @@ void StateManager::escapePressed() if(input_manager->isInMode(InputManager::INPUT_SENSE_KEYBOARD) || input_manager->isInMode(InputManager::INPUT_SENSE_GAMEPAD) ) { + ScreenKeyboard::dismiss(); ModalDialog::dismiss(); input_manager->setMode(InputManager::MENU); } // when another modal dialog is visible + else if(ScreenKeyboard::isActive()) + { + if(ScreenKeyboard::getCurrent()->onEscapePressed()) + ScreenKeyboard::getCurrent()->dismiss(); + } + // when another modal dialog is visible else if(ModalDialog::isADialogActive()) { if(ModalDialog::getCurrent()->onEscapePressed())