blob: 91a1c117f85f84da69bf92b5db82a8672a9ebaaa [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");
Ethan Yonker58f21322018-08-24 11:17:36 -0500125 if (mFont && mFont->GetResource())
126 mFontHeight = mFont->GetHeight();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200127 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400128
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600129 child = FindNode(node, "data");
Dees_Troy51a0e822012-09-05 15:24:24 -0400130 if (child)
131 {
132 attr = child->first_attribute("name");
133 if (attr)
134 mVariable = attr->value();
135 attr = child->first_attribute("default");
136 if (attr)
137 DataManager::SetValue(mVariable, attr->value());
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600138 mMask = LoadAttrString(child, "mask");
139 HasMask = !mMask.empty();
Dees_Troy51a0e822012-09-05 15:24:24 -0400140 }
141
142 // Load input restrictions
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600143 child = FindNode(node, "restrict");
Dees_Troy51a0e822012-09-05 15:24:24 -0400144 if (child)
145 {
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600146 MinLen = LoadAttrInt(child, "minlen", MinLen);
147 MaxLen = LoadAttrInt(child, "maxlen", MaxLen);
148 AllowedList = LoadAttrString(child, "allow");
149 HasAllowed = !AllowedList.empty();
150 DisabledList = LoadAttrString(child, "disable");
151 HasDisabled = !DisabledList.empty();
Dees_Troy51a0e822012-09-05 15:24:24 -0400152 }
153
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200154 // Load the placement
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600155 LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400156 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
157
158 if (mInputText && mFontHeight && mFontHeight < (unsigned)mRenderH) {
159 mFontY = ((mRenderH - mFontHeight) / 2) + mRenderY;
160 mInputText->SetRenderPos(mRenderX, mFontY);
161 } else
162 mFontY = mRenderY;
163
164 if (mInputText)
Ethan Yonkera5db7122016-03-14 15:47:09 -0500165 mInputText->SetMaxWidth(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400166}
167
168GUIInput::~GUIInput()
169{
thatf6ed8fc2015-02-14 20:23:16 +0100170 delete mInputText;
171 delete mAction;
Dees_Troy51a0e822012-09-05 15:24:24 -0400172}
173
Ethan Yonkera5db7122016-03-14 15:47:09 -0500174void GUIInput::HandleTextLocation(int x) {
175 mRendered = false;
176 if (textWidth <= mRenderW) {
177 if (x != TW_INPUT_NO_UPDATE)
178 lastX = x;
179 scrollingX = 0;
180 return;
181 }
182 if (scrollingX + textWidth < mRenderW) {
183 scrollingX = mRenderW - textWidth;
184 }
185
186 if (x == TW_INPUT_NO_UPDATE)
187 return;
188
189 scrollingX += x - lastX;
190 if (scrollingX > 0)
191 scrollingX = 0;
192 else if (scrollingX + textWidth < mRenderW)
193 scrollingX = mRenderW - textWidth;
194 lastX = x;
195}
196
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400197void GUIInput::UpdateDisplayText() {
Dees_Troy51a0e822012-09-05 15:24:24 -0400198 void* fontResource = NULL;
199
Ethan Yonkera5db7122016-03-14 15:47:09 -0500200 if (mFont) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200201 fontResource = mFont->GetResource();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500202 } else {
203 textWidth = 0;
204 return;
205 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400206
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400207 DataManager::GetValue(mVariable, mValue);
Dees_Troy51a0e822012-09-05 15:24:24 -0400208 if (HasMask) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400209 int index, string_size = mValue.size();
Dees_Troy51a0e822012-09-05 15:24:24 -0400210 string maskedValue;
211 for (index=0; index<string_size; index++)
212 maskedValue += mMask;
213 displayValue = maskedValue;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400214 } else {
215 displayValue = mValue;
Dees_Troy51a0e822012-09-05 15:24:24 -0400216 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400217
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100218 textWidth = gr_ttf_measureEx(displayValue.c_str(), fontResource);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500219}
220
221void GUIInput::HandleCursorByTouch(int x) {
222// Uses x to find mCursorLocation and cursorX
223 if (displayValue.size() == 0) {
224 mCursorLocation = -1;
225 cursorX = mRenderX;
226 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400227 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200228
Ethan Yonkera5db7122016-03-14 15:47:09 -0500229 void* fontResource = NULL;
230 if (mFont) {
231 fontResource = mFont->GetResource();
232 } else {
233 return;
234 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200235
Ethan Yonkera5db7122016-03-14 15:47:09 -0500236 string cursorString;
237 unsigned index = 0, displaySize = displayValue.size();
238 int prevX = mRenderX + scrollingX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400239
Matt Mowera8a89d12016-12-30 18:10:37 -0600240 for (index = 0; index <= displaySize; index++) {
Ethan Yonkera5db7122016-03-14 15:47:09 -0500241 cursorString = displayValue.substr(0, index);
242 cursorX = gr_ttf_measureEx(cursorString.c_str(), fontResource) + mRenderX + scrollingX;
243 if (cursorX > x) {
244 if (index > 0 && x <= cursorX - ((x - prevX) / 2) && prevX >= mRenderX) {
245 // This helps make sure that we can place the cursor before the very first char if the first char is
246 // is fully visible while also still letting us place the cursor after the last char if fully visible
247 mCursorLocation = index - 1;
248 cursorX = prevX;
249 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400250 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500251 mCursorLocation = index;
252 if (cursorX > mRenderX + mRenderW) {
253 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 -0400254 mCursorLocation--;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500255 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400256 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500257 if (cursorX >= mRenderX) {
258 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 -0400259 }
260 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500261 prevX = cursorX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400262 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500263 mCursorLocation = -1; // x is at or past the end of the string
264}
265
266void GUIInput::HandleCursorByText() {
Matt Mowera8a89d12016-12-30 18:10:37 -0600267// Uses mCursorLocation to find cursorX
Ethan Yonkera5db7122016-03-14 15:47:09 -0500268 if (!DrawCursor)
269 return;
270
271 void* fontResource = NULL;
272 if (mFont) {
273 fontResource = mFont->GetResource();
274 } else {
275 return;
276 }
277
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400278 int cursorTextWidth = textWidth; // width of text to the left of the cursor
Ethan Yonkera5db7122016-03-14 15:47:09 -0500279
280 if (mCursorLocation != -1) {
281 string cursorDisplay = displayValue;
282 cursorDisplay.resize(mCursorLocation);
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400283 cursorTextWidth = gr_ttf_measureEx(cursorDisplay.c_str(), fontResource);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500284 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400285 cursorX = mRenderX + cursorTextWidth + scrollingX;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500286 if (cursorX >= mRenderX + mRenderW) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400287 scrollingX = mRenderW - cursorTextWidth;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500288 cursorX = mRenderX + mRenderW - CursorWidth;
289 } else if (cursorX < mRenderX) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400290 scrollingX = cursorTextWidth * -1;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500291 cursorX = mRenderX;
292 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400293}
294
295int GUIInput::Render(void)
296{
297 if (!isConditionTrue())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200298 {
299 mRendered = false;
300 return 0;
301 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400302
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200303 // First step, fill background
Dees_Troy51a0e822012-09-05 15:24:24 -0400304 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
305 gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);
306
307 // Next, render the background resource (if it exists)
308 if (mBackground && mBackground->GetResource())
309 {
310 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
311 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
312 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
313 }
314
315 int ret = 0;
316
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200317 // Render the text
Ethan Yonkera5db7122016-03-14 15:47:09 -0500318 if (mInputText) {
319 mInputText->SetRenderPos(mRenderX + scrollingX, mFontY);
320 mInputText->SetText(displayValue);
321 gr_clip(mRenderX, mRenderY, mRenderW, mRenderH);
322 ret = mInputText->Render();
323 gr_noclip();
324 }
325 if (ret < 0)
326 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400327
328 if (HasInputFocus && DrawCursor) {
329 // Render the cursor
Dees_Troy51a0e822012-09-05 15:24:24 -0400330 gr_color(mCursorColor.red, mCursorColor.green, mCursorColor.blue, 255);
331 gr_fill(cursorX, mFontY, CursorWidth, mFontHeight);
332 }
333
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200334 mRendered = true;
335 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400336}
337
338int GUIInput::Update(void)
339{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200340 if (!isConditionTrue()) return (mRendered ? 2 : 0);
341 if (!mRendered) return 2;
Dees_Troy51a0e822012-09-05 15:24:24 -0400342
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200343 int ret = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400344
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 if (mInputText) ret = mInputText->Update();
346 if (ret < 0) return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400347
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200348 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400349}
350
351int GUIInput::GetSelection(int x, int y)
352{
353 if (x < mRenderX || x - mRenderX > mRenderW || y < mRenderY || y - mRenderY > mRenderH) return -1;
354 return (x - mRenderX);
355}
356
357int GUIInput::NotifyTouch(TOUCH_STATE state, int x, int y)
358{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200359 static int startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400360
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200361 if (!isConditionTrue())
362 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400363
364 if (!HasInputFocus) {
365 if (state != TOUCH_RELEASE)
366 return 0; // Only change focus if touch releases within the input box
367 if (GetSelection(x, y) >= 0) {
368 // When changing focus, we don't scroll or change the cursor location
369 PageManager::SetKeyBoardFocus(0);
that8834a0f2016-01-05 23:29:30 +0100370 PageManager::NotifyCharInput(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400371 SetInputFocus(1);
372 DrawCursor = true;
373 mRendered = false;
374 }
375 } else {
376 switch (state) {
377 case TOUCH_HOLD:
378 case TOUCH_REPEAT:
379 break;
380 case TOUCH_START:
381 startSelection = GetSelection(x,y);
382 lastX = x;
383 DrawCursor = false;
384 mRendered = false;
385 break;
386
387 case TOUCH_DRAG:
388 // Check if we dragged out of the selection window
389 if (GetSelection(x, y) == -1) {
390 lastX = 0;
391 break;
392 }
393
394 DrawCursor = false;
395
396 // Provide some debounce on initial touches
397 if (startSelection != -1 && abs(x - lastX) < 6) {
398 break;
399 }
400
401 startSelection = -1;
402 if (lastX != x)
403 HandleTextLocation(x);
404 break;
405
406 case TOUCH_RELEASE:
407 // We've moved the cursor location
Dees_Troy51a0e822012-09-05 15:24:24 -0400408 mRendered = false;
409 DrawCursor = true;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500410 HandleCursorByTouch(x);
Dees_Troy51a0e822012-09-05 15:24:24 -0400411 break;
412 }
413 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200414 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400415}
416
Vojtech Bocek07220562014-02-08 02:05:33 +0100417int GUIInput::NotifyVarChange(const std::string& varName, const std::string& value)
Dees_Troy51a0e822012-09-05 15:24:24 -0400418{
Vojtech Bocek07220562014-02-08 02:05:33 +0100419 GUIObject::NotifyVarChange(varName, value);
420
Ethan Yonkera5db7122016-03-14 15:47:09 -0500421 if (varName == mVariable) {
422 if (!isLocalChange) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400423 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500424 HandleTextLocation(TW_INPUT_NO_UPDATE);
425 } else
426 isLocalChange = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400427 return 0;
428 }
Ethan Yonkera5db7122016-03-14 15:47:09 -0500429 if (varName.empty()) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400430 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500431 HandleTextLocation(TW_INPUT_NO_UPDATE);
432 HandleCursorByText();
433 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400434 return 0;
435}
436
that8834a0f2016-01-05 23:29:30 +0100437int GUIInput::NotifyKey(int key, bool down)
438{
439 if (!HasInputFocus || !down)
440 return 1;
441
that8834a0f2016-01-05 23:29:30 +0100442 switch (key)
443 {
444 case KEY_LEFT:
Ethan Yonkera5db7122016-03-14 15:47:09 -0500445 if (mCursorLocation == 0)
that8834a0f2016-01-05 23:29:30 +0100446 return 0; // we're already at the beginning
447 if (mCursorLocation == -1) {
Ethan Yonkera5db7122016-03-14 15:47:09 -0500448 if (displayValue.size() == 0) {
449 cursorX = mRenderX;
that8834a0f2016-01-05 23:29:30 +0100450 return 0;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500451 }
452 mCursorLocation = displayValue.size() - 1;
that8834a0f2016-01-05 23:29:30 +0100453 } else {
454 mCursorLocation--;
that8834a0f2016-01-05 23:29:30 +0100455 }
456 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500457 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100458 return 0;
459
460 case KEY_RIGHT:
461 if (mCursorLocation == -1)
462 return 0; // we're already at the end
463 mCursorLocation++;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500464 if ((int)displayValue.size() <= mCursorLocation)
that8834a0f2016-01-05 23:29:30 +0100465 mCursorLocation = -1;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500466 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100467 mRendered = false;
468 return 0;
469
470 case KEY_HOME:
471 case KEY_UP:
Ethan Yonkera5db7122016-03-14 15:47:09 -0500472 if (displayValue.size() == 0)
that8834a0f2016-01-05 23:29:30 +0100473 return 0;
474 mCursorLocation = 0;
that8834a0f2016-01-05 23:29:30 +0100475 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500476 cursorX = mRenderX;
that8834a0f2016-01-05 23:29:30 +0100477 return 0;
478
479 case KEY_END:
480 case KEY_DOWN:
481 mCursorLocation = -1;
482 mRendered = false;
Ethan Yonkera5db7122016-03-14 15:47:09 -0500483 HandleCursorByText();
that8834a0f2016-01-05 23:29:30 +0100484 return 0;
485 }
486
487 return 1;
488}
489
490int GUIInput::NotifyCharInput(int key)
Dees_Troy51a0e822012-09-05 15:24:24 -0400491{
Dees_Troy51a0e822012-09-05 15:24:24 -0400492 if (HasInputFocus) {
493 if (key == KEYBOARD_BACKSPACE) {
494 //Backspace
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400495 if (mValue.size() > 0 && mCursorLocation != 0) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400496 if (mCursorLocation == -1) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400497 mValue.resize(mValue.size() - 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400498 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400499 mValue.erase(mCursorLocation - 1, 1);
Ethan Yonkera5db7122016-03-14 15:47:09 -0500500 mCursorLocation--;
Dees_Troy51a0e822012-09-05 15:24:24 -0400501 }
502 isLocalChange = true;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400503 DataManager::SetValue(mVariable, mValue);
504 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500505 HandleTextLocation(TW_INPUT_NO_UPDATE);
506 HandleCursorByText();
Dees_Troy51a0e822012-09-05 15:24:24 -0400507 }
508 } else if (key == KEYBOARD_SWIPE_LEFT) {
509 // Delete all
510 isLocalChange = true;
511 if (mCursorLocation == -1) {
512 DataManager::SetValue (mVariable, "");
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400513 mValue = "";
Ethan Yonkera5db7122016-03-14 15:47:09 -0500514 textWidth = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400515 mCursorLocation = -1;
516 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400517 mValue.erase(0, mCursorLocation);
518 DataManager::SetValue(mVariable, mValue);
Dees_Troy51a0e822012-09-05 15:24:24 -0400519 mCursorLocation = 0;
520 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400521 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500522 cursorX = mRenderX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400523 scrollingX = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400524 mRendered = false;
525 return 0;
that8834a0f2016-01-05 23:29:30 +0100526 } else if (key >= 32) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400527 // Regular key
528 if (HasAllowed && AllowedList.find((char)key) == string::npos) {
529 return 0;
530 }
531 if (HasDisabled && DisabledList.find((char)key) != string::npos) {
532 return 0;
533 }
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400534 if (MaxLen != 0 && mValue.size() >= MaxLen) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400535 return 0;
536 }
537 if (mCursorLocation == -1) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400538 mValue += key;
Dees_Troy51a0e822012-09-05 15:24:24 -0400539 } else {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400540 mValue.insert(mCursorLocation, 1, key);
Dees_Troy51a0e822012-09-05 15:24:24 -0400541 mCursorLocation++;
542 }
543 isLocalChange = true;
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400544 DataManager::SetValue(mVariable, mValue);
545 UpdateDisplayText();
Ethan Yonkera5db7122016-03-14 15:47:09 -0500546 HandleTextLocation(TW_INPUT_NO_UPDATE);
547 HandleCursorByText();
Dees_Troy51a0e822012-09-05 15:24:24 -0400548 } else if (key == KEYBOARD_ACTION) {
549 // Action
Dees_Troy51a0e822012-09-05 15:24:24 -0400550 if (mAction) {
Sultan Qasim Khan14138d92016-04-04 04:11:25 -0400551 unsigned inputLen = mValue.length();
Dees_Troy51a0e822012-09-05 15:24:24 -0400552 if (inputLen < MinLen)
553 return 0;
554 else if (MaxLen != 0 && inputLen > MaxLen)
555 return 0;
556 else
557 return (mAction ? mAction->NotifyTouch(TOUCH_RELEASE, mRenderX, mRenderY) : 1);
558 }
559 }
560 return 0;
561 } else {
562 if (key == 0) {
563 // Somewhat ugly hack-ish way to tell the box to redraw after losing focus to remove the cursor
564 mRendered = false;
565 return 1;
566 }
567 }
568 return 1;
569}