summaryrefslogblamecommitdiffstats
path: root/gui/listbox.cpp
blob: 888947b290141880a95031d3c3377ce375248cee (plain) (tree)




























































































































































































































































































































































































                                                                                                                                   
// ListBox.cpp - GUIListBox object

#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 "../common.h"
#include "../roots.h"
#include "../minuitwrp/minui.h"
#include "../recovery_ui.h"
}

#include "rapidxml.hpp"
#include "objects.hpp"
#include "../data.hpp"

GUIListBox::GUIListBox(xml_node<>* node)
{
    xml_attribute<>* attr;
    xml_node<>* child;

    mStart = mLineSpacing = mIconWidth = mIconHeight = 0;
    mIconSelected = mIconUnselected = mBackground = mFont = NULL;
    mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
    mUpdate = 0;
    ConvertStrToColor("black", &mBackgroundColor);
    ConvertStrToColor("white", &mFontColor);
    
    child = node->first_node("icon");
    if (child)
    {
        attr = child->first_attribute("selected");
        if (attr)
            mIconSelected = PageManager::FindResource(attr->value());
        attr = child->first_attribute("unselected");
        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);
        }
    }

    // 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);
        }

        attr = child->first_attribute("spacing");
        if (attr) {
			string parsevalue = gui_parse_text(attr->value());
            mLineSpacing = atoi(parsevalue.c_str());
		}
    }

    // Handle the result variable
    child = node->first_node("data");
    if (child)
    {
        attr = child->first_attribute("name");
        if (attr)
            mVariable = attr->value();
        attr = child->first_attribute("default");
        if (attr)
            DataManager::SetValue(mVariable, attr->value());
    }

    // Retrieve the line height
    gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
    mLineHeight = mFontHeight;
    if (mIconSelected && mIconSelected->GetResource())
    {
        if (gr_get_height(mIconSelected->GetResource()) > mLineHeight)
            mLineHeight = gr_get_height(mIconSelected->GetResource());
        mIconWidth = gr_get_width(mIconSelected->GetResource());
        mIconHeight = gr_get_height(mIconSelected->GetResource());
    }
    if (mIconUnselected && mIconUnselected->GetResource())
    {
        if (gr_get_height(mIconUnselected->GetResource()) > mLineHeight)
            mLineHeight = gr_get_height(mIconUnselected->GetResource());
        mIconWidth = gr_get_width(mIconUnselected->GetResource());
        mIconHeight = gr_get_height(mIconUnselected->GetResource());
    }
        
    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)
    {
        ListData data;

		attr = child->first_attribute("name");
        if (!attr) return;
        data.displayName = attr->value();

		data.variableValue = child->value();
		if (child->value() == currentValue)
			data.selected = 1;
		else
			data.selected = 0;

        mList.push_back(data);

        child = child->next_sibling("listitem");
    }

	// Call this to get the selected item to be shown in the list on first render
	NotifyVarChange(mVariable, currentValue);
}

GUIListBox::~GUIListBox()
{
}

int GUIListBox::Render(void)
{	
	// First step, fill background
    gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
    gr_fill(mRenderX, mRenderY, mRenderW, mRenderH);

    // 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);
    }

    // Now, we need the lines (icon + text)
    gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha);

    // This tells us how many lines we can actually render
    int lines = mRenderH / (mLineHeight + mLineSpacing);
    int line;

    int listSize = mList.size();

    if (listSize < lines)  lines = listSize;

    void* fontResource = NULL;
    if (mFont)  fontResource = mFont->GetResource();

    int yPos = mRenderY + (mLineSpacing / 2);
    for (line = 0; line < lines; line++)
    {
        Resource* icon;
        std::string label;

        label = mList.at(line + mStart).displayName;
		if (mList.at(line + mStart).selected != 0)
        {
            icon = mIconSelected;
        }
        else
        {
            icon = mIconUnselected;
        }

        if (icon && icon->GetResource())
        {
            gr_blit(icon->GetResource(), 0, 0, mIconWidth, mIconHeight, mRenderX, (yPos + (int)((mLineHeight - mIconHeight) / 2)));
        }
        gr_textExW(mRenderX + mIconWidth + 5, yPos, label.c_str(), fontResource, mRenderX + mRenderW - mIconWidth - 5);

        // Move the yPos
        yPos += mLineHeight + mLineSpacing;
    }

    mUpdate = 0;
    return 0;
}

int GUIListBox::Update(void)
{
    if (mUpdate)
    {
        mUpdate = 0;
        if (Render() == 0)
			return 2;
    }
    return 0;
}

int GUIListBox::GetSelection(int x, int y)
{
    // We only care about y position
    return (y - mRenderY) / (mLineHeight + mLineSpacing);
}

int GUIListBox::NotifyTouch(TOUCH_STATE state, int x, int y)
{
    static int startSelection = -1;
    static int startY = 0;
    int selection = 0;

    switch (state)
    {
    case TOUCH_START:
        startSelection = GetSelection(x,y);
        startY = y;
        break;

    case TOUCH_DRAG:
        // Check if we dragged out of the selection window
        selection = GetSelection(x,y);
        if (startSelection != selection)
        {
            startSelection = -1;

            // Handle scrolling
            if (y > (int) (startY + (mLineHeight + mLineSpacing)))
            {
                if (mStart)     mStart--;
                mUpdate = 1;
                startY = y;
            }
            else if (y < (int) (startY - (mLineHeight + mLineSpacing)))
            {
                int listSize = mList.size();
                int lines = mRenderH / (mLineHeight + mLineSpacing);

                if (mStart + lines < listSize)     mStart++;
                mUpdate = 1;
                startY = y;
            }
        }
        break;

    case TOUCH_RELEASE:
        if (startSelection >= 0)
        {
            // We've selected an item!
            std::string str;

            int listSize = mList.size();

            // Move the selection to the proper place in the array
            startSelection += mStart;

            if (startSelection < listSize)
            {
                if (!mVariable.empty())
                {
                    int i;
					for (i=0; i<listSize; i++)
						mList.at(i).selected = 0;

					str = mList.at(startSelection).variableValue;
					mList.at(startSelection).selected = 1;
                    DataManager::SetValue(mVariable, str);
					mUpdate = 1;
                }
            }
        }
	case TOUCH_HOLD:
	case TOUCH_REPEAT:
        break;
    }
    return 0;
}

int GUIListBox::NotifyVarChange(std::string varName, std::string value)
{
    string checkValue;
	int var_changed = 0;

	if (varName.empty())
    {
		DataManager::GetValue(mVariable, checkValue);
		if (checkValue != currentValue) {
			varName = mVariable;
			value = checkValue;
			currentValue = checkValue;
			var_changed = 1;
		}
    }
    if (varName == mVariable || var_changed != 0)
    {
        int i, listSize = mList.size(), selected_index = 0;

		currentValue = value;

		for (i=0; i<listSize; i++) {
			if (mList.at(i).variableValue == 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;
		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)
    {
        mUpdate = 1;
    }
}