diff --git a/apps/SOURCES b/apps/SOURCES index 93ec93fe27..58186d2154 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -102,6 +102,9 @@ gui/skin_engine/skin_fonts.c #endif gui/skin_engine/skin_parser.c gui/skin_engine/skin_tokens.c +#ifdef HAVE_TOUCHSCREEN +gui/skin_engine/skin_touchsupport.c +#endif #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) gui/backdrop.c diff --git a/apps/action.c b/apps/action.c index cd76faafec..8f427c8d68 100644 --- a/apps/action.c +++ b/apps/action.c @@ -38,6 +38,9 @@ #include "language.h" #endif #include "viewport.h" +#ifdef HAVE_TOUCHSCREEN +#include "statusbar-skinned.h" +#endif static int last_button = BUTTON_NONE|BUTTON_REL; /* allow the ipod wheel to work on startup */ @@ -320,7 +323,12 @@ static int get_action_worker(int context, int timeout, int get_action(int context, int timeout) { - return get_action_worker(context,timeout,NULL); + int button = get_action_worker(context,timeout,NULL); +#ifdef HAVE_TOUCHSCREEN + if (button == ACTION_TOUCHSCREEN) + button = sb_touch_to_button(context); +#endif + return button; } int get_custom_action(int context,int timeout, diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c index ae7b19821e..fa015bf71a 100644 --- a/apps/gui/bitmap/list.c +++ b/apps/gui/bitmap/list.c @@ -359,7 +359,8 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list) if (button == BUTTON_NONE) return ACTION_NONE; - if (x > list_text_vp->x + list_width) + /* make sure it is inside the UI viewport */ + if (!viewport_point_within_vp(list_text_vp, x, y)) /* wider than the list's viewport, ignore it */ return ACTION_NONE; diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h index 380b854d24..69991ab587 100644 --- a/apps/gui/skin_engine/skin_engine.h +++ b/apps/gui/skin_engine/skin_engine.h @@ -40,7 +40,8 @@ enum skinnable_screens { #ifdef HAVE_TOUCHSCREEN -int wps_get_touchaction(struct wps_data *data); +int skin_get_touchaction(struct wps_data *data, int* edge_offset); +void skin_disarm_touchregions(struct wps_data *data); #endif /* Do a update_type update of the skinned screen */ diff --git a/apps/gui/skin_engine/skin_touchsupport.c b/apps/gui/skin_engine/skin_touchsupport.c new file mode 100644 index 0000000000..9c0cda779a --- /dev/null +++ b/apps/gui/skin_engine/skin_touchsupport.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 - Jonathan Gordon + * + * This program 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. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include +#include "action.h" +#include "skin_engine.h" +#include "wps_internals.h" + +/** Disarms all touchregions. */ +void skin_disarm_touchregions(struct wps_data *data) +{ + struct skin_token_list *regions = data->touchregions; + while (regions) + { + ((struct touchregion *)regions->token->value.data)->armed = false; + regions = regions->next; + } +} + +/* Get the touched action. + * egde_offset is a percentage value for the position of the touch + * inside the bar for regions which arnt WPS_TOUCHREGION_ACTION type. + */ +int skin_get_touchaction(struct wps_data *data, int* edge_offset) +{ + int returncode = ACTION_NONE; + short x,y; + short vx, vy; + int type = action_get_touchscreen_press(&x, &y); + static int last_action = ACTION_NONE; + struct touchregion *r; + bool repeated = (type == BUTTON_REPEAT); + bool released = (type == BUTTON_REL); + bool pressed = (type == BUTTON_TOUCHSCREEN); + struct skin_token_list *regions = data->touchregions; + + while (regions) + { + r = (struct touchregion *)regions->token->value.data; + /* make sure this region's viewport is visible */ + if (r->wvp->hidden_flags&VP_DRAW_HIDDEN) + { + regions = regions->next; + continue; + } + /* check if it's inside this viewport */ + if (viewport_point_within_vp(&(r->wvp->vp), x, y)) + { /* reposition the touch inside the viewport since touchregions + * are relative to a preceding viewport */ + vx = x - r->wvp->vp.x; + vy = y - r->wvp->vp.y; + /* now see if the point is inside this region */ + if (vx >= r->x && vx < r->x+r->width && + vy >= r->y && vy < r->y+r->height) + { + /* reposition the touch within the area */ + vx -= r->x; + vy -= r->y; + + + switch(r->type) + { + case WPS_TOUCHREGION_ACTION: + if (r->armed && ((repeated && r->repeat) || (released && !r->repeat))) + { + last_action = r->action; + returncode = r->action; + } + if (pressed) + r->armed = true; + break; + default: + if (edge_offset) + { + if(r->width > r->height) + *edge_offset = vx*100/r->width; + else + *edge_offset = vy*100/r->height; + } + returncode = r->type; + break; + } + } + } + regions = regions->next; + } + + /* On release, all regions are disarmed. */ + if (released) + skin_disarm_touchregions(data); + + if (returncode != ACTION_NONE) + return returncode; + + last_action = ACTION_TOUCHSCREEN; + return ACTION_TOUCHSCREEN; +} diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c index fcd4cfbd9e..168b17fa38 100644 --- a/apps/gui/statusbar-skinned.c +++ b/apps/gui/statusbar-skinned.c @@ -21,6 +21,7 @@ #include "config.h" +#include "action.h" #include "system.h" #include "settings.h" #include "appevents.h" @@ -253,3 +254,36 @@ void sb_skin_init(void) sb_skin[i].sync_data = &sb_skin_sync_data; } } + +#ifdef HAVE_TOUCHSCREEN +static bool bypass_sb_touchregions = true; +void sb_bypass_touchregions(bool enable) +{ + bypass_sb_touchregions = enable; +} + +int sb_touch_to_button(int context) +{ + static int last_context = -1; + int button, offset; + if (bypass_sb_touchregions) + return ACTION_TOUCHSCREEN; + + if (last_context != context) + skin_disarm_touchregions(&sb_skin_data[SCREEN_MAIN]); + last_context = context; + button = skin_get_touchaction(&sb_skin_data[SCREEN_MAIN], &offset); + + switch (button) + { +#ifdef HAVE_VOLUME_IN_LIST + case ACTION_WPS_VOLUP: + return ACTION_LIST_VOLUP; + case ACTION_WPS_VOLDOWN: + return ACTION_LIST_VOLDOWN; +#endif + /* TODO */ + } + return button; +} +#endif diff --git a/apps/gui/statusbar-skinned.h b/apps/gui/statusbar-skinned.h index eb27b06196..7925aa8093 100644 --- a/apps/gui/statusbar-skinned.h +++ b/apps/gui/statusbar-skinned.h @@ -43,6 +43,11 @@ void sb_skin_update(enum screen_type screen, bool force); void sb_skin_set_update_delay(int delay); bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen); +#ifdef HAVE_TOUCHSCREEN +void sb_bypass_touchregions(bool enable); +int sb_touch_to_button(int context); +#endif + #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) char* sb_get_backdrop(enum screen_type screen); bool sb_set_backdrop(enum screen_type screen, char* filename); diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c index 7b4419f107..9e07c0fe08 100644 --- a/apps/gui/viewport.c +++ b/apps/gui/viewport.c @@ -169,6 +169,7 @@ static void toggle_theme(enum screen_type screen, bool force) screens[screen].set_viewport(NULL); } intptr_t force = first_boot?0:1; + send_event(GUI_EVENT_ACTIONUPDATE, (void*)force); } else @@ -182,7 +183,9 @@ static void toggle_theme(enum screen_type screen, bool force) send_event(GUI_EVENT_THEME_CHANGED, NULL); FOR_NB_SCREENS(i) was_enabled[i] = is_theme_enabled(i); - +#ifdef HAVE_TOUCHSCREEN + sb_bypass_touchregions(!is_theme_enabled(SCREEN_MAIN)); +#endif after_boot[screen] = true; } diff --git a/apps/gui/wps.c b/apps/gui/wps.c index 0a8ce899c5..dafc1cd278 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -85,10 +85,6 @@ static void wps_state_init(void); static void track_changed_callback(void *param); static void nextid3available_callback(void* param); -#ifdef HAVE_TOUCHSCREEN -static void wps_disarm_touchregions(struct wps_data *data); -#endif - #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps" #ifdef HAVE_REMOTE_LCD #define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps" @@ -227,6 +223,55 @@ static bool update_onvol_change(struct gui_wps * gwps) } +#ifdef HAVE_TOUCHSCREEN +int skintouch_to_wps(struct wps_data *data) +{ + int offset = 0; + int button = skin_get_touchaction(data, &offset); + switch (button) + { + case ACTION_STD_PREV: + return ACTION_WPS_SKIPPREV; + case ACTION_STD_PREVREPEAT: + return ACTION_WPS_SEEKBACK; + case ACTION_STD_NEXT: + return ACTION_WPS_SKIPNEXT; + case ACTION_STD_NEXTREPEAT: + return ACTION_WPS_SEEKFWD; + case ACTION_STD_MENU: + return ACTION_WPS_MENU; + case ACTION_STD_CONTEXT: + return ACTION_WPS_CONTEXT; + case ACTION_STD_QUICKSCREEN: + return ACTION_WPS_QUICKSCREEN; + case WPS_TOUCHREGION_SCROLLBAR: + wps_state.id3->elapsed = wps_state.id3->length*offset/100; + if (!wps_state.paused) +#if (CONFIG_CODEC == SWCODEC) + audio_pre_ff_rewind(); +#else + audio_pause(); +#endif + audio_ff_rewind(wps_state.id3->elapsed); +#if (CONFIG_CODEC != SWCODEC) + if (!wps_state.paused) + audio_resume(); +#endif + return ACTION_TOUCHSCREEN; + case WPS_TOUCHREGION_VOLUME: + { + const int min_vol = sound_min(SOUND_VOLUME); + const int max_vol = sound_max(SOUND_VOLUME); + global_settings.volume = (offset * (max_vol - min_vol)) / 100; + global_settings.volume += min_vol; + setvol(); + } + return ACTION_TOUCHSCREEN; + } + return button; +} +#endif + bool ffwd_rew(int button) { unsigned int step = 0; /* current ff/rewind step */ @@ -359,7 +404,7 @@ bool ffwd_rew(int button) button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,TIMEOUT_BLOCK); #ifdef HAVE_TOUCHSCREEN if (button == ACTION_TOUCHSCREEN) - button = wps_get_touchaction(gui_wps[SCREEN_MAIN].data); + button = skintouch_to_wps(gui_wps[SCREEN_MAIN].data); if (button != ACTION_WPS_SEEKFWD && button != ACTION_WPS_SEEKBACK) button = ACTION_WPS_STOPSEEK; @@ -616,150 +661,13 @@ static void gwps_enter_wps(void) skin_update(gwps, WPS_REFRESH_ALL); #ifdef HAVE_TOUCHSCREEN - wps_disarm_touchregions(gui_wps[i].data); + skin_disarm_touchregions(gui_wps[i].data); #endif } /* force statusbar/skin update since we just cleared the whole screen */ send_event(GUI_EVENT_ACTIONUPDATE, (void*)1); } -#ifdef HAVE_TOUCHSCREEN -/** Disarms all touchregions. */ -static void wps_disarm_touchregions(struct wps_data *data) -{ - struct skin_token_list *regions = data->touchregions; - while (regions) - { - ((struct touchregion *)regions->token->value.data)->armed = false; - regions = regions->next; - } -} - -int wps_get_touchaction(struct wps_data *data) -{ - int returncode = ACTION_NONE; - short x,y; - short vx, vy; - int type = action_get_touchscreen_press(&x, &y); - static int last_action = ACTION_NONE; - struct touchregion *r; - bool repeated = (type == BUTTON_REPEAT); - bool released = (type == BUTTON_REL); - bool pressed = (type == BUTTON_TOUCHSCREEN); - struct skin_token_list *regions = data->touchregions; - - while (regions) - { - r = (struct touchregion *)regions->token->value.data; - /* make sure this region's viewport is visible */ - if (r->wvp->hidden_flags&VP_DRAW_HIDDEN) - { - regions = regions->next; - continue; - } - /* check if it's inside this viewport */ - if (viewport_point_within_vp(&(r->wvp->vp), x, y)) - { /* reposition the touch inside the viewport since touchregions - * are relative to a preceding viewport */ - vx = x - r->wvp->vp.x; - vy = y - r->wvp->vp.y; - /* now see if the point is inside this region */ - if (vx >= r->x && vx < r->x+r->width && - vy >= r->y && vy < r->y+r->height) - { - /* reposition the touch within the area */ - vx -= r->x; - vy -= r->y; - - switch(r->type) - { - case WPS_TOUCHREGION_ACTION: - if (r->armed && ((repeated && r->repeat) || (released && !r->repeat))) - { - last_action = r->action; - returncode = r->action; - } - if (pressed) - r->armed = true; - break; - case WPS_TOUCHREGION_SCROLLBAR: - if(r->width > r->height) - /* landscape */ - wps_state.id3->elapsed = (vx * - wps_state.id3->length) / r->width; - else - /* portrait */ - wps_state.id3->elapsed = (vy * - wps_state.id3->length) / r->height; - - if (!wps_state.paused) -#if (CONFIG_CODEC == SWCODEC) - audio_pre_ff_rewind(); -#else - audio_pause(); -#endif - audio_ff_rewind(wps_state.id3->elapsed); -#if (CONFIG_CODEC != SWCODEC) - if (!wps_state.paused) - audio_resume(); -#endif - break; - case WPS_TOUCHREGION_VOLUME: - { - const int min_vol = sound_min(SOUND_VOLUME); - const int max_vol = sound_max(SOUND_VOLUME); - if(r->width > r->height) - /* landscape */ - global_settings.volume = (vx * - (max_vol - min_vol)) / r->width; - else - /* portrait */ - global_settings.volume = ((r->height - vy) * - (max_vol-min_vol)) / r->height; - - global_settings.volume += min_vol; - setvol(); - returncode = ACTION_REDRAW; - } - } - } - } - regions = regions->next; - } - - /* On release, all regions are disarmed. */ - if (released) - wps_disarm_touchregions(data); - - /* Now we need to convert buttons to the WPS context */ - switch (returncode) - { - case ACTION_STD_PREV: - return ACTION_WPS_SKIPPREV; - case ACTION_STD_PREVREPEAT: - return ACTION_WPS_SEEKBACK; - case ACTION_STD_NEXT: - return ACTION_WPS_SKIPNEXT; - case ACTION_STD_NEXTREPEAT: - return ACTION_WPS_SEEKFWD; - case ACTION_STD_MENU: - return ACTION_WPS_MENU; - case ACTION_STD_CONTEXT: - return ACTION_WPS_CONTEXT; - case ACTION_STD_QUICKSCREEN: - return ACTION_WPS_QUICKSCREEN; - } - - if (returncode != ACTION_NONE) - return returncode; - - - if ((last_action == ACTION_WPS_SEEKBACK || last_action == ACTION_WPS_SEEKFWD)) - return ACTION_WPS_STOPSEEK; - last_action = ACTION_TOUCHSCREEN; - return ACTION_TOUCHSCREEN; -} -#endif /* The WPS can be left in two ways: * a) call a function, which draws over the wps. In this case, the wps * will be still active (i.e. the below function didn't return) @@ -818,7 +726,7 @@ long gui_wps_show(void) exit = true; #ifdef HAVE_TOUCHSCREEN if (button == ACTION_TOUCHSCREEN) - button = wps_get_touchaction(gui_wps[SCREEN_MAIN].data); + button = skintouch_to_wps(gui_wps[SCREEN_MAIN].data); #endif /* The iPods/X5/M5 use a single button for the A-B mode markers, defined as ACTION_WPSAB_SINGLE in their config files. */ diff --git a/apps/radio/radio_skin.c b/apps/radio/radio_skin.c index 838d1f96da..c7994b3135 100644 --- a/apps/radio/radio_skin.c +++ b/apps/radio/radio_skin.c @@ -108,8 +108,32 @@ void fms_skin_init(void) int fms_do_button_loop(bool update_screen) { - return skin_wait_for_action(fms_skin, CONTEXT_FM, + int button = skin_wait_for_action(fms_skin, CONTEXT_FM, update_screen ? TIMEOUT_NOBLOCK : HZ); +#ifdef HAVE_TOUCHSCREEN + int offset; + if (button == ACTION_TOUCHSCREEN) + button = skin_get_touchaction(&fms_skin_data[SCREEN_MAIN], &offset); + switch (button) + { + case ACTION_WPS_STOP: + return ACTION_FM_STOP; + case ACTION_STD_CANCEL: + return ACTION_FM_EXIT; + case ACTION_WPS_VOLUP: + return ACTION_SETTINGS_INC; + case ACTION_WPS_VOLDOWN: + return ACTION_SETTINGS_DEC; + case ACTION_WPS_PLAY: + return ACTION_FM_PLAY; + case ACTION_STD_MENU: + return ACTION_FM_MENU; + case WPS_TOUCHREGION_SCROLLBAR: + /* TODO */ + break; + } +#endif + return button; } struct gui_wps *fms_get(enum screen_type screen)