From c6a6593411b835036e9176c86483d7339914e6de Mon Sep 17 00:00:00 2001 From: jdgordon Date: Mon, 21 Jun 2010 06:04:19 +0000 Subject: [PATCH] Touchregion support for the Base Skin and FM Skins. display obviously needs to be in stylus mode for this to work. Just about all screens should be mostly useable if your sbs has the next/prev/select/cancel/menu regions defined. Plenty of room to add new action abilities if they are wanted. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27004 a1c6a512-1295-4272-9138-f99709370657 --- apps/SOURCES | 3 + apps/action.c | 10 +- apps/gui/bitmap/list.c | 3 +- apps/gui/skin_engine/skin_engine.h | 3 +- apps/gui/skin_engine/skin_touchsupport.c | 116 ++++++++++++++++++ apps/gui/statusbar-skinned.c | 34 ++++++ apps/gui/statusbar-skinned.h | 5 + apps/gui/viewport.c | 5 +- apps/gui/wps.c | 196 ++++++++----------------------- apps/radio/radio_skin.c | 26 +++- 10 files changed, 252 insertions(+), 149 deletions(-) create mode 100644 apps/gui/skin_engine/skin_touchsupport.c diff --git a/apps/SOURCES b/apps/SOURCES index 93ec93fe2..58186d215 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 cd76faafe..8f427c8d6 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 ae7b19821..fa015bf71 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 380b854d2..69991ab58 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 000000000..9c0cda779 --- /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 fcd4cfbd9..168b17fa3 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 eb27b0619..7925aa809 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 7b4419f10..9e07c0fe0 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 0a8ce899c..dafc1cd27 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 838d1f96d..c7994b313 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) -- 2.11.4.GIT