Unify scrollable list code

The goal of this patch set is to eliminate the code duplication
caused by copy/paste of the code in the file selector, listbox,
and partition list GUI elements. Those classes will now utilize a
single GUIScrollList class that will handle rendering and
scrolling.

Change-Id: I0cb98ab36cf47178296034293435225658c779cd
diff --git a/gui/listbox.cpp b/gui/listbox.cpp
index 851b373..545b7a2 100644
--- a/gui/listbox.cpp
+++ b/gui/listbox.cpp
@@ -16,26 +16,9 @@
 	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <linux/input.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <fcntl.h>
-#include <sys/reboot.h>
 #include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <time.h>
-#include <unistd.h>
-#include <stdlib.h>
 #include <dirent.h>
-#include <ctype.h>
-
-#include <algorithm>
 
 extern "C" {
 #include "../twcommon.h"
@@ -45,100 +28,18 @@
 #include "rapidxml.hpp"
 #include "objects.hpp"
 #include "../data.hpp"
-#include "../twrp-functions.hpp"
 
-#define SCROLLING_SPEED_DECREMENT 6
-#define SCROLLING_FLOOR 10
-#define SCROLLING_MULTIPLIER 6
-
-GUIListBox::GUIListBox(xml_node<>* node) : GUIObject(node)
+GUIListBox::GUIListBox(xml_node<>* node) : GUIScrollList(node)
 {
 	xml_attribute<>* attr;
 	xml_node<>* child;
-	int header_separator_color_specified = 0, header_separator_height_specified = 0, header_text_color_specified = 0, header_background_color_specified = 0;
-
-	mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
-	mIconWidth = mIconHeight = mSelectedIconHeight = mSelectedIconWidth = mUnselectedIconHeight = mUnselectedIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
-	mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
-	mIconSelected = mIconUnselected = mBackground = mFont = mHeaderIcon = NULL;
-	mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
-	mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
-	mFastScrollRectX = mFastScrollRectY = -1;
+	mIconSelected = mIconUnselected = NULL;
+	int mSelectedIconWidth = 0, mSelectedIconHeight = 0, mUnselectedIconWidth = 0, mUnselectedIconHeight = 0, mIconWidth = 0, mIconHeight = 0;
 	mUpdate = 0;
-	touchDebounce = 6;
-	ConvertStrToColor("black", &mBackgroundColor);
-	ConvertStrToColor("black", &mHeaderBackgroundColor);
-	ConvertStrToColor("black", &mSeparatorColor);
-	ConvertStrToColor("black", &mHeaderSeparatorColor);
-	ConvertStrToColor("white", &mFontColor);
-	ConvertStrToColor("white", &mHeaderFontColor);
-	ConvertStrToColor("white", &mFastScrollLineColor);
-	ConvertStrToColor("white", &mFastScrollRectColor);
-	hasHighlightColor = false;
-	hasFontHighlightColor = false;
-	isHighlighted = false;
-	startSelection = -1;
 
-	// Load header text
-	child = node->first_node("header");
-	if (child)
-	{
-		attr = child->first_attribute("icon");
-		if (attr)
-			mHeaderIcon = PageManager::FindResource(attr->value());
-
-		attr = child->first_attribute("background");
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mHeaderBackgroundColor);
-			header_background_color_specified = -1;
-		}
-		attr = child->first_attribute("textcolor");
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mHeaderFontColor);
-			header_text_color_specified = -1;
-		}
-		attr = child->first_attribute("separatorcolor");
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mHeaderSeparatorColor);
-			header_separator_color_specified = -1;
-		}
-		attr = child->first_attribute("separatorheight");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mHeaderSeparatorH = atoi(parsevalue.c_str());
-			header_separator_height_specified = -1;
-		}
-	}
-	child = node->first_node("text");
-	if (child)  mHeaderText = child->value();
-
-	memset(&mHighlightColor, 0, sizeof(COLOR));
-	child = node->first_node("highlight");
-	if (child) {
-		attr = child->first_attribute("color");
-		if (attr) {
-			hasHighlightColor = true;
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mHighlightColor);
-		}
-	}
-
-	// Simple way to check for static state
-	mLastValue = gui_parse_text(mHeaderText);
-	if (mLastValue != mHeaderText)
-		mHeaderIsStatic = 0;
-	else
-		mHeaderIsStatic = -1;
-
+	// Get the icons, if any
 	child = node->first_node("icon");
