From a5db7121ab731d3d725ce77da46658dc098cfe45 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Mon, 14 Mar 2016 15:47:09 -0500 Subject: Improve input box text handling Change-Id: I79cfaac1adf85d1ee5514bf5266930823c1a15ff --- gui/input.cpp | 467 +++++++++++++++++++------------------------------------- gui/objects.hpp | 14 +- gui/text.cpp | 35 +++-- 3 files changed, 187 insertions(+), 329 deletions(-) diff --git a/gui/input.cpp b/gui/input.cpp index c12ecc2b2..4bf01ada2 100644 --- a/gui/input.cpp +++ b/gui/input.cpp @@ -1,5 +1,5 @@ /* - Copyright 2012 bigbiff/Dees_Troy TeamWin + Copyright 2012 to 2016 bigbiff/Dees_Troy TeamWin This file is part of TWRP/TeamWin Recovery Project. TWRP is free software: you can redistribute it and/or modify @@ -46,6 +46,8 @@ extern "C" { #include "objects.hpp" #include "../data.hpp" +#define TW_INPUT_NO_UPDATE -1000 // Magic value for HandleTextLocation when no change in scrolling has occurred + GUIInput::GUIInput(xml_node<>* node) : GUIObject(node) { @@ -63,12 +65,13 @@ GUIInput::GUIInput(xml_node<>* node) isLocalChange = true; HasAllowed = false; HasDisabled = false; - skipChars = scrollingX = mFontHeight = mFontY = lastX = 0; + cursorX = textWidth = scrollingX = mFontHeight = mFontY = lastX = 0; mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = MinLen = MaxLen = 0; mCursorLocation = -1; // -1 is always the end of the string CursorWidth = 3; ConvertStrToColor("black", &mBackgroundColor); ConvertStrToColor("white", &mCursorColor); + displayValue = ""; if (!node) return; @@ -136,11 +139,6 @@ GUIInput::GUIInput(xml_node<>* node) DataManager::SetValue(mVariable, attr->value()); mMask = LoadAttrString(child, "mask"); HasMask = !mMask.empty(); - attr = child->first_attribute("maskvariable"); - if (attr) - mMaskVariable = attr->value(); - else - mMaskVariable = mVariable; } // Load input restrictions @@ -166,10 +164,7 @@ GUIInput::GUIInput(xml_node<>* node) mFontY = mRenderY; if (mInputText) - mInputText->SetMaxWidth(mRenderW); - - isLocalChange = false; - HandleTextLocation(-3); + mInputText->SetMaxWidth(0); } GUIInput::~GUIInput() @@ -178,17 +173,40 @@ GUIInput::~GUIInput() delete mAction; } -int GUIInput::HandleTextLocation(int x) -{ - int textWidth; - string displayValue, originalValue, insertChar; +void GUIInput::HandleTextLocation(int x) { + mRendered = false; + if (textWidth <= mRenderW) { + if (x != TW_INPUT_NO_UPDATE) + lastX = x; + scrollingX = 0; + return; + } + if (scrollingX + textWidth < mRenderW) { + scrollingX = mRenderW - textWidth; + } + + if (x == TW_INPUT_NO_UPDATE) + return; + + scrollingX += x - lastX; + if (scrollingX > 0) + scrollingX = 0; + else if (scrollingX + textWidth < mRenderW) + scrollingX = mRenderW - textWidth; + lastX = x; +} + +void GUIInput::UpdateTextWidth() { void* fontResource = NULL; - if (mFont) + if (mFont) { fontResource = mFont->GetResource(); + } else { + textWidth = 0; + return; + } - DataManager::GetValue(mVariable, originalValue); - displayValue = originalValue; + DataManager::GetValue(mVariable, displayValue); if (HasMask) { int index, string_size = displayValue.size(); string maskedValue; @@ -197,153 +215,80 @@ int GUIInput::HandleTextLocation(int x) displayValue = maskedValue; } textWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); - if (textWidth <= mRenderW) { - lastX = x; - scrollingX = 0; - skipChars = 0; - mInputText->SkipCharCount(skipChars); - mRendered = false; - return 0; - } - - if (skipChars && skipChars < displayValue.size()) - displayValue.erase(0, skipChars); - - textWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); - mRendered = false; +} - int deltaX, deltaText, newWidth; +void GUIInput::HandleCursorByTouch(int x) { +// Uses x to find mCursorLocation and cursorX + if (displayValue.size() == 0) { + mCursorLocation = -1; + cursorX = mRenderX; + return; + } - if (x < -1000) { - // No change in scrolling - if (x == -1003) - mCursorLocation = -1; + void* fontResource = NULL; + if (mFont) { + fontResource = mFont->GetResource(); + } else { + return; + } - if (mCursorLocation == -1) { - displayValue = originalValue; - skipChars = 0; - textWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); - while (textWidth > mRenderW) { - displayValue.erase(0, 1); - skipChars++; - textWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); + string cursorString; + unsigned index = 0, displaySize = displayValue.size(); + int prevX = mRenderX + scrollingX; + + for(index = 0; index <= displaySize; index++) { + cursorString = displayValue.substr(0, index); + cursorX = gr_ttf_measureEx(cursorString.c_str(), fontResource) + mRenderX + scrollingX; + if (cursorX > x) { + if (index > 0 && x <= cursorX - ((x - prevX) / 2) && prevX >= mRenderX) { + // This helps make sure that we can place the cursor before the very first char if the first char is + // is fully visible while also still letting us place the cursor after the last char if fully visible + mCursorLocation = index - 1; + cursorX = prevX; + return; } - scrollingX = mRenderW - textWidth; - mInputText->SkipCharCount(skipChars); - } else if (x == -1001) { - // Added a new character - int adjust_scrollingX = 0; - string cursorLocate; - - cursorLocate = displayValue; - cursorLocate.resize(mCursorLocation); - textWidth = gr_ttf_measureEx(cursorLocate.c_str(), fontResource); - while (textWidth > mRenderW) { - skipChars++; + mCursorLocation = index; + if (cursorX > mRenderX + mRenderW) { + cursorX = prevX; // This makes sure that the cursor doesn't get placed after the end of the input box mCursorLocation--; - cursorLocate.erase(0, 1); - textWidth = gr_ttf_measureEx(cursorLocate.c_str(), fontResource); - adjust_scrollingX = -1; - } - if (adjust_scrollingX) { - scrollingX = mRenderW - textWidth; - if (scrollingX < 0) - scrollingX = 0; - } - mInputText->SkipCharCount(skipChars); - } else if (x == -1002) { - // Deleted a character - while (-1) { - if (skipChars == 0) { - scrollingX = 0; - mInputText->SkipCharCount(skipChars); - return 0; - } - insertChar = originalValue.substr(skipChars - 1, 1); - displayValue.insert(0, insertChar); - newWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); - deltaText = newWidth - textWidth; - if (newWidth > mRenderW) { - scrollingX = mRenderW - textWidth; - if (scrollingX < 0) - scrollingX = 0; - mInputText->SkipCharCount(skipChars); - return 0; - } else { - textWidth = newWidth; - skipChars--; - mCursorLocation++; - } + return; } - } else - LOGINFO("GUIInput::HandleTextLocation -> We really shouldn't ever get here...\n"); - } else if (x > lastX) { - // Dragging to right, scrolling left - while (-1) { - deltaX = x - lastX + scrollingX; - if (skipChars == 0 || deltaX == 0) { - scrollingX = 0; - lastX = x; - mInputText->SkipCharCount(skipChars); - return 0; - } - insertChar = originalValue.substr(skipChars - 1, 1); - displayValue.insert(0, insertChar); - newWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); - deltaText = newWidth - textWidth; - if (deltaText < deltaX) { - lastX += deltaText; - textWidth = newWidth; - skipChars--; - } else { - scrollingX = deltaX; - lastX = x; - mInputText->SkipCharCount(skipChars); - return 0; - } - } - } else if (x < lastX) { - // Dragging to left, scrolling right - if (textWidth <= mRenderW) { - lastX = x; - scrollingX = mRenderW - textWidth; - return 0; - } - if (scrollingX) { - deltaX = lastX - x; - if (scrollingX > deltaX) { - scrollingX -= deltaX; - lastX = x; - return 0; - } else { - lastX -= deltaX; - scrollingX = 0; - } - } - while (-1) { - deltaX = lastX - x; - displayValue.erase(0, 1); - skipChars++; - newWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource); - deltaText = textWidth - newWidth; - if (newWidth <= mRenderW) { - scrollingX = mRenderW - newWidth; - lastX = x; - mInputText->SkipCharCount(skipChars); - return 0; - } - if (deltaText < deltaX) { - lastX -= deltaText; - textWidth = newWidth; - } else { - scrollingX = deltaText - deltaX; - lastX = x; - mInputText->SkipCharCount(skipChars); - return 0; + if (cursorX >= mRenderX) { + return; // This makes sure that the cursor doesn't get placed before the beginning of the input box } } + prevX = cursorX; + } + mCursorLocation = -1; // x is at or past the end of the string +} + +void GUIInput::HandleCursorByText() { +// Uses mCursorLocation to find cursorX + if (!DrawCursor) + return; + + void* fontResource = NULL; + if (mFont) { + fontResource = mFont->GetResource(); + } else { + return; + } + + int cursorWidth = textWidth; + + if (mCursorLocation != -1) { + string cursorDisplay = displayValue; + cursorDisplay.resize(mCursorLocation); + cursorWidth = gr_ttf_measureEx(cursorDisplay.c_str(), fontResource); + } + cursorX = mRenderX + cursorWidth + scrollingX; + if (cursorX >= mRenderX + mRenderW) { + scrollingX = mRenderW - cursorWidth; + cursorX = mRenderX + mRenderW - CursorWidth; + } else if (cursorX < mRenderX) { + scrollingX = cursorWidth * -1; + cursorX = mRenderX; } - return 0; } int GUIInput::Render(void) @@ -372,58 +317,18 @@ int GUIInput::Render(void) int ret = 0; // Render the text - mInputText->SetRenderPos(mRenderX + scrollingX, mFontY); - mInputText->SetMaxWidth(mRenderW - scrollingX); - if (mInputText) ret = mInputText->Render(); - if (ret < 0) return ret; + if (mInputText) { + mInputText->SetRenderPos(mRenderX + scrollingX, mFontY); + mInputText->SetText(displayValue); + gr_clip(mRenderX, mRenderY, mRenderW, mRenderH); + ret = mInputText->Render(); + gr_noclip(); + } + if (ret < 0) + return ret; if (HasInputFocus && DrawCursor) { // Render the cursor - string displayValue; - int cursorX; - DataManager::GetValue(mVariable, displayValue); - if (HasMask) { - int index, string_size = displayValue.size(); - string maskedValue; - for (index=0; index 0) { - // Cursor is in the middle - if (displayValue.size() > (unsigned)mCursorLocation) { - string cursorDisplay; - - cursorDisplay = displayValue; - cursorDisplay.resize(mCursorLocation); - cursorX = gr_ttf_measureEx(cursorDisplay.c_str(), fontResource) + mRenderX; - } else { - // Cursor location is after the end of the text - reset to -1 - mCursorLocation = -1; - cursorX = gr_ttf_measureEx(displayValue.c_str(), fontResource) + mRenderX; - } - } else { - // Cursor is at the end (-1) - cursorX = gr_ttf_measureEx(displayValue.c_str(), fontResource) + mRenderX; - } - } - cursorX += scrollingX; - // Make sure that the cursor doesn't go past the boundaries of the box - if (cursorX + (int)CursorWidth > mRenderX + mRenderW) - cursorX = mRenderX + mRenderW - CursorWidth; - - // Set the color for the cursor gr_color(mCursorColor.red, mCursorColor.green, mCursorColor.blue, 255); gr_fill(cursorX, mFontY, CursorWidth, mFontHeight); } @@ -454,8 +359,6 @@ int GUIInput::GetSelection(int x, int y) int GUIInput::NotifyTouch(TOUCH_STATE state, int x, int y) { static int startSelection = -1; - int textWidth; - string displayValue, originalValue; void* fontResource = NULL; if (mFont) fontResource = mFont->GetResource(); @@ -507,43 +410,9 @@ int GUIInput::NotifyTouch(TOUCH_STATE state, int x, int y) case TOUCH_RELEASE: // We've moved the cursor location - int relativeX = x - mRenderX; - mRendered = false; DrawCursor = true; - DataManager::GetValue(mVariable, displayValue); - if (HasMask) { - int index, string_size = displayValue.size(); - string maskedValue; - for (index=0; index x) { - if (index > 0) - mCursorLocation = index - 1; - else - mCursorLocation = index; - return 0; - } - } - mCursorLocation = -1; + HandleCursorByTouch(x); break; } } @@ -554,10 +423,19 @@ int GUIInput::NotifyVarChange(const std::string& varName, const std::string& val { GUIObject::NotifyVarChange(varName, value); - if (varName == mVariable && !isLocalChange) { - HandleTextLocation(-1003); + if (varName == mVariable) { + if (!isLocalChange) { + UpdateTextWidth(); + HandleTextLocation(TW_INPUT_NO_UPDATE); + } else + isLocalChange = false; return 0; } + if (varName.empty()) { + UpdateTextWidth(); + HandleTextLocation(TW_INPUT_NO_UPDATE); + HandleCursorByText(); + } return 0; } @@ -566,54 +444,48 @@ int GUIInput::NotifyKey(int key, bool down) if (!HasInputFocus || !down) return 1; - string variableValue; switch (key) { case KEY_LEFT: - if (mCursorLocation == 0 && skipChars == 0) + if (mCursorLocation == 0) return 0; // we're already at the beginning if (mCursorLocation == -1) { - DataManager::GetValue(mVariable, variableValue); - if (variableValue.size() == 0) + if (displayValue.size() == 0) { + cursorX = mRenderX; return 0; - mCursorLocation = variableValue.size() - skipChars - 1; - } else if (mCursorLocation == 0) { - skipChars--; - HandleTextLocation(-1002); + } + mCursorLocation = displayValue.size() - 1; } else { mCursorLocation--; - HandleTextLocation(-1002); } mRendered = false; + HandleCursorByText(); return 0; case KEY_RIGHT: if (mCursorLocation == -1) return 0; // we're already at the end mCursorLocation++; - DataManager::GetValue(mVariable, variableValue); - if (variableValue.size() <= mCursorLocation + skipChars) + if ((int)displayValue.size() <= mCursorLocation) mCursorLocation = -1; - HandleTextLocation(-1001); + HandleCursorByText(); mRendered = false; return 0; case KEY_HOME: case KEY_UP: - DataManager::GetValue(mVariable, variableValue); - if (variableValue.size() == 0) + if (displayValue.size() == 0) return 0; mCursorLocation = 0; - skipChars = 0; mRendered = false; - HandleTextLocation(-1002); + cursorX = mRenderX; return 0; case KEY_END: case KEY_DOWN: mCursorLocation = -1; mRendered = false; - HandleTextLocation(-1003); + HandleCursorByText(); return 0; } @@ -622,58 +494,38 @@ int GUIInput::NotifyKey(int key, bool down) int GUIInput::NotifyCharInput(int key) { - string variableValue; - if (HasInputFocus) { if (key == KEYBOARD_BACKSPACE) { //Backspace - DataManager::GetValue(mVariable, variableValue); - if (variableValue.size() > 0 && (mCursorLocation + skipChars != 0 || mCursorLocation == -1)) { + if (displayValue.size() > 0 && mCursorLocation != 0) { if (mCursorLocation == -1) { - variableValue.resize(variableValue.size() - 1); + displayValue.resize(displayValue.size() - 1); } else { - variableValue.erase(mCursorLocation + skipChars - 1, 1); - if (mCursorLocation > 0) - mCursorLocation--; - else if (skipChars > 0) - skipChars--; + displayValue.erase(mCursorLocation - 1, 1); + mCursorLocation--; } isLocalChange = true; - DataManager::SetValue(mVariable, variableValue); - isLocalChange = false; - - if (HasMask) { - int index, string_size = variableValue.size(); - string maskedValue; - for (index=0; indexSkipCharCount(skipChars); - isLocalChange = false; mRendered = false; return 0; } else if (key >= 32) { @@ -684,33 +536,24 @@ int GUIInput::NotifyCharInput(int key) if (HasDisabled && DisabledList.find((char)key) != string::npos) { return 0; } - DataManager::GetValue(mVariable, variableValue); - if (MaxLen != 0 && variableValue.size() >= MaxLen) { + if (MaxLen != 0 && displayValue.size() >= MaxLen) { return 0; } if (mCursorLocation == -1) { - variableValue += key; + displayValue += key; } else { - variableValue.insert(mCursorLocation + skipChars, 1, key); + displayValue.insert(mCursorLocation, 1, key); mCursorLocation++; } isLocalChange = true; - DataManager::SetValue(mVariable, variableValue); - HandleTextLocation(-1001); - isLocalChange = false; - - if (HasMask) { - int index, string_size = variableValue.size(); - string maskedValue; - for (index=0; index MaxLen) diff --git a/gui/objects.hpp b/gui/objects.hpp index 6c6fa5eb0..7913b36cb 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -192,8 +192,7 @@ public: // Set maximum width in pixels virtual int SetMaxWidth(unsigned width); - // Set number of characters to skip (for scrolling) - virtual int SkipCharCount(unsigned skip); + void SetText(string newtext); public: bool isHighlighted; @@ -209,7 +208,6 @@ protected: int mIsStatic; int mVarChanged; int mFontHeight; - unsigned charSkip; }; // GUIImage - Used for static image @@ -1001,7 +999,10 @@ protected: virtual int GetSelection(int x, int y); // Handles displaying the text properly when chars are added, deleted, or for scrolling - virtual int HandleTextLocation(int x); + void HandleTextLocation(int x); + void UpdateTextWidth(); + void HandleCursorByTouch(int x); + void HandleCursorByText(); protected: GUIText* mInputText; @@ -1013,15 +1014,16 @@ protected: std::string mLastValue; std::string mVariable; std::string mMask; - std::string mMaskVariable; + std::string displayValue; COLOR mBackgroundColor; COLOR mCursorColor; int scrollingX; + int cursorX; int lastX; int mCursorLocation; int mBackgroundX, mBackgroundY, mBackgroundW, mBackgroundH; int mFontY; - unsigned skipChars; + int textWidth; unsigned mFontHeight; unsigned CursorWidth; bool mRendered; diff --git a/gui/text.cpp b/gui/text.cpp index 6498af62c..49e27a104 100644 --- a/gui/text.cpp +++ b/gui/text.cpp @@ -1,3 +1,21 @@ +/* + Copyright 2012 to 2016 bigbiff/Dees_Troy TeamWin + This file is part of TWRP/TeamWin Recovery Project. + + TWRP 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. + + TWRP 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 TWRP. If not, see . +*/ + // text.cpp - GUIText object #include @@ -33,7 +51,6 @@ GUIText::GUIText(xml_node<>* node) mVarChanged = 0; mFontHeight = 0; maxWidth = 0; - charSkip = 0; scaleWidth = true; isHighlighted = false; mText = ""; @@ -94,22 +111,18 @@ int GUIText::Render(void) return -1; mLastValue = gui_parse_text(mText); - string displayValue = mLastValue; - - if (charSkip) - displayValue.erase(0, charSkip); mVarChanged = 0; int x = mRenderX, y = mRenderY; - int width = gr_ttf_measureEx(displayValue.c_str(), fontResource); + int width = gr_ttf_measureEx(mLastValue.c_str(), fontResource); if (isHighlighted) gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha); else gr_color(mColor.red, mColor.green, mColor.blue, mColor.alpha); - gr_textEx_scaleW(mRenderX, mRenderY, displayValue.c_str(), fontResource, maxWidth, mPlacement, scaleWidth); + gr_textEx_scaleW(mRenderX, mRenderY, mLastValue.c_str(), fontResource, maxWidth, mPlacement, scaleWidth); return 0; } @@ -164,13 +177,13 @@ int GUIText::NotifyVarChange(const std::string& varName, const std::string& valu int GUIText::SetMaxWidth(unsigned width) { maxWidth = width; + if (!maxWidth) + scaleWidth = false; mVarChanged = 1; return 0; } -int GUIText::SkipCharCount(unsigned skip) +void GUIText::SetText(string newtext) { - charSkip = skip; - mVarChanged = 1; - return 0; + mText = newtext; } -- cgit v1.2.3