text: /*
  	Copyright 2013 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 <http://www.gnu.org/licenses/>.
  */
  
  #include <string.h>
  
  extern "C" {
  #include "../twcommon.h"
  }
  #include "../minuitwrp/minui.h"
  
  #include "rapidxml.hpp"
  #include "objects.hpp"
  #include "../data.hpp"
  #include "../partitions.hpp"
  #include "pages.hpp"
  
  extern std::vector<language_struct> Language_List;
  
  GUIListBox::GUIListBox(xml_node<>* node) : GUIScrollList(node)
  {
  	xml_attribute<>* attr;
  	xml_node<>* child;
  	mIconSelected = mIconUnselected = NULL;
  	mUpdate = 0;
  	isCheckList = isTextParsed = false;
  
  	// Get the icons, if any
  	child = FindNode(node, "icon");
  	if (child) {
  		mIconSelected = LoadAttrImage(child, "selected");
  		mIconUnselected = LoadAttrImage(child, "unselected");
  	}
  	int iconWidth = 0, iconHeight = 0;
  	if (mIconSelected && mIconSelected->GetResource() && mIconUnselected && mIconUnselected->GetResource()) {
  		iconWidth = std::max(mIconSelected->GetWidth(), mIconUnselected->GetWidth());
  		iconHeight = std::max(mIconSelected->GetHeight(), mIconUnselected->GetHeight());
  	} else if (mIconSelected && mIconSelected->GetResource()) {
  		iconWidth = mIconSelected->GetWidth();
  		iconHeight = mIconSelected->GetHeight();
  	} else if (mIconUnselected && mIconUnselected->GetResource()) {
  		iconWidth = mIconUnselected->GetWidth();
  		iconHeight = mIconUnselected->GetHeight();
  	}
  	SetMaxIconSize(iconWidth, iconHeight);
  
  	// Handle the result variable
  	child = FindNode(node, "data");
  	if (child) {
  		attr = child->first_attribute("name");
  		if (attr)
  			mVariable = attr->value();
  		attr = child->first_attribute("default");
  		if (attr)
  			DataManager::SetValue(mVariable, attr->value());
  		// Get the currently selected value for the list
  		DataManager::GetValue(mVariable, currentValue);
  		if (mVariable == "tw_language") {
  			std::vector<language_struct>::iterator iter;
  			for (iter = Language_List.begin(); iter != Language_List.end(); iter++) {
  				ListItem data;
  				data.displayName = (*iter).displayvalue;
  				data.variableValue = (*iter).filename;
  				data.action = NULL;
  				if (currentValue == (*iter).filename) {
  					data.selected = 1;
  					DataManager::SetValue("tw_language_display", (*iter).displayvalue);
  				} else
  					data.selected = 0;
  				if(!(*iter).font.empty()) {
  					data.mFont = PageManager::GetResources()->FindFont((*iter).font);
  					if (!data.mFont) {
  						continue;
  					}
  				}
  				mListItems.push_back(data);
  			}
  		} else if (mVariable == "tw_crypto_user_id") {
  			std::vector<users_struct>::iterator iter;
  			std::vector<users_struct>* Users_List = PartitionManager.Get_Users_List();
  			for (iter = Users_List->begin(); iter != Users_List->end(); iter++) {
  				if (!(*iter).isDecrypted) {
  					ListItem data;
  					data.displayName = (*iter).userName;
  					data.variableValue = (*iter).userId;
  					data.action = NULL;
  					DataManager::GetValue("tw_crypto_user_id", currentValue);
  					if (currentValue == (*iter).userId || currentValue == "") {
  						data.selected = 1;
  						DataManager::SetValue("tw_crypto_user_id", (*iter).userId);
  						DataManager::SetValue("tw_crypto_pwtype", (*iter).type);
  					} else
  						data.selected = 0;
  					mListItems.push_back(data);
  				}
  			}
  		}
  	} else
  		allowSelection = false;  // allows using listbox as a read-only list or menu
  
  	// Get the data for the list
  	child = FindNode(node, "listitem");
  	if (!child) return;
  	while (child) {
  		ListItem item;
  
  		attr = child->first_attribute("name");
  		if (!attr) continue;
  		// We will parse display names when we get page focus to ensure that translating takes place
  		item.displayName = attr->value();
  		item.variableValue = gui_parse_text(child->value());
  		item.selected = (child->value() == currentValue);
  		item.mIconSelected = NULL;
  		xml_node<>* icon = child->first_node("icon");
  		if (icon) {
  			item.mIconSelected = LoadAttrImage(icon, "icon");
  			if (item.mIconSelected && item.mIconSelected->GetResource()) {
  				iconWidth = item.mIconSelected->GetWidth();
  				iconHeight = item.mIconSelected->GetHeight();
  			}
  			SetMaxIconSize(iconWidth, iconHeight);
  		}
  		item.mFont = NULL;
  		item.textDesc = "";
  		icon = child->first_node("text");
  		if (icon) {
  			item.textDesc = icon->value();
  		}
  		item.action = NULL;
  		xml_node<>* action = child->first_node("action");
  		if (!action) action = child->first_node("actions");
  		if (action) {
  			item.action = new GUIAction(child);
  			allowSelection = true;
  		}
  		xml_node<>* variable_name = child->first_node("data");
  		if (variable_name) {
  			attr = variable_name->first_attribute("variable");
  			if (attr) {
  				item.variableName = attr->value();
  				item.selected = (DataManager::GetIntValue(item.variableName) != 0);
  				allowSelection = true;
  				isCheckList = true;
  			}
  		}
  
  		LoadConditions(child, item.mConditions);
  
  		mListItems.push_back(item);
  		mVisibleItems.push_back(mListItems.size() - 1);
  
  		child = child->next_sibling("listitem");
  	}
  }
  
  GUIListBox::~GUIListBox()
  {
  }
  
  int GUIListBox::Update(void)
  {
  	if (!isConditionTrue())
  		return 0;
  
  	if (mVariable == "tw_crypto_user_id") {
  		mListItems.clear();
  		std::vector<users_struct>::iterator iter;
  		std::vector<users_struct>* Users_List = PartitionManager.Get_Users_List();
  		for (iter = Users_List->begin(); iter != Users_List->end(); iter++) {
  			if (!(*iter).isDecrypted) {
  				ListItem data;
  				data.displayName = (*iter).userName;
  				data.variableValue = (*iter).userId;
  				data.action = NULL;
  				data.textDesc = "";
  				data.mFont = NULL;
  				DataManager::GetValue("tw_crypto_user_id", currentValue);
  				if (currentValue == (*iter).userId || currentValue == "") {
  					data.selected = 1;
  					DataManager::SetValue("tw_crypto_user_id", (*iter).userId);
  					DataManager::SetValue("tw_crypto_pwtype", (*iter).type);
  				} else
  				data.selected = 0;
  				mListItems.push_back(data);
  			}
  		}
  		mVisibleItems.clear();
  		for (size_t i = 0; i < mListItems.size(); i++) {
  			mVisibleItems.push_back(i);
  		}
  		mUpdate = 1;
  	}
  
  	GUIScrollList::Update();
  
  	if (mUpdate) {
  		mUpdate = 0;
  		if (Render() == 0)
  			return 2;
  	}
  	return 0;
  }
  
  int GUIListBox::NotifyVarChange(const std::string& varName, const std::string& value)
  {
  	GUIScrollList::NotifyVarChange(varName, value);
  
  	if (!isConditionTrue())
  		return 0;
  
  	// Check to see if the variable that we are using to store the list selected value has been updated
  	if (varName == mVariable) {
  		currentValue = value;
  		mUpdate = 1;
  	}
  
  	std::vector<size_t> mVisibleItemsOld;
  	std::swap(mVisibleItemsOld, mVisibleItems);
  	for (size_t i = 0; i < mListItems.size(); i++) {
  		ListItem& item = mListItems[i];
  		// update per-item visibility condition
  		bool itemVisible = UpdateConditions(item.mConditions, varName);
  		if (itemVisible)
  			mVisibleItems.push_back(i);
  
  		if (isCheckList)
  		{
  			if (item.variableName == varName || varName.empty()) {
  				std::string val;
  				DataManager::GetValue(item.variableName, val);
  				item.selected = (val != "0");
  				mUpdate = 1;
  			}
  		}
  		else if (varName == mVariable) {
  			if (item.variableValue == currentValue) {
  				item.selected = 1;
  				SetVisibleListLocation(mVisibleItems.empty() ? 0 : mVisibleItems.size()-1);
  			} else {
  				item.selected = 0;
  			}
  		}
  	}
  
  	if (mVisibleItemsOld != mVisibleItems) {
  		mUpdate = 1; // some item's visibility has changed
  		if (firstDisplayedItem >= (int)mVisibleItems.size()) {
  			// all items in the view area were removed - make last item visible
  			SetVisibleListLocation(mVisibleItems.empty() ? 0 : mVisibleItems.size()-1);
  		}
  	}
  	SetVisibleListLocation(0);
  
  	return 0;
  }
  
  void GUIListBox::SetPageFocus(int inFocus)
  {
  	GUIScrollList::SetPageFocus(inFocus);
  	if (inFocus) {
  		if (!isTextParsed) {
  			isTextParsed = true;
  			for (size_t i = 0; i < mListItems.size(); i++) {
  				ListItem& item = mListItems[i];
  				item.displayName = gui_parse_text(item.displayName);
  				item.textDesc = gui_parse_text(item.textDesc);
  			}
  		}
  		DataManager::GetValue(mVariable, currentValue);
  		NotifyVarChange(mVariable, currentValue);
  	}
  }
  
  size_t GUIListBox::GetItemCount()
  {
  	return mVisibleItems.size();
  }
  
  void GUIListBox::RenderItem(size_t itemindex, int yPos, bool selected)
  {
  	// note: the "selected" parameter above is for the currently touched item
  	// don't confuse it with the more persistent "selected" flag per list item used below
  	ListItem& item = mListItems[mVisibleItems[itemindex]];
  	ImageResource* icon = item.selected ? mIconSelected : mIconUnselected;
  	if (!icon && item.mIconSelected)
  		icon = item.mIconSelected;
  	const std::string& text = item.displayName;
  	std::string& textDesc = item.textDesc;
  	RenderStdItem(yPos, selected, icon, text.c_str(), textDesc.c_str(), 0, item.mFont);
  }
  
  void GUIListBox::NotifySelect(size_t item_selected)
  {
  	if (!isCheckList) {
  		// deselect all items, even invisible ones
  		for (size_t i = 0; i < mListItems.size(); i++) {
  			mListItems[i].selected = 0;
  		}
  	}
  
  	ListItem& item = mListItems[mVisibleItems[item_selected]];
  
  	if (isCheckList) {
  		int selected = 1 - item.selected;
  		item.selected = selected;
  		DataManager::SetValue(item.variableName, selected ? "1" : "0");
  	} else {
  		item.selected = 1;
  		string str = item.variableValue;	// [check] should this set currentValue instead?
  		DataManager::SetValue(mVariable, str);
  	}
  	if (item.action)
  		item.action->doActions();
  	mUpdate = 1;
  }
  