Skip to content

Commit 95680d8

Browse files
authored
xmb improvements for mobile/touch (#18375)
1 parent 0a253e3 commit 95680d8

1 file changed

Lines changed: 184 additions & 1 deletion

File tree

menu/drivers/xmb.c

Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,19 @@ typedef struct xmb_handle
340340
xmb_node_t netplay_tab_node;
341341
menu_input_pointer_t pointer;
342342

343+
/* Touch drag state for direction locking */
344+
enum
345+
{
346+
XMB_DRAG_NONE,
347+
XMB_DRAG_DETECTING,
348+
XMB_DRAG_HORIZONTAL,
349+
XMB_DRAG_VERTICAL
350+
} drag_mode;
351+
float drag_start_x;
352+
float drag_start_y;
353+
float categories_drag_start_pos;
354+
size_t drag_start_selection;
355+
343356
font_data_t *font;
344357
font_data_t *font2;
345358
video_font_raster_block_t raster_block;
@@ -517,6 +530,7 @@ static int xmb_menu_entry_action(void *userdata,
517530
menu_entry_t *entry, size_t i, enum menu_action action);
518531
static bool xmb_load_image(void *userdata, void *data,
519532
enum menu_image_type type);
533+
static void xmb_navigation_set(void *data, bool scroll);
520534

521535

522536
static INLINE float xmb_item_y(const xmb_handle_t *xmb,
@@ -6782,6 +6796,123 @@ static void xmb_render(void *data,
67826796
/* Read pointer state */
67836797
menu_input_get_pointer_state(&xmb->pointer);
67846798

6799+
/* Direction locking for horizontal category dragging */
6800+
if (xmb->pointer.type == MENU_POINTER_TOUCHSCREEN)
6801+
{
6802+
if (xmb->pointer.flags & MENU_INP_PTR_FLG_PRESSED)
6803+
{
6804+
if (xmb->drag_mode == XMB_DRAG_DETECTING)
6805+
{
6806+
/* Wait for movement threshold before locking direction */
6807+
float dx = fabs((float)xmb->pointer.x - xmb->drag_start_x);
6808+
float dy = fabs((float)xmb->pointer.y - xmb->drag_start_y);
6809+
float threshold = 10.0f;
6810+
6811+
if (dx > threshold || dy > threshold)
6812+
{
6813+
/* Lock to dominant direction */
6814+
if (dx > dy)
6815+
xmb->drag_mode = XMB_DRAG_HORIZONTAL;
6816+
else
6817+
xmb->drag_mode = XMB_DRAG_VERTICAL;
6818+
}
6819+
}
6820+
6821+
if (xmb->drag_mode == XMB_DRAG_HORIZONTAL)
6822+
{
6823+
/* Only allow horizontal category switching at the top level (depth == 1)
6824+
* When in submenus (depth > 1), horizontal drag is disabled */
6825+
if (xmb->depth == 1)
6826+
{
6827+
/* Apply horizontal drag to categories */
6828+
size_t list_size = xmb_list_get_size(xmb, MENU_LIST_HORIZONTAL) + xmb->system_tab_end + 1;
6829+
float current_dx = (float)xmb->pointer.x - xmb->drag_start_x;
6830+
float min_x = -xmb->icon_spacing_horizontal * (float)(list_size > 0 ? list_size - 1 : 0);
6831+
float max_x = 0.0f;
6832+
6833+
xmb->categories_x_pos = xmb->categories_drag_start_pos + current_dx;
6834+
6835+
/* Bounds checking */
6836+
if (xmb->categories_x_pos > max_x)
6837+
xmb->categories_x_pos = max_x;
6838+
if (xmb->categories_x_pos < min_x)
6839+
xmb->categories_x_pos = min_x;
6840+
6841+
/* Update selection and switch categories during drag */
6842+
{
6843+
float normalized = -xmb->categories_x_pos / xmb->icon_spacing_horizontal;
6844+
size_t nearest = (size_t)(normalized + 0.5f);
6845+
6846+
/* Clamp to valid range */
6847+
if (nearest >= list_size)
6848+
nearest = list_size > 0 ? list_size - 1 : 0;
6849+
6850+
/* If category changed, do full switch */
6851+
if (nearest != xmb->categories_selection_ptr)
6852+
{
6853+
struct menu_state *menu_st = menu_state_get_ptr();
6854+
menu_list_t *menu_list = menu_st->entries.list;
6855+
file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0);
6856+
6857+
/* Determine direction */
6858+
enum menu_action action = (nearest > xmb->categories_selection_ptr)
6859+
? MENU_ACTION_RIGHT
6860+
: MENU_ACTION_LEFT;
6861+
6862+
/* Call list_cache to update state (increments/decrements by 1) */
6863+
if (menu_st->driver_ctx && menu_st->driver_ctx->list_cache)
6864+
menu_st->driver_ctx->list_cache(menu_st->userdata, MENU_LIST_HORIZONTAL, action);
6865+
6866+
/* Repopulate vertical list with new category content */
6867+
menu_driver_deferred_push_content_list(selection_buf);
6868+
6869+
/* Visual update without animation during drag */
6870+
xmb_list_switch_horizontal_list(xmb, false, 0);
6871+
}
6872+
}
6873+
}
6874+
}
6875+
else if (xmb->drag_mode == XMB_DRAG_VERTICAL)
6876+
{
6877+
/* Apply vertical drag to list selection */
6878+
struct menu_state *menu_st = menu_state_get_ptr();
6879+
menu_list_t *menu_list = menu_st->entries.list;
6880+
size_t list_size = MENU_LIST_GET_SELECTION(menu_list, 0)->size;
6881+
6882+
/* Calculate how many items to move based on drag distance */
6883+
float dy = (float)xmb->pointer.y - xmb->drag_start_y;
6884+
float item_height = xmb->icon_spacing_vertical;
6885+
6886+
/* Convert drag distance to item steps with threshold */
6887+
int steps = (int)((dy + (dy > 0 ? item_height * 0.5f : -item_height * 0.5f)) / item_height);
6888+
6889+
/* Calculate new selection (negative because dragging down = scroll up) */
6890+
int new_selection = (int)xmb->drag_start_selection - steps;
6891+
6892+
/* Clamp to valid range */
6893+
if (new_selection < 0)
6894+
new_selection = 0;
6895+
if (new_selection >= (int)list_size)
6896+
new_selection = list_size > 0 ? (int)list_size - 1 : 0;
6897+
6898+
/* Update selection if changed */
6899+
if ((size_t)new_selection != menu_st->selection_ptr)
6900+
{
6901+
file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0);
6902+
uintptr_t tag = (uintptr_t)selection_buf;
6903+
6904+
menu_st->selection_ptr = (size_t)new_selection;
6905+
6906+
/* Kill existing animations to prevent stacking during continuous drag */
6907+
gfx_animation_kill_by_tag(&tag);
6908+
6909+
/* Enable animations for smooth scrolling */
6910+
xmb_navigation_set(xmb, true);
6911+
}
6912+
}
6913+
}
6914+
}
6915+
67856916
/* If menu screensaver is active, update
67866917
* screensaver and return */
67876918
if (xmb->show_screensaver)
@@ -9701,6 +9832,26 @@ static bool xmb_menu_init_list(void *data)
97019832
return false;
97029833
}
97039834

