Subversion Repositories freemyipod

Rev

Rev 504 | Rev 686 | 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 "chooser.h"


void chooser_button_handler(void* user, enum button_event event, int which, int value)
{
    struct chooser_data* data = (struct chooser_data*)user;
    switch (data->info->actionhandler->handleevent(data, event, which, value))
    {
    case CHOOSER_RESULT_REDRAW:
        mutex_lock(&data->statemutex, TIMEOUT_BLOCK);
        data->redrawneeded = true;
        wakeup_signal(&data->eventwakeup);
        mutex_unlock(&data->statemutex);
        break;
    case CHOOSER_RESULT_CANCEL:
        mutex_lock(&data->statemutex, TIMEOUT_BLOCK);
        data->canceled = true;
        wakeup_signal(&data->eventwakeup);
        mutex_unlock(&data->statemutex);
        break;
    case CHOOSER_RESULT_FINISHED:
        mutex_lock(&data->statemutex, TIMEOUT_BLOCK);
        data->finished = true;
        wakeup_signal(&data->eventwakeup);
        mutex_unlock(&data->statemutex);
        break;
    }
}

const struct chooser_item* chooser_run(const struct chooser_info* info)
{
    struct chooser_data data;
    const struct chooser_item* rc = NULL;
    if (info->version != CHOOSER_INFO_VERSION) goto done;
    if (!info->actionhandler) goto done;
    if (info->actionhandler->version != CHOOSER_ACTION_HANDLER_VERSION) goto done;
    if (!info->renderer) goto done;
    if (info->renderer->version != CHOOSER_RENDERER_VERSION) goto done;
    if (info->defaultitem >= info->itemcount) data.selected = &info->items[info->itemcount - 1];
    else data.selected = &info->items[info->defaultitem];
    data.info = info;
    data.redrawneeded = false;
    data.canceled = false;
    data.finished = false;
    data.position = 0;
    data.actionhandlerdata = NULL;
    data.rendererdata = NULL;
    mutex_init(&data.statemutex);
    wakeup_init(&data.eventwakeup);
    if (info->actionhandler->init)
        if (info->actionhandler->init(&data) < 0)
            goto done;
    data.selected = &info->items[info->defaultitem];
    int spi = info->actionhandler->stepsperitem(&data);
    data.position = info->defaultitem * spi + spi / 2;
    if (info->renderer->init)
        if (info->renderer->init(&data) < 0)
            goto destroy_actionhandler;
    struct button_hook_entry* hook = button_register_handler(chooser_button_handler, &data);
    if (!hook) goto destroy_renderer;
    long lasttick = USEC_TIMER;
    bool redrawneeded = true;
    while (true)
    {
        long sleeptime = lasttick + info->tickinterval - USEC_TIMER;
        if (sleeptime > 0 && !redrawneeded) wakeup_wait(&data.eventwakeup, sleeptime);
        mutex_lock(&data.statemutex, TIMEOUT_BLOCK);
        if (data.canceled) goto cancel;
        if (data.finished) goto finished;
        redrawneeded |= data.redrawneeded;
        data.redrawneeded = false;
        mutex_unlock(&data.statemutex);
        if ((long)(lasttick + info->tickinterval - USEC_TIMER) < 0)
        {
            if (info->actionhandler->handletick)
                switch (info->actionhandler->handletick(&data))
                {
                case CHOOSER_RESULT_REDRAW:
                    redrawneeded = true;
                    break;
                case CHOOSER_RESULT_CANCEL:
                    goto cancel;
                case CHOOSER_RESULT_FINISHED:
                    goto finished;
                }
            lasttick = USEC_TIMER;
        }
        if (redrawneeded) redrawneeded = info->renderer->render(&data) == CHOOSER_RESULT_REDRAW;
    }
cancel:
    data.selected = NULL;
finished:
    rc = data.selected;
destroy_buttonhook:
    button_unregister_handler(hook);
destroy_renderer:
    if (info->renderer->destroy)
        info->renderer->destroy(&data);
destroy_actionhandler:
    if (info->actionhandler->destroy)
        info->actionhandler->destroy(&data);
done:
    return rc;
}