touchscreen: Port skin engine to gesture API

Use the gesture API for improved reliability.

Change-Id: I44c4e124132605ecf4f1499f97defd7b4b2d78e8
This commit is contained in:
Aidan MacDonald 2022-04-24 12:17:26 +01:00 committed by Solomon Peachy
parent 0f99defe1f
commit 010d22ed29
4 changed files with 268 additions and 256 deletions

View file

@ -119,6 +119,7 @@ static void gui_skin_reset(struct gui_skin *skin)
skin->data.tree = -1; skin->data.tree = -1;
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
skin->data.touchregions = -1; skin->data.touchregions = -1;
gesture_reset(&skin->data.gesture);
#endif #endif
#ifdef HAVE_SKIN_VARIABLES #ifdef HAVE_SKIN_VARIABLES
skin->data.skinvars = -1; skin->data.skinvars = -1;

View file

@ -1284,7 +1284,6 @@ static int parse_progressbar_tag(struct skin_element* element,
region->allow_while_locked = false; region->allow_while_locked = false;
region->press_length = PRESS; region->press_length = PRESS;
region->last_press = -1; region->last_press = -1;
region->armed = false;
region->bar = PTRTOSKINOFFSET(skin_buffer, pb); region->bar = PTRTOSKINOFFSET(skin_buffer, pb);
region->label = PTRTOSKINOFFSET(skin_buffer, NULL); region->label = PTRTOSKINOFFSET(skin_buffer, NULL);
@ -1781,13 +1780,13 @@ static int parse_touchregion(struct skin_element *element,
p++; p++;
region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp); region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
region->armed = false;
region->reverse_bar = false; region->reverse_bar = false;
region->value = 0; region->value = 0;
region->last_press = -1; region->last_press = -1;
region->press_length = PRESS; region->press_length = PRESS;
region->allow_while_locked = false; region->allow_while_locked = false;
region->bar = PTRTOSKINOFFSET(skin_buffer, NULL); region->bar = PTRTOSKINOFFSET(skin_buffer, NULL);
action = get_param_text(element, p++); action = get_param_text(element, p++);
/* figure out the action */ /* figure out the action */

View file

@ -37,16 +37,7 @@
/** Disarms all touchregions. */ /** Disarms all touchregions. */
void skin_disarm_touchregions(struct gui_wps *gwps) void skin_disarm_touchregions(struct gui_wps *gwps)
{ {
struct wps_data *data = gwps->data; gesture_reset(&gwps->data->gesture);
char* skin_buffer = get_skin_buffer(data);
struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions);
while (regions)
{
struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token);
struct touchregion *region = SKINOFFSETTOPTR(skin_buffer, token->value.data);
region->armed = false;
regions = SKINOFFSETTOPTR(skin_buffer, regions->next);
}
} }
/* Get the touched action. /* Get the touched action.
@ -56,272 +47,293 @@ void skin_disarm_touchregions(struct gui_wps *gwps)
int skin_get_touchaction(struct gui_wps *gwps, int* edge_offset) int skin_get_touchaction(struct gui_wps *gwps, int* edge_offset)
{ {
struct wps_data *data = gwps->data; struct wps_data *data = gwps->data;
int returncode = ACTION_NONE;
short x,y;
short vx, vy;
int type = action_get_touchscreen_press(&x, &y);
struct skin_viewport *wvp;
struct touchregion *r, *temp = NULL;
char* skin_buffer = get_skin_buffer(data); char* skin_buffer = get_skin_buffer(data);
bool repeated = (type == BUTTON_REPEAT); struct touchregion *region = NULL;
bool released = (type == BUTTON_REL); struct touchevent tevent;
bool pressed = (type == BUTTON_TOUCHSCREEN); struct gesture_event gevent;
struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions);
bool needs_repeat;
while (regions) action_get_touch_event(&tevent);
gesture_process(&data->gesture, &tevent);
struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions);
for (; regions && !region;
regions = SKINOFFSETTOPTR(skin_buffer, regions->next))
{ {
struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token); struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token);
r = SKINOFFSETTOPTR(skin_buffer, token->value.data); struct touchregion *r = SKINOFFSETTOPTR(skin_buffer, token->value.data);
wvp = SKINOFFSETTOPTR(skin_buffer, r->wvp); struct skin_viewport *wvp = SKINOFFSETTOPTR(skin_buffer, r->wvp);
/* make sure this region's viewport is visible */ /* make sure this region's viewport is visible */
if (wvp->hidden_flags&VP_DRAW_HIDDEN) if (wvp->hidden_flags & VP_DRAW_HIDDEN)
{
regions = SKINOFFSETTOPTR(skin_buffer, regions->next);
continue; continue;
}
/* unless it's allow_while_locked, ignore the region if locked
* (this is a special skin engine lock, different from softlock) */
if (data->touchscreen_locked && if (data->touchscreen_locked &&
(r->action != ACTION_TOUCH_SOFTLOCK && !r->allow_while_locked)) (r->action != ACTION_TOUCH_SOFTLOCK && !r->allow_while_locked))
{
regions = SKINOFFSETTOPTR(skin_buffer, regions->next);
continue; continue;
}
needs_repeat = r->press_length != PRESS;
/* check if it's inside this viewport */
if (viewport_point_within_vp(&(wvp->vp), x, y))
{ /* reposition the touch inside the viewport since touchregions
* are relative to a preceding viewport */
vx = x - wvp->vp.x;
vy = y - wvp->vp.y;
/* project touches in the padding region so they clamp to the /* check for a gesture inside the region's parent viewport */
* edge of the region instead */ if (!gesture_get_event_in_vp(&data->gesture, &gevent, &wvp->vp))
if(r->x - r->wpad <= vx && vx < r->x) continue;
vx = r->x;
else if(r->x + r->width <= vx && vx < r->x + r->width + r->wpad)
vx = r->x + r->width - 1;
if(r->y - r->hpad <= vy && vy < r->y)
vy = r->y;
else if(r->y + r->height <= vy && vy < r->y + r->height + r->hpad)
vy = r->y + r->height - 1;
/* now see if the point is inside this region */ /* project touches inside the padding box to the region edge */
if (vx >= r->x && vx < r->x+r->width && if (r->x - r->wpad <= gevent.ox && gevent.ox < r->x)
vy >= r->y && vy < r->y+r->height) gevent.ox = r->x;
else if (r->x + r->width <= gevent.ox && gevent.ox < r->x + r->width + r->wpad)
gevent.ox = r->x + r->width - 1;
if (r->y - r->hpad <= gevent.y && gevent.y < r->y)
gevent.oy = r->y;
else if (r->y + r->height <= gevent.oy && gevent.oy < r->y + r->height + r->hpad)
gevent.oy = r->y + r->height - 1;
/* ignore anything outside of the region */
if (gevent.ox < r->x || gevent.ox >= r->x + r->width)
continue;
if (gevent.oy < r->y || gevent.oy >= r->y + r->height)
continue;
/* convert coordinates to region-relative and clamp */
gevent.x -= r->x;
gevent.y -= r->y;
switch (r->action)
{
case ACTION_TOUCH_SCROLLBAR:
case ACTION_TOUCH_VOLUME:
case ACTION_TOUCH_SETTING:
/* we need something press-like */
if (!(gevent.id == GESTURE_TAP ||
gevent.id == GESTURE_LONG_PRESS ||
gevent.id == GESTURE_HOLD ||
gevent.id == GESTURE_DRAGSTART ||
gevent.id == GESTURE_DRAG))
break;
if (edge_offset)
{ {
/* reposition the touch within the area */ struct progressbar *bar = SKINOFFSETTOPTR(skin_buffer, r->bar);
vx -= r->x; bool reverse = r->reverse_bar || (bar && bar->invert_fill_direction);
vy -= r->y; int pos, lim;
switch(r->action) if (r->width > r->height) {
{ /* left to right by default */
case ACTION_TOUCH_SCROLLBAR: pos = MIN(MAX(0, gevent.x), r->width - 1);
case ACTION_TOUCH_VOLUME: lim = r->width;
case ACTION_TOUCH_SETTING: } else {
if (edge_offset) /* bottom up by default, so we need to add a reversal */
{ pos = MIN(MAX(0, gevent.y), r->height - 1);
struct progressbar *bar = lim = r->height;
SKINOFFSETTOPTR(skin_buffer, r->bar); reverse = !reverse;
if(r->width > r->height) {
if(r->width > 1)
*edge_offset = vx*1000/(r->width - 1);
else
*edge_offset = 0;
} else {
/* vertical bars are bottom-up by default */
if(r->height > 1)
*edge_offset = 1000 - vy*1000/(r->height - 1);
else
*edge_offset = 0;
}
if (r->reverse_bar || (bar && bar->invert_fill_direction))
*edge_offset = 1000 - *edge_offset;
}
temp = r;
returncode = r->action;
r->last_press = current_tick;
break;
default:
if (r->armed && ((repeated && needs_repeat) ||
(released && !needs_repeat)))
{
returncode = r->action;
temp = r;
}
if (pressed)
{
r->armed = true;
r->last_press = current_tick;
}
break;
} }
if (lim > 1)
*edge_offset = pos * 1000 / (lim - 1);
else
*edge_offset = 0;
if (reverse)
*edge_offset = 1000 - *edge_offset;
} }
region = r;
break;
default:
if (r->press_length == PRESS)
{
if (gevent.id != GESTURE_TAP)
break;
}
else if (r->press_length == LONG_PRESS)
{
if (gevent.id != GESTURE_LONG_PRESS)
break;
}
else /* REPEAT */
{
/* for repeat regions we allow dragging inside the region */
if (gevent.id != GESTURE_HOLD &&
gevent.id != GESTURE_DRAGSTART &&
gevent.id != GESTURE_DRAG)
break;
if (gevent.x < 0 || gevent.x >= r->width ||
gevent.y < 0 || gevent.y >= r->height)
break;
}
/* gesture is OK */
region = r;
break;
} }
regions = SKINOFFSETTOPTR(skin_buffer, regions->next);
} }
/* On release, all regions are disarmed. */ /* no region - pass the event upward */
if (released) if (!region)
skin_disarm_touchregions(gwps); return ACTION_TOUCHSCREEN;
if (temp && temp->press_length == LONG_PRESS)
temp->armed = false;
if (returncode != ACTION_NONE) int action = region->action;
region->last_press = tevent.tick;
if (global_settings.party_mode)
{ {
if (global_settings.party_mode) switch (action)
{ {
switch (returncode) case ACTION_WPS_PLAY:
{ case ACTION_WPS_SKIPPREV:
case ACTION_WPS_PLAY: case ACTION_WPS_SKIPNEXT:
case ACTION_WPS_SKIPPREV: case ACTION_WPS_STOP:
case ACTION_WPS_SKIPNEXT: action = ACTION_NONE;
case ACTION_WPS_STOP:
returncode = ACTION_NONE;
break;
default:
break;
}
}
switch (returncode)
{
case ACTION_TOUCH_SOFTLOCK:
data->touchscreen_locked = !data->touchscreen_locked;
returncode = ACTION_NONE;
break;
case ACTION_WPS_PLAY:
if (!audio_status())
{
if ( global_status.resume_index != -1 )
{
if (playlist_resume() != -1)
{
playlist_start(global_status.resume_index,
global_status.resume_elapsed,
global_status.resume_offset);
}
}
else
{
splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
}
}
else
{
wps_do_playpause(false);
}
returncode = ACTION_REDRAW;
break;
case ACTION_WPS_SKIPPREV:
audio_prev();
returncode = ACTION_REDRAW;
break;
case ACTION_WPS_SKIPNEXT:
audio_next();
returncode = ACTION_REDRAW;
break;
case ACTION_WPS_STOP:
audio_stop();
returncode = ACTION_REDRAW;
break;
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_DEC:
{
const struct settings_list *setting =
temp->setting_data.setting;
option_select_next_val(setting,
returncode == ACTION_SETTINGS_DEC,
true);
returncode = ACTION_REDRAW;
}
break; break;
case ACTION_SETTINGS_SET: default:
{
struct touchsetting *data = &temp->setting_data;
const struct settings_list *s = data->setting;
void (*f)(int) = NULL;
switch (s->flags&F_T_MASK)
{
case F_T_CUSTOM:
s->custom_setting
->load_from_cfg(s->setting, SKINOFFSETTOPTR(skin_buffer, data->value.text));
break;
case F_T_INT:
case F_T_UINT:
*(int*)s->setting = data->value.number;
if ((s->flags & F_T_SOUND) == F_T_SOUND)
sound_set(s->sound_setting->setting, data->value.number);
else if (s->flags&F_CHOICE_SETTING)
f = s->choice_setting->option_callback;
else if (s->flags&F_TABLE_SETTING)
f = s->table_setting->option_callback;
else
f = s->int_setting->option_callback;
if (f)
f(data->value.number);
break;
case F_T_BOOL:
*(bool*)s->setting = data->value.number ? true : false;
if (s->bool_setting->option_callback)
s->bool_setting
->option_callback(data->value.number ? true : false);
break;
}
returncode = ACTION_REDRAW;
}
break;
case ACTION_TOUCH_MUTE:
{
const int min_vol = sound_min(SOUND_VOLUME);
if (global_status.volume == min_vol)
global_status.volume = temp->value;
else
{
temp->value = global_status.volume;
global_status.volume = min_vol;
}
setvol();
returncode = ACTION_REDRAW;
}
break;
case ACTION_TOUCH_SHUFFLE: /* toggle shuffle mode */
{
global_settings.playlist_shuffle =
!global_settings.playlist_shuffle;
replaygain_update();
if (global_settings.playlist_shuffle)
playlist_randomise(NULL, current_tick, true);
else
playlist_sort(NULL, true);
returncode = ACTION_REDRAW;
}
break;
case ACTION_TOUCH_REPMODE: /* cycle the repeat mode setting */
{
const struct settings_list *rep_setting =
find_setting(&global_settings.repeat_mode);
option_select_next_val(rep_setting, false, true);
audio_flush_and_reload_tracks();
returncode = ACTION_REDRAW;
}
break;
case ACTION_TOUCH_SETTING:
{
struct progressbar *bar =
SKINOFFSETTOPTR(skin_buffer, temp->bar);
if (bar && edge_offset)
{
int val, count;
get_setting_info_for_bar(bar->setting, bar->setting_offset, &count, &val);
val = *edge_offset * count / 1000;
update_setting_value_from_touch(bar->setting, bar->setting_offset, val);
}
}
break; break;
} }
return returncode;
} }
return ACTION_TOUCHSCREEN; switch (action)
{
case ACTION_TOUCH_SOFTLOCK:
data->touchscreen_locked = !data->touchscreen_locked;
action = ACTION_NONE;
break;
case ACTION_WPS_PLAY:
if (!audio_status())
{
if ( global_status.resume_index != -1 )
{
if (playlist_resume() != -1)
{
playlist_start(global_status.resume_index,
global_status.resume_elapsed,
global_status.resume_offset);
}
}
else
{
splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
}
}
else
{
wps_do_playpause(false);
}
action = ACTION_REDRAW;
break;
case ACTION_WPS_SKIPPREV:
audio_prev();
action = ACTION_REDRAW;
break;
case ACTION_WPS_SKIPNEXT:
audio_next();
action = ACTION_REDRAW;
break;
case ACTION_WPS_STOP:
audio_stop();
action = ACTION_REDRAW;
break;
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_DEC:
{
const struct settings_list *setting = region->setting_data.setting;
bool decrement = (action == ACTION_SETTINGS_DEC);
option_select_next_val(setting, decrement, true);
action = ACTION_REDRAW;
} break;
case ACTION_SETTINGS_SET:
{
struct touchsetting *data = &region->setting_data;
const struct settings_list *s = data->setting;
void (*f)(int) = NULL;
switch (s->flags & F_T_MASK)
{
case F_T_CUSTOM:
s->custom_setting
->load_from_cfg(s->setting, SKINOFFSETTOPTR(skin_buffer, data->value.text));
break;
case F_T_INT:
case F_T_UINT:
*(int*)s->setting = data->value.number;
if ((s->flags & F_T_SOUND) == F_T_SOUND)
sound_set(s->sound_setting->setting, data->value.number);
else if (s->flags&F_CHOICE_SETTING)
f = s->choice_setting->option_callback;
else if (s->flags&F_TABLE_SETTING)
f = s->table_setting->option_callback;
else
f = s->int_setting->option_callback;
if (f)
f(data->value.number);
break;
case F_T_BOOL:
*(bool*)s->setting = data->value.number ? true : false;
if (s->bool_setting->option_callback)
s->bool_setting
->option_callback(data->value.number ? true : false);
break;
}
action = ACTION_REDRAW;
} break;
case ACTION_TOUCH_MUTE:
{
const int min_vol = sound_min(SOUND_VOLUME);
if (global_status.volume == min_vol)
global_status.volume = region->value;
else
{
region->value = global_status.volume;
global_status.volume = min_vol;
}
setvol();
action = ACTION_REDRAW;
} break;
case ACTION_TOUCH_SHUFFLE:
global_settings.playlist_shuffle = !global_settings.playlist_shuffle;
replaygain_update();
if (global_settings.playlist_shuffle)
playlist_randomise(NULL, current_tick, true);
else
playlist_sort(NULL, true);
action = ACTION_REDRAW;
break;
case ACTION_TOUCH_REPMODE:
{
const struct settings_list *rep_setting =
find_setting(&global_settings.repeat_mode);
option_select_next_val(rep_setting, false, true);
audio_flush_and_reload_tracks();
action = ACTION_REDRAW;
} break;
case ACTION_TOUCH_SETTING:
{
struct progressbar *bar = SKINOFFSETTOPTR(skin_buffer, region->bar);
if (bar && edge_offset)
{
int val, count;
get_setting_info_for_bar(bar->setting, 0, &count, &val);
val = *edge_offset * count / 1000;
update_setting_value_from_touch(bar->setting, 0, val);
}
action = ACTION_NONE;
} break;
}
return action;
} }

