gui: introduce virtual RenderItem method in ScrollList

- so derived lists can draw whatever they want (multi-line etc.)
- replace GetListItem with RenderItem
- minor cleanup

Change-Id: I062e0a354f1c18ce0a5232b7542c4987b480e232
diff --git a/gui/fileselector.cpp b/gui/fileselector.cpp
index 8f6a7fa..a97ff34 100644
--- a/gui/fileselector.cpp
+++ b/gui/fileselector.cpp
@@ -308,19 +308,23 @@
 	return folderSize + fileSize;
 }
 
-int GUIFileSelector::GetListItem(size_t item_index, ImageResource*& icon, std::string &text)
+void GUIFileSelector::RenderItem(size_t itemindex, int yPos, bool selected)
 {
 	size_t folderSize = mShowFolders ? mFolderList.size() : 0;
 	size_t fileSize = mShowFiles ? mFileList.size() : 0;
 
-	if (item_index < folderSize) {
-		text = mFolderList.at(item_index).fileName;
+	ImageResource* icon;
+	std::string text;
+
+	if (itemindex < folderSize) {
+		text = mFolderList.at(itemindex).fileName;
 		icon = mFolderIcon;
 	} else {
-		text = mFileList.at(item_index - folderSize).fileName;
+		text = mFileList.at(itemindex - folderSize).fileName;
 		icon = mFileIcon;
 	}
-	return 0;
+
+	RenderStdItem(yPos, selected, icon, text.c_str());
 }
 
 void GUIFileSelector::NotifySelect(size_t item_selected)
diff --git a/gui/listbox.cpp b/gui/listbox.cpp
index 625b4b7..a607699 100644
--- a/gui/listbox.cpp
+++ b/gui/listbox.cpp
@@ -141,14 +141,14 @@
 	return mList.size();
 }
 
-int GUIListBox::GetListItem(size_t item_index, ImageResource*& icon, std::string &text)
+void GUIListBox::RenderItem(size_t itemindex, int yPos, bool selected)
 {
-	text = mList.at(item_index).displayName;
-	if (mList.at(item_index).selected)
-		icon = mIconSelected;
-	else
-		icon = mIconUnselected;
-	return 0;
+	// 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
+	ImageResource* icon = mList.at(itemindex).selected ? mIconSelected : mIconUnselected;
+	const std::string& text = mList.at(itemindex).displayName;
+
+	RenderStdItem(yPos, selected, icon, text.c_str());
 }
 
 void GUIListBox::NotifySelect(size_t item_selected)
diff --git a/gui/objects.hpp b/gui/objects.hpp
index 0f853ac..d5c3b27 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -533,12 +533,14 @@
 	// derived classes need to implement these
 	// get number of items
 	virtual size_t GetItemCount() { return 0; }
-	// get data for one item
-	virtual int GetListItem(size_t item_index, ImageResource*& icon, std::string &text)
-		{ icon = NULL; text = ""; return -1; }
+	// render a single item in rect (mRenderX, yPos, mRenderW, actualItemHeight)
+	virtual void RenderItem(size_t itemindex, int yPos, bool selected);
 	// an item was selected
 	virtual void NotifySelect(size_t item_selected) {}
 
+	// render a standard-layout list item with optional icon and text
+	void RenderStdItem(int yPos, bool selected, ImageResource* icon, const char* text, int iconAndTextH = 0);
+
 	enum { NO_ITEM = (size_t)-1 };
 	// returns item index at coordinates or NO_ITEM if there is no item there
 	size_t HitTestItem(int x, int y);
@@ -562,7 +564,6 @@
 	// Background
 	COLOR mBackgroundColor;
 	ImageResource* mBackground; // background image, if any, automatically centered
-	int mBackgroundW, mBackgroundH; // background width and height if using an image for the background
 
 	// Header
 	COLOR mHeaderBackgroundColor;
@@ -630,7 +631,7 @@
 	virtual void SetPageFocus(int inFocus);
 
 	virtual size_t GetItemCount();
-	virtual int GetListItem(size_t item_index, ImageResource*& icon, std::string &text);
+	virtual void RenderItem(size_t itemindex, int yPos, bool selected);
 	virtual void NotifySelect(size_t item_selected);
 
 protected:
