diff --git a/include/justui/config.h.in b/include/justui/config.h.in index 51bd296..323549f 100644 --- a/include/justui/config.h.in +++ b/include/justui/config.h.in @@ -16,6 +16,6 @@ #endif /* Set to 1 to enable a touch-following widget inspector. */ -#define J_CONFIG_TOUCH_INSPECTOR (J_CONFIG_TOUCH && 1) +#define J_CONFIG_TOUCH_INSPECTOR (J_CONFIG_TOUCH && 0) #endif /* _JUSTUI_CONFIG */ diff --git a/include/justui/jlist.h b/include/justui/jlist.h index 27ffedd..16965db 100644 --- a/include/justui/jlist.h +++ b/include/justui/jlist.h @@ -77,6 +77,8 @@ typedef struct jlist { /* Currently selected item, -1 if none */ int cursor; + /* Index of the currently touch-clicked item, -1 none */ + int touch_cursor; /* User data pointer */ void *user; diff --git a/include/justui/jwidget.h b/include/justui/jwidget.h index e1f6345..ffbf66a 100644 --- a/include/justui/jwidget.h +++ b/include/justui/jwidget.h @@ -434,6 +434,9 @@ void jwidget_render(void *w, int x, int y); while the widget has focus, the focus will be lost. */ void jwidget_set_focus_policy(void *w, jwidget_focus_policy_t fp); +/* Check whether a widget accepts focus. */ +bool jwidget_accepts_focus(void *w); + /* Check whether a widget is currently focused within its surrounding scope. */ GINLINE static bool jwidget_has_focus(void *w) { diff --git a/src/jlist.c b/src/jlist.c index 65f1d9e..d208ce3 100644 --- a/src/jlist.c +++ b/src/jlist.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "util.h" #include @@ -38,6 +39,7 @@ jlist *jlist_create(jlist_item_info_function info_function, l->info_function = info_function; l->paint_function = paint_function; l->cursor = -1; + l->touch_cursor = -1; l->user = NULL; return l; } @@ -165,6 +167,25 @@ jrect jlist_selected_region(jlist *l) // Polymorphic widget operations //--- +static int item_index_at(void *l0, int ly) +{ + jlist *l = l0; + int y = 0; + + for(int i = 0; i < l->item_count; i++) { + jlist_item_info *info = &l->items[i]; + int h = info->delegate + ? jwidget_full_height(info->delegate) + : info->natural_height; + + if(ly >= y && ly < y + h) + return i; + y += h; + } + + return -1; +} + static void jlist_poly_csize(void *l0) { jlist *l = l0; @@ -224,10 +245,38 @@ static bool jlist_poly_event(void *l0, jevent e) { jlist *l = l0; + if(e.type == JWIDGET_FOCUS_CHANGED && !jwidget_has_active_focus(l)) + l->touch_cursor = -1; + if(e.type != JWIDGET_KEY || l->cursor < 0) return false; key_event_t ev = e.key; + +#if J_CONFIG_TOUCH + if(ev.type == KEYEV_TOUCH_DOWN || ev.type == KEYEV_TOUCH_DRAG || + ev.type == KEYEV_TOUCH_UP) { + int lx = ev.x - jwidget_absolute_content_x(l); + int ly = ev.y - jwidget_absolute_content_y(l); + uint w = jwidget_content_width(l); + uint h = jwidget_content_height(l); + int index = ((uint)lx < w && (uint)ly < h) ? item_index_at(l, ly) : -1; + + if(ev.type == KEYEV_TOUCH_DOWN && index >= 0) { + jlist_select(l, index); + l->touch_cursor = jlist_selected_item(l); + } + if(ev.type == KEYEV_TOUCH_DRAG && index >= 0) + jlist_select(l, index); + if(ev.type == KEYEV_TOUCH_UP && index >= 0 && index == l->touch_cursor) { + jevent e = { .type = JLIST_ITEM_TRIGGERED, + .data = l->touch_cursor }; + jwidget_emit(l, e); + } + return true; + } +#endif + if(ev.type != KEYEV_DOWN && ev.type != KEYEV_HOLD) return false; diff --git a/src/jscene.c b/src/jscene.c index b7ac3a9..4881395 100644 --- a/src/jscene.c +++ b/src/jscene.c @@ -283,6 +283,16 @@ void jscene_show_and_focus(jscene *scene, void *w0) bool jscene_process_key_event(jscene *scene, key_event_t event) { + /* If the event is a touch down, start by moving the focus. */ +#if J_CONFIG_TOUCH + if(event.type == KEYEV_TOUCH_DOWN) { + jwidget *w = jscene_widget_at(scene, event.x - scene->x, + event.y - scene->y, true); + if(w && jwidget_accepts_focus(w)) + jscene_set_focused_widget(scene, w); + } +#endif + jwidget *candidate = jscene_focused_widget(scene); jevent e = { .type = JWIDGET_KEY, .key = event }; diff --git a/src/jwidget.c b/src/jwidget.c index fa1fd75..e2e0f9d 100644 --- a/src/jwidget.c +++ b/src/jwidget.c @@ -753,6 +753,13 @@ void jwidget_set_focus_policy(void *w0, jwidget_focus_policy_t fp) w->focus_policy = fp; } +bool jwidget_accepts_focus(void *w0) +{ + J_CAST(w) + return w->focus_policy == J_FOCUS_POLICY_SCOPE || + w->focus_policy == J_FOCUS_POLICY_ACCEPT; +} + static void notify_focus_changed(jwidget *w) { jevent e;