mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2024-12-28 20:43:40 +01:00
270 lines
5.7 KiB
C
270 lines
5.7 KiB
C
#include <justui/jwidget.h>
|
|
#include <justui/jwidget-api.h>
|
|
#include <justui/jscene.h>
|
|
|
|
#include <gint/display.h>
|
|
#include <gint/keyboard.h>
|
|
#include <gint/drivers/keydev.h>
|
|
#include <gint/clock.h>
|
|
#include <gint/std/stdlib.h>
|
|
#include <gint/gint.h>
|
|
#include <gint/drivers/t6k11.h>
|
|
|
|
/* Type identifier for jscene */
|
|
static int jscene_type_id = -1;
|
|
/* Events */
|
|
uint16_t JSCENE_NONE;
|
|
uint16_t JSCENE_PAINT;
|
|
uint16_t JSCENE_KEY;
|
|
|
|
/* Keyboard transformation for inputs in a jscene */
|
|
static int jscene_repeater(int key, GUNUSED int duration, int count)
|
|
{
|
|
if(key != KEY_LEFT && key != KEY_RIGHT && key != KEY_UP && key != KEY_DOWN)
|
|
return -1;
|
|
|
|
return (count ? 40 : 400) * 1000;
|
|
}
|
|
static keydev_transform_t jscene_tr = {
|
|
.enabled =
|
|
KEYDEV_TR_DELAYED_SHIFT |
|
|
KEYDEV_TR_INSTANT_SHIFT |
|
|
KEYDEV_TR_DELAYED_ALPHA |
|
|
KEYDEV_TR_INSTANT_ALPHA |
|
|
KEYDEV_TR_REPEATS,
|
|
.repeater = jscene_repeater,
|
|
};
|
|
|
|
jscene *jscene_create(int x, int y, int w, int h, void *parent)
|
|
{
|
|
if(jscene_type_id < 0) return NULL;
|
|
|
|
jscene *s = malloc(sizeof *s);
|
|
if(!s) return NULL;
|
|
|
|
jwidget_init(&s->widget, jscene_type_id, parent);
|
|
jwidget_set_fixed_size(s, w, h);
|
|
|
|
s->x = x;
|
|
s->y = y;
|
|
|
|
s->focus = NULL;
|
|
s->queue_first = 0;
|
|
s->queue_next = 0;
|
|
s->lost_events = 0;
|
|
s->mainmenu = true;
|
|
|
|
/* Prepare first layout/paint operation */
|
|
s->widget.dirty = 1;
|
|
|
|
return s;
|
|
}
|
|
|
|
jscene *jscene_create_fullscreen(void *parent)
|
|
{
|
|
return jscene_create(0, 0, DWIDTH, DHEIGHT, parent);
|
|
}
|
|
|
|
jscene *jscene_owning(void *w0)
|
|
{
|
|
J_CAST(w)
|
|
|
|
while(w) {
|
|
if(w->type == jscene_type_id) return (void *)w;
|
|
w = w->parent;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void jscene_render(jscene *scene)
|
|
{
|
|
jwidget_layout(scene);
|
|
jwidget_render(scene, scene->x, scene->y);
|
|
}
|
|
|
|
//---
|
|
// Event management
|
|
//---
|
|
|
|
jevent jscene_read_event(jscene *s)
|
|
{
|
|
if(s->queue_first == s->queue_next)
|
|
return (jevent){ .source = NULL, .type = JSCENE_NONE };
|
|
|
|
jevent e = s->queue[s->queue_first];
|
|
s->queue_first = (s->queue_first + 1) % JSCENE_QUEUE_SIZE;
|
|
return e;
|
|
}
|
|
|
|
void jscene_queue_event(jscene *s, jevent e)
|
|
{
|
|
/* Prevent filling and overflowing the queue */
|
|
int next = (s->queue_next + 1) % JSCENE_QUEUE_SIZE;
|
|
if(next == s->queue_first) {
|
|
s->lost_events++;
|
|
return;
|
|
}
|
|
|
|
s->queue[s->queue_next] = e;
|
|
s->queue_next = next;
|
|
}
|
|
|
|
//---
|
|
// Keyboard focus and keyboard events
|
|
//---
|
|
|
|
void *jscene_focused_widget(jscene *s)
|
|
{
|
|
return s->focus;
|
|
}
|
|
|
|
void jscene_set_focused_widget(jscene *s, void *w0)
|
|
{
|
|
J_CAST(w)
|
|
|
|
/* Check that (s) is an ancestor of (w) */
|
|
if(w) for(jwidget *anc = w; anc != (jwidget *)s; anc = anc->parent) {
|
|
if(anc == NULL) return;
|
|
}
|
|
|
|
/* Focus out old focused widget */
|
|
if(s->focus) jwidget_event(s->focus,
|
|
(jevent){ .type = JWIDGET_FOCUS_OUT, .source = s->focus });
|
|
|
|
s->focus = w;
|
|
|
|
/* Focus in newly-selected widget */
|
|
if(w) jwidget_event(w,
|
|
(jevent){ .type = JWIDGET_FOCUS_IN, .source = w });
|
|
}
|
|
|
|
void jscene_show_and_focus(jscene *scene, void *w0)
|
|
{
|
|
J_CAST(w)
|
|
|
|
/* Ensure the widget is visible */
|
|
jwidget_set_visible(w, true);
|
|
|
|
/* Force stacked layouts all the wat up to [scene] to show [w] */
|
|
jwidget *current = w;
|
|
jwidget *parent = w->parent;
|
|
|
|
while(parent != (jwidget *)scene) {
|
|
jlayout_stack *stack = jlayout_get_stack(parent);
|
|
if(stack) {
|
|
int pos = jwidget_child_position(parent, current);
|
|
if(stack->active != pos) {
|
|
stack->active = pos;
|
|
parent->update = true;
|
|
}
|
|
}
|
|
|
|
current = parent;
|
|
parent = current->parent;
|
|
}
|
|
|
|
/* Give the widget focus */
|
|
jscene_set_focused_widget(scene, w);
|
|
}
|
|
|
|
bool jscene_process_key_event(jscene *scene, key_event_t event)
|
|
{
|
|
jwidget *candidate = scene->focus;
|
|
jevent e = { .type = JWIDGET_KEY, .key = event };
|
|
|
|
while(candidate) {
|
|
if(jwidget_event(candidate, e)) return true;
|
|
candidate = candidate->parent;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool jscene_process_event(GUNUSED jscene *scene, jevent event)
|
|
{
|
|
if(!event.source) return false;
|
|
jwidget *candidate = ((jwidget *)event.source)->parent;
|
|
|
|
while(candidate) {
|
|
if(jwidget_event(candidate, event)) return true;
|
|
candidate = candidate->parent;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void jscene_set_mainmenu(jscene *scene, bool mainmenu)
|
|
{
|
|
scene->mainmenu = mainmenu;
|
|
}
|
|
|
|
jevent jscene_run(jscene *s)
|
|
{
|
|
keydev_t *d = keydev_std();
|
|
keydev_transform_t tr0 = keydev_transform(d);
|
|
keydev_set_transform(d, jscene_tr);
|
|
|
|
jevent e;
|
|
while(1) {
|
|
/* Create repaint events (also handle relayout if needed) */
|
|
if(jwidget_layout_dirty(s) || jwidget_needs_update(s)) {
|
|
jscene_queue_event(s, (jevent){ .type = JSCENE_PAINT });
|
|
}
|
|
|
|
/* Queued GUI events */
|
|
e = jscene_read_event(s);
|
|
if(e.type != JSCENE_NONE && !jscene_process_event(s, e)) break;
|
|
|
|
/* Queued keyboard events */
|
|
key_event_t k = keydev_read(d, false, NULL);
|
|
|
|
if(k.type == KEYEV_DOWN && k.key == KEY_MENU && !k.shift && !k.alpha) {
|
|
if(s->mainmenu) {
|
|
gint_osmenu();
|
|
jscene_queue_event(s, (jevent){ .type = JSCENE_PAINT });
|
|
continue;
|
|
}
|
|
}
|
|
#ifdef FX9860G
|
|
if(k.type == KEYEV_DOWN && k.key == KEY_OPTN && k.shift && !k.alpha) {
|
|
t6k11_backlight(-1);
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
getkey_feature_t feat = getkey_feature_function();
|
|
if((k.type == KEYEV_DOWN || k.type == KEYEV_HOLD) && feat && feat(k))
|
|
continue;
|
|
|
|
if(k.type != KEYEV_NONE && !jscene_process_key_event(s, k)) {
|
|
e.type = JWIDGET_KEY;
|
|
e.key = k;
|
|
break;
|
|
}
|
|
|
|
// TODO: Should only sleep when out of events!
|
|
sleep();
|
|
}
|
|
|
|
keydev_set_transform(d, tr0);
|
|
return e;
|
|
}
|
|
|
|
/* jscene type definition */
|
|
static jwidget_poly type_jscene = {
|
|
.name = "jscene",
|
|
.csize = NULL,
|
|
.layout = NULL,
|
|
.render = NULL,
|
|
.event = NULL,
|
|
.destroy = NULL,
|
|
};
|
|
|
|
__attribute__((constructor(1001)))
|
|
static void j_register_jscene(void)
|
|
{
|
|
jscene_type_id = j_register_widget(&type_jscene, "jwidget");
|
|
JSCENE_NONE = j_register_event();
|
|
JSCENE_PAINT = j_register_event();
|
|
JSCENE_KEY = JWIDGET_KEY;
|
|
}
|