@@ -685,7 +686,7 @@
 	virtual void SetPageFocus(int inFocus);
 
 	virtual size_t GetItemCount();
-	virtual int GetListItem(size_t item_index, ImageResource*& icon, std::string &text);
+	virtual void RenderItem(size_t itemindex, int yPos, bool selected);
 	virtual void NotifySelect(size_t item_selected);
 
 protected:
@@ -721,7 +722,7 @@
 	virtual void SetPageFocus(int inFocus);
 
 	virtual size_t GetItemCount();
-	virtual int GetListItem(size_t item_index, ImageResource*& icon, std::string &text);
+	virtual void RenderItem(size_t itemindex, int yPos, bool selected);
 	virtual void NotifySelect(size_t item_selected);
 
 protected:
diff --git a/gui/partitionlist.cpp b/gui/partitionlist.cpp
index ba8a94b..102802d 100644
--- a/gui/partitionlist.cpp
+++ b/gui/partitionlist.cpp
@@ -197,14 +197,14 @@
 	return mList.size();
 }
 
-int GUIPartitionList::GetListItem(size_t item_index, ImageResource*& icon, std::string &text)
+void GUIPartitionList::RenderItem(size_t itemindex, int yPos, bool selected)
 {
-	text = mList.at(item_index).Display_Name;
-	if (mList.at(item_index).selected)
-		icon = mIconSelected;
-	else
-		icon = mIconUnselected;
-	return 0;
+	// 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
+	ImageResource* icon = mList.at(itemindex).selected ? mIconSelected : mIconUnselected;
+	const std::string& text = mList.at(itemindex).Display_Name;
+
+	RenderStdItem(yPos, selected, icon, text.c_str());
 }
 
 void GUIPartitionList::NotifySelect(size_t item_selected)
diff --git a/gui/scrolllist.cpp b/gui/scrolllist.cpp
index 70a54e5..aa9623c 100644
--- a/gui/scrolllist.cpp
+++ b/gui/scrolllist.cpp
@@ -42,7 +42,6 @@
 	mHeaderIsStatic = false;
 	mBackground = mHeaderIcon = NULL;
 	mFont = NULL;
-	mBackgroundW = mBackgroundH = 0;
 	mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
 	mFastScrollRectCurrentY = mFastScrollRectCurrentH = mFastScrollRectTouchY = 0;
 	lastY = last2Y = fastScroll = 0;
@@ -142,12 +141,6 @@
 
 	if (actualItemHeight / 3 > 6)
 		touchDebounce = actualItemHeight / 3;
-
-	if (mBackground && mBackground->GetResource())
-	{
-		mBackgroundW = mBackground->GetWidth();
-		mBackgroundH = mBackground->GetHeight();
-	}
 }
 
 GUIScrollList::~GUIScrollList()
@@ -207,16 +200,18 @@
 	// Next, render the background resource (if it exists)
 	if (mBackground && mBackground->GetResource())
 	{
-		int mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
-		int mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
-		gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
+		int BackgroundW = mBackground->GetWidth();
+		int BackgroundH = mBackground->GetHeight();
+		int BackgroundX = mRenderX + ((mRenderW - BackgroundW) / 2);
+		int BackgroundY = mRenderY + ((mRenderH - BackgroundH) / 2);
+		gr_blit(mBackground->GetResource(), 0, 0, BackgroundW, BackgroundH, BackgroundX, BackgroundY);
 	}
 
 	// This tells us how many full lines we can actually render
 	size_t lines = GetDisplayItemCount();
 
 	size_t listSize = GetItemCount();
-	int listW = mRenderW;
+	int listW = mRenderW; // this is only used for the separators - the list items are rendered in the full width of the list
 
 	if (listSize <= lines) {
 		hasScroll = false;
@@ -231,11 +226,7 @@
 			lines++;
 	}
 
-	void* fontResource = NULL;
-	if (mFont)  fontResource = mFont->GetResource();
-
 	int yPos = mRenderY + mHeaderH + y_offset;
-	int fontOffsetY = (int)((actualItemHeight - mFontHeight) / 2);
 
 	// render all visible items
 	for (size_t line = 0; line < lines; line++)
@@ -244,38 +235,7 @@
 		if (itemindex >= listSize)
 			break;
 
