From aab839fae840b57ef194061fde8ea62bd979a9cd Mon Sep 17 00:00:00 2001 From: Sads Date: Fri, 12 Jun 2026 22:13:48 +0200 Subject: [PATCH] added touch scroll --- CMakeLists.txt | 1 + src/main.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6651b3d..4467514 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ target_link_libraries(${PROJECT_NAME} SceGxm_stub SceSysmodule_stub SceCtrl_stub + SceTouch_stub SceCommonDialog_stub ScePgf_stub SceAppMgr_stub diff --git a/src/main.c b/src/main.c index 18ab881..e649570 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1403,6 +1404,33 @@ static int month_jump(int d, int dir) return i; } +/* display slot whose grid cell contains the (screen-x, world-y) point, + * or -1: touch hit-testing for tap-to-open */ +static int item_at(float x, float wy) +{ + for (int i = 0; i < g_disp_count; i++) { + if (g_item_y[i] > wy) + break; /* item y is non-decreasing */ + if (wy < g_item_y[i] + CELL_H && + x >= g_item_x[i] && x < g_item_x[i] + CELL_W) + return i; + } + return -1; +} + +/* display slot nearest a world-y (used to keep the selection inside the + * viewport while a touch drag/fling moves the grid) */ +static int item_near(float wy) +{ + int last = -1; + for (int i = 0; i < g_disp_count; i++) { + if (g_item_y[i] + CELL_H > wy) + return i; + last = i; + } + return last; +} + /* find the display slot for a given source item (after a rebuild reorders * things, to keep the selection on the same photo) */ static int find_disp(unsigned char src, int idx) @@ -2731,6 +2759,9 @@ int main(void) /* analog mode so the left stick reports lx/ly for detail-view panning */ sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG); + /* front touch: drag scrolls the grid, a tap opens the item */ + sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, + SCE_TOUCH_SAMPLING_STATE_START); /* start a fresh debug log each launch */ sceIoMkdir(CONFIG_DIR, 0777); @@ -2833,6 +2864,13 @@ int main(void) int detail_issued = 0; /* the worker request has been handed over */ float zoom = 1.0f, panx = 0.0f, pany = 0.0f; + /* front-touch state (grid: drag scrolls, tap opens) */ + int touch_active = 0; /* finger currently down */ + int touch_dragged = 0; /* moved past the tap threshold */ + float touch_x = 0, touch_y = 0; /* last position, screen px */ + float touch_start_y = 0, touch_start_scroll = 0; + float touch_vel = 0; /* px/frame at the moment of release */ + for (;;) { SceCtrlData pad; sceCtrlPeekBufferPositive(0, &pad, 1); @@ -2950,6 +2988,89 @@ int main(void) sel = g_disp_count - 1; } + /* front touch: drag scrolls the timeline directly, a + * fling keeps it gliding, a tap opens the item under + * the finger. the front panel reports 2x screen px. */ + { + SceTouchData td; + sceTouchPeek(SCE_TOUCH_PORT_FRONT, &td, 1); + float maxs = g_content_h - SCREEN_H; + if (maxs < 0) + maxs = 0; + if (td.reportNum > 0) { + float tx = td.report[0].x * 0.5f; + float ty = td.report[0].y * 0.5f; + if (!touch_active) { + touch_active = 1; + touch_dragged = 0; + touch_start_y = ty; + touch_start_scroll = scroll; + touch_vel = 0; + } else { + float dy = ty - touch_start_y; + if (!touch_dragged && + (dy > 14.0f || dy < -14.0f)) + touch_dragged = 1; + if (touch_dragged) { + float ns = touch_start_scroll - dy; + if (ns < 0) + ns = 0; + if (ns > maxs) + ns = maxs; + touch_vel = ns - scroll; + scroll = target = ns; + /* keep the selection inside + * the dragged viewport */ + int c = item_near(ns + SCREEN_H / 2); + if (c >= 0) + sel = c; + } + } + touch_x = tx; + touch_y = ty; + } else if (touch_active) { + touch_active = 0; + if (!touch_dragged) { + /* tap: open the item under it */ + int i = item_at(touch_x, + touch_y + scroll); + if (i >= 0) { + sel = i; + if (disp_is_video(i)) { + struct disp_item ti = g_disp[i]; + if (ti.src == SRC_LOCAL) + play_video_file(g_local_path[ti.idx]); + else + view_video(ti.idx); + do { + sceCtrlPeekBufferPositive(0, &pad, 1); + sceKernelDelayThread(10 * 1000); + } while (pad.buttons); + prev_buttons = 0; + continue; + } + mode = MODE_DETAIL; + zoom = 1.0f; + panx = pany = 0.0f; + } + } else if (touch_vel > 2.0f || + touch_vel < -2.0f) { + /* fling: glide on; aim the + * selection at the destination + * so scroll-follow doesn't + * fight the glide */ + target = scroll + touch_vel * 18.0f; + if (target < 0) + target = 0; + if (target > maxs) + target = maxs; + int c = item_near(target + SCREEN_H / 2); + if (c >= 0) + sel = c; + } + } + } + /* scroll follows the selection, using the precomputed * per-item y so month headers shift it correctly. when * moving up, reveal the header band above the item. */