Subversion Repositories freemyipod

Rev

Rev 826 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

//
//
//    Copyright 2011 TheSeven
//
//
//    This file is part of emCORE.
//
//    emCORE 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 2 of the
//    License, or (at your option) any later version.
//
//    emCORE 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 emCORE.  If not, see <http://www.gnu.org/licenses/>.
//
//


#include "emcorelib.h"
#include "libui.h"
#include "settingchooser.h"
#include "chooser.h"
#include "chooser_renderer_list.h"
#include "chooser_action_handler_wheel.h"


static bool settingchooser_event_filter(struct chooser_data* data, enum button_event event,
                                        int which, int value)
{
    struct settingchooser_data* state = (struct settingchooser_data*)data->info->userparams;
    struct settingchooser_info* info = (struct settingchooser_info*)state->info;
    struct settingchooser_item* item = (struct settingchooser_item*)data->selected->user;
    struct chooser_renderer_list_itemdata* rp;
    rp = (struct chooser_renderer_list_itemdata*)data->selected->renderparams;
    bool redraw = false;
    bool handled = false;
    bool setcolors = false;
    switch (event)
    {
        case BUTTON_PRESS:
            switch (which)
            {
                case 0:
                    switch (item->type)
                    {
                        case SETTINGCHOOSER_TYPE_INTEGER:
                            handled = true;
                            setcolors = true;
                            state->editing = !state->editing;
                            if (state->editing) state->collect = 0;
                            break;
                    }
                    break;

                case 2:
                    if (state->editing)
                    {
                        handled = true;
                        setcolors = true;
                        state->editing = false;
                    }
                    break;

                default:
                    handled = state->editing;
                    break;
            }
            break;
            
        case WHEEL_MOVED_ACCEL:
            if (state->editing)
            {
                switch (item->type)
                {
                    case SETTINGCHOOSER_TYPE_INTEGER:
                        handled = true;
                        state->collect += value;
                        int change = (state->collect * item->config.integer.step) / 128;
                        if (!change) break;
                        state->collect -= (change * 128) / item->config.integer.step;
                        int* setting = (int*)item->setting;
                        if (*setting + change < item->config.integer.min)
                            *setting = item->config.integer.min;
                        else if (*setting + change > item->config.integer.max)
                            *setting = item->config.integer.max;
                        else *setting += change;
                        if (item->validator) item->validator(item->setting);
                        state->changed = true;
                        redraw = true;
                        break;
                }
            }
            break;
    }
    if (setcolors)
    {
        if (state->editing)
        {
            rp->fill_color_selected = info->itemparams.fill_color_active;
            rp->text_color_selected = info->itemparams.text_color_active;
            rp->icon_selected_opacity = info->itemparams.icon_active_opacity;
        }
        else
        {
            rp->fill_color_selected = info->itemparams.fill_color_selected;
            rp->text_color_selected = info->itemparams.text_color_selected;
            rp->icon_selected_opacity = info->itemparams.icon_selected_opacity;
        }
        redraw = true;
    }
    if (redraw)
    {
        mutex_lock(&data->statemutex, TIMEOUT_BLOCK);
        data->redrawneeded = true;
        wakeup_signal(&data->eventwakeup);
        mutex_unlock(&data->statemutex);
    }
    return handled;
}

static struct chooser_action_handler_wheel_params settingchooser_aparams =
{
    .version = CHOOSER_ACTION_HANDLER_WHEEL_PARAMS_VERSION,
    .stepsperitem = 128,
    .eventfilter = settingchooser_event_filter,
    .timeout_initial = TIMEOUT_BLOCK,
    .timeout_idle = TIMEOUT_BLOCK,
    .timeout_item = 0,
    .tick_force_redraw = true,
    .buttoncount = 5,
    .buttonmap =
    {
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_SELECT,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_NONE,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_CANCEL,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_NEXT,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_PREV
    }
};
static struct chooser_action_handler_wheel_params settingchooser_aparams2 =
{
    .version = CHOOSER_ACTION_HANDLER_WHEEL_PARAMS_VERSION,
    .stepsperitem = 128,
    .eventfilter = NULL,
    .timeout_initial = TIMEOUT_BLOCK,
    .timeout_idle = TIMEOUT_BLOCK,
    .timeout_item = 0,
    .tick_force_redraw = true,
    .buttoncount = 5,
    .buttonmap =
    {
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_SELECT,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_NONE,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_CANCEL,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_NEXT,
        CHOOSER_ACTION_HANDLER_WHEEL_ACTION_PREV
    }
};

static void settingchooser_render_preview(struct chooser_data* data,
                                          const struct chooser_item* item,
                                          bool selected, int x, int y)
{
    struct settingchooser_item* itemdata = (struct settingchooser_item*)item->user;
    int value = *((int*)itemdata->setting);
    const char* str = NULL;
    char buf[16];
    switch (itemdata->type)
    {
        case SETTINGCHOOSER_TYPE_INTEGER:
            if (itemdata->config.integer.tostring)
                itemdata->config.integer.tostring(buf, sizeof(buf), itemdata->setting, value);
            else snprintf(buf, sizeof(buf), "%d", value);
            str = buf;
            break;

        case SETTINGCHOOSER_TYPE_SELECT:
            if (value < itemdata->config.select.options->optioncount)
                str = itemdata->config.select.options->options[value].preview;
            break;
    }
    if (str) chooser_renderer_list_render_attached_text(data, item, selected, x, y, str);
}