-	if (child)
-	{
+	if (child) {
 		attr = child->first_attribute("selected");
 		if (attr)
 			mIconSelected = PageManager::FindResource(attr->value());
@@ -146,187 +47,41 @@
 		if (attr)
 			mIconUnselected = PageManager::FindResource(attr->value());
 	}
-	child = node->first_node("background");
-	if (child)
-	{
-		attr = child->first_attribute("resource");
-		if (attr)
-			mBackground = PageManager::FindResource(attr->value());
-		attr = child->first_attribute("color");
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mBackgroundColor);
-			if (!header_background_color_specified)
-				ConvertStrToColor(color, &mHeaderBackgroundColor);
-		}
+	if (mIconSelected && mIconSelected->GetResource()) {
+		mSelectedIconWidth = gr_get_width(mIconSelected->GetResource());
+		mSelectedIconHeight = gr_get_height(mIconSelected->GetResource());
+		if (mSelectedIconHeight > mIconHeight)
+			mIconHeight = mSelectedIconHeight;
+		mIconWidth = mSelectedIconWidth;
 	}
 
-	// Load the placement
-	LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
-	SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
-
-	// Load the font, and possibly override the color
-	child = node->first_node("font");
-	if (child)
-	{
-		attr = child->first_attribute("resource");
-		if (attr)
-			mFont = PageManager::FindResource(attr->value());
-
-		attr = child->first_attribute("color");
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mFontColor);
-			if (!header_text_color_specified)
-				ConvertStrToColor(color, &mHeaderFontColor);
-		}
-
-		attr = child->first_attribute("spacing");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mLineSpacing = atoi(parsevalue.c_str());
-		}
-
-		attr = child->first_attribute("highlightcolor");
-		memset(&mFontHighlightColor, 0, sizeof(COLOR));
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mFontHighlightColor);
-			hasFontHighlightColor = true;
-		}
+	if (mIconUnselected && mIconUnselected->GetResource()) {
+		mUnselectedIconWidth = gr_get_width(mIconUnselected->GetResource());
+		mUnselectedIconHeight = gr_get_height(mIconUnselected->GetResource());
+		if (mUnselectedIconHeight > mIconHeight)
+			mIconHeight = mUnselectedIconHeight;
+		if (mUnselectedIconWidth > mIconWidth)
+			mIconWidth = mUnselectedIconWidth;
 	}
-
-	// Load the separator if it exists
-	child = node->first_node("separator");
-	if (child)
-	{
-		attr = child->first_attribute("color");
-		if (attr)
-		{
-			std::string color = attr->value();
-			ConvertStrToColor(color, &mSeparatorColor);
-			if (!header_separator_color_specified)
-				ConvertStrToColor(color, &mHeaderSeparatorColor);
-		}
-
-		attr = child->first_attribute("height");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mSeparatorH = atoi(parsevalue.c_str());
-			if (!header_separator_height_specified)
-				mHeaderSeparatorH = mSeparatorH;
-		}
-	}
+	SetMaxIconSize(mIconWidth, mIconHeight);
 
 	// Handle the result variable
 	child = node->first_node("data");
-	if (child)
-	{
+	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);
 	}
 
