From a398c2846aa86650aa386a68cb51929477b6aa23 Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Mon, 21 Jun 2010 06:04:19 +0000 Subject: 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/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 ++++++++----------------------- 7 files changed, 215 insertions(+), 147 deletions(-) create mode 100644 apps/gui/skin_engine/skin_touchsupport.c (limited to 'apps/gui') 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. */ -- cgit v1.2.3