static void settingchooser_populate_rp(const struct settingchooser_info* info,
                                       struct chooser_renderer_list_itemdata* rp)
{
    rp->size = info->itemparams.size;
    rp->fill_box = info->itemparams.fill_box;
    rp->fill_color = info->itemparams.fill_color;
    rp->fill_color_selected = info->itemparams.fill_color_selected;
    rp->icon_pos = info->itemparams.icon_pos;
    rp->icon_opacity = info->itemparams.icon_opacity;
    rp->icon_selected_opacity = info->itemparams.icon_selected_opacity;
    rp->text_pos = info->itemparams.text_pos;
    rp->text_color = info->itemparams.text_color;
    rp->text_color_selected = info->itemparams.text_color_selected;
}

bool settingchooser_run(const struct settingchooser_info* info)
{
    int i;
    bool rc = false;
    struct chooser_renderer_list_itemdata* rp;
    if (info->version != SETTINGCHOOSER_INFO_VERSION) return false;
    int allocsize = sizeof(struct settingchooser_data)
                  + sizeof(struct chooser_info)
                  + sizeof(struct chooser_item) * (info->itemcount + 1)
                  + sizeof(struct chooser_renderer_list_itemdata) * (info->itemcount + 1);
    void* mem = malloc(allocsize);
    if (!mem) return false;
    memset(mem, 0, allocsize);
    void* ptr = mem;
    struct settingchooser_data* data = (struct settingchooser_data*)ptr;
    ptr += sizeof(struct settingchooser_data);
    struct chooser_info* chooser = (struct chooser_info*)ptr;
    ptr += sizeof(struct chooser_info);
    ptr += sizeof(struct chooser_item) * (info->itemcount + 1);
    for (i = 0; i < info->itemcount + 1; i++)
    {
        chooser->items[i].renderparams = (struct chooser_renderer_list_itemdata*)ptr;
        ptr += sizeof(struct chooser_renderer_list_itemdata);
    }
    data->info = info;
    chooser->version = CHOOSER_INFO_VERSION;
    chooser->actionhandler = &chooser_action_handler_wheel;
    chooser->actionhandlerparams = &settingchooser_aparams;
    chooser->renderer = &chooser_renderer_list;
    chooser->rendererparams = &info->rendererparams;
    chooser->userparams = data;
    chooser->tickinterval = info->tickinterval;
    chooser->itemcount = info->itemcount + 1;
    rp = (struct chooser_renderer_list_itemdata*)chooser->items[0].renderparams;
    settingchooser_populate_rp(info, rp);
    rp->text = info->returntext;
    rp->render = chooser_renderer_list_show_arrow_left;
    for (i = 0; i < info->itemcount; i++)
    {
        chooser->items[i + 1].user = &info->items[i];
        rp = (struct chooser_renderer_list_itemdata*)chooser->items[i + 1].renderparams;
        settingchooser_populate_rp(info, rp);
        rp->text = info->items[i].text;
        rp->icon = info->items[i].icon;
        rp->icon_selected = info->items[i].icon_selected;
        rp->render = settingchooser_render_preview;
    }
    while (true)
    {
        const struct chooser_item* result = chooser_run(chooser);
        if (!result) break;
        struct settingchooser_item* item = (struct settingchooser_item*)result->user;
        if (!item) break;
        chooser->defaultitem = result - chooser->items;
        const struct settingchooser_select_options* options = item->config.select.options;
        int allocsize2 = sizeof(struct chooser_info)
                       + sizeof(struct chooser_item) * (options->optioncount + 1)
                       + sizeof(struct chooser_renderer_list_itemdata)
                       * (options->optioncount + 1);
        void* mem2 = malloc(allocsize2);
        if (!mem2) continue;
        memset(mem2, 0, allocsize2);
        void* ptr = mem2;
        struct chooser_info* chooser2 = (struct chooser_info*)ptr;
        ptr += sizeof(struct chooser_info);
        ptr += sizeof(struct chooser_item) * (options->optioncount + 1);
        for (i = 0; i < options->optioncount + 1; i++)
        {
            chooser2->items[i].renderparams = (struct chooser_renderer_list_itemdata*)ptr;
            ptr += sizeof(struct chooser_renderer_list_itemdata);
        }
        chooser2->version = CHOOSER_INFO_VERSION;
        chooser2->actionhandler = &chooser_action_handler_wheel;
        chooser2->actionhandlerparams = &settingchooser_aparams;
        chooser2->renderer = &chooser_renderer_list;
        chooser2->rendererparams = &info->rendererparams;
        chooser2->userparams = data;
        chooser2->tickinterval = info->tickinterval;
        chooser2->itemcount = options->optioncount + 1;
        chooser2->defaultitem = *((int*)item->setting) + 1;
        rp = (struct chooser_renderer_list_itemdata*)chooser2->items[0].renderparams;
        settingchooser_populate_rp(info, rp);
        rp->text = "Cancel";
        rp->render = chooser_renderer_list_show_arrow_left;
        for (i = 0; i < options->optioncount; i++)
        {
            chooser2->items[i + 1].user = &options->options[i];
            rp = (struct chooser_renderer_list_itemdata*)chooser2->items[i + 1].renderparams;
            settingchooser_populate_rp(info, rp);
            rp->text = options->options[i].text;
            rp->icon = options->options[i].icon;
            rp->icon_selected = options->options[i].icon_selected;
        }
        result = chooser_run(chooser2);
        int value = result - chooser2->items;
        if (result && value && *((int*)item->setting) != value - 1)
        {
            data->changed = true;
            *((int*)item->setting) = value - 1;
            if (item->validator) item->validator(item->setting);
        }
        free(mem2);
    }
    rc = data->changed;
    free(mem);
    return rc;
}