-	// Fast scroll colors
-	child = node->first_node("fastscroll");
-	if (child)
-	{
-		attr = child->first_attribute("linecolor");
-		if(attr)
-			ConvertStrToColor(attr->value(), &mFastScrollLineColor);
-
-		attr = child->first_attribute("rectcolor");
-		if(attr)
-			ConvertStrToColor(attr->value(), &mFastScrollRectColor);
-
-		attr = child->first_attribute("w");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mFastScrollW = atoi(parsevalue.c_str());
-		}
-
-		attr = child->first_attribute("linew");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mFastScrollLineW = atoi(parsevalue.c_str());
-		}
-
-		attr = child->first_attribute("rectw");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mFastScrollRectW = atoi(parsevalue.c_str());
-		}
-
-		attr = child->first_attribute("recth");
-		if (attr) {
-			string parsevalue = gui_parse_text(attr->value());
-			mFastScrollRectH = atoi(parsevalue.c_str());
-		}
-	}
-
-	// Retrieve the line height
-	mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
-	mLineHeight = mFontHeight;
-	mHeaderH = mFontHeight;
-
-	if (mIconSelected && mIconSelected->GetResource())
-	{
-		mSelectedIconWidth = gr_get_width(mIconSelected->GetResource());
-		mSelectedIconHeight = gr_get_height(mIconSelected->GetResource());
-		if (mSelectedIconHeight > (int)mLineHeight)
-			mLineHeight = mSelectedIconHeight;
-		mIconWidth = mSelectedIconWidth;
-	}
-
-	if (mIconUnselected && mIconUnselected->GetResource())
-	{
-		mUnselectedIconWidth = gr_get_width(mIconUnselected->GetResource());
-		mUnselectedIconHeight = gr_get_height(mIconUnselected->GetResource());
-		if (mUnselectedIconHeight > (int)mLineHeight)
-			mLineHeight = mUnselectedIconHeight;
-		if (mUnselectedIconWidth > mIconWidth)
-			mIconWidth = mUnselectedIconWidth;
-	}
-
-	if (mHeaderIcon && mHeaderIcon->GetResource())
-	{
-		mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
-		mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
-		if (mHeaderIconHeight > mHeaderH)
-			mHeaderH = mHeaderIconHeight;
-		if (mHeaderIconWidth > mIconWidth)
-			mIconWidth = mHeaderIconWidth;
-	}
-
-	mHeaderH += mLineSpacing + mHeaderSeparatorH;
-	actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
-	if (mHeaderH < actualLineHeight)
-		mHeaderH = actualLineHeight;
-
-	if (actualLineHeight / 3 > 6)
-		touchDebounce = actualLineHeight / 3;
-
-	if (mBackground && mBackground->GetResource())
-	{
-		mBackgroundW = gr_get_width(mBackground->GetResource());
-		mBackgroundH = gr_get_height(mBackground->GetResource());
-	}
-
-	// Get the currently selected value for the list
-	DataManager::GetValue(mVariable, currentValue);
-
 	// Get the data for the list
 	child = node->first_node("listitem");
 	if (!child) return;
