mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2025-06-03 01:15:15 +02:00
Compare commits
3 commits
0d0919ecd7
...
b75c8979ba
Author | SHA1 | Date | |
---|---|---|---|
|
b75c8979ba | ||
|
bd89221d33 | ||
|
5d3a6639ee |
9 changed files with 292 additions and 25 deletions
|
@ -34,6 +34,7 @@ add_library(${NAME} STATIC
|
|||
src/jframe.c
|
||||
src/jlist.c
|
||||
src/jscrolledlist.c
|
||||
src/jbutton.c
|
||||
src/vec.c
|
||||
src/keymap.c
|
||||
${ASSETS_${FXSDK_PLATFORM}}
|
||||
|
|
59
include/justui/jbutton.h
Normal file
59
include/justui/jbutton.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
//---
|
||||
// JustUI.jbutton: Touchable multi-state click button
|
||||
//---
|
||||
|
||||
#ifndef _J_JBUTTON
|
||||
#define _J_JBUTTON
|
||||
|
||||
#include <justui/defs.h>
|
||||
#include <justui/jwidget.h>
|
||||
|
||||
#include <gint/display.h>
|
||||
|
||||
/* jbutton: Button with multiple states
|
||||
|
||||
This widget is your everyday interactible button. It responds to touch by
|
||||
changing its background color for idle, focused and active states. It also
|
||||
has a disabled states which can be used to make a "selected" visual.
|
||||
|
||||
TODO: Allow jbutton it to hold any widget inside.
|
||||
TODO: jbutton's focus state is untested since I only tested touch.
|
||||
|
||||
Events:
|
||||
* JBUTTON_TRIGGERED when activated. */
|
||||
|
||||
enum {
|
||||
JBUTTON_IDLE,
|
||||
JBUTTON_ACTIVE,
|
||||
JBUTTON_DISABLED,
|
||||
|
||||
JBUTTON_STATE_NUM,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
jwidget widget;
|
||||
|
||||
/* Text shown on the button; not owned by the button */
|
||||
char const *text;
|
||||
/* Rendering font */
|
||||
font_t const *font;
|
||||
/* Colors for all states */
|
||||
color_t fg_colors[JBUTTON_STATE_NUM];
|
||||
color_t bg_colors[JBUTTON_STATE_NUM];
|
||||
/* Current state */
|
||||
int state;
|
||||
|
||||
} jbutton;
|
||||
|
||||
/* Event IDs */
|
||||
extern uint16_t JBUTTON_TRIGGERED;
|
||||
|
||||
/* jbutton_create(): Create a button */
|
||||
jbutton *jbutton_create(char const *text, void *parent);
|
||||
|
||||
/* Trivial properties */
|
||||
void jbutton_set_text(jbutton *b, char const *text);
|
||||
void jbutton_set_font(jbutton *b, font_t const *font);
|
||||
void jbutton_set_disabled(jbutton *b, bool disabled);
|
||||
|
||||
#endif /* _J_JBUTTON */
|
|
@ -79,10 +79,10 @@ void jscene_render(jscene *scene);
|
|||
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);
|
||||
If exclude_mp is set, this function only intersects with the content and
|
||||
padding box, excluding margins and borders. 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 exclude_mp);
|
||||
|
||||
//---
|
||||
// Events sent from the scene to the user
|
||||
|
|
|
@ -341,6 +341,8 @@ 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_padding_x(): Absolute x-position of a widget's padding box
|
||||
jwidget_absolute_padding_y(): Absolute y-position of a widget's padding box
|
||||
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
|
||||
|
||||
|
@ -348,6 +350,8 @@ void jwidget_layout(void *scene_root);
|
|||
with a full-screen scene. */
|
||||
int jwidget_absolute_x(void *w);
|
||||
int jwidget_absolute_y(void *w);
|
||||
int jwidget_absolute_padding_x(void *w);
|
||||
int jwidget_absolute_padding_y(void *w);
|
||||
int jwidget_absolute_content_x(void *w);
|
||||
int jwidget_absolute_content_y(void *w);
|
||||
|
||||
|
@ -361,6 +365,17 @@ int jwidget_absolute_content_y(void *w);
|
|||
int jwidget_content_width(void *w);
|
||||
int jwidget_content_height(void *w);
|
||||
|
||||
/* jwidget_width(): With of a widget's padding box
|
||||
jwidget_height(): Height of a widget's padding box
|
||||
|
||||
These functions return the size of the padding box of a widget, which
|
||||
includes the content and padding. These are the dimensions that appear as
|
||||
the widget's size when there is a background. These dimensions are known
|
||||
only after layout; calling these functions when the layout is not up-to-date
|
||||
will return funny results. */
|
||||
int jwidget_padding_width(void *w);
|
||||
int jwidget_padding_height(void *w);
|
||||
|
||||
/* jwidget_full_width(): Width of a widget's margin box
|
||||
jwidget_full_height(): Height of a widget's margin box
|
||||
|
||||
|
|
139
src/jbutton.c
Normal file
139
src/jbutton.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include <justui/jwidget.h>
|
||||
#include <justui/jwidget-api.h>
|
||||
#include <justui/jbutton.h>
|
||||
#include <justui/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
J_DEFINE_WIDGET(jbutton, csize, render, event)
|
||||
J_DEFINE_EVENTS(JBUTTON_TRIGGERED)
|
||||
|
||||
static void jbutton_set_state(jbutton *b, int state)
|
||||
{
|
||||
if((uint)state >= JBUTTON_STATE_NUM || b->state == state)
|
||||
return;
|
||||
b->state = state;
|
||||
jwidget_set_background(b, b->bg_colors[state]);
|
||||
b->widget.update = 1;
|
||||
}
|
||||
|
||||
jbutton *jbutton_create(char const *text, void *parent)
|
||||
{
|
||||
if(jbutton_type_id < 0)
|
||||
return NULL;
|
||||
|
||||
jbutton *b = malloc(sizeof *b);
|
||||
if(!b)
|
||||
return NULL;
|
||||
|
||||
jwidget_init(&b->widget, jbutton_type_id, parent);
|
||||
jwidget_set_focus_policy(b, J_FOCUS_POLICY_ACCEPT);
|
||||
|
||||
b->text = text ? text : "";
|
||||
b->font = dfont_default();
|
||||
|
||||
#if GINT_RENDER_MONO
|
||||
b->fg_colors[JBUTTON_IDLE] = C_WHITE;
|
||||
b->fg_colors[JBUTTON_ACTIVE] = C_WHITE;
|
||||
b->fg_colors[JBUTTON_DISABLED] = C_BLACK;
|
||||
b->bg_colors[JBUTTON_IDLE] = C_BLACK;
|
||||
b->bg_colors[JBUTTON_ACTIVE] = C_BLACK;
|
||||
b->bg_colors[JBUTTON_DISABLED] = C_WHITE;
|
||||
jwidget_set_padding(b, 1, 2, 1, 2);
|
||||
#endif
|
||||
#if GINT_RENDER_RGB
|
||||
b->fg_colors[JBUTTON_IDLE] = C_WHITE;
|
||||
b->fg_colors[JBUTTON_ACTIVE] = C_WHITE;
|
||||
b->fg_colors[JBUTTON_DISABLED] = C_RGB(8, 8, 8);
|
||||
b->bg_colors[JBUTTON_IDLE] = C_BLACK;
|
||||
b->bg_colors[JBUTTON_ACTIVE] = C_RGB(8, 8, 8);
|
||||
b->bg_colors[JBUTTON_DISABLED] = C_RGB(24, 24, 24);
|
||||
jwidget_set_padding(b, 2, 4, 2, 4);
|
||||
#endif
|
||||
|
||||
jbutton_set_state(b, JBUTTON_IDLE);
|
||||
return b;
|
||||
}
|
||||
|
||||
void jbutton_set_text(jbutton *b, char const *text)
|
||||
{
|
||||
b->text = text ? text : "";
|
||||
b->widget.dirty = 1;
|
||||
}
|
||||
|
||||
void jbutton_set_font(jbutton *b, font_t const *font)
|
||||
{
|
||||
b->font = font ? font : dfont_default();
|
||||
b->widget.dirty = 1;
|
||||
}
|
||||
|
||||
void jbutton_set_disabled(jbutton *b, bool disabled)
|
||||
{
|
||||
if(disabled)
|
||||
jbutton_set_state(b, JBUTTON_DISABLED);
|
||||
else if(b->state == JBUTTON_DISABLED)
|
||||
jbutton_set_state(b, JBUTTON_IDLE);
|
||||
}
|
||||
|
||||
//---
|
||||
// Polymorphic widget operations
|
||||
//---
|
||||
|
||||
void jbutton_poly_csize(void *b0)
|
||||
{
|
||||
jbutton *b = b0;
|
||||
int w, h;
|
||||
dsize(b->text, b->font ? b->font : dfont_default(), &w, &h);
|
||||
b->widget.w = w;
|
||||
b->widget.h = h;
|
||||
}
|
||||
|
||||
void jbutton_poly_render(void *b0, int x, int y)
|
||||
{
|
||||
jbutton *b = b0;
|
||||
int cw = jwidget_content_width(b);
|
||||
int ch = jwidget_content_height(b);
|
||||
|
||||
int fg = b->fg_colors[b->state];
|
||||
font_t const *old_font = dfont(b->font);
|
||||
dtext_opt(x + cw / 2, y + ch / 2, fg, C_NONE, DTEXT_CENTER, DTEXT_MIDDLE,
|
||||
b->text, -1);
|
||||
dfont(old_font);
|
||||
}
|
||||
|
||||
bool jbutton_poly_event(void *b0, jevent e)
|
||||
{
|
||||
jbutton *b = b0;
|
||||
key_event_t ev = { .type = KEYEV_NONE };
|
||||
if(e.type == JWIDGET_KEY)
|
||||
ev = e.key;
|
||||
|
||||
#if J_CONFIG_TOUCH
|
||||
bool accepts_touch = b->state != JBUTTON_DISABLED;
|
||||
if((ev.type == KEYEV_TOUCH_DOWN || ev.type == KEYEV_TOUCH_DRAG ||
|
||||
ev.type == KEYEV_TOUCH_UP) && accepts_touch) {
|
||||
int lx = ev.x - jwidget_absolute_padding_x(b);
|
||||
int ly = ev.y - jwidget_absolute_padding_y(b);
|
||||
uint cw = jwidget_padding_width(b);
|
||||
uint ch = jwidget_padding_height(b);
|
||||
bool inside = (uint)lx < cw && (uint)ly < ch;
|
||||
|
||||
if(ev.type == KEYEV_TOUCH_DOWN)
|
||||
jbutton_set_state(b, JBUTTON_ACTIVE);
|
||||
if(ev.type == KEYEV_TOUCH_DRAG)
|
||||
jbutton_set_state(b, inside ? JBUTTON_ACTIVE : JBUTTON_IDLE);
|
||||
if(ev.type == KEYEV_TOUCH_UP && b->state == JBUTTON_ACTIVE) {
|
||||
jbutton_set_state(b, JBUTTON_IDLE);
|
||||
jwidget_emit(b, (jevent){ .type = JBUTTON_TRIGGERED });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ev.type == KEYEV_DOWN && (ev.key == KEY_EXE || ev.key == KEY_OK)) {
|
||||
jwidget_emit(b, (jevent){ .type = JBUTTON_TRIGGERED });
|
||||
return true;
|
||||
}
|
||||
|
||||
return jwidget_poly_event(b, e);
|
||||
}
|
|
@ -21,7 +21,7 @@ static int jfileselect_type_id = -1;
|
|||
# define JFILESELECT_SCROLLBAR_WIDTH 1
|
||||
# define JFILESELECT_INFO_SHORT 1
|
||||
#elif GINT_RENDER_RGB
|
||||
# define JFILESELECT_LINE_SPACING 4
|
||||
# define JFILESELECT_LINE_SPACING (J_CONFIG_TOUCH ? 6 : 4)
|
||||
# define JFILESELECT_SCROLLBAR_WIDTH 2
|
||||
# define JFILESELECT_INFO_SHORT 0
|
||||
#endif
|
||||
|
@ -353,6 +353,8 @@ bool jfileselect_default_filter(struct dirent const *ent)
|
|||
return false;
|
||||
if(!strcmp(ent->d_name, "SAVE-F"))
|
||||
return false;
|
||||
if(!strcmp(ent->d_name, "AutoImport"))
|
||||
return false;
|
||||
if(!strcmp(ent->d_name, "."))
|
||||
return false;
|
||||
if(!strcmp(ent->d_name, ".."))
|
||||
|
@ -360,7 +362,7 @@ bool jfileselect_default_filter(struct dirent const *ent)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void jfileselect_select(jfileselect *fs, int index)
|
||||
GUNUSED static void jfileselect_select(jfileselect *fs, int index)
|
||||
{
|
||||
/* Normalize out-of-bounds to -1 */
|
||||
if(index < 0 || index >= fs->entry_count)
|
||||
|
|
|
@ -167,7 +167,7 @@ jrect jlist_selected_region(jlist *l)
|
|||
// Polymorphic widget operations
|
||||
//---
|
||||
|
||||
static int item_index_at(void *l0, int ly)
|
||||
GUNUSED static int item_index_at(void *l0, int ly)
|
||||
{
|
||||
jlist *l = l0;
|
||||
int y = 0;
|
||||
|
|
39
src/jscene.c
39
src/jscene.c
|
@ -97,10 +97,10 @@ void jscene_render(jscene *s)
|
|||
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;
|
||||
int x1 = jwidget_absolute_padding_x(w);
|
||||
int y1 = jwidget_absolute_padding_y(w);
|
||||
int x2 = x1 + jwidget_padding_width(w) - 1;
|
||||
int y2 = y1 + jwidget_padding_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,
|
||||
|
@ -112,24 +112,31 @@ void jscene_render(jscene *s)
|
|||
|
||||
/* 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)
|
||||
jwidget *w, int x, int y, bool exclude_mp, bool visible_only)
|
||||
{
|
||||
if(!w)
|
||||
return NULL;
|
||||
jwidget *found;
|
||||
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
/* Content box (this is what children's xy are measured against) */
|
||||
int xC = g->margin.left + g->border.left + g->padding.left;
|
||||
int yC = w->y + g->margin.top + g->border.top + g->padding.top;
|
||||
int yC = g->margin.top + g->border.top + g->padding.top;
|
||||
uint wC = jwidget_content_width(w);
|
||||
uint hC = jwidget_content_height(w);
|
||||
/* Padding box */
|
||||
int xP = xC - g->padding.left;
|
||||
int yP = yC - g->padding.top;
|
||||
uint wP = wC + g->padding.left + g->padding.right;
|
||||
uint hP = hC + g->padding.top + g->padding.bottom;
|
||||
/* Full box (implicitly starts at 0,0) */
|
||||
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);
|
||||
if(exclude_mp)
|
||||
intersects = ((uint)(x - xP) < wP) && ((uint)(y - yP) < hP);
|
||||
else
|
||||
intersects = (uint)x < wF && (uint)y < hF;
|
||||
if(!intersects)
|
||||
|
@ -141,8 +148,8 @@ static jwidget *jscene_widget_at_rec(
|
|||
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);
|
||||
found = jscene_widget_at_rec(child, x - xC - child->x,
|
||||
y - yC - child->y, exclude_mp, visible_only);
|
||||
return found ? found : w;
|
||||
}
|
||||
|
||||
|
@ -150,8 +157,8 @@ static jwidget *jscene_widget_at_rec(
|
|||
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);
|
||||
found = jscene_widget_at_rec(child, x - xC - child->x,
|
||||
y - yC - child->y, exclude_mp, visible_only);
|
||||
if(found)
|
||||
return found;
|
||||
}
|
||||
|
@ -161,8 +168,8 @@ static jwidget *jscene_widget_at_rec(
|
|||
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);
|
||||
found = jscene_widget_at_rec(child, x - xC - child->x,
|
||||
y - yC - child->y, exclude_mp, visible_only);
|
||||
if(found)
|
||||
return found;
|
||||
}
|
||||
|
@ -172,9 +179,9 @@ static jwidget *jscene_widget_at_rec(
|
|||
return w;
|
||||
}
|
||||
|
||||
jwidget *jscene_widget_at(jscene *scene, int x, int y, bool content_only)
|
||||
jwidget *jscene_widget_at(jscene *scene, int x, int y, bool exclude_mp)
|
||||
{
|
||||
return jscene_widget_at_rec(&scene->widget, x, y, content_only, true);
|
||||
return jscene_widget_at_rec(&scene->widget, x, y, exclude_mp, true);
|
||||
}
|
||||
|
||||
//---
|
||||
|
|
|
@ -570,13 +570,39 @@ void jwidget_layout(void *root0)
|
|||
int jwidget_absolute_x(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
return w ? w->x + jwidget_absolute_x(w->parent) : 0;
|
||||
if(!w)
|
||||
return 0;
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
return jwidget_absolute_content_x(w) -
|
||||
g->padding.left - g->border.left - g->margin.left;
|
||||
}
|
||||
|
||||
int jwidget_absolute_y(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
return w ? w->y + jwidget_absolute_y(w->parent) : 0;
|
||||
if(!w)
|
||||
return 0;
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
return jwidget_absolute_content_y(w) -
|
||||
g->padding.top - g->border.top - g->margin.top;
|
||||
}
|
||||
|
||||
int jwidget_absolute_padding_x(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
if(!w)
|
||||
return 0;
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
return jwidget_absolute_content_x(w) - g->padding.left;
|
||||
}
|
||||
|
||||
int jwidget_absolute_padding_y(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
if(!w)
|
||||
return 0;
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
return jwidget_absolute_content_y(w) - g->padding.top;
|
||||
}
|
||||
|
||||
int jwidget_absolute_content_x(void *w0)
|
||||
|
@ -617,6 +643,24 @@ int jwidget_content_height(void *w0)
|
|||
- g->margin.bottom - g->border.bottom - g->padding.bottom;
|
||||
}
|
||||
|
||||
int jwidget_padding_width(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
|
||||
return w->w - g->margin.left - g->border.left
|
||||
- g->margin.right - g->border.right;
|
||||
}
|
||||
|
||||
int jwidget_padding_height(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
jwidget_geometry const *g = jwidget_geometry_r(w);
|
||||
|
||||
return w->h - g->margin.top - g->border.top
|
||||
- g->margin.bottom - g->border.bottom;
|
||||
}
|
||||
|
||||
int jwidget_full_width(void *w0)
|
||||
{
|
||||
J_CAST(w)
|
||||
|
|
Loading…
Add table
Reference in a new issue