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
This commit is contained in:
@@ -25,7 +25,8 @@ LOCAL_SRC_FILES := \
|
||||
input.cpp \
|
||||
blanktimer.cpp \
|
||||
partitionlist.cpp \
|
||||
mousecursor.cpp
|
||||
mousecursor.cpp \
|
||||
scrolllist.cpp
|
||||
|
||||
ifneq ($(TWRP_CUSTOM_KEYBOARD),)
|
||||
LOCAL_SRC_FILES += $(TWRP_CUSTOM_KEYBOARD)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
775
gui/listbox.cpp
775
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 @@ extern "C" {
|
||||
#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 @@ GUIListBox::GUIListBox(xml_node<>* node) : GUIObject(node)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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(xml_node<>* node) : GUIObject(node)
|
||||
|
||||
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 @@ int GUIListBox::Update(void)
|
||||
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;
|
||||
}
|
||||
|
||||
295
gui/objects.hpp
295
gui/objects.hpp
@@ -501,11 +501,17 @@ protected:
|
||||
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
|
||||
@@ -530,6 +536,106 @@ public:
|
||||
// SetPageFocus - Notify when a page gains or loses focus
|
||||
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;
|
||||
@@ -544,96 +650,46 @@ protected:
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -641,90 +697,38 @@ protected:
|
||||
unsigned int selected;
|
||||
};
|
||||
|
||||
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 @@ protected:
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
709
gui/scrolllist.cpp
Normal file
709
gui/scrolllist.cpp
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user