-
-	while (child)
-	{
+	while (child) {
 		ListData data;
 
 		attr = child->first_attribute("name");
@@ -348,179 +103,8 @@
 
 GUIListBox::~GUIListBox()
 {
-}
-
-int GUIListBox::Render(void)
-{
-	if(!isConditionTrue())
-		return 0;
-
-	// First step, fill background
-	gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
-	gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
-
-	// Next, render the background resource (if it exists)
-	if (mBackground && mBackground->GetResource())
-	{
-		mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
-		mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
-		gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
-	}
-
-	// This tells us how many lines we can actually render
-	int lines = (mRenderH - mHeaderH) / (actualLineHeight);
-	int line;
-
-	int listSize = mList.size();
-	int listW = mRenderW;
-
-	if (listSize < lines) {
-		lines = listSize;
-		scrollingY = 0;
-		mFastScrollRectX = mFastScrollRectY = -1;
-	} else {
-		listW -= mFastScrollW; // space for fast scroll
-		lines++;
-		if (lines < listSize)
-			lines++;
-	}
-
-	void* fontResource = NULL;
-	if (mFont)  fontResource = mFont->GetResource();
-
-	int yPos = mRenderY + mHeaderH + scrollingY;
-	int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
-	int currentIconHeight = 0, currentIconWidth = 0;
-	int currentIconOffsetY = 0, currentIconOffsetX = 0;
-	int UnselectedIconOffsetY = (int)((actualLineHeight - mUnselectedIconHeight) / 2), SelectedIconOffsetY = (int)((actualLineHeight - mSelectedIconHeight) / 2);
-	int UnselectedIconOffsetX = (mIconWidth - mUnselectedIconWidth) / 2, SelectedIconOffsetX = (mIconWidth - mSelectedIconWidth) / 2;
-	int actualSelection = mStart;
-
-	if (isHighlighted) {
-		int selectY = scrollingY;
-
-		// Locate the correct line for highlighting
-		while (selectY + actualLineHeight < startSelection) {
-			selectY += actualLineHeight;
-			actualSelection++;
-		}
-		if (hasHighlightColor) {
-			// Highlight the area
-			gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
-			int HighlightHeight = actualLineHeight;
-			if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
-				HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
-			}
-			gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
-		}
-	}
-
-	for (line = 0; line < lines; line++)
-	{
-		Resource* icon;
-		std::string label;
-
-		if (line + mStart >= listSize)
-			continue;
-
-		label = mList.at(line + mStart).displayName;
-		if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
-			// Use the highlight color for the font
-			gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
-		} else {
-			// Set the color for the font
-			gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
-		}
-
-		if (mList.at(line + mStart).selected != 0)
-		{
-			icon = mIconSelected;
-			currentIconHeight = mSelectedIconHeight;
-			currentIconWidth = mSelectedIconWidth;
-			currentIconOffsetY = SelectedIconOffsetY;
-			currentIconOffsetX = SelectedIconOffsetX;
-		}
-		else
-		{
-			icon = mIconUnselected;
-			currentIconHeight = mSelectedIconHeight;
-			currentIconWidth = mSelectedIconWidth;
-			currentIconOffsetY = SelectedIconOffsetY;
-			currentIconOffsetX = SelectedIconOffsetX;
-		}
-
-		if (icon && icon->GetResource())
-		{
-			int rect_y = 0, image_y = (yPos + currentIconOffsetY);
-			if (image_y + currentIconHeight > mRenderY + mRenderH)
-				rect_y = mRenderY + mRenderH - image_y;
-			else
-				rect_y = currentIconHeight;
-			gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
-		}
-		gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
-
-		// Add the separator
-		if (yPos + actualLineHeight < mRenderH + mRenderY) {
-			gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
-			gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
-		}
-
-		// Move the yPos
-		yPos += actualLineHeight;
-	}
-
-	// Render the Header (last so that it overwrites the top most row for per pixel scrolling)
-	// First step, fill background
-	gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
-	gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
-
-	// Now, we need the header (icon + text)
-	yPos = mRenderY;
-	{
-		Resource* headerIcon;
-		int mIconOffsetX = 0;
-
-		// render the icon if it exists
-		headerIcon = mHeaderIcon;
-		if (headerIcon && headerIcon->GetResource())
-		{
-			gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
-			mIconOffsetX = mIconWidth;
-		}
-
-		// render the text
-		gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
-		gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
-
-		// Add the separator
-		gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
-		gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
-	}
-
-	// render fast scroll
-	lines = (mRenderH - mHeaderH) / (actualLineHeight);
-	if(mFastScrollW > 0 &&  listSize > lines)
-	{
-		int startX = listW + mRenderX;
-		int fWidth = mRenderW - listW;
-		int fHeight = mRenderH - mHeaderH;
-
-		// line
-		gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
-		gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
-
-		// rect
-		int pct = ((mStart*actualLineHeight - scrollingY)*100)/((listSize)*actualLineHeight-lines*actualLineHeight);
-		mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
-		mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
-
-		gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
-		gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
-	}
-
-	mUpdate = 0;
-	return 0;
+	delete mIconSelected;
+	delete mIconUnselected;
 }
 
 int GUIListBox::Update(void)
@@ -528,306 +112,75 @@
 	if(!isConditionTrue())
 		return 0;
 
-	if (!mHeaderIsStatic) {
-		std::string newValue = gui_parse_text(mHeaderText);
-		if (mLastValue != newValue) {
-			mLastValue = newValue;
-			mUpdate = 1;
-		}
-	}
+	GUIScrollList::Update();
 
