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/Android.mk b/gui/Android.mk
index fca5e07..93913f5 100644
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -25,7 +25,8 @@
input.cpp \
blanktimer.cpp \
partitionlist.cpp \
- mousecursor.cpp
+ mousecursor.cpp \
+ scrolllist.cpp
ifneq ($(TWRP_CUSTOM_KEYBOARD),)
LOCAL_SRC_FILES += $(TWRP_CUSTOM_KEYBOARD)
diff --git a/gui/fileselector.cpp b/gui/fileselector.cpp
index cf7a9a9..c7805c4 100644
--- a/gui/fileselector.cpp
+++ b/gui/fileselector.cpp
@@ -16,25 +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" {
@@ -49,188 +33,23 @@
#define TW_FILESELECTOR_UP_A_LEVEL "(Up A Level)"
-#define SCROLLING_SPEED_DECREMENT 6
-#define SCROLLING_FLOOR 10
-#define SCROLLING_MULTIPLIER 6
-
int GUIFileSelector::mSortOrder = 0;
-GUIFileSelector::GUIFileSelector(xml_node<>* node) : GUIObject(node)
+GUIFileSelector::GUIFileSelector(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 = mFolderIconHeight = mFileIconHeight = mFolderIconWidth = mFileIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
- mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
- mFolderIcon = mFileIcon = mBackground = mFont = mHeaderIcon = NULL;
- mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
+ int mIconWidth = 0, mIconHeight = 0, mFolderIconHeight = 0, mFileIconHeight = 0, mFolderIconWidth = 0, mFileIconWidth = 0;
+ mFolderIcon = mFileIcon = NULL;
mShowFolders = mShowFiles = mShowNavFolders = 1;
- mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
- mFastScrollRectX = mFastScrollRectY = -1;
mUpdate = 0;
- touchDebounce = 6;
mPathVar = "cwd";
- 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;
updateFileList = 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;
-
- child = node->first_node("icon");
- if (child)
- {
- attr = child->first_attribute("folder");
- if (attr)
- mFolderIcon = PageManager::FindResource(attr->value());
- attr = child->first_attribute("file");
- if (attr)
- mFileIcon = 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);
- }
- }
-
- // 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;
- }
- }
-
- // 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;
- }
- }
-
+ // Load filter for filtering files (e.g. *.zip for only zips)
child = node->first_node("filter");
- if (child)
- {
+ if (child) {
attr = child->first_attribute("extn");
if (attr)
mExtn = attr->value();
@@ -247,8 +66,7 @@
// Handle the path variable
child = node->first_node("path");
- if (child)
- {
+ if (child) {
attr = child->first_attribute("name");
if (attr)
mPathVar = attr->value();
@@ -259,8 +77,7 @@
// Handle the result variable
child = node->first_node("data");
- if (child)
- {
+ if (child) {
attr = child->first_attribute("name");
if (attr)
mVariable = attr->value();
@@ -271,8 +88,7 @@
// Handle the sort variable
child = node->first_node("sort");
- if (child)
- {
+ if (child) {
attr = child->first_attribute("name");
if (attr)
mSortVariable = attr->value();
@@ -285,100 +101,37 @@
// Handle the selection variable
child = node->first_node("selection");
- if (child)
- {
- attr = child->first_attribute("name");
- if (attr)
- mSelection = attr->value();
- else
- mSelection = "0";
- } else
+ if (child && (attr = child->first_attribute("name")))
+ mSelection = attr->value();
+ else
mSelection = "0";
- // 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());
- }
+ // Get folder and file icons if present
+ child = node->first_node("icon");
+ if (child) {
+ attr = child->first_attribute("folder");
+ if (attr)
+ mFolderIcon = PageManager::FindResource(attr->value());
+ attr = child->first_attribute("file");
+ if (attr)
+ mFileIcon = PageManager::FindResource(attr->value());
}
-
- // Retrieve the line height
- mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL);
- mLineHeight = mFontHeight;
- mHeaderH = mFontHeight;
-
- if (mFolderIcon && mFolderIcon->GetResource())
- {
+ if (mFolderIcon && mFolderIcon->GetResource()) {
mFolderIconWidth = gr_get_width(mFolderIcon->GetResource());
mFolderIconHeight = gr_get_height(mFolderIcon->GetResource());
- if (mFolderIconHeight > (int)mLineHeight)
- mLineHeight = mFolderIconHeight;
+ if (mFolderIconHeight > mIconHeight)
+ mIconHeight = mFolderIconHeight;
mIconWidth = mFolderIconWidth;
}
-
- if (mFileIcon && mFileIcon->GetResource())
- {
+ if (mFileIcon && mFileIcon->GetResource()) {
mFileIconWidth = gr_get_width(mFileIcon->GetResource());
mFileIconHeight = gr_get_height(mFileIcon->GetResource());
- if (mFileIconHeight > (int)mLineHeight)
- mLineHeight = mFileIconHeight;
+ if (mFileIconHeight > mIconHeight)
+ mIconHeight = mFileIconHeight;
if (mFileIconWidth > mIconWidth)
mIconWidth = mFileIconWidth;
}
-
- 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());
- }
+ SetMaxIconSize(mIconWidth, mIconHeight);
// Fetch the file/folder list
std::string value;
@@ -388,194 +141,8 @@
GUIFileSelector::~GUIFileSelector()
{
-}
-
-int GUIFileSelector::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);
- }
-
- // Update the file list if needed
- if (updateFileList) {
- string value;
- DataManager::GetValue(mPathVar, value);
- if (GetFileList(value) == 0)
- updateFileList = false;
- else
- return 0;
- }
-
- // This tells us how many lines we can actually render
- int lines = (mRenderH - mHeaderH) / (actualLineHeight);
- int line;
-
- int folderSize = mShowFolders ? mFolderList.size() : 0;
- int fileSize = mShowFiles ? mFileList.size() : 0;
-
- int listW = mRenderW;
-
- if (folderSize + fileSize < lines) {
- lines = folderSize + fileSize;
- scrollingY = 0;
- mFastScrollRectX = mFastScrollRectY = -1;
- } else {
- listW -= mFastScrollW; // space for fast scroll
- lines++;
- if (lines < folderSize + fileSize)
- 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 folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
- int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 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 (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 (line + mStart < folderSize)
- {
- icon = mFolderIcon;
- label = mFolderList.at(line + mStart).fileName;
- currentIconHeight = mFolderIconHeight;
- currentIconWidth = mFolderIconWidth;
- currentIconOffsetY = folderIconOffsetY;
- currentIconOffsetX = folderIconOffsetX;
- }
- else if (line + mStart < folderSize + fileSize)
- {
- icon = mFileIcon;
- label = mFileList.at((line + mStart) - folderSize).fileName;
- currentIconHeight = mFileIconHeight;
- currentIconWidth = mFileIconWidth;
- currentIconOffsetY = fileIconOffsetY;
- currentIconOffsetX = fileIconOffsetX;
- } else {
- continue;
- }
-
- 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 && folderSize + fileSize > 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)/((folderSize + fileSize)*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);
- }
-
- // If a change came in during the render then we need to do another redraw so leave mUpdate alone if updateFileList is true.
- if (!updateFileList) {
- mUpdate = 0;
- }
- return 0;
+ delete mFileIcon;
+ delete mFolderIcon;
}
int GUIFileSelector::Update(void)
@@ -583,338 +150,52 @@
if(!isConditionTrue())
return 0;
- if (!mHeaderIsStatic) {
- std::string newValue = gui_parse_text(mHeaderText);
- if (mLastValue != newValue) {
- mLastValue = newValue;
+ GUIScrollList::Update();
+
+ // Update the file list if needed
+ if (updateFileList) {
+ string value;
+ DataManager::GetValue(mPathVar, value);
+ if (GetFileList(value) == 0) {
+ updateFileList = false;
mUpdate = 1;
- }
+ } else
+ return 0;
}
- 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 = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
- 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 GUIFileSelector::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 GUIFileSelector::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 = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
- 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 = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
- 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 folderSize = mShowFolders ? mFolderList.size() : 0;
- int fileSize = mShowFiles ? mFileList.size() : 0;
- int selectY = scrollingY, actualSelection = mStart;
-
- // Move the selection to the proper place in the array
- while (selectY + actualLineHeight < startSelection) {
- selectY += actualLineHeight;
- actualSelection++;
- }
- startSelection = actualSelection;
-
- if (startSelection < folderSize + fileSize)
- {
- DataManager::Vibrate("tw_button_vibrate");
-
- if (startSelection < folderSize)
- {
- std::string oldcwd;
- std::string cwd;
-
- str = mFolderList.at(startSelection).fileName;
- if (mSelection != "0")
- DataManager::SetValue(mSelection, str);
- DataManager::GetValue(mPathVar, cwd);
-
- oldcwd = cwd;
- // Ignore requests to do nothing
- if (str == ".") return 0;
- if (str == TW_FILESELECTOR_UP_A_LEVEL)
- {
- if (cwd != "/")
- {
- size_t found;
- found = cwd.find_last_of('/');
- cwd = cwd.substr(0,found);
-
- if (cwd.length() < 2) cwd = "/";
- }
- }
- else
- {
- // Add a slash if we're not the root folder
- if (cwd != "/") cwd += "/";
- cwd += str;
- }
-
- if (mShowNavFolders == 0 && mShowFiles == 0)
- {
- // This is a "folder" selection
- DataManager::SetValue(mVariable, cwd);
- }
- else
- {
- DataManager::SetValue(mPathVar, cwd);
- mStart = 0;
- scrollingY = 0;
- mUpdate = 1;
- }
- }
- else if (!mVariable.empty())
- {
- str = mFileList.at(startSelection - folderSize).fileName;
- if (mSelection != "0")
- DataManager::SetValue(mSelection, str);
-
- std::string cwd;
- DataManager::GetValue(mPathVar, cwd);
- if (cwd != "/") cwd += "/";
- DataManager::SetValue(mVariable, cwd + str);
- }
- }
- } 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 GUIFileSelector::NotifyVarChange(const std::string& varName, const std::string& value)
{
- GUIObject::NotifyVarChange(varName, value);
-
if(!isConditionTrue())
return 0;
+ GUIScrollList::NotifyVarChange(varName, value);
+
if (varName.empty()) {
// Always clear the data variable so we know to use it
DataManager::SetValue(mVariable, "");
}
- if (!mHeaderIsStatic) {
- std::string newValue = gui_parse_text(mHeaderText);
- if (mLastValue != newValue) {
- mLastValue = newValue;
- mStart = 0;
- scrollingY = 0;
- scrollingSpeed = 0;
- mUpdate = 1;
- }
- }
- if (varName == mPathVar || varName == mSortVariable)
- {
+ if (varName == mPathVar || varName == mSortVariable) {
if (varName == mSortVariable) {
DataManager::GetValue(mSortVariable, mSortOrder);
+ } else {
+ // Reset the list to the top
+ SetVisibleListLocation(0);
}
updateFileList = true;
- mStart = 0;
- scrollingY = 0;
- scrollingSpeed = 0;
mUpdate = 1;
return 0;
}
return 0;
}
-int GUIFileSelector::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;
-}
-
bool GUIFileSelector::fileSort(FileData d1, FileData d2)
{
if (d1.fileName == ".")
@@ -948,6 +229,7 @@
default: // should be a 1 - sort by name ascending
return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
}
+ return 0;
}
int GUIFileSelector::GetFileList(const std::string folder)
@@ -961,8 +243,7 @@
mFileList.clear();
d = opendir(folder.c_str());
- if (d == NULL)
- {
+ if (d == NULL) {
LOGINFO("Unable to open '%s'\n", folder.c_str());
if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
size_t found;
@@ -978,8 +259,7 @@
return -1;
}
- while ((de = readdir(d)) != NULL)
- {
+ while ((de = readdir(d)) != NULL) {
FileData data;
data.fileName = de->d_name;
@@ -1007,15 +287,11 @@
if (data.fileType == DT_UNKNOWN) {
data.fileType = TWFunc::Get_D_Type_From_Stat(path);
}
- if (data.fileType == DT_DIR)
- {
+ if (data.fileType == DT_DIR) {
if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
mFolderList.push_back(data);
- }
- else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
- {
- if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
- {
+ } else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK) {
+ if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn)) {
mFileList.push_back(data);
}
}
@@ -1030,11 +306,85 @@
void GUIFileSelector::SetPageFocus(int inFocus)
{
- if (inFocus)
- {
+ GUIScrollList::SetPageFocus(inFocus);
+ if (inFocus) {
updateFileList = true;
- scrollingY = 0;
- scrollingSpeed = 0;
mUpdate = 1;
}
}
+
+size_t GUIFileSelector::GetItemCount()
+{
+ size_t folderSize = mShowFolders ? mFolderList.size() : 0;
+ size_t fileSize = mShowFiles ? mFileList.size() : 0;
+ return folderSize + fileSize;
+}
+
+int GUIFileSelector::GetListItem(size_t item_index, Resource*& icon, std::string &text)
+{
+ size_t folderSize = mShowFolders ? mFolderList.size() : 0;
+ size_t fileSize = mShowFiles ? mFileList.size() : 0;
+
+ if (item_index < folderSize) {
+ text = mFolderList.at(item_index).fileName;
+ icon = mFolderIcon;
+ } else {
+ text = mFileList.at(item_index - folderSize).fileName;
+ icon = mFileIcon;
+ }
+ return 0;
+}
+
+void GUIFileSelector::NotifySelect(size_t item_selected)
+{
+ size_t folderSize = mShowFolders ? mFolderList.size() : 0;
+ size_t fileSize = mShowFiles ? mFileList.size() : 0;
+
+ if (item_selected < folderSize + fileSize) {
+ // We've selected an item!
+ std::string str;
+ if (item_selected < folderSize) {
+ std::string cwd;
+
+ str = mFolderList.at(item_selected).fileName;
+ if (mSelection != "0")
+ DataManager::SetValue(mSelection, str);
+ DataManager::GetValue(mPathVar, cwd);
+
+ // Ignore requests to do nothing
+ if (str == ".") return;
+ if (str == TW_FILESELECTOR_UP_A_LEVEL) {
+ if (cwd != "/") {
+ size_t found;
+ found = cwd.find_last_of('/');
+ cwd = cwd.substr(0,found);
+
+ if (cwd.length() < 2) cwd = "/";
+ }
+ } else {
+ // Add a slash if we're not the root folder
+ if (cwd != "/") cwd += "/";
+ cwd += str;
+ }
+
+ if (mShowNavFolders == 0 && mShowFiles == 0) {
+ // nav folders and files are disabled, this is probably the restore list and we need to save chosen location to mVariable instead of mPathVar
+ DataManager::SetValue(mVariable, cwd);
+ } else {
+ // We are changing paths, so we need to set mPathVar
+ DataManager::SetValue(mPathVar, cwd);
+ }
+ } else if (!mVariable.empty()) {
+ str = mFileList.at(item_selected - folderSize).fileName;
+ if (mSelection != "0")
+ DataManager::SetValue(mSelection, str);
+
+ std::string cwd;
+ DataManager::GetValue(mPathVar, cwd);
+ if (cwd != "/")
+ cwd += "/";
+ DataManager::SetValue(mVariable, cwd + str);
+ }
+ }
+ mUpdate = 1;
+}
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;
+}
diff --git a/gui/objects.hpp b/gui/objects.hpp
index 3e33561..0928f30 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -501,11 +501,17 @@
std::string mVarName;
};
-class GUIFileSelector : public GUIObject, public RenderObject, public ActionObject
+struct ScrollListData {
+ Resource* displayResource;
+ std::string displayName;
+ int list_index;
+};
+
+class GUIScrollList : public GUIObject, public RenderObject, public ActionObject
{
public:
- GUIFileSelector(xml_node<>* node);
- virtual ~GUIFileSelector();
+ GUIScrollList(xml_node<>* node);
+ virtual ~GUIScrollList();
public:
// Render - Render the full object to the GL surface
@@ -531,6 +537,106 @@
virtual void SetPageFocus(int inFocus);
protected:
+ // 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, Resource*& icon, std::string &text)
+ { icon = NULL; text = ""; return -1; }
+ // an item was selected
+ virtual void NotifySelect(size_t item_selected) {}
+
+ 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);
+
+ // Called by the derived class to set the max icon size so we can calculate the proper actualItemHeight and center smaller icons if the icon size varies
+ void SetMaxIconSize(int w, int h);
+
+ // This will make sure that the item indicated by list_index is visible on the screen
+ void SetVisibleListLocation(size_t list_index);
+
+ // Handle scrolling changes for drags and kinetic scrolling
+ void HandleScrolling();
+
+ // Returns many rows the list is capable of displaying
+ int GetDisplayItemCount();
+
+ // Returns the size in pixels of a partial item or row size
+ int GetDisplayRemainder();
+
+protected:
+ // Background
+ COLOR mBackgroundColor;
+ Resource* mBackground; // background image, if any, automatically centered
+ int mBackgroundW, mBackgroundH; // background width and height if using an image for the background
+
+ // Header
+ COLOR mHeaderBackgroundColor;
+ COLOR mHeaderFontColor;
+ std::string mHeaderText; // Original header text without parsing any variables
+ std::string mLastHeaderValue; // Header text after parsing variables
+ int mHeaderIsStatic; // indicates if the header is static (no need to check for changes in NotifyVarChange)
+ int mHeaderH; // actual header height including font, icon, padding, and separator heights
+ Resource* mHeaderIcon;
+ int mHeaderIconHeight, mHeaderIconWidth; // width and height of the header icon if present
+ int mHeaderSeparatorH; // Height of the separator between header and list items
+ COLOR mHeaderSeparatorColor; // color of the header separator
+
+ // Per-item layout
+ Resource* mFont;
+ COLOR mFontColor;
+ bool hasHighlightColor; // indicates if a hightlight color was set
+ bool hasFontHighlightColor; // indicates if the font hightlight color is set
+ COLOR mHighlightColor; // background row hightlight color
+ COLOR mFontHighlightColor;
+ int mFontHeight;
+ int actualItemHeight; // Actual height of each item in pixels including max icon size, font size, and padding
+ int maxIconWidth, maxIconHeight; // max icon width and height for the list, set by derived class in SetMaxIconSize
+ int mItemSpacing; // stores the spacing or padding on the y axis, part of the actualItemHeight
+ int mSeparatorH; // Height of the separator between items
+ COLOR mSeparatorColor; // color of the separator that is between items
+
+ // Scrolling and dynamic state
+ int mFastScrollW; // width of the fastscroll area
+ int mFastScrollLineW; // width of the line for fastscroll rendering
+ int mFastScrollRectW; // width of the rectangle for fastscroll
+ int mFastScrollRectH; // height of the rectangle for fastscroll
+ COLOR mFastScrollLineColor;
+ COLOR mFastScrollRectColor;
+ bool hasScroll; // indicates that we have enough items in the list to scroll
+ int firstDisplayedItem; // this item goes at the top of the display list - may only be partially visible
+ int scrollingSpeed; // on a touch release, this is set based on the difference in the y-axis between the last 2 touches and indicates how fast the kinetic scrolling will go
+ int y_offset; // this is how many pixels offset in the y axis for per pixel scrolling, is always <= 0 and should never be < -actualItemHeight
+ size_t selectedItem; // selected item index after the initial touch, set to -1 if we are scrolling
+ int touchDebounce; // debounce for touches, minimum of 6 pixels but may be larger calculated based actualItemHeight / 3
+ int lastY, last2Y; // last 2 touch locations, used for tracking kinetic scroll speed
+ int fastScroll; // indicates that the inital touch was inside the fastscroll region - makes for easier fast scrolling as the touches don't have to stay within the fast scroll region and you drag your finger
+ int mUpdate; // indicates that a change took place and we need to re-render
+};
+
+class GUIFileSelector : public GUIScrollList
+{
+public:
+ GUIFileSelector(xml_node<>* node);
+ virtual ~GUIFileSelector();
+
+public:
+ // Update - Update any UI component animations (called <= 30 FPS)
+ // Return 0 if nothing to update, 1 on success and contiue, >1 if full render required, and <0 on error
+ virtual int Update(void);
+
+ // NotifyVarChange - Notify of a variable change
+ virtual int NotifyVarChange(const std::string& varName, const std::string& value);
+
+ // SetPageFocus - Notify when a page gains or loses focus
+ virtual void SetPageFocus(int inFocus);
+
+ virtual size_t GetItemCount();
+ virtual int GetListItem(size_t item_index, Resource*& icon, std::string &text);
+ virtual void NotifySelect(size_t item_selected);
+
+protected:
struct FileData {
std::string fileName;
unsigned char fileType; // Uses d_type format from struct dirent
@@ -544,96 +650,46 @@
};
protected:
- virtual int GetSelection(int x, int y);
-
virtual int GetFileList(const std::string folder);
static bool fileSort(FileData d1, FileData d2);
protected:
std::vector<FileData> mFolderList;
std::vector<FileData> mFileList;
- std::string mPathVar;
- std::string mExtn;
- std::string mVariable;
- std::string mSortVariable;
- std::string mSelection;
- std::string mHeaderText;
- std::string mLastValue;
- int actualLineHeight;
- int mStart;
- int mLineSpacing;
- int mSeparatorH;
- int mHeaderSeparatorH;
- int mShowFolders, mShowFiles, mShowNavFolders;
- int mUpdate;
- int mBackgroundX, mBackgroundY, mBackgroundW, mBackgroundH;
- int mHeaderH;
- int mFastScrollW;
- int mFastScrollLineW;
- int mFastScrollRectW;
- int mFastScrollRectH;
- int mFastScrollRectX;
- int mFastScrollRectY;
- static int mSortOrder;
- int startY;
- int scrollingSpeed;
- int scrollingY;
- int mHeaderIsStatic;
- int touchDebounce;
- unsigned mFontHeight;
- unsigned mLineHeight;
- int mIconWidth, mIconHeight, mFolderIconHeight, mFileIconHeight, mFolderIconWidth, mFileIconWidth, mHeaderIconHeight, mHeaderIconWidth;
- Resource* mHeaderIcon;
+ std::string mPathVar; // current path displayed, saved in the data manager
+ std::string mExtn; // used for filtering the file list, for example, *.zip
+ std::string mVariable; // set when the user selects an item, pull path like /path/to/foo
+ std::string mSortVariable; // data manager variable used to change the sorting of files
+ std::string mSelection; // set when the user selects an item without the full path like selecting /path/to/foo would just be set to foo
+ int mShowFolders, mShowFiles; // indicates if the list should show folders and/or files
+ int mShowNavFolders; // indicates if the list should include the "up a level" item and allow you to traverse folders (nav folders are disabled for the restore list, for instance)
+ static int mSortOrder; // must be static because it is used by the static function fileSort
Resource* mFolderIcon;
Resource* mFileIcon;
- Resource* mBackground;
- Resource* mFont;
- COLOR mBackgroundColor;
- COLOR mFontColor;
- COLOR mHeaderBackgroundColor;
- COLOR mHeaderFontColor;
- COLOR mSeparatorColor;
- COLOR mHeaderSeparatorColor;
- COLOR mFastScrollLineColor;
- COLOR mFastScrollRectColor;
- bool hasHighlightColor;
- bool hasFontHighlightColor;
- bool isHighlighted;
- COLOR mHighlightColor;
- COLOR mFontHighlightColor;
- int startSelection;
bool updateFileList;
};
-class GUIListBox : public GUIObject, public RenderObject, public ActionObject
+class GUIListBox : public GUIScrollList
{
public:
GUIListBox(xml_node<>* node);
virtual ~GUIListBox();
public:
- // Render - Render the full object to the GL surface
- // Return 0 on success, <0 on error
- virtual int Render(void);
-
// Update - Update any UI component animations (called <= 30 FPS)
// Return 0 if nothing to update, 1 on success and contiue, >1 if full render required, and <0 on error
virtual int Update(void);
- // NotifyTouch - Notify of a touch event
- // Return 0 on success, >0 to ignore remainder of touch, and <0 on error
- virtual int NotifyTouch(TOUCH_STATE state, int x, int y);
-
// NotifyVarChange - Notify of a variable change
virtual int NotifyVarChange(const std::string& varName, const std::string& value);
- // SetPos - Update the position of the render object
- // Return 0 on success, <0 on error
- virtual int SetRenderPos(int x, int y, int w = 0, int h = 0);
-
// SetPageFocus - Notify when a page gains or loses focus
virtual void SetPageFocus(int inFocus);
+ virtual size_t GetItemCount();
+ virtual int GetListItem(size_t item_index, Resource*& icon, std::string &text);
+ virtual void NotifySelect(size_t item_selected);
+
protected:
struct ListData {
std::string displayName;
@@ -642,89 +698,37 @@
};
protected:
- virtual int GetSelection(int x, int y);
-
-protected:
std::vector<ListData> mList;
std::string mVariable;
- std::string mSelection;
std::string currentValue;
- std::string mHeaderText;
- std::string mLastValue;
- int actualLineHeight;
- int mStart;
- int startY;
- int mSeparatorH, mHeaderSeparatorH;
- int mLineSpacing;
- int mUpdate;
- int mBackgroundX, mBackgroundY, mBackgroundW, mBackgroundH, mHeaderH;
- int mFastScrollW;
- int mFastScrollLineW;
- int mFastScrollRectW;
- int mFastScrollRectH;
- int mFastScrollRectX;
- int mFastScrollRectY;
- int mIconWidth, mIconHeight, mSelectedIconWidth, mSelectedIconHeight, mUnselectedIconWidth, mUnselectedIconHeight, mHeaderIconHeight, mHeaderIconWidth;
- int scrollingSpeed;
- int scrollingY;
- static int mSortOrder;
- unsigned mFontHeight;
- unsigned mLineHeight;
- Resource* mHeaderIcon;
Resource* mIconSelected;
Resource* mIconUnselected;
- Resource* mBackground;
- Resource* mFont;
- COLOR mBackgroundColor;
- COLOR mFontColor;
- COLOR mHeaderBackgroundColor;
- COLOR mHeaderFontColor;
- COLOR mSeparatorColor;
- COLOR mHeaderSeparatorColor;
- COLOR mFastScrollLineColor;
- COLOR mFastScrollRectColor;
- bool hasHighlightColor;
- bool hasFontHighlightColor;
- bool isHighlighted;
- COLOR mHighlightColor;
- COLOR mFontHighlightColor;
- int mHeaderIsStatic;
- int startSelection;
- int touchDebounce;
};
-class GUIPartitionList : public GUIObject, public RenderObject, public ActionObject
+class GUIPartitionList : public GUIScrollList
{
public:
GUIPartitionList(xml_node<>* node);
virtual ~GUIPartitionList();
public:
- // Render - Render the full object to the GL surface
- // Return 0 on success, <0 on error
- virtual int Render(void);
-
// Update - Update any UI component animations (called <= 30 FPS)
// Return 0 if nothing to update, 1 on success and contiue, >1 if full render required, and <0 on error
- virtual int Update(void);
-
- // NotifyTouch - Notify of a touch event
- // Return 0 on success, >0 to ignore remainder of touch, and <0 on error
- virtual int NotifyTouch(TOUCH_STATE state, int x, int y);
+ virtual int Update();
// NotifyVarChange - Notify of a variable change
virtual int NotifyVarChange(const std::string& varName, const std::string& value);
- // SetPos - Update the position of the render object
- // Return 0 on success, <0 on error
- virtual int SetRenderPos(int x, int y, int w = 0, int h = 0);
-
// SetPageFocus - Notify when a page gains or loses focus
virtual void SetPageFocus(int inFocus);
+ virtual size_t GetItemCount();
+ virtual int GetListItem(size_t item_index, Resource*& icon, std::string &text);
+ virtual void NotifySelect(size_t item_selected);
+
protected:
- virtual int GetSelection(int x, int y);
- virtual void MatchList(void);
+ void MatchList();
+ void SetStoragePosition();
protected:
std::vector<PartitionList> mList;
@@ -732,48 +736,9 @@
std::string mVariable;
std::string selectedList;
std::string currentValue;
- std::string mHeaderText;
std::string mLastValue;
- int actualLineHeight;
- int mStart;
- int startY;
- int mSeparatorH, mHeaderSeparatorH;
- int mLineSpacing;
- int mUpdate;
- int mBackgroundX, mBackgroundY, mBackgroundW, mBackgroundH, mHeaderH;
- int mFastScrollW;
- int mFastScrollLineW;
- int mFastScrollRectW;
- int mFastScrollRectH;
- int mFastScrollRectX;
- int mFastScrollRectY;
- int mIconWidth, mIconHeight, mSelectedIconWidth, mSelectedIconHeight, mUnselectedIconWidth, mUnselectedIconHeight, mHeaderIconHeight, mHeaderIconWidth;
- int scrollingSpeed;
- int scrollingY;
- static int mSortOrder;
- unsigned mFontHeight;
- unsigned mLineHeight;
- Resource* mHeaderIcon;
Resource* mIconSelected;
Resource* mIconUnselected;
- Resource* mBackground;
- Resource* mFont;
- COLOR mBackgroundColor;
- COLOR mFontColor;
- COLOR mHeaderBackgroundColor;
- COLOR mHeaderFontColor;
- COLOR mSeparatorColor;
- COLOR mHeaderSeparatorColor;
- COLOR mFastScrollLineColor;
- COLOR mFastScrollRectColor;
- bool hasHighlightColor;
- bool hasFontHighlightColor;
- bool isHighlighted;
- COLOR mHighlightColor;
- COLOR mFontHighlightColor;
- int mHeaderIsStatic;
- int startSelection;
- int touchDebounce;
bool updateList;
};
diff --git a/gui/partitionlist.cpp b/gui/partitionlist.cpp
index 3ec1548..48bd295 100644
--- a/gui/partitionlist.cpp
+++ b/gui/partitionlist.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,98 +28,17 @@
#include "rapidxml.hpp"
#include "objects.hpp"
#include "../data.hpp"
-#include "../twrp-functions.hpp"
#include "../partitions.hpp"
-#define SCROLLING_SPEED_DECREMENT 6
-#define SCROLLING_FLOOR 10
-#define SCROLLING_MULTIPLIER 6
-
-GUIPartitionList::GUIPartitionList(xml_node<>* node) : GUIObject(node)
+GUIPartitionList::GUIPartitionList(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;
+ int mIconWidth = 0, mIconHeight = 0, mSelectedIconHeight = 0, mSelectedIconWidth = 0, mUnselectedIconHeight = 0, mUnselectedIconWidth = 0;
+ mIconSelected = mIconUnselected = NULL;
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;
updateList = 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;
child = node->first_node("icon");
if (child)
@@ -148,80 +50,6 @@
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);
- }
- }
-
- // 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;
- }
- }
-
- // 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;
- }
- }
// Handle the result variable
child = node->first_node("data");
@@ -235,54 +63,12 @@
selectedList = attr->value();
}
- // 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;
+ if (mSelectedIconHeight > mIconHeight)
+ mIconHeight = mSelectedIconHeight;
mIconWidth = mSelectedIconWidth;
}
@@ -290,47 +76,17 @@
{
mUnselectedIconWidth = gr_get_width(mIconUnselected->GetResource());
mUnselectedIconHeight = gr_get_height(mIconUnselected->GetResource());
- if (mUnselectedIconHeight > (int)mLineHeight)
- mLineHeight = mUnselectedIconHeight;
+ if (mUnselectedIconHeight > mIconHeight)
+ mIconHeight = 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());
- }
+ SetMaxIconSize(mIconWidth, mIconHeight);
child = node->first_node("listtype");
- if (child) {
- attr = child->first_attribute("name");
- if (attr) {
- ListType = attr->value();
- PartitionManager.Get_Partition_List(ListType, &mList);
- } else {
- mList.clear();
- LOGERR("No partition listtype name specified for partitionlist GUI element\n");
- return;
- }
+ if (child && (attr = child->first_attribute("name"))) {
+ ListType = attr->value();
+ updateList = true;
} else {
mList.clear();
LOGERR("No partition listtype specified for partitionlist GUI element\n");
@@ -340,190 +96,8 @@
GUIPartitionList::~GUIPartitionList()
{
-}
-
-int GUIPartitionList::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;
-
- if (updateList) {
- mList.clear();
- PartitionManager.Get_Partition_List(ListType, &mList);
- updateList = false;
- if (ListType == "backup")
- MatchList();
- }
-
- int listSize = mList.size();
- int listW = mRenderW;
-
- if (listSize < lines) {
- lines = listSize;
- scrollingY = 0;
- mFastScrollRectX = mFastScrollRectY = -1;
- } else {
- lines++;
- if (lines < listSize)
- lines++;
- if (listSize >= lines)
- listW -= mFastScrollW; // space for fast scrollbar
- else
- mFastScrollRectX = mFastScrollRectY = -1; // no fast scrollbar
- }
-
- 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).Display_Name;
- 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 GUIPartitionList::Update(void)
@@ -531,14 +105,6 @@
if(!isConditionTrue())
return 0;
- if (!mHeaderIsStatic) {
- std::string newValue = gui_parse_text(mHeaderText);
- if (mLastValue != newValue) {
- mLastValue = newValue;
- mUpdate = 1;
- }
- }
-
// Check for changes in mount points if the list type is mount and update the list and render if needed
if (ListType == "mount") {
int listSize = mList.size();
@@ -553,329 +119,49 @@
}
}
- if (mUpdate)
- {
+ GUIScrollList::Update();
+
+ if (updateList) {
+ int listSize = 0;
+
+ // Completely update the list if needed -- Used primarily for
+ // restore as the list for restore will change depending on what
+ // partitions were backed up
+ mList.clear();
+ PartitionManager.Get_Partition_List(ListType, &mList);
+ SetVisibleListLocation(0);
+ updateList = false;
+ mUpdate = 1;
+ if (ListType == "backup")
+ MatchList();
+ }
+
+ 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 GUIPartitionList::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 GUIPartitionList::NotifyTouch(TOUCH_STATE state, int x, int y)
-{
- if(!isConditionTrue())
- return -1;
-
- static int lastY = 0, last2Y = 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;
- 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(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
- {
- 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;
- if (startSelection >= 0)
- {
- // We've selected an item!
- 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 && ListType == "mount") {
- DataManager::Vibrate("tw_button_vibrate");
-
- if (!mList.at(actualSelection).selected) {
- if (PartitionManager.Mount_By_Path(mList.at(actualSelection).Mount_Point, true)) {
- mList.at(actualSelection).selected = 1;
- PartitionManager.Add_MTP_Storage(mList.at(actualSelection).Mount_Point);
- mUpdate = 1;
- }
- } else {
- if (PartitionManager.UnMount_By_Path(mList.at(actualSelection).Mount_Point, true)) {
- mList.at(actualSelection).selected = 0;
- mUpdate = 1;
- }
- }
- } else if (actualSelection < listSize && !mVariable.empty()) {
- DataManager::Vibrate("tw_button_vibrate");
-
- if (ListType == "storage") {
- int i;
- std::string str = mList.at(actualSelection).Mount_Point;
- bool update_size = false;
- TWPartition* Part = PartitionManager.Find_Partition_By_Path(str);
- if (Part == NULL) {
- LOGERR("Unable to locate partition for '%s'\n", str.c_str());
- return 0;
- }
- if (!Part->Is_Mounted() && Part->Removable)
- update_size = true;
- if (!Part->Mount(true)) {
- // Do Nothing
- } else if (update_size && !Part->Update_Size(true)) {
- // Do Nothing
- } else {
- for (i=0; i<listSize; i++)
- mList.at(i).selected = 0;
-
- if (update_size) {
- char free_space[255];
- sprintf(free_space, "%llu", Part->Free / 1024 / 1024);
- mList.at(actualSelection).Display_Name = Part->Storage_Name + " (";
- mList.at(actualSelection).Display_Name += free_space;
- mList.at(actualSelection).Display_Name += "MB)";
- }
- mList.at(actualSelection).selected = 1;
- mUpdate = 1;
-
- DataManager::SetValue(mVariable, str);
- }
- } else {
- if (ListType == "flashimg") { // only one item can be selected for flashing images
- for (int i=0; i<listSize; i++)
- mList.at(i).selected = 0;
- }
- if (mList.at(actualSelection).selected)
- mList.at(actualSelection).selected = 0;
- else
- mList.at(actualSelection).selected = 1;
-
- int i;
- string variablelist;
- for (i=0; i<listSize; i++) {
- if (mList.at(i).selected) {
- variablelist += mList.at(i).Mount_Point + ";";
- }
- }
-
- mUpdate = 1;
- if (selectedList.empty())
- DataManager::SetValue(mVariable, variablelist);
- else
- DataManager::SetValue(selectedList, variablelist);
- }
- }
- } 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 GUIPartitionList::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;
- }
- }
+ GUIScrollList::NotifyVarChange(varName, value);
+
if (varName == mVariable && !mUpdate)
{
if (ListType == "storage") {
- int i, listSize = mList.size(), selected_index = 0;
-
currentValue = value;
-
- for (i=0; i<listSize; i++) {
- if (mList.at(i).Mount_Point == currentValue) {
- mList.at(i).selected = 1;
- selected_index = i;
- } else
- mList.at(i).selected = 0;
- }
-
- int lines = mRenderH / (mLineHeight + mLineSpacing);
- int line;
-
- if (selected_index > mStart + lines - 1) {
- mStart = selected_index;
- } else if (selected_index < mStart) {
- mStart = selected_index;
- }
+ SetStoragePosition();
} else if (ListType == "backup") {
MatchList();
} else if (ListType == "restore") {
updateList = true;
+ SetVisibleListLocation(0);
}
mUpdate = 1;
@@ -884,44 +170,13 @@
return 0;
}
-int GUIPartitionList::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 GUIPartitionList::SetPageFocus(int inFocus)
{
+ GUIScrollList::SetPageFocus(inFocus);
if (inFocus) {
if (ListType == "storage") {
- int i, listSize = mList.size(), selected_index = 0;
-
DataManager::GetValue(mVariable, currentValue);
-
- for (i=0; i<listSize; i++) {
- if (mList.at(i).Mount_Point == currentValue) {
- mList.at(i).selected = 1;
- selected_index = i;
- } else
- mList.at(i).selected = 0;
- }
-
- int lines = mRenderH / (mLineHeight + mLineSpacing);
- int line;
-
- if (selected_index > mStart + lines - 1) {
- mStart = selected_index;
- } else if (selected_index < mStart) {
- mStart = selected_index;
- }
+ SetStoragePosition();
}
updateList = true;
mUpdate = 1;
@@ -935,7 +190,7 @@
DataManager::GetValue(mVariable, variablelist);
- for (i=0; i<listSize; i++) {
+ for (i = 0; i < listSize; i++) {
searchvalue = mList.at(i).Mount_Point + ";";
pos = variablelist.find(searchvalue);
if (pos != string::npos) {
@@ -945,3 +200,109 @@
}
}
}
+
+void GUIPartitionList::SetStoragePosition() {
+ int listSize = mList.size();
+
+ for (int i = 0; i < listSize; i++) {
+ if (mList.at(i).Mount_Point == currentValue) {
+ mList.at(i).selected = 1;
+ SetVisibleListLocation(i);
+ } else {
+ mList.at(i).selected = 0;
+ SetVisibleListLocation(0);
+ }
+ }
+}
+
+size_t GUIPartitionList::GetItemCount()
+{
+ return mList.size();
+}
+
+int GUIPartitionList::GetListItem(size_t item_index, Resource*& icon, std::string &text)
+{
+ text = mList.at(item_index).Display_Name;
+ if (mList.at(item_index).selected)
+ icon = mIconSelected;
+ else
+ icon = mIconUnselected;
+ return 0;
+}
+
+void GUIPartitionList::NotifySelect(size_t item_selected)
+{
+ if (item_selected < mList.size()) {
+ int listSize = mList.size();
+ if (ListType == "mount") {
+ if (!mList.at(item_selected).selected) {
+ if (PartitionManager.Mount_By_Path(mList.at(item_selected).Mount_Point, true)) {
+ mList.at(item_selected).selected = 1;
+ PartitionManager.Add_MTP_Storage(mList.at(item_selected).Mount_Point);
+ mUpdate = 1;
+ }
+ } else {
+ if (PartitionManager.UnMount_By_Path(mList.at(item_selected).Mount_Point, true)) {
+ mList.at(item_selected).selected = 0;
+ mUpdate = 1;
+ }
+ }
+ } else if (!mVariable.empty()) {
+ if (ListType == "storage") {
+ int i;
+ std::string str = mList.at(item_selected).Mount_Point;
+ bool update_size = false;
+ TWPartition* Part = PartitionManager.Find_Partition_By_Path(str);
+ if (Part == NULL) {
+ LOGERR("Unable to locate partition for '%s'\n", str.c_str());
+ return;
+ }
+ if (!Part->Is_Mounted() && Part->Removable)
+ update_size = true;
+ if (!Part->Mount(true)) {
+ // Do Nothing
+ } else if (update_size && !Part->Update_Size(true)) {
+ // Do Nothing
+ } else {
+ for (i=0; i<listSize; i++)
+ mList.at(i).selected = 0;
+
+ if (update_size) {
+ char free_space[255];
+ sprintf(free_space, "%llu", Part->Free / 1024 / 1024);
+ mList.at(item_selected).Display_Name = Part->Storage_Name + " (";
+ mList.at(item_selected).Display_Name += free_space;
+ mList.at(item_selected).Display_Name += "MB)";
+ }
+ mList.at(item_selected).selected = 1;
+ mUpdate = 1;
+
+ DataManager::SetValue(mVariable, str);
+ }
+ } else {
+ if (ListType == "flashimg") { // only one item can be selected for flashing images
+ for (int i=0; i<listSize; i++)
+ mList.at(i).selected = 0;
+ }
+ if (mList.at(item_selected).selected)
+ mList.at(item_selected).selected = 0;
+ else
+ mList.at(item_selected).selected = 1;
+
+ int i;
+ string variablelist;
+ for (i=0; i<listSize; i++) {
+ if (mList.at(i).selected) {
+ variablelist += mList.at(i).Mount_Point + ";";
+ }
+ }
+
+ mUpdate = 1;
+ if (selectedList.empty())
+ DataManager::SetValue(mVariable, variablelist);
+ else
+ DataManager::SetValue(selectedList, variablelist);
+ }
+ }
+ }
+}
diff --git a/gui/scrolllist.cpp b/gui/scrolllist.cpp
new file mode 100644
index 0000000..9e8db4c
--- /dev/null
+++ b/gui/scrolllist.cpp
@@ -0,0 +1,709 @@
+/*
+ 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"
+
+const int SCROLLING_SPEED_DECREMENT = 12; // friction
+const int SCROLLING_FLOOR = 10; // minimum pixels for scrolling to start or stop
+const int SCROLLING_MULTIPLIER = 2; // initial speed of kinetic scrolling
+const float SCROLLING_SPEED_LIMIT = 2.5; // maximum number of items to scroll per update
+
+GUIScrollList::GUIScrollList(xml_node<>* node) : GUIObject(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;
+
+ firstDisplayedItem = mItemSpacing = mFontHeight = mSeparatorH = y_offset = scrollingSpeed = 0;
+ maxIconWidth = maxIconHeight = mHeaderIconHeight = mHeaderIconWidth = 0;
+ mHeaderSeparatorH = mHeaderIsStatic = mHeaderH = actualItemHeight = 0;
+ mBackground = mFont = mHeaderIcon = NULL;
+ mBackgroundW = mBackgroundH = 0;
+ mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
+ lastY = last2Y = fastScroll = 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;
+ selectedItem = NO_ITEM;
+
+ // 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
+ mLastHeaderValue = gui_parse_text(mHeaderText);
+ if (mLastHeaderValue != mHeaderText)
+ mHeaderIsStatic = 0;
+ else
+ mHeaderIsStatic = -1;
+
+ 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);
+ }
+ }
+
+ // 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());
+ mItemSpacing = 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;
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ // 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);
+ mHeaderH = mFontHeight;
+
+ if (mHeaderIcon && mHeaderIcon->GetResource())
+ {
+ mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
+ mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
+ if (mHeaderIconHeight > mHeaderH)
+ mHeaderH = mHeaderIconHeight;
+ if (mHeaderIconWidth > maxIconWidth)
+ maxIconWidth = mHeaderIconWidth;
+ }
+
+ mHeaderH += mItemSpacing + mHeaderSeparatorH;
+ actualItemHeight = mFontHeight + mItemSpacing + mSeparatorH;
+ if (mHeaderH < actualItemHeight)
+ mHeaderH = actualItemHeight;
+
+ if (actualItemHeight / 3 > 6)
+ touchDebounce = actualItemHeight / 3;
+
+ if (mBackground && mBackground->GetResource())
+ {
+ mBackgroundW = gr_get_width(mBackground->GetResource());
+ mBackgroundH = gr_get_height(mBackground->GetResource());
+ }
+}
+
+GUIScrollList::~GUIScrollList()
+{
+ delete mHeaderIcon;
+ delete mBackground;
+ delete mFont;
+}
+
+void GUIScrollList::SetMaxIconSize(int w, int h)
+{
+ if (w > maxIconWidth)
+ maxIconWidth = w;
+ if (h > maxIconHeight)
+ maxIconHeight = h;
+ if (maxIconHeight > mFontHeight) {
+ actualItemHeight = maxIconHeight + mItemSpacing + mSeparatorH;
+ if (actualItemHeight > mHeaderH)
+ mHeaderH = actualItemHeight;
+ }
+}
+
+void GUIScrollList::SetVisibleListLocation(size_t list_index)
+{
+ // This will make sure that the item indicated by list_index is visible on the screen
+ size_t lines = GetDisplayItemCount(), listSize = GetItemCount();
+
+ if (list_index <= (unsigned)firstDisplayedItem) {
+ // list_index is above the currently displayed items, put the selected item at the very top
+ firstDisplayedItem = list_index;
+ y_offset = 0;
+ } else if (list_index >= firstDisplayedItem + lines) {
+ // list_index is below the currently displayed items, put the selected item at the very bottom
+ firstDisplayedItem = list_index - lines + 1;
+ if (GetDisplayRemainder() != 0) {
+ // There's a partial row displayed, set the scrolling offset so that the selected item really is at the very bottom
+ firstDisplayedItem--;
+ y_offset = GetDisplayRemainder() - actualItemHeight;
+ } else {
+ // There's no partial row so zero out the offset
+ y_offset = 0;
+ }
+ }
+ scrollingSpeed = 0; // stop kinetic scrolling on setting visible location
+ mUpdate = 1;
+}
+
+int GUIScrollList::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())
+ {
+ int mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
+ int 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
+ size_t lines = GetDisplayItemCount();
+
+ size_t listSize = GetItemCount();
+ int listW = mRenderW;
+
+ if (listSize <= lines) {
+ hasScroll = false;
+ scrollingSpeed = 0;
+ lines = listSize;
+ y_offset = 0;
+ } else {
+ hasScroll = true;
+ listW -= mFastScrollW; // space for fast scroll
+ lines++;
+ if (lines < listSize)
+ 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++)
+ {
+ size_t itemindex = line + firstDisplayedItem;
+ if (itemindex >= listSize)
+ break;
+
+ // get item data
+ Resource* 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, 255);
+ int HighlightHeight = actualItemHeight;
+ if (yPos + HighlightHeight > mRenderY + mRenderH) {
+ HighlightHeight = mRenderY + mRenderH - yPos;
+ }
+ gr_fill(mRenderX, yPos, mRenderW, HighlightHeight);
+ }
+
+ if (hasFontHighlightColor && itemindex == selectedItem) {
+ // 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 (icon && icon->GetResource()) {
+ int currentIconHeight = gr_get_height(icon->GetResource());
+ int currentIconWidth = gr_get_width(icon->GetResource());
+ int currentIconOffsetY = (int)((actualItemHeight - currentIconHeight) / 2);
+ int currentIconOffsetX = (maxIconWidth - currentIconWidth) / 2;
+ 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 + maxIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
+
+ // Add the separator
+ if (yPos + actualItemHeight < mRenderH + mRenderY) {
+ gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
+ gr_fill(mRenderX, yPos + actualItemHeight - mSeparatorH, listW, mSeparatorH);
+ }
+
+ // Move the yPos
+ yPos += actualItemHeight;
+ }
+
+ // 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 - maxIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
+ mIconOffsetX = maxIconWidth;
+ }
+
+ // render the text
+ gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
+ gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastHeaderValue.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 = GetDisplayItemCount();
+ if (hasScroll) {
+ 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 = 0;
+ if (GetDisplayRemainder() != 0) {
+ // Properly handle the percentage if a partial line is present
+ int partial_line_size = actualItemHeight - GetDisplayRemainder();
+ pct = ((firstDisplayedItem*actualItemHeight - y_offset)*100)/(listSize*actualItemHeight-((lines + 1)*actualItemHeight) + partial_line_size);
+ } else {
+ pct = ((firstDisplayedItem*actualItemHeight - y_offset)*100)/(listSize*actualItemHeight-lines*actualItemHeight);
+ }
+ int mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
+ int 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;
+}
+
+int GUIScrollList::Update(void)
+{
+ if(!isConditionTrue())
+ return 0;
+
+ if (!mHeaderIsStatic) {
+ std::string newValue = gui_parse_text(mHeaderText);
+ if (mLastHeaderValue != newValue) {
+ mLastHeaderValue = newValue;
+ mUpdate = 1;
+ }
+ }
+
+ // Handle kinetic scrolling
+ int maxScrollDistance = actualItemHeight * SCROLLING_SPEED_LIMIT;
+ if (scrollingSpeed == 0) {
+ // Do nothing
+ return 0;
+ } else if (scrollingSpeed > 0) {
+ if (scrollingSpeed < maxScrollDistance)
+ y_offset += scrollingSpeed;
+ else
+ y_offset += maxScrollDistance;
+ scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
+ } else if (scrollingSpeed < 0) {
+ if (abs(scrollingSpeed) < maxScrollDistance)
+ y_offset += scrollingSpeed;
+ else
+ y_offset -= maxScrollDistance;
+ scrollingSpeed += SCROLLING_SPEED_DECREMENT;
+ }
+ if (abs(scrollingSpeed) < SCROLLING_FLOOR)
+ scrollingSpeed = 0;
+ HandleScrolling();
+ mUpdate = 1;
+
+ return 0;
+}
+
+size_t GUIScrollList::HitTestItem(int x, int y)
+{
+ // We only care about y position
+ if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH)
+ return NO_ITEM;
+
+ int startSelection = (y - mRenderY - mHeaderH);
+
+ // Locate the correct item
+ size_t actualSelection = firstDisplayedItem;
+ int selectY = y_offset;
+ while (selectY + actualItemHeight < startSelection) {
+ selectY += actualItemHeight;
+ actualSelection++;
+ }
+
+ if (actualSelection < GetItemCount())
+ return actualSelection;
+
+ return NO_ITEM;
+}
+
+int GUIScrollList::NotifyTouch(TOUCH_STATE state, int x, int y)
+{
+ if(!isConditionTrue())
+ return -1;
+
+ switch (state)
+ {
+ case TOUCH_START:
+ if (hasScroll && x >= mRenderX + mRenderW - mFastScrollW)
+ fastScroll = 1; // Initial touch is in the fast scroll region
+ if (scrollingSpeed != 0) {
+ selectedItem = NO_ITEM; // this allows the user to tap the list to stop the scrolling without selecting the item they tap
+ scrollingSpeed = 0; // stop scrolling on a new touch
+ } else if (!fastScroll) {
+ // find out which item the user touched
+ selectedItem = HitTestItem(x, y);
+ }
+ if (selectedItem != NO_ITEM)
+ mUpdate = 1;
+ lastY = last2Y = y;
+ break;
+
+ case TOUCH_DRAG:
+ if (fastScroll)
+ {
+ int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
+ int totalSize = GetItemCount();
+ int lines = GetDisplayItemCount();
+
+ float l = float((totalSize-lines)*pct)/100;
+ if(l + lines >= totalSize)
+ {
+ firstDisplayedItem = totalSize - lines;
+ if (GetDisplayRemainder() != 0) {
+ // There's a partial row displayed, set the scrolling offset so that the last item really is at the very bottom
+ firstDisplayedItem--;
+ y_offset = GetDisplayRemainder() - actualItemHeight;
+ } else {
+ // There's no partial row so zero out the offset
+ y_offset = 0;
+ }
+ }
+ else
+ {
+ if (l < 0)
+ l = 0;
+ firstDisplayedItem = l;
+ y_offset = -(l - int(l))*actualItemHeight;
+ if (GetDisplayRemainder() != 0) {
+ // There's a partial row displayed, make sure y_offset doesn't go past the max
+ if (firstDisplayedItem == totalSize - lines - 1 && y_offset < GetDisplayRemainder() - actualItemHeight)
+ y_offset = GetDisplayRemainder() - actualItemHeight;
+ } else if (firstDisplayedItem == totalSize - lines)
+ y_offset = 0;
+ }
+
+ selectedItem = NO_ITEM;
+ mUpdate = 1;
+ scrollingSpeed = 0; // prevent kinetic scrolling when using fast scroll
+ break;
+ }
+
+ // Provide some debounce on initial touches
+ if (selectedItem != NO_ITEM && abs(y - lastY) < touchDebounce) {
+ mUpdate = 1;
+ break;
+ }
+
+ selectedItem = NO_ITEM; // nothing is selected because we dragged too far
+ // Handle scrolling
+ if (hasScroll) {
+ y_offset += y - lastY; // adjust the scrolling offset based on the difference between the starting touch and the current touch
+ last2Y = lastY; // keep track of previous y locations so that we can tell how fast to scroll for kinetic scrolling
+ lastY = y; // update last touch to the current touch so we can tell how far and what direction we scroll for the next touch event
+
+ HandleScrolling();
+ } else
+ y_offset = 0;
+ mUpdate = 1;
+ break;
+
+ case TOUCH_RELEASE:
+ fastScroll = 0;
+ if (selectedItem != NO_ITEM) {
+ // We've selected an item!
+ NotifySelect(selectedItem);
+ mUpdate = 1;
+
+ DataManager::Vibrate("tw_button_vibrate");
+ selectedItem = NO_ITEM;
+ } else {
+ // Start 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;
+}
+
+void GUIScrollList::HandleScrolling()
+{
+ // handle dragging downward, scrolling upward
+ // the offset should always be <= 0 and > -actualItemHeight, adjust the first display row and offset as needed
+ while(firstDisplayedItem && y_offset > 0) {
+ firstDisplayedItem--;
+ y_offset -= actualItemHeight;
+ }
+ if (firstDisplayedItem == 0 && y_offset > 0)
+ y_offset = 0; // user kept dragging downward past the top of the list, so always reset the offset to 0 since we can't scroll any further in this direction
+
+ // handle dragging upward, scrolling downward
+ int totalSize = GetItemCount();
+ int lines = GetDisplayItemCount(); // number of full lines our list can display at once
+ int bottom_offset = GetDisplayRemainder() - actualItemHeight; // extra display area that can display a partial line for per pixel scrolling
+
+ // the offset should always be <= 0 and > -actualItemHeight, adjust the first display row and offset as needed
+ while (firstDisplayedItem + lines + (bottom_offset ? 1 : 0) < totalSize && abs(y_offset) > actualItemHeight) {
+ firstDisplayedItem++;
+ y_offset += actualItemHeight;
+ }
+ // Check if we dragged too far, set the list at the bottom and adjust offset as needed
+ if (bottom_offset != 0 && firstDisplayedItem + lines + 1 >= totalSize && y_offset <= bottom_offset) {
+ firstDisplayedItem = totalSize - lines - 1;
+ y_offset = bottom_offset;
+ } else if (firstDisplayedItem + lines >= totalSize && y_offset < 0) {
+ firstDisplayedItem = totalSize - lines;
+ y_offset = 0;
+ }
+}
+
+int GUIScrollList::GetDisplayItemCount()
+{
+ return (mRenderH - mHeaderH) / (actualItemHeight);
+}
+
+int GUIScrollList::GetDisplayRemainder()
+{
+ return (mRenderH - mHeaderH) % actualItemHeight;
+}
+
+int GUIScrollList::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 (mLastHeaderValue != newValue) {
+ mLastHeaderValue = newValue;
+ firstDisplayedItem = 0;
+ y_offset = 0;
+ scrollingSpeed = 0; // stop kinetic scrolling on variable changes
+ mUpdate = 1;
+ }
+ }
+ return 0;
+}
+
+int GUIScrollList::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 GUIScrollList::SetPageFocus(int inFocus)
+{
+ if (inFocus) {
+ NotifyVarChange("", ""); // This forces a check for the header text
+ scrollingSpeed = 0; // stop kinetic scrolling on page changes
+ mUpdate = 1;
+ }
+}