9835+
static int xmb_pointer_down(void *userdata,
9836+
unsigned x, unsigned y,
9837+
unsigned ptr, menu_file_list_cbs_t *cbs,
9838+
menu_entry_t *entry, unsigned action)
9839+
{
9840+
xmb_handle_t *xmb = (xmb_handle_t*)userdata;
9841+
9842+
if (!xmb)
9843+
return -1;
9844+
9845+
/* Initialize drag detection */
9846+
xmb->drag_mode = XMB_DRAG_DETECTING;
9847+
xmb->drag_start_x = (float)x;
9848+
xmb->drag_start_y = (float)y;
9849+
xmb->categories_drag_start_pos = xmb->categories_x_pos;
9850+
xmb->drag_start_selection = menu_state_get_ptr()->selection_ptr;
9851+
9852+
return 0;
9853+
}
9854+
97049855
static int xmb_pointer_up(void *userdata,
97059856
unsigned x, unsigned y, unsigned ptr,
97069857
enum menu_input_pointer_gesture gesture,
@@ -9730,6 +9881,38 @@ static int xmb_pointer_up(void *userdata,
97309881
return 0;
97319882
}
97329883

9884+
/* Handle snap animation if we were dragging */
9885+
if (xmb->drag_mode == XMB_DRAG_HORIZONTAL || xmb->drag_mode == XMB_DRAG_VERTICAL)
9886+
{
9887+
/* Snap horizontal scrolling to final category position */
9888+
if (xmb->drag_mode == XMB_DRAG_HORIZONTAL)
9889+
{
9890+
settings_t *settings = config_get_ptr();
9891+
bool horizontal_animation = settings->bools.menu_horizontal_animation;
9892+
float target_x = xmb->icon_spacing_horizontal * -(float)xmb->categories_selection_ptr;
9893+
9894+
/* Animate to exact category position */
9895+
if (horizontal_animation)
9896+
{
9897+
gfx_animation_ctx_entry_t anim_entry;
9898+
anim_entry.duration = XMB_DELAY;
9899+
anim_entry.target_value = target_x;
9900+
anim_entry.subject = &xmb->categories_x_pos;
9901+
anim_entry.easing_enum = EASING_OUT_QUAD;
9902+
anim_entry.tag = -1;
9903+
anim_entry.cb = NULL;
9904+
9905+
if (anim_entry.subject)
9906+
gfx_animation_push(&anim_entry);
9907+
}
9908+
else
9909+
xmb->categories_x_pos = target_x;
9910+
}
9911+
9912+
xmb->drag_mode = XMB_DRAG_NONE;
9913+
return 0;
9914+
}
9915+
97339916
video_driver_get_size(&width, &height);
97349917
margin_top = (int16_t)xmb->margins_screen_top;
97359918
margin_left = (int16_t)xmb->margins_screen_left;
@@ -9921,7 +10104,7 @@ menu_ctx_driver_t menu_ctx_xmb = {
992110104
gfx_display_osk_ptr_at_pos,
992210105
xmb_update_savestate_thumbnail_path,
992310106
xmb_update_savestate_thumbnail_image,
9924-
NULL, /* pointer_down */
10107+
xmb_pointer_down,
992510108
xmb_pointer_up,
992610109
xmb_menu_entry_action
992710110
};

0 commit comments

Comments
 (0)