-	if (mUpdate)
-	{
+	if (mUpdate) {
 		mUpdate = 0;
 		if (Render() == 0)
 			return 2;
 	}
-
-	// Handle kinetic scrolling
-	if (scrollingSpeed == 0) {
-		// Do nothing
-	} else if (scrollingSpeed > 0) {
-		if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
-			scrollingY += scrollingSpeed;
-			scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
-		} else {
-			scrollingY += ((int) (actualLineHeight * 2.5));
-			scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
-		}
-		while (mStart && scrollingY > 0) {
-			mStart--;
-			scrollingY -= actualLineHeight;
-		}
-		if (mStart == 0 && scrollingY > 0) {
-			scrollingY = 0;
-			scrollingSpeed = 0;
-		} else if (scrollingSpeed < SCROLLING_FLOOR)
-			scrollingSpeed = 0;
-		mUpdate = 1;
-	} else if (scrollingSpeed < 0) {
-		int totalSize = mList.size();
-		int lines = (mRenderH - mHeaderH) / (actualLineHeight);
-
-		if (totalSize > lines) {
-			int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
-
-			bottom_offset -= actualLineHeight;
-
-			if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
-				scrollingY += scrollingSpeed;
-				scrollingSpeed += SCROLLING_SPEED_DECREMENT;
-			} else {
-				scrollingY -= ((int) (actualLineHeight * 2.5));
-				scrollingSpeed += SCROLLING_SPEED_DECREMENT;
-			}
-			while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
-				mStart++;
-				scrollingY += actualLineHeight;
-			}
-			if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
-				mStart = totalSize - lines - 1;
-				scrollingY = bottom_offset;
-			} else if (mStart + lines >= totalSize && scrollingY < 0) {
-				mStart = totalSize - lines;
-				scrollingY = 0;
-			} else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
-				scrollingSpeed = 0;
-			mUpdate = 1;
-		}
-	}
-
-	return 0;
-}
-
-int GUIListBox::GetSelection(int x, int y)
-{
-	// We only care about y position
-	if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
-	return (y - mRenderY - mHeaderH);
-}
-
-int GUIListBox::NotifyTouch(TOUCH_STATE state, int x, int y)
-{
-	if(!isConditionTrue())
-		return -1;
-
-	static int lastY = 0, last2Y = 0, fastScroll = 0;
-	int selection = 0;
-
-	switch (state)
-	{
-	case TOUCH_START:
-		if (scrollingSpeed != 0)
-			startSelection = -1;
-		else
-			startSelection = GetSelection(x,y);
-		isHighlighted = (startSelection > -1);
-		if (isHighlighted)
-			mUpdate = 1;
-		startY = lastY = last2Y = y;
-		scrollingSpeed = 0;
-
-		if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
-			fastScroll = 1;
-		break;
-
-	case TOUCH_DRAG:
-		// Check if we dragged out of the selection window
-		if (GetSelection(x, y) == -1) {
-			last2Y = lastY = 0;
-			if (isHighlighted) {
-				isHighlighted = false;
-				mUpdate = 1;
-			}
-			break;
-		}
-
-		// Fast scroll
-		if(fastScroll)
-		{
-			int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
-			int totalSize = mList.size();
-			int lines = (mRenderH - mHeaderH) / (actualLineHeight);
-
-			float l = float((totalSize-lines)*pct)/100;
-			if(l + lines >= totalSize)
-			{
-				mStart = totalSize - lines;
-				scrollingY = 0;
-			}
-			else
-			{
-				mStart = l;
-				scrollingY = -(l - int(l))*actualLineHeight;
-			}
-
-			startSelection = -1;
-			mUpdate = 1;
-			scrollingSpeed = 0;
-			isHighlighted = false;
-			break;
-		}
-
-		// Provide some debounce on initial touches
-		if (startSelection != -1 && abs(y - startY) < touchDebounce) {
-			isHighlighted = true;
-			mUpdate = 1;
-			break;
-		}
-
-		isHighlighted = false;
-		last2Y = lastY;
-		lastY = y;
-		startSelection = -1;
-
-		// Handle scrolling
-		scrollingY += y - startY;
-		startY = y;
-		while(mStart && scrollingY > 0) {
-			mStart--;
-			scrollingY -= actualLineHeight;
-		}
-		if (mStart == 0 && scrollingY > 0)
-			scrollingY = 0;
-		{
-			int totalSize = mList.size();
-			int lines = (mRenderH - mHeaderH) / (actualLineHeight);
-
-			if (totalSize > lines) {
-				int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
-
-				bottom_offset -= actualLineHeight;
-
-				while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
-					mStart++;
-					scrollingY += actualLineHeight;
-				}
-				if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
-					mStart = totalSize - lines - 1;
-					scrollingY = bottom_offset;
-				} else if (mStart + lines >= totalSize && scrollingY < 0) {
-					mStart = totalSize - lines;
-					scrollingY = 0;
-				}
-			} else
-				scrollingY = 0;
-		}
-		mUpdate = 1;
-		break;
-
-	case TOUCH_RELEASE:
-		isHighlighted = false;
-		fastScroll = 0;
-		if (startSelection >= 0)
-		{
-			// We've selected an item!
-			std::string str;
-
-			int listSize = mList.size();
-			int selectY = scrollingY, actualSelection = mStart;
-
-			// Move the selection to the proper place in the array
-			while (selectY + actualLineHeight < startSelection) {
-				selectY += actualLineHeight;
-				actualSelection++;
-			}
-
-			if (actualSelection < listSize && !mVariable.empty())
-			{
-				int i;
-				for (i=0; i<listSize; i++)
-					mList.at(i).selected = 0;
-
-				str = mList.at(actualSelection).variableValue;
-				mList.at(actualSelection).selected = 1;
-				DataManager::SetValue(mVariable, str);
-				mUpdate = 1;
-
-				DataManager::Vibrate("tw_button_vibrate");
-			}
-		} else {
-			// This is for kinetic scrolling
-			scrollingSpeed = lastY - last2Y;
-			if (abs(scrollingSpeed) > SCROLLING_FLOOR)
-				scrollingSpeed *= SCROLLING_MULTIPLIER;
-			else
-				scrollingSpeed = 0;
-		}
-	case TOUCH_REPEAT:
-	case TOUCH_HOLD:
-		break;
-	}
 	return 0;
 }
 
 int GUIListBox::NotifyVarChange(const std::string& varName, const std::string& value)
 {
-	GUIObject::NotifyVarChange(varName, value);
-
 	if(!isConditionTrue())
 		return 0;
 
-	if (!mHeaderIsStatic) {
-		std::string newValue = gui_parse_text(mHeaderText);
-		if (mLastValue != newValue) {
-			mLastValue = newValue;
-			mStart = 0;
-			scrollingY = 0;
-			scrollingSpeed = 0;
-			mUpdate = 1;
-		}
-	}
-	if (varName == mVariable)
-	{
-		int i, listSize = mList.size(), selected_index = 0;
+	GUIScrollList::NotifyVarChange(varName, value);
+
+	// Check to see if the variable that we are using to store the list selected value has been updated
+	if (varName == mVariable) {
+		int i, listSize = mList.size();
 
 		currentValue = value;
 
-		for (i=0; i<listSize; i++) {
+		for (i = 0; i < listSize; i++) {
 			if (mList.at(i).variableValue == currentValue) {
 				mList.at(i).selected = 1;
-				selected_index = i;
+				SetVisibleListLocation(i);
 			} else
 				mList.at(i).selected = 0;
 		}
-
-		int lines = mRenderH / (mLineHeight + mLineSpacing);
-		int line;
-
-		if (selected_index > mStart + lines - 1)
-			mStart = selected_index;
-		if (mStart > listSize - lines) {
-			mStart = listSize - lines;
-		} else if (selected_index < mStart) {
-			mStart = selected_index;
-		}
-
 		mUpdate = 1;
 		return 0;
 	}
 	return 0;
 }
 
-int GUIListBox::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
-{
-	mRenderX = x;
-	mRenderY = y;
-	if (w || h)
-	{
-		mRenderW = w;
-		mRenderH = h;
-	}
-	SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
-	mUpdate = 1;
-	return 0;
-}
-
 void GUIListBox::SetPageFocus(int inFocus)
 {
-	if (inFocus)
-	{
+	GUIScrollList::SetPageFocus(inFocus);
+	if (inFocus) {
 		DataManager::GetValue(mVariable, currentValue);
 		NotifyVarChange(mVariable, currentValue);
-		mUpdate = 1;
 	}
 }
+
+size_t GUIListBox::GetItemCount()
+{
+	return mList.size();
+}
+
+int GUIListBox::GetListItem(size_t item_index, Resource*& icon, std::string &text)
+{
+	text = mList.at(item_index).displayName;
+	if (mList.at(item_index).selected)
+		icon = mIconSelected;
+	else
+		icon = mIconUnselected;
+	return 0;
+}
+
+void GUIListBox::NotifySelect(size_t item_selected)
+{
+	for (size_t i = 0; i < mList.size(); i++) {
+		mList.at(i).selected = 0;
+	}
+	if (item_selected < mList.size()) {
+		mList.at(item_selected).selected = 1;
+		string str = mList.at(item_selected).variableValue;
+		DataManager::SetValue(mVariable, str);
+	}
+	mUpdate = 1;
+}