blob: 3386465e290b4f6733a43a21a0325edf8decb87f [file] [log] [blame]
Dees_Troya13d74f2013-03-24 08:54:55 -05001/*
2 Copyright 2013 bigbiff/Dees_Troy TeamWin
3 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*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
Dees_Troy51a0e822012-09-05 15:24:24 -040019#include <string.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040020
21extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000022#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040023}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010024#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040025
26#include "rapidxml.hpp"
27#include "objects.hpp"
28#include "../data.hpp"
Noah Jacobson5a79f672019-04-28 00:10:07 -040029#include "../partitions.hpp"
Ethan Yonker74db1572015-10-28 12:44:49 -050030#include "pages.hpp"
31
32extern std::vector<language_struct> Language_List;
Dees_Troyeead9852013-02-15 14:31:06 -060033
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010034GUIListBox::GUIListBox(xml_node<>* node) : GUIScrollList(node)
Dees_Troy51a0e822012-09-05 15:24:24 -040035{
Dees_Troyeead9852013-02-15 14:31:06 -060036 xml_attribute<>* attr;
37 xml_node<>* child;
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010038 mIconSelected = mIconUnselected = NULL;
Dees_Troyeead9852013-02-15 14:31:06 -060039 mUpdate = 0;
Ethan Yonkerdedbb7f2016-01-17 18:17:38 -060040 isCheckList = isTextParsed = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040041
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010042 // Get the icons, if any
Ethan Yonker21ff02a2015-02-18 14:35:00 -060043 child = FindNode(node, "icon");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010044 if (child) {
thatf6ed8fc2015-02-14 20:23:16 +010045 mIconSelected = LoadAttrImage(child, "selected");
46 mIconUnselected = LoadAttrImage(child, "unselected");
Dees_Troyeead9852013-02-15 14:31:06 -060047 }
Ethan Yonker58f21322018-08-24 11:17:36 -050048 int iconWidth = 0, iconHeight = 0;
49 if (mIconSelected && mIconSelected->GetResource() && mIconUnselected && mIconUnselected->GetResource()) {
50 iconWidth = std::max(mIconSelected->GetWidth(), mIconUnselected->GetWidth());
51 iconHeight = std::max(mIconSelected->GetHeight(), mIconUnselected->GetHeight());
52 } else if (mIconSelected && mIconSelected->GetResource()) {
53 iconWidth = mIconSelected->GetWidth();
54 iconHeight = mIconSelected->GetHeight();
55 } else if (mIconUnselected && mIconUnselected->GetResource()) {
56 iconWidth = mIconUnselected->GetWidth();
57 iconHeight = mIconUnselected->GetHeight();
58 }
thatf6ed8fc2015-02-14 20:23:16 +010059 SetMaxIconSize(iconWidth, iconHeight);
Dees_Troyeead9852013-02-15 14:31:06 -060060
61 // Handle the result variable
Ethan Yonker21ff02a2015-02-18 14:35:00 -060062 child = FindNode(node, "data");
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010063 if (child) {
Dees_Troyeead9852013-02-15 14:31:06 -060064 attr = child->first_attribute("name");
65 if (attr)
66 mVariable = attr->value();
67 attr = child->first_attribute("default");
68 if (attr)
69 DataManager::SetValue(mVariable, attr->value());
Ethan Yonker0a3a98f2015-02-05 00:48:28 +010070 // Get the currently selected value for the list
71 DataManager::GetValue(mVariable, currentValue);
Ethan Yonker74db1572015-10-28 12:44:49 -050072 if (mVariable == "tw_language") {
73 std::vector<language_struct>::iterator iter;
74 for (iter = Language_List.begin(); iter != Language_List.end(); iter++) {
75 ListItem data;
76 data.displayName = (*iter).displayvalue;
77 data.variableValue = (*iter).filename;
78 data.action = NULL;
79 if (currentValue == (*iter).filename) {
80 data.selected = 1;
81 DataManager::SetValue("tw_language_display", (*iter).displayvalue);
82 } else
83 data.selected = 0;
84 mListItems.push_back(data);
85 }
Noah Jacobson5a79f672019-04-28 00:10:07 -040086 } else if (mVariable == "tw_crypto_user_id") {
87 std::vector<users_struct>::iterator iter;
88 std::vector<users_struct>* Users_List = PartitionManager.Get_Users_List();
89 for (iter = Users_List->begin(); iter != Users_List->end(); iter++) {
90 if (!(*iter).isDecrypted) {
91 ListItem data;
92 data.displayName = (*iter).userName;
93 data.variableValue = (*iter).userId;
94 data.action = NULL;
95 DataManager::GetValue("tw_crypto_user_id", currentValue);
96 if (currentValue == (*iter).userId || currentValue == "") {
97 data.selected = 1;
98 DataManager::SetValue("tw_crypto_user_id", (*iter).userId);
99 DataManager::SetValue("tw_crypto_pwtype", (*iter).type);
100 } else
101 data.selected = 0;
102 mListItems.push_back(data);
103 }
104 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500105 }
Noah Jacobson5a79f672019-04-28 00:10:07 -0400106 } else
107 allowSelection = false; // allows using listbox as a read-only list or menu
Dees_Troyeead9852013-02-15 14:31:06 -0600108
Dees_Troy51a0e822012-09-05 15:24:24 -0400109 // Get the data for the list
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600110 child = FindNode(node, "listitem");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200111 if (!child) return;
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100112 while (child) {
that8ab5c132015-09-13 23:00:54 +0200113 ListItem item;
Dees_Troy51a0e822012-09-05 15:24:24 -0400114
115 attr = child->first_attribute("name");
Noah Jacobson5a79f672019-04-28 00:10:07 -0400116 if (!attr) continue;
Ethan Yonkerdedbb7f2016-01-17 18:17:38 -0600117 // We will parse display names when we get page focus to ensure that translating takes place
118 item.displayName = attr->value();
that8ab5c132015-09-13 23:00:54 +0200119 item.variableValue = gui_parse_text(child->value());
120 item.selected = (child->value() == currentValue);
121 item.action = NULL;
thatc01391c2015-07-09 00:19:58 +0200122 xml_node<>* action = child->first_node("action");
Noah Jacobson5a79f672019-04-28 00:10:07 -0400123 if (!action) action = child->first_node("actions");
thatc01391c2015-07-09 00:19:58 +0200124 if (action) {
Ethan Yonker64e0a652018-07-25 09:52:17 -0500125 item.action = new GUIAction(child);
thatc01391c2015-07-09 00:19:58 +0200126 allowSelection = true;
127 }
Ethan Yonker56ce3322015-07-30 15:04:32 -0500128 xml_node<>* variable_name = child->first_node("data");
129 if (variable_name) {
130 attr = variable_name->first_attribute("variable");
131 if (attr) {
that8ab5c132015-09-13 23:00:54 +0200132 item.variableName = attr->value();
133 item.selected = (DataManager::GetIntValue(item.variableName) != 0);
Ethan Yonker56ce3322015-07-30 15:04:32 -0500134 allowSelection = true;
135 isCheckList = true;
136 }
137 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400138
that8ab5c132015-09-13 23:00:54 +0200139 LoadConditions(child, item.mConditions);
140
141 mListItems.push_back(item);
Noah Jacobson5a79f672019-04-28 00:10:07 -0400142 mVisibleItems.push_back(mListItems.size() - 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400143
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200144 child = child->next_sibling("listitem");
145 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400146}
147
148GUIListBox::~GUIListBox()
149{
Dees_Troy51a0e822012-09-05 15:24:24 -0400150}
151
152int GUIListBox::Update(void)
153{
Matt Mowera8a89d12016-12-30 18:10:37 -0600154 if (!isConditionTrue())
Vojtech Bocekede51c52014-02-07 23:58:09 +0100155 return 0;
156
Noah Jacobson5a79f672019-04-28 00:10:07 -0400157 if (mVariable == "tw_crypto_user_id") {
158 mListItems.clear();
159 std::vector<users_struct>::iterator iter;
160 std::vector<users_struct>* Users_List = PartitionManager.Get_Users_List();
161 for (iter = Users_List->begin(); iter != Users_List->end(); iter++) {
162 if (!(*iter).isDecrypted) {
163 ListItem data;
164 data.displayName = (*iter).userName;
165 data.variableValue = (*iter).userId;
166 data.action = NULL;
167 DataManager::GetValue("tw_crypto_user_id", currentValue);
168 if (currentValue == (*iter).userId || currentValue == "") {
169 data.selected = 1;
170 DataManager::SetValue("tw_crypto_user_id", (*iter).userId);
171 DataManager::SetValue("tw_crypto_pwtype", (*iter).type);
172 } else
173 data.selected = 0;
174 mListItems.push_back(data);
175 }
176 }
177 mVisibleItems.clear();
178 for (size_t i = 0; i < mListItems.size(); i++) {
179 mVisibleItems.push_back(i);
180 }
181 mUpdate = 1;
182 }
183
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100184 GUIScrollList::Update();
Dees_Troyeead9852013-02-15 14:31:06 -0600185
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100186 if (mUpdate) {
Dees_Troyeead9852013-02-15 14:31:06 -0600187 mUpdate = 0;
188 if (Render() == 0)
Dees_Troy51a0e822012-09-05 15:24:24 -0400189 return 2;
Dees_Troyeead9852013-02-15 14:31:06 -0600190 }
Dees_Troyeead9852013-02-15 14:31:06 -0600191 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400192}
193
Vojtech Bocek07220562014-02-08 02:05:33 +0100194int GUIListBox::NotifyVarChange(const std::string& varName, const std::string& value)
Dees_Troy51a0e822012-09-05 15:24:24 -0400195{
thatfa30aca2015-02-13 01:22:22 +0100196 GUIScrollList::NotifyVarChange(varName, value);
197
Matt Mowera8a89d12016-12-30 18:10:37 -0600198 if (!isConditionTrue())
Vojtech Bocekede51c52014-02-07 23:58:09 +0100199 return 0;
200
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100201 // Check to see if the variable that we are using to store the list selected value has been updated
202 if (varName == mVariable) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400203 currentValue = value;
Dees_Troy51a0e822012-09-05 15:24:24 -0400204 mUpdate = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200205 }
that8ab5c132015-09-13 23:00:54 +0200206
207 std::vector<size_t> mVisibleItemsOld;
208 std::swap(mVisibleItemsOld, mVisibleItems);
209 for (size_t i = 0; i < mListItems.size(); i++) {
210 ListItem& item = mListItems[i];
211 // update per-item visibility condition
212 bool itemVisible = UpdateConditions(item.mConditions, varName);
213 if (itemVisible)
214 mVisibleItems.push_back(i);
215
216 if (isCheckList)
217 {
that35f17402015-11-02 20:15:07 +0100218 if (item.variableName == varName || varName.empty()) {
219 std::string val;
220 DataManager::GetValue(item.variableName, val);
221 item.selected = (val != "0");
that8ab5c132015-09-13 23:00:54 +0200222 mUpdate = 1;
223 }
224 }
225 else if (varName == mVariable) {
226 if (item.variableValue == currentValue) {
227 item.selected = 1;
228 SetVisibleListLocation(mVisibleItems.empty() ? 0 : mVisibleItems.size()-1);
229 } else {
230 item.selected = 0;
231 }
232 }
233 }
234
235 if (mVisibleItemsOld != mVisibleItems) {
236 mUpdate = 1; // some item's visibility has changed
Ethan Yonkerd0514ba2015-10-22 14:17:47 -0500237 if (firstDisplayedItem >= (int)mVisibleItems.size()) {
that8ab5c132015-09-13 23:00:54 +0200238 // all items in the view area were removed - make last item visible
239 SetVisibleListLocation(mVisibleItems.empty() ? 0 : mVisibleItems.size()-1);
240 }
241 }
242
Dees_Troyeead9852013-02-15 14:31:06 -0600243 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400244}
245
Dees_Troy51a0e822012-09-05 15:24:24 -0400246void GUIListBox::SetPageFocus(int inFocus)
247{
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100248 GUIScrollList::SetPageFocus(inFocus);
249 if (inFocus) {
Ethan Yonkerdedbb7f2016-01-17 18:17:38 -0600250 if (!isTextParsed) {
251 isTextParsed = true;
252 for (size_t i = 0; i < mListItems.size(); i++) {
253 ListItem& item = mListItems[i];
254 item.displayName = gui_parse_text(item.displayName);
255 }
256 }
Dees_Troyeead9852013-02-15 14:31:06 -0600257 DataManager::GetValue(mVariable, currentValue);
258 NotifyVarChange(mVariable, currentValue);
Dees_Troyeead9852013-02-15 14:31:06 -0600259 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400260}
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100261
262size_t GUIListBox::GetItemCount()
263{
that8ab5c132015-09-13 23:00:54 +0200264 return mVisibleItems.size();
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100265}
266
that0af77952015-02-25 08:52:19 +0100267void GUIListBox::RenderItem(size_t itemindex, int yPos, bool selected)
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100268{
that0af77952015-02-25 08:52:19 +0100269 // note: the "selected" parameter above is for the currently touched item
270 // don't confuse it with the more persistent "selected" flag per list item used below
that8ab5c132015-09-13 23:00:54 +0200271 ListItem& item = mListItems[mVisibleItems[itemindex]];
272 ImageResource* icon = item.selected ? mIconSelected : mIconUnselected;
273 const std::string& text = item.displayName;
that0af77952015-02-25 08:52:19 +0100274
275 RenderStdItem(yPos, selected, icon, text.c_str());
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100276}
277
278void GUIListBox::NotifySelect(size_t item_selected)
279{
Ethan Yonker56ce3322015-07-30 15:04:32 -0500280 if (!isCheckList) {
that8ab5c132015-09-13 23:00:54 +0200281 // deselect all items, even invisible ones
282 for (size_t i = 0; i < mListItems.size(); i++) {
283 mListItems[i].selected = 0;
Ethan Yonker56ce3322015-07-30 15:04:32 -0500284 }
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100285 }
that8ab5c132015-09-13 23:00:54 +0200286
287 ListItem& item = mListItems[mVisibleItems[item_selected]];
288
289 if (isCheckList) {
290 int selected = 1 - item.selected;
291 item.selected = selected;
292 DataManager::SetValue(item.variableName, selected ? "1" : "0");
293 } else {
294 item.selected = 1;
295 string str = item.variableValue; // [check] should this set currentValue instead?
296 DataManager::SetValue(mVariable, str);
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100297 }
that8ab5c132015-09-13 23:00:54 +0200298 if (item.action)
299 item.action->doActions();
Ethan Yonker0a3a98f2015-02-05 00:48:28 +0100300 mUpdate = 1;
301}