mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2025-06-03 01:15:15 +02:00
jscene: basic touch support with "inspector"-like debug
This commit is contained in:
parent
0878c16182
commit
cd73b2ea6f
5 changed files with 177 additions and 3 deletions
|
@ -5,6 +5,17 @@
|
|||
#ifndef _JUSTUI_CONFIG
|
||||
#define _JUSTUI_CONFIG
|
||||
|
||||
#include <gint/config.h>
|
||||
|
||||
#define J_VERSION "@JustUI_VERSION@"
|
||||
|
||||
#if GINT_HW_CP
|
||||
#define J_CONFIG_TOUCH 1
|
||||
#else
|
||||
#define J_CONFIG_TOUCH 0
|
||||
#endif
|
||||
|
||||
/* Set to 1 to enable a touch-following widget inspector. */
|
||||
#define J_CONFIG_TOUCH_INSPECTOR (J_CONFIG_TOUCH && 1)
|
||||
|
||||
#endif /* _JUSTUI_CONFIG */
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <justui/defs.h>
|
||||
#include <justui/jwidget.h>
|
||||
#include <justui/jevent.h>
|
||||
#include <justui/config.h>
|
||||
|
||||
#define JSCENE_QUEUE_SIZE 32
|
||||
|
||||
|
@ -36,6 +37,9 @@ typedef struct {
|
|||
/* Whether jscene_run() will autopaint */
|
||||
bool autopaint;
|
||||
|
||||
/* Last coordinates a touch cursor was seen at */
|
||||
int16_t touch_last_x, touch_last_y;
|
||||
|
||||
} jscene;
|
||||
|
||||
/* Events */
|
||||
|
@ -65,6 +69,21 @@ jscene *jscene_owning(void *widget);
|
|||
(x,y) point. */
|
||||
void jscene_render(jscene *scene);
|
||||
|
||||
/* jscene_widget_at(): Find top-most widget at specified location
|
||||
|
||||
Returns the top-most widget at the given scene-local location.
|
||||
* If there is no widget in the scene covering this location, returns NULL.
|
||||
* If there is exactly one, returns it.
|
||||
* If there are multiple, this function returns the first found by depth-
|
||||
first search where children are enumerated floating first, non-floating
|
||||
next, and increasing within child index order within each group.
|
||||
* For widgets with a stacked layout, only the active child is considered.
|
||||
|
||||
If content_only is set, this function only intersects with the content box.
|
||||
Otherwise, an intersection with the full box (padding, border and margin
|
||||
included) is performed. */
|
||||
jwidget *jscene_widget_at(jscene *scene, int x, int y, bool content_only);
|
||||
|
||||
//---
|
||||
// Events sent from the scene to the user
|
||||
//---
|
||||
|
|
|
@ -339,6 +339,18 @@ bool jwidget_layout_dirty(void *scene_root);
|
|||
need to keep the layout up-to-date before doing it. */
|
||||
void jwidget_layout(void *scene_root);
|
||||
|
||||
/* jwidget_absolute_x(): Absolute x-position of a widget
|
||||
jwidget_absolute_y(): Absolute y-position of a widget
|
||||
jwidget_absolute_content_x(): Absolute x-position of a widget's content box
|
||||
jwidget_absolute_content_y(): Absolute y-position of a widget's content box
|
||||
|
||||
These are actually based on the root's coordinates, which are typically 0,0
|
||||
with a full-screen scene. */
|
||||
int jwidget_absolute_x(void *w);
|
||||
int jwidget_absolute_y(void *w);
|
||||
int jwidget_absolute_content_x(void *w);
|
||||
int jwidget_absolute_content_y(void *w);
|
||||
|
||||
/* jwidget_width(): With of a widget's content box
|
||||
jwidget_height(): Height of a widget's content box
|
||||
|
||||
|
|
106
src/jscene.c
106
src/jscene.c
|
@ -62,6 +62,9 @@ jscene *jscene_create(int x, int y, int w, int h, void *parent)
|
|||
s->poweroff = true;
|
||||
s->autopaint = false;
|
||||
|
||||
s->touch_last_x = -1;
|
||||
s->touch_last_y = -1;
|
||||
|
||||
/* Prepare first layout/paint operation */
|
||||
s->widget.dirty = 1;
|
||||
|
||||
|
@ -84,10 +87,94 @@ jscene *jscene_owning(void *w0)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void jscene_render(jscene *scene)
|
||||
void jscene_render(jscene *s)
|
||||
{
|
||||
jwidget_layout(scene);
|
||||
jwidget_render(scene, scene->x, scene->y);
|
||||
jwidget_layout(s);
|
||||
jwidget_render(s, s->x, s->y);
|
||||
|
||||
#if J_CONFIG_TOUCH_INSPECTOR
|
||||
if(s->touch_last_x >= 0 && s->touch_last_y >= 0) {
|
||||
jwidget *w =
|
||||
jscene_widget_at(s, s->touch_last_x, s->touch_last_y, true);
|
||||
if(w) {
|
||||
int x1 = jwidget_absolute_content_x(w);
|
||||
int y1 = jwidget_absolute_content_y(w);
|
||||
int x2 = x1 + jwidget_content_width(w) - 1;
|
||||
int y2 = y1 + jwidget_content_height(w) - 1;
|
||||
drect_border(x1, y1, x2, y2, C_NONE, 1, C_RED);
|
||||
|
||||
dprint_opt(DWIDTH-1, 0, C_WHITE, C_RED, DTEXT_RIGHT, DTEXT_TOP,
|
||||
"%s", jwidget_type(w));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Find sub-widget based on w-local coordinates. */
|
||||
static jwidget *jscene_widget_at_rec(
|
||||
jwidget *w, int x, int y, bool content_only, bool visible_only)
|
||||
{
|
||||
if(!w)
|
||||
return NULL;
|
||||
jwidget *found;
|
||||
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
int xC = g->margin.left + g->border.left + g->padding.left;
|
||||
int yC = w->y + g->margin.top + g->border.top + g->padding.top;
|
||||
uint wC = jwidget_content_width(w);
|
||||
uint hC = jwidget_content_height(w);
|
||||
uint wF = jwidget_full_width(w);
|
||||
uint hF = jwidget_full_height(w);
|
||||
|
||||
/* Check if we intersect w at all */
|
||||
bool intersects;
|
||||
if(content_only)
|
||||
intersects = ((uint)(x - xC) < wC) && ((uint)(y - yC) < hC);
|
||||
else
|
||||
intersects = (uint)x < wF && (uint)y < hF;
|
||||
if(!intersects)
|
||||
return NULL;
|
||||
|
||||
/* If we have a stacked widget, only consider the visible child */
|
||||
jlayout_stack *stack;
|
||||
if((stack = jlayout_get_stack(w))) {
|
||||
if(stack->active < 0)
|
||||
return w;
|
||||
jwidget *child = w->children[stack->active];
|
||||
found = jscene_widget_at_rec(child, x - xC, y - yC, content_only,
|
||||
visible_only);
|
||||
return found ? found : w;
|
||||
}
|
||||
|
||||
/* Try to find a descendant of a floating child that intersects... */
|
||||
for(int k = 0; k < w->child_count; k++) {
|
||||
jwidget *child = w->children[k];
|
||||
if(child->visible >= visible_only && child->floating) {
|
||||
found = jscene_widget_at_rec(child, x - xC, y - yC, content_only,
|
||||
visible_only);
|
||||
if(found)
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
/* ... or a descendant of a non-floating child */
|
||||
for(int k = 0; k < w->child_count; k++) {
|
||||
jwidget *child = w->children[k];
|
||||
if(child->visible >= visible_only && !child->floating) {
|
||||
found = jscene_widget_at_rec(child, x - xC, y - yC, content_only,
|
||||
visible_only);
|
||||
if(found)
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no descendants do, then the best match is w itself. */
|
||||
return w;
|
||||
}
|
||||
|
||||
jwidget *jscene_widget_at(jscene *scene, int x, int y, bool content_only)
|
||||
{
|
||||
return jscene_widget_at_rec(&scene->widget, x, y, content_only, true);
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -260,6 +347,19 @@ static jevent poll_next_unhandled_event(keydev_t *d, jscene *s)
|
|||
|
||||
/* Then try to dequeue keyboard events, if there are any. */
|
||||
while((k = keydev_read(d, false, NULL)).type != KEYEV_NONE) {
|
||||
/* Keep track of where the touch cursor was last seen. */
|
||||
#if J_CONFIG_TOUCH_INSPECTOR
|
||||
if(k.type == KEYEV_TOUCH_DOWN || k.type == KEYEV_TOUCH_DRAG) {
|
||||
s->touch_last_x = k.x - s->x;
|
||||
s->touch_last_y = k.y - s->y;
|
||||
s->widget.update = true;
|
||||
}
|
||||
if(k.type == KEYEV_TOUCH_UP) {
|
||||
s->touch_last_x = -1;
|
||||
s->touch_last_y = -1;
|
||||
s->widget.update = true;
|
||||
}
|
||||
#endif
|
||||
/* Auto return-to-menu */
|
||||
if(k.type == KEYEV_DOWN && k.key == KEY_MENU && !k.shift && !k.alpha) {
|
||||
if(s->mainmenu) {
|
||||
|
|
|
@ -567,6 +567,38 @@ void jwidget_layout(void *root0)
|
|||
jwidget_layout_apply(root);
|
||||
}
|
||||
|
||||
int jwidget_absolute_x(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
return w ? w->x + jwidget_absolute_x(w->parent) : 0;
|
||||
}
|
||||
|
||||
int jwidget_absolute_y(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
return w ? w->y + jwidget_absolute_y(w->parent) : 0;
|
||||
}
|
||||
|
||||
int jwidget_absolute_content_x(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
if(!w)
|
||||
return 0;
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
return jwidget_absolute_content_x(w->parent) +
|
||||
w->x + g->margin.left + g->border.left + g->padding.left;
|
||||
}
|
||||
|
||||
int jwidget_absolute_content_y(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
if(!w)
|
||||
return 0;
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
return jwidget_absolute_content_y(w->parent) +
|
||||
w->y + g->margin.top + g->border.top + g->padding.top;
|
||||
}
|
||||
|
||||
int jwidget_content_width(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
|
|
Loading…
Add table
Reference in a new issue