View file

@ -27,6 +27,7 @@
#include "tag_table.h" #include "tag_table.h"
#include "skin_parser.h" #include "skin_parser.h"
#include "gesture.h"
#ifndef __PCTOOL__ #ifndef __PCTOOL__
#include "core_alloc.h" #include "core_alloc.h"
#endif #endif
@ -218,8 +219,6 @@ struct touchregion {
int16_t hpad; /* padding to height */ int16_t hpad; /* padding to height */
bool reverse_bar; /* if true 0% is the left or top */ bool reverse_bar; /* if true 0% is the left or top */
bool allow_while_locked; bool allow_while_locked;
bool armed; /* A region is armed on press. Only armed regions are triggered
on repeat or release. */
enum { enum {
PRESS, /* quick press only */ PRESS, /* quick press only */
LONG_PRESS, /* Long press without repeat */ LONG_PRESS, /* Long press without repeat */
@ -371,6 +370,7 @@ struct wps_data
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
bool touchscreen_locked; bool touchscreen_locked;
OFFSETTYPE(struct skin_token_list *) touchregions; OFFSETTYPE(struct skin_token_list *) touchregions;
struct gesture gesture;
#endif #endif
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
OFFSETTYPE(struct skin_albumart *) albumart; OFFSETTYPE(struct skin_albumart *) albumart;