blob: ec370abe591b8b4092eaacaac770372b9984fec9 [file] [log] [blame]
Dees Troy3be70a82013-10-22 14:25:12 +00001/*
Ethan Yonkera5db7122016-03-14 15:47:09 -05002 Copyright 2012 to 2016 bigbiff/Dees_Troy TeamWin
Dees Troy3be70a82013-10-22 14:25:12 +00003 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
Dees_Troy51a0e822012-09-05 15:24:24 -040019// input.cpp - GUIInput object
20
21#include <linux/input.h>
22#include <pthread.h>
23#include <stdarg.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <fcntl.h>
28#include <sys/reboot.h>
29#include <sys/stat.h>
30#include <sys/time.h>
31#include <sys/mman.h>
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <time.h>
35#include <unistd.h>
36#include <stdlib.h>
37
38#include <string>
39
40extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000041#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010043#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040044
45#include "rapidxml.hpp"
46#include "objects.hpp"
47#include "../data.hpp"
48
Ethan Yonkera5db7122016-03-14 15:47:09 -050049#define TW_INPUT_NO_UPDATE -1000 // Magic value for HandleTextLocation when no change in scrolling has occurred
50
Dees_Troy51a0e822012-09-05 15:24:24 -040051GUIInput::GUIInput(xml_node<>* node)
Vojtech Bocekede51c52014-02-07 23:58:09 +010052 : GUIObject(node)
Dees_Troy51a0e822012-09-05 15:24:24 -040053{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020054 xml_attribute<>* attr;
55 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -040056
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020057 mInputText = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040058 mAction = NULL;
59 mBackground = NULL;
60 mCursor = NULL;
61 mFont = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020062 mRendered = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040063 HasMask = false;
64 DrawCursor = false;
65 isLocalChange = true;
66 HasAllowed = false;
67 HasDisabled = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -050068 cursorX = textWidth = scrollingX = mFontHeight = mFontY = lastX = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040069 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = MinLen = MaxLen = 0;
70 mCursorLocation = -1; // -1 is always the end of the string
71 CursorWidth = 3;
72 ConvertStrToColor("black", &mBackgroundColor);
73 ConvertStrToColor("white", &mCursorColor);
Sultan Qasim Khan14138d92016-04-04 04:11:25 -040074 mValue = "";
Ethan Yonkera5db7122016-03-14 15:47:09 -050075 displayValue = "";
Dees_Troy51a0e822012-09-05 15:24:24 -040076
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020077 if (!node)
78 return;
Dees_Troy51a0e822012-09-05 15:24:24 -040079
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020080 // Load text directly from the node
81 mInputText = new GUIText(node);
Dees_Troy51a0e822012-09-05 15:24:24 -040082 // Load action directly from the node
83 mAction = new GUIAction(node);
84
85 if (mInputText->Render() < 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020086 {
87 delete mInputText;
88 mInputText = NULL;
89 }
Dees_Troy51a0e822012-09-05 15:24:24 -040090
91 // Load the background
Ethan Yonker21ff02a2015-02-18 14:35:00 -060092 child = FindNode(node, "background");
Dees_Troy51a0e822012-09-05 15:24:24 -040093 if (child)
94 {
thatf6ed8fc2015-02-14 20:23:16 +010095 mBackground = LoadAttrImage(child, "resource");
96 mBackgroundColor = LoadAttrColor(child, "color", mBackgroundColor);
Dees_Troy51a0e822012-09-05 15:24:24 -040097 }
98 if (mBackground && mBackground->GetResource())
99 {
thatf6ed8fc2015-02-14 20:23:16 +0100100 mBackgroundW = mBackground->GetWidth();
101 mBackgroundH = mBackground->GetHeight();
Dees_Troy51a0e822012-09-05 15:24:24 -0400102 }
103
104 // Load the cursor color
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600105 child = FindNode(node, "cursor");
Dees_Troy51a0e822012-09-05 15:24:24 -0400106 if (child)
107 {
thatf6ed8fc2015-02-14 20:23:16 +0100108 mCursor = LoadAttrImage(child, "resource");
109 mCursorColor = LoadAttrColor(child, "color", mCursorColor);
Dees_Troy51a0e822012-09-05 15:24:24 -0400110 attr = child->first_attribute("hasfocus");
111 if (attr)
112 {
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600113 std::string focus = attr->value();
114 SetInputFocus(atoi(focus.c_str()));
Dees_Troy51a0e822012-09-05 15:24:24 -0400115 }
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600116 CursorWidth = LoadAttrIntScaleX(child, "width", CursorWidth);
Dees_Troy51a0e822012-09-05 15:24:24 -0400117 }
118 DrawCursor = HasInputFocus;
119
thatf6ed8fc2015-02-14 20:23:16 +0100120 // Load the font
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600121 child = FindNode(node, "font");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200122 if (child)
123 {
thatf6ed8fc2015-02-14 20:23:16 +0100124 mFont = LoadAttrFont(child, "resource");
125 mFontHeight = mFont->GetHeight();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200126 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400127
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600128 child = FindNode(node, "data");
Dees_Troy51a0e822012-09-05 15:24:24 -0400129 if (child)
130 {
131 attr = child->first_attribute("name");
132 if (attr)
133 mVariable = attr->value();
134 attr = child->first_attribute("default");
135 if (attr)
136 DataManager::SetValue(mVariable, attr->value());
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600137 mMask = LoadAttrString(child, "mask");
138 HasMask = !mMask.empty();
Dees_Troy51a0e822012-09-05 15:24:24 -0400139 }
140
141 // Load input restrictions
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600142 child = FindNode(node, "restrict");
Dees_Troy51a0e822012-09-05 15:24:24 -0400143 if (child)
144 {
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600145 MinLen = LoadAttrInt(child, "minlen", MinLen);
146 MaxLen = LoadAttrInt(child, "maxlen", MaxLen);
147 AllowedList = LoadAttrString(child, "allow");
148 HasAllowed = !AllowedList.empty();
149 DisabledList = LoadAttrString(child, "disable");
150 HasDisabled = !DisabledList.empty();
Dees_Troy51a0e822012-09-05 15:24:24 -0400151 }
152
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200153 // Load the placement
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600154 LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400155 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
156
157 if (mInputText && mFontHeight && mFontHeight < (unsigned)mRenderH) {
158 mFontY = ((mRenderH - mFontHeight) / 2) + mRenderY;
159 mInputText->SetRenderPos(mRenderX, mFontY);
160 } else
161 mFontY = mRenderY;
162
163 if (mInputText)
Ethan Yonkera5db7122016-03-14 15:47:09 -0500164 mInputText->SetMaxWidth(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400165}
166
167GUIInput::~GUIInput()
168{
thatf6ed8fc2015-02-14 20:23:16 +0100169 delete mInputText;
170 delete mAction;
Dees_Troy51a0e822012-09-05 15:24:24 -0400171}
172
Ethan Yonkera5db7122016-03-14 15:47:09 -0500173void GUIInput::HandleTextLocation(int x) {
174 mRendered = false;
175 if (textWidth <= mRenderW) {
176 if (x != TW_INPUT_NO_UPDATE)
177 lastX = x;
178 scrollingX = 0;
179 return;
180 }
181 if (scrollingX + textWidth < mRenderW) {
182 scrollingX = mRenderW - textWidth;
183 }
184
185 if (x == TW_INPUT_NO_UPDATE)
186 return;
187
188 scrollingX += x - lastX;
189 if (scrollingX > 0)
190 scrollingX = 0;
191 else if (scrollingX + textWidth < mRenderW)
192 scrollingX = mRenderW - textWidth;
193 lastX = x;
194}
195
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400196void GUIInput::UpdateDisplayText() {
Dees_Troy51a0e822012-09-05 15:24:24 -0400197 void* fontResource = NULL;
198
Ethan Yonkera5db7122016-03-14 15:47:09 -0500199 if (mFont) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200200 fontResource = mFont->GetResource();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500201 } else {
202 textWidth = 0;
203 return;
204 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400205
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400206 DataManager::GetValue(mVariable, mValue);
Dees_Troy51a0e822012-09-05 15:24:24 -0400207 if (HasMask) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400208 int index, string_size = mValue.size();
Dees_Troy51a0e822012-09-05 15:24:24 -0400209 string maskedValue;
210 for (index=0; index<string_size; index++)
211 maskedValue += mMask;
212 displayValue = maskedValue;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400213 } else {
214 displayValue = mValue;
Dees_Troy51a0e822012-09-05 15:24:24 -0400215 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400216
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100217 textWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500218}
219
220void GUIInput::HandleCursorByTouch(int x) {
221// Uses x to find mCursorLocation and cursorX
222 if (displayValue.size() == 0) {
223 mCursorLocation = -1;
224 cursorX = mRenderX;
225 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400226 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200227
Ethan Yonkera5db7122016-03-14 15:47:09 -0500228 void* fontResource = NULL;
229 if (mFont) {
230 fontResource = mFont->GetResource();
231 } else {
232 return;
233 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200234
Ethan Yonkera5db7122016-03-14 15:47:09 -0500235 string cursorString;
236 unsigned index = 0, displaySize = displayValue.size();
237 int prevX = mRenderX + scrollingX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400238
Ethan Yonkera5db7122016-03-14 15:47:09 -0500239 for(index = 0; index <= displaySize; index++) {
240 cursorString = displayValue.substr(0, index);
241 cursorX = gr_ttf_measureEx(cursorString.c_str(), fontResource) + mRenderX + scrollingX;
242 if (cursorX > x) {
243 if (index > 0 && x <= cursorX - ((x - prevX) / 2) && prevX >= mRenderX) {
244 // This helps make sure that we can place the cursor before the very first char if the first char is
245 // is fully visible while also still letting us place the cursor after the last char if fully visible
246 mCursorLocation = index - 1;
247 cursorX = prevX;
248 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400249 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500250 mCursorLocation = index;
251 if (cursorX > mRenderX + mRenderW) {
252 cursorX = prevX; // This makes sure that the cursor doesn't get placed after the end of the input box
Dees_Troy51a0e822012-09-05 15:24:24 -0400253 mCursorLocation--;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500254 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400255 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500256 if (cursorX >= mRenderX) {
257 return; // This makes sure that the cursor doesn't get placed before the beginning of the input box
Dees_Troy51a0e822012-09-05 15:24:24 -0400258 }
259 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500260 prevX = cursorX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400261 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500262 mCursorLocation = -1; // x is at or past the end of the string
263}
264
265void GUIInput::HandleCursorByText() {
266// Uses mCursorLocation to find cursorX
267 if (!DrawCursor)
268 return;
269
270 void* fontResource = NULL;
271 if (mFont) {
272 fontResource = mFont->GetResource();
273 } else {
274 return;
275 }
276
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400277 int cursorTextWidth = textWidth; // width of text to the left of the cursor
Ethan Yonkera5db7122016-03-14 15:47:09 -0500278
279 if (mCursorLocation != -1) {
280 string cursorDisplay = displayValue;
281 cursorDisplay.resize(mCursorLocation);
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400282 cursorTextWidth = gr_ttf_measureEx(cursorDisplay.c_str(), fontResource);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500283 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400284 cursorX = mRenderX + cursorTextWidth + scrollingX;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500285 if (cursorX >= mRenderX + mRenderW) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400286 scrollingX = mRenderW - cursorTextWidth;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500287 cursorX = mRenderX + mRenderW - CursorWidth;
288 } else if (cursorX < mRenderX) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400289 scrollingX = cursorTextWidth * -1;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500290 cursorX = mRenderX;
291 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400292}
293
294int GUIInput::Render(void)
295{
296 if (!isConditionTrue())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200297 {
298 mRendered = false;
299 return 0;
300 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400301
302 void* fontResource = NULL;
303 if (mFont) fontResource = mFont->GetResource();
304
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200305 // First step, fill background
Dees_Troy51a0e822012-09-05 15:24:24 -0400306 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
307 gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);
308
309 // Next, render the background resource (if it exists)
310 if (mBackground && mBackground->GetResource())
311 {
312 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
313 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
314 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
315 }
316
317 int ret = 0;
318
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200319 // Render the text
Ethan Yonkera5db7122016-03-14 15:47:09 -0500320 if (mInputText) {
321 mInputText->SetRenderPos(mRenderX + scrollingX, mFontY);
322 mInputText->SetText(displayValue);
323 gr_clip(mRenderX, mRenderY, mRenderW, mRenderH);
324 ret = mInputText->Render();
325 gr_noclip();
326 }
327 if (ret < 0)
328 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400329
330 if (HasInputFocus && DrawCursor) {
331 // Render the cursor
Dees_Troy51a0e822012-09-05 15:24:24 -0400332 gr_color(mCursorColor.red, mCursorColor.green, mCursorColor.blue, 255);
333 gr_fill(cursorX, mFontY, CursorWidth, mFontHeight);
334 }
335
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200336 mRendered = true;
337 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400338}
339
340int GUIInput::Update(void)
341{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200342 if (!isConditionTrue()) return (mRendered ? 2 : 0);
343 if (!mRendered) return 2;
Dees_Troy51a0e822012-09-05 15:24:24 -0400344
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 int ret = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400346
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200347 if (mInputText) ret = mInputText->Update();
348 if (ret < 0) return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400349
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200350 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400351}
352
353int GUIInput::GetSelection(int x, int y)
354{
355 if (x < mRenderX || x - mRenderX > mRenderW || y < mRenderY || y - mRenderY > mRenderH) return -1;
356 return (x - mRenderX);
357}
358
359int GUIInput::NotifyTouch(TOUCH_STATE state, int x, int y)
360{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200361 static int startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400362 void* fontResource = NULL;
363
364 if (mFont) fontResource = mFont->GetResource();
365
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200366 if (!isConditionTrue())
367 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400368
369 if (!HasInputFocus) {
370 if (state != TOUCH_RELEASE)
371 return 0; // Only change focus if touch releases within the input box
372 if (GetSelection(x, y) >= 0) {
373 // When changing focus, we don't scroll or change the cursor location
374 PageManager::SetKeyBoardFocus(0);
that8834a0f2016-01-05 23:29:30 +0100375 PageManager::NotifyCharInput(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400376 SetInputFocus(1);
377 DrawCursor = true;
378 mRendered = false;
379 }
380 } else {
381 switch (state) {
382 case TOUCH_HOLD:
383 case TOUCH_REPEAT:
384 break;
385 case TOUCH_START:
386 startSelection = GetSelection(x,y);
387 lastX = x;
388 DrawCursor = false;
389 mRendered = false;
390 break;
391
392 case TOUCH_DRAG:
393 // Check if we dragged out of the selection window
394 if (GetSelection(x, y) == -1) {
395 lastX = 0;
396 break;
397 }
398
399 DrawCursor = false;
400
401 // Provide some debounce on initial touches
402 if (startSelection != -1 && abs(x - lastX) < 6) {
403 break;
404 }
405
406 startSelection = -1;
407 if (lastX != x)
408 HandleTextLocation(x);
409 break;
410
411 case TOUCH_RELEASE:
412 // We've moved the cursor location
Dees_Troy51a0e822012-09-05 15:24:24 -0400413 mRendered = false;
414 DrawCursor = true;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500415 HandleCursorByTouch(x);
Dees_Troy51a0e822012-09-05 15:24:24 -0400416 break;
417 }
418 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200419 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400420}
421
Vojtech Bocek07220562014-02-08 02:05:33 +0100422int GUIInput::NotifyVarChange(const std::string& varName, const std::string& value)
Dees_Troy51a0e822012-09-05 15:24:24 -0400423{
Vojtech Bocek07220562014-02-08 02:05:33 +0100424 GUIObject::NotifyVarChange(varName, value);
425
Ethan Yonkera5db7122016-03-14 15:47:09 -0500426 if (varName == mVariable) {
427 if (!isLocalChange) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400428 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500429 HandleTextLocation(TW_INPUT_NO_UPDATE);
430 } else
431 isLocalChange = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400432 return 0;
433 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500434 if (varName.empty()) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400435 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500436 HandleTextLocation(TW_INPUT_NO_UPDATE);
437 HandleCursorByText();
438 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400439 return 0;
440}
441
that8834a0f2016-01-05 23:29:30 +0100442int GUIInput::NotifyKey(int key, bool down)
443{
444 if (!HasInputFocus || !down)
445 return 1;
446
that8834a0f2016-01-05 23:29:30 +0100447 switch (key)
448 {
449 case KEY_LEFT:
Ethan Yonkera5db7122016-03-14 15:47:09 -0500450 if (mCursorLocation == 0)
that8834a0f2016-01-05 23:29:30 +0100451 return 0; // we're already at the beginning
452 if (mCursorLocation == -1) {
Ethan Yonkera5db7122016-03-14 15:47:09 -0500453 if (displayValue.size() == 0) {
454 cursorX = mRenderX;
that8834a0f2016-01-05 23:29:30 +0100455 return 0;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500456 }
457 mCursorLocation = displayValue.size() - 1;
that8834a0f2016-01-05 23:29:30 +0100458 } else {
459 mCursorLocation--;
that8834a0f2016-01-05 23:29:30 +0100460 }
461 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500462 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100463 return 0;
464
465 case KEY_RIGHT:
466 if (mCursorLocation == -1)
467 return 0; // we're already at the end
468 mCursorLocation++;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500469 if ((int)displayValue.size() <= mCursorLocation)
that8834a0f2016-01-05 23:29:30 +0100470 mCursorLocation = -1;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500471 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100472 mRendered = false;
473 return 0;
474
475 case KEY_HOME:
476 case KEY_UP:
Ethan Yonkera5db7122016-03-14 15:47:09 -0500477 if (displayValue.size() == 0)
that8834a0f2016-01-05 23:29:30 +0100478 return 0;
479 mCursorLocation = 0;
that8834a0f2016-01-05 23:29:30 +0100480 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500481 cursorX = mRenderX;
that8834a0f2016-01-05 23:29:30 +0100482 return 0;
483
484 case KEY_END:
485 case KEY_DOWN:
486 mCursorLocation = -1;
487 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500488 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100489 return 0;
490 }
491
492 return 1;
493}
494
495int GUIInput::NotifyCharInput(int key)
Dees_Troy51a0e822012-09-05 15:24:24 -0400496{
Dees_Troy51a0e822012-09-05 15:24:24 -0400497 if (HasInputFocus) {
498 if (key == KEYBOARD_BACKSPACE) {
499 //Backspace
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400500 if (mValue.size() > 0 && mCursorLocation != 0) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400501 if (mCursorLocation == -1) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400502 mValue.resize(mValue.size() - 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400503 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400504 mValue.erase(mCursorLocation - 1, 1);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500505 mCursorLocation--;
Dees_Troy51a0e822012-09-05 15:24:24 -0400506 }
507 isLocalChange = true;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400508 DataManager::SetValue(mVariable, mValue);
509 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500510 HandleTextLocation(TW_INPUT_NO_UPDATE);
511 HandleCursorByText();
Dees_Troy51a0e822012-09-05 15:24:24 -0400512 }
513 } else if (key == KEYBOARD_SWIPE_LEFT) {
514 // Delete all
515 isLocalChange = true;
516 if (mCursorLocation == -1) {
517 DataManager::SetValue (mVariable, "");
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400518 mValue = "";
Ethan Yonkera5db7122016-03-14 15:47:09 -0500519 textWidth = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400520 mCursorLocation = -1;
521 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400522 mValue.erase(0, mCursorLocation);
523 DataManager::SetValue(mVariable, mValue);
Dees_Troy51a0e822012-09-05 15:24:24 -0400524 mCursorLocation = 0;
525 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400526 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500527 cursorX = mRenderX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400528 scrollingX = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400529 mRendered = false;
530 return 0;
that8834a0f2016-01-05 23:29:30 +0100531 } else if (key >= 32) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400532 // Regular key
533 if (HasAllowed && AllowedList.find((char)key) == string::npos) {
534 return 0;
535 }
536 if (HasDisabled && DisabledList.find((char)key) != string::npos) {
537 return 0;
538 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400539 if (MaxLen != 0 && mValue.size() >= MaxLen) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400540 return 0;
541 }
542 if (mCursorLocation == -1) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400543 mValue += key;
Dees_Troy51a0e822012-09-05 15:24:24 -0400544 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400545 mValue.insert(mCursorLocation, 1, key);
Dees_Troy51a0e822012-09-05 15:24:24 -0400546 mCursorLocation++;
547 }
548 isLocalChange = true;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400549 DataManager::SetValue(mVariable, mValue);
550 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500551 HandleTextLocation(TW_INPUT_NO_UPDATE);
552 HandleCursorByText();
Dees_Troy51a0e822012-09-05 15:24:24 -0400553 } else if (key == KEYBOARD_ACTION) {
554 // Action
Dees_Troy51a0e822012-09-05 15:24:24 -0400555 if (mAction) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400556 unsigned inputLen = mValue.length();
Dees_Troy51a0e822012-09-05 15:24:24 -0400557 if (inputLen < MinLen)
558 return 0;
559 else if (MaxLen != 0 && inputLen > MaxLen)
560 return 0;
561 else
562 return (mAction ? mAction->NotifyTouch(TOUCH_RELEASE, mRenderX, mRenderY) : 1);
563 }
564 }
565 return 0;
566 } else {
567 if (key == 0) {
568 // Somewhat ugly hack-ish way to tell the box to redraw after losing focus to remove the cursor
569 mRendered = false;
570 return 1;
571 }
572 }
573 return 1;
574}