diff options
Diffstat (limited to 'src/gui/widgets/textfield.cpp')
-rw-r--r-- | src/gui/widgets/textfield.cpp | 837 |
1 files changed, 0 insertions, 837 deletions
diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp deleted file mode 100644 index e536b5b13..000000000 --- a/src/gui/widgets/textfield.cpp +++ /dev/null @@ -1,837 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2017 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * 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 2 of the License, or - * 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, see <http://www.gnu.org/licenses/>. - */ - -/* _______ __ __ __ ______ __ __ _______ __ __ - * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ - * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / - * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / - * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / - * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / - * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ - * - * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson - * - * - * Per Larsson a.k.a finalman - * Olof Naessén a.k.a jansem/yakslem - * - * Visit: http://guichan.sourceforge.net - * - * License: (BSD) - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of Guichan nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "gui/widgets/textfield.h" - -#include "settings.h" - -#ifdef USE_SDL2 -#include "enums/input/keyvalue.h" -#endif // USE_SDL2 - -#include "gui/gui.h" -#include "gui/skin.h" -#ifdef ANDROID -#include "gui/windowmanager.h" -#endif // ANDROID - -#include "gui/fonts/font.h" - -#include "gui/popups/popupmenu.h" - -#include "input/inputmanager.h" - -#include "utils/copynpaste.h" -#include "utils/stringutils.h" - -#ifndef USE_SDL2 -#include "utils/timer.h" -#endif // USE_SDL2 - -#include "render/graphics.h" - -#include "resources/imagerect.h" - -#include "resources/image/image.h" - -#undef DELETE // Win32 compatibility hack - -#include "debug.h" - -Skin *TextField::mSkin; -int TextField::instances = 0; -float TextField::mAlpha = 1.0; -ImageRect TextField::skin; - -TextField::TextField(const Widget2 *restrict const widget, - const std::string &restrict text, - const LoseFocusOnTab loseFocusOnTab, - ActionListener *restrict const listener, - const std::string &restrict eventId, - const bool sendAlwaysEvents) : - Widget(widget), - FocusListener(), - KeyListener(), - MouseListener(), - WidgetListener(), - mText(text), - mTextChunk(), - mCaretPosition(0), - mXScroll(0), - mCaretColor(&getThemeColor(ThemeColorId::CARET)), - mMinimum(0), - mMaximum(0), - mLastEventPaste(0), - mPadding(1), - mNumeric(false), - mLoseFocusOnTab(loseFocusOnTab), - mAllowSpecialActions(true), - mSendAlwaysEvents(sendAlwaysEvents), - mTextChanged(true) -{ - mAllowLogic = false; - setFocusable(true); - addMouseListener(this); - addKeyListener(this); - - setFrameSize(2); - mForegroundColor = getThemeColor(ThemeColorId::TEXTFIELD); - mForegroundColor2 = getThemeColor(ThemeColorId::TEXTFIELD_OUTLINE); - - addFocusListener(this); - - if (instances == 0) - { - if (theme != nullptr) - { - mSkin = theme->loadSkinRect(skin, "textfield.xml", - "textfield_background.xml"); - } - } - - instances++; - - if (mSkin != nullptr) - { - mPadding = mSkin->getPadding(); - mFrameSize = mSkin->getOption("frameSize", 2); - } - - adjustSize(); - if (!eventId.empty()) - setActionEventId(eventId); - - if (listener != nullptr) - addActionListener(listener); -} - -TextField::~TextField() -{ - if (mWindow != nullptr) - mWindow->removeWidgetListener(this); - - if (gui != nullptr) - gui->removeDragged(this); - - instances--; - if (instances == 0) - { - if (theme != nullptr) - { - theme->unload(mSkin); - Theme::unloadRect(skin); - } - } - mTextChunk.deleteImage(); -} - -void TextField::updateAlpha() -{ - const float alpha = std::max(settings.guiAlpha, - theme->getMinimumOpacity()); - - if (alpha != mAlpha) - { - mAlpha = alpha; - for (int a = 0; a < 9; a++) - { - if (skin.grid[a] != nullptr) - skin.grid[a]->setAlpha(mAlpha); - } - } -} - -void TextField::draw(Graphics *const graphics) -{ - BLOCK_START("TextField::draw") - updateAlpha(); - - Font *const font = getFont(); - if (isFocused()) - { - drawCaret(graphics, - font->getWidth(mText.substr(0, mCaretPosition)) - mXScroll); - } - - if (mTextChanged) - { - mTextChunk.textFont = font; - mTextChunk.deleteImage(); - mTextChunk.text = mText; - mTextChunk.color = mForegroundColor; - mTextChunk.color2 = mForegroundColor2; - font->generate(mTextChunk); - mTextChanged = false; - } - - const Image *const image = mTextChunk.img; - if (image != nullptr) - graphics->drawImage(image, mPadding - mXScroll, mPadding); - - BLOCK_END("TextField::draw") -} - -void TextField::safeDraw(Graphics *const graphics) -{ - TextField::draw(graphics); -} - -void TextField::drawFrame(Graphics *const graphics) -{ - BLOCK_START("TextField::drawFrame") - const int bs = 2 * mFrameSize; - graphics->drawImageRect(0, - 0, - mDimension.width + bs, - mDimension.height + bs, - skin); - BLOCK_END("TextField::drawFrame") -} - -void TextField::safeDrawFrame(Graphics *const graphics) -{ - BLOCK_START("TextField::drawFrame") - const int bs = 2 * mFrameSize; - graphics->drawImageRect(0, - 0, - mDimension.width + bs, - mDimension.height + bs, - skin); - BLOCK_END("TextField::drawFrame") -} - -void TextField::setNumeric(const bool numeric) -{ - mNumeric = numeric; - if (!numeric) - return; - - const char *const text = mText.c_str(); - for (const char *textPtr = text; *textPtr != 0; ++textPtr) - { - if (*textPtr < '0' || *textPtr > '9') - { - setText(mText.substr(0, textPtr - text)); - return; - } - } -} - -int TextField::getValue() const -{ - if (!mNumeric) - return 0; - - const int value = atoi(mText.c_str()); - if (value < mMinimum) - return mMinimum; - - if (value > mMaximum) - return mMaximum; - - return value; -} - -void TextField::keyPressed(KeyEvent &event) -{ - const int val = event.getKey().getValue(); - -#ifdef USE_SDL2 - if (val == KeyValue::TEXTINPUT) - { - std::string str = event.getText(); - mText.insert(mCaretPosition, str); - mTextChanged = true; - mCaretPosition += CAST_U32(str.size()); - event.consume(); - fixScroll(); - if (mSendAlwaysEvents) - distributeActionEvent(); - return; - } - bool consumed(false); -#else // USE_SDL2 - - if (val >= 32) - { - if (mNumeric) - { - if ((val >= '0' && val <= '9') || - (val == '-' && mCaretPosition == 0u)) - { - char buf[2]; - buf[0] = CAST_8(val); - buf[1] = 0; - mText.insert(mCaretPosition, std::string(buf)); - mTextChanged = true; - mCaretPosition += 1; - event.consume(); - fixScroll(); - if (mSendAlwaysEvents) - distributeActionEvent(); - return; - } - } - else if ((mMaximum == 0) || - CAST_S32(mText.size()) < mMaximum) - { - int len; - if (val < 128) - len = 1; // 0xxxxxxx - else if (val < 0x800) - len = 2; // 110xxxxx 10xxxxxx - else if (val < 0x10000) - len = 3; // 1110xxxx 10xxxxxx 10xxxxxx - else - len = 4; // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - - char buf[4]; - for (int i = 0; i < len; ++ i) - { - buf[i] = CAST_8(val >> (6 * (len - i - 1))); - if (i > 0) - buf[i] = CAST_8((buf[i] & 63) | 128); - } - - if (len > 1) - buf[0] |= CAST_8(255U << (8 - len)); - - mText.insert(mCaretPosition, std::string(buf, buf + len)); - mCaretPosition += len; - mTextChanged = true; - event.consume(); - fixScroll(); - if (mSendAlwaysEvents) - distributeActionEvent(); - return; - } - } - - /* In UTF-8, 10xxxxxx is only used for inner parts of characters. So skip - them when processing key presses. */ - - // unblock past key - if (val != 22) - mLastEventPaste = 0; - - bool consumed(false); -#endif // USE_SDL2 - - const InputActionT action = event.getActionId(); - if (!inputManager.isActionActive(InputAction::GUI_CTRL)) - { - if (!handleNormalKeys(action, consumed)) - { - if (consumed) - event.consume(); - return; - } - } - else - { - handleCtrlKeys(action, consumed); - } - - if (mSendAlwaysEvents) - distributeActionEvent(); - - if (consumed) - event.consume(); - fixScroll(); -} - -bool TextField::handleNormalKeys(const InputActionT action, bool &consumed) -{ - PRAGMA45(GCC diagnostic push) - PRAGMA45(GCC diagnostic ignored "-Wswitch-enum") - switch (action) - { - case InputAction::GUI_LEFT: - { - consumed = true; - while (mCaretPosition > 0) - { - --mCaretPosition; - if ((mText[mCaretPosition] & 192) != 128) - break; - } - break; - } - - case InputAction::GUI_RIGHT: - { - consumed = true; - const unsigned sz = CAST_U32(mText.size()); - while (mCaretPosition < sz) - { - ++mCaretPosition; - if (mCaretPosition == sz || - (mText[mCaretPosition] & 192) != 128) - { - break; - } - } - break; - } - - case InputAction::GUI_DELETE: - { - consumed = true; - unsigned sz = CAST_U32(mText.size()); - while (mCaretPosition < sz) - { - --sz; - mText.erase(mCaretPosition, 1); - mTextChanged = true; - if (mCaretPosition == sz || - (mText[mCaretPosition] & 192) != 128) - { - break; - } - } - break; - } - - case InputAction::GUI_BACKSPACE: - consumed = true; - deleteCharLeft(mText, &mCaretPosition); - mTextChanged = true; - break; - - case InputAction::GUI_SELECT2: - distributeActionEvent(); - consumed = true; - fixScroll(); - return false; - - case InputAction::GUI_HOME: - mCaretPosition = 0; - consumed = true; - break; - - case InputAction::GUI_END: - mCaretPosition = CAST_U32(mText.size()); - consumed = true; - break; - - case InputAction::GUI_TAB: - if (mLoseFocusOnTab == LoseFocusOnTab_true) - return false; - consumed = true; - break; - - default: - break; - } - PRAGMA45(GCC diagnostic pop) - return true; -} - -void TextField::handleCtrlKeys(const InputActionT action, bool &consumed) -{ - PRAGMA45(GCC diagnostic push) - PRAGMA45(GCC diagnostic ignored "-Wswitch-enum") - switch (action) - { - case InputAction::GUI_LEFT: - { - moveCaretWordBack(); - consumed = true; - break; - } - case InputAction::GUI_RIGHT: - { - moveCaretWordForward(); - consumed = true; - break; - } - case InputAction::GUI_B: - { - if (mAllowSpecialActions) - { - moveCaretBack(); - consumed = true; - } - break; - } - case InputAction::GUI_F: - { - moveCaretForward(); - consumed = true; - break; - } - case InputAction::GUI_D: - { - caretDelete(); - consumed = true; - break; - } - case InputAction::GUI_E: - { - mCaretPosition = CAST_S32(mText.size()); - consumed = true; - break; - } - case InputAction::GUI_H: - { - deleteCharLeft(mText, &mCaretPosition); - mTextChanged = true; - consumed = true; - break; - } - case InputAction::GUI_K: - { - mText = mText.substr(0, mCaretPosition); - mTextChanged = true; - consumed = true; - break; - } - case InputAction::GUI_U: - { - caretDeleteToStart(); - consumed = true; - break; - } - case InputAction::GUI_C: - { - handleCopy(); - consumed = true; - break; - } - case InputAction::GUI_V: - { -#ifdef USE_SDL2 - handlePaste(); -#else // USE_SDL2 - - // hack to prevent paste key sticking - if ((mLastEventPaste != 0) && mLastEventPaste > cur_time) - break; - handlePaste(); - mLastEventPaste = cur_time + 2; -#endif // USE_SDL2 - - consumed = true; - break; - } - case InputAction::GUI_W: - { - caretDeleteWord(); - consumed = true; - break; - } - default: - break; - } - PRAGMA45(GCC diagnostic pop) -} - -void TextField::moveCaretBack() -{ - while (mCaretPosition > 0) - { - --mCaretPosition; - if ((mText[mCaretPosition] & 192) != 128) - break; - } -} - -void TextField::moveCaretForward() -{ - const unsigned sz = CAST_U32(mText.size()); - while (mCaretPosition < sz) - { - ++mCaretPosition; - if (mCaretPosition == sz || (mText[mCaretPosition] & 192) != 128) - break; - } -} - -void TextField::caretDelete() -{ - unsigned sz = CAST_U32(mText.size()); - while (mCaretPosition < sz) - { - --sz; - mText.erase(mCaretPosition, 1); - if (mCaretPosition == sz || (mText[mCaretPosition] & 192) != 128) - break; - } - mTextChanged = true; -} - -void TextField::handlePaste() -{ - std::string text = getText(); - size_t caretPos = CAST_SIZE(getCaretPosition()); - - if (retrieveBuffer(text, caretPos)) - { - setText(text); - setCaretPosition(CAST_U32(caretPos)); - } -} - -void TextField::caretDeleteToStart() -{ - if (mCaretPosition > 0) - { - mText = mText.substr(mCaretPosition); - mCaretPosition = 0; - } - mTextChanged = true; -} - -void TextField::moveCaretWordBack() -{ - const unsigned int oldCaret = mCaretPosition; - while (mCaretPosition > 0) - { - if (!isWordSeparator(mText[mCaretPosition - 1])) - break; - mCaretPosition --; - } - if (oldCaret != mCaretPosition) - return; - while (mCaretPosition > 0) - { - if (isWordSeparator(mText[mCaretPosition - 1])) - break; - mCaretPosition --; - } -} - -void TextField::moveCaretWordForward() -{ - const unsigned sz = CAST_U32(mText.size()); - const unsigned int oldCaret = mCaretPosition; - while (mCaretPosition < sz) - { - if (!isWordSeparator(mText[mCaretPosition])) - break; - mCaretPosition ++; - } - if (oldCaret != mCaretPosition) - return; - while (mCaretPosition < sz) - { - if (isWordSeparator(mText[mCaretPosition])) - break; - mCaretPosition ++; - } -} - -void TextField::caretDeleteWord() -{ - while (mCaretPosition > 0) - { - deleteCharLeft(mText, &mCaretPosition); - if (mCaretPosition > 0 && isWordSeparator(mText[mCaretPosition - 1])) - break; - } - mTextChanged = true; -} - -void TextField::handleCopy() const -{ - std::string text = getText(); - sendBuffer(text); -} - -void TextField::drawCaret(Graphics* graphics, int x) -{ - const ClipRect &clipArea = graphics->getTopClip(); - - graphics->setColor(*mCaretColor); - graphics->drawLine(x + mPadding, clipArea.height - mPadding, - x + mPadding, mPadding); -} - -void TextField::adjustSize() -{ - setWidth(getFont()->getWidth(mText) + 2 * mPadding + 1); - adjustHeight(); - - fixScroll(); -} - -void TextField::adjustHeight() -{ - setHeight(getFont()->getHeight() + 2 * mPadding); -} - -void TextField::fixScroll() -{ - if (isFocused()) - { - const int caretX = getFont()->getWidth( - mText.substr(0, mCaretPosition)); - - const int width = mDimension.width; - const int pad = 2 * mPadding; - if (caretX - mXScroll >= width - pad) - { - mXScroll = caretX - width + pad; - } - else if (caretX - mXScroll <= 0) - { - mXScroll = caretX - width / 2; - - if (mXScroll < 0) - mXScroll = 0; - } - } -} - -void TextField::setCaretPosition(unsigned int position) -{ - const unsigned int sz = CAST_U32(mText.size()); - if (position > sz) - mCaretPosition = CAST_S32(sz); - else - mCaretPosition = position; - - fixScroll(); -} - -void TextField::fontChanged() -{ - fixScroll(); -} - -void TextField::mousePressed(MouseEvent &event) -{ -#ifdef ANDROID - if (!WindowManager::isKeyboardVisible()) - inputManager.executeAction(InputAction::SHOW_KEYBOARD); -#endif // ANDROID - - event.consume(); - if (event.getButton() == MouseButton::RIGHT) - { -#ifndef DYECMD - if (popupMenu != nullptr) - popupMenu->showTextFieldPopup(this); -#endif // DYECMD - } - else if (event.getButton() == MouseButton::LEFT) - { - mCaretPosition = getFont()->getStringIndexAt( - mText, event.getX() + mXScroll); - fixScroll(); - } -} - -void TextField::focusGained(const Event &event A_UNUSED) -{ -#ifdef ANDROID - if (!WindowManager::isKeyboardVisible()) - inputManager.executeAction(InputAction::SHOW_KEYBOARD); -#endif // ANDROID -} - -void TextField::focusLost(const Event &event A_UNUSED) -{ -} - -void TextField::setText(const std::string& text) -{ - const unsigned int sz = CAST_U32(text.size()); - if (sz < mCaretPosition) - mCaretPosition = sz; - mText = text; - mTextChanged = true; -} - -void TextField::mouseDragged(MouseEvent& event) -{ - event.consume(); -} - -void TextField::widgetHidden(const Event &event A_UNUSED) -{ - mTextChanged = true; - mTextChunk.deleteImage(); -} - -void TextField::setParent(Widget *widget) -{ - if (mWindow != nullptr) - mWindow->addWidgetListener(this); - Widget::setParent(widget); -} - -void TextField::setWindow(Widget *const widget) -{ - if ((widget == nullptr) && (mWindow != nullptr)) - { - mWindow->removeWidgetListener(this); - mWindow = nullptr; - } - else - { - Widget2::setWindow(widget); - } -} |