-		// get item data
-		ImageResource* icon;
-		std::string label;
-		if (GetListItem(itemindex, icon, label))
-			break;
-
-		if (hasHighlightColor && itemindex == selectedItem) {
-			// Highlight the item background of the selected item
-			gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha);
-			gr_fill(mRenderX, yPos, mRenderW, actualItemHeight);
-		}
-
-		if (itemindex == selectedItem) {
-			// Use the highlight color for the font
-			gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, mFontHighlightColor.alpha);
-		} else {
-			// Set the color for the font
-			gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha);
-		}
-
-		// render icon
-		if (icon && icon->GetResource()) {
-			int currentIconHeight = icon->GetHeight();
-			int currentIconWidth = icon->GetWidth();
-			int currentIconOffsetY = (actualItemHeight - currentIconHeight) / 2;
-			int currentIconOffsetX = (maxIconWidth - currentIconWidth) / 2;
-			int image_y = (yPos + currentIconOffsetY);
-			gr_blit(icon->GetResource(), 0, 0, currentIconWidth, currentIconHeight, mRenderX + currentIconOffsetX, image_y);
-		}
-
-		// render label text
-		gr_textEx(mRenderX + maxIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource);
+		RenderItem(itemindex, yPos, itemindex == selectedItem);
 
 		// Add the separator
 		gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, mSeparatorColor.alpha);
@@ -285,26 +245,25 @@
 		yPos += actualItemHeight;
 	}
 
-	// Render the Header
+	// Render the Header (last so that it overwrites the top most row for per pixel scrolling)
 	yPos = mRenderY;
 	if (mHeaderH > 0) {
 		// First step, fill background
 		gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, mHeaderBackgroundColor.alpha);
 		gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
 
-		int mIconOffsetX = 0;
+		int IconOffsetX = 0;
 
 		// render the icon if it exists
-		ImageResource* headerIcon = mHeaderIcon;
-		if (headerIcon && headerIcon->GetResource())
+		if (mHeaderIcon && mHeaderIcon->GetResource())
 		{
-			gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - maxIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
-			mIconOffsetX = maxIconWidth;
+			gr_blit(mHeaderIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - maxIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
+			IconOffsetX = maxIconWidth;
 		}
 
 		// render the text
 		gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, mHeaderFontColor.alpha);
-		gr_textEx(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastHeaderValue.c_str(), fontResource);
+		gr_textEx(mRenderX + IconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastHeaderValue.c_str(), mFont->GetResource());
 
 		// Add the separator
 		gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, mHeaderSeparatorColor.alpha);
@@ -349,6 +308,45 @@
 	return 0;
 }
 
+void GUIScrollList::RenderItem(size_t itemindex, int yPos, bool selected)
+{
+	RenderStdItem(yPos, selected, NULL, "implement RenderItem!");
+}
+
+void GUIScrollList::RenderStdItem(int yPos, bool selected, ImageResource* icon, const char* text, int iconAndTextH)
+{
+	if (hasHighlightColor && selected) {
+		// Highlight the item background of the selected item
+		gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha);
+		gr_fill(mRenderX, yPos, mRenderW, actualItemHeight);
+	}
+
+	if (selected) {
+		// Use the highlight color for the font
+		gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, mFontHighlightColor.alpha);
+	} else {
+		// Set the color for the font
+		gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha);
+	}
+
+	if (!iconAndTextH)
+		iconAndTextH = actualItemHeight;
+
+	// render icon
+	if (icon && icon->GetResource()) {
+		int iconH = icon->GetHeight();
+		int iconW = icon->GetWidth();
+		int iconY = yPos + (iconAndTextH - iconH) / 2;
+		int iconX = mRenderX + (maxIconWidth - iconW) / 2;
+		gr_blit(icon->GetResource(), 0, 0, iconW, iconH, iconX, iconY);
+	}
+
+	// render label text
+	int textX = mRenderX + maxIconWidth + 5;
+	int textY = yPos + (iconAndTextH - mFontHeight) / 2;
+	gr_textEx(textX, textY, text, mFont->GetResource());
+}
+
 int GUIScrollList::Update(void)
 {
 	if(!isConditionTrue())