|
|
|
|
@ -32,12 +32,15 @@ struct app_instance {
|
|
|
|
|
struct tex framebuf;
|
|
|
|
|
// each instance has its own space for font rendering
|
|
|
|
|
struct tex fontbuf;
|
|
|
|
|
struct Component *component_root;
|
|
|
|
|
struct Component *component_focused;
|
|
|
|
|
struct app_instance *next_app;
|
|
|
|
|
struct app_instance *prev_app;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct slab_cache app_slab_cache;
|
|
|
|
|
struct slab_cache fontbuf_slab_cache;
|
|
|
|
|
struct slab_cache component_cache;
|
|
|
|
|
|
|
|
|
|
struct app_instance *app_root = NULL;
|
|
|
|
|
|
|
|
|
|
@ -56,6 +59,7 @@ void app_init_global(void) {
|
|
|
|
|
|
|
|
|
|
slab_cache_init(&app_slab_cache, sizeof(struct app_instance), NULL, NULL);
|
|
|
|
|
slab_cache_init(&fontbuf_slab_cache, font_width(&app_font) * font_height(&app_font) * 4, NULL, NULL);
|
|
|
|
|
slab_cache_init(&component_cache, sizeof(struct Component), NULL, NULL);
|
|
|
|
|
extern struct app_template app_launcher_template;
|
|
|
|
|
ASSERT(app_push(&app_launcher_template, NULL, NULL));
|
|
|
|
|
|
|
|
|
|
@ -63,6 +67,137 @@ void app_init_global(void) {
|
|
|
|
|
atomic_store(&app_initialized, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void layout(struct Component *cpnt) {
|
|
|
|
|
int x = 0, y = 0;
|
|
|
|
|
unsigned fw = app_text_width(), fh = app_text_height();
|
|
|
|
|
// at the moment everything has the same size
|
|
|
|
|
for ( ; cpnt; cpnt = cpnt->next) {
|
|
|
|
|
cpnt->rect = RECT_XYWH(x, y, 20 * fw + 6, fh + 6);
|
|
|
|
|
y += fh + 6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct MyApp {
|
|
|
|
|
struct Component *one;
|
|
|
|
|
struct Component *two;
|
|
|
|
|
struct Component *out;
|
|
|
|
|
} my_app_instance; // TODO dynamic
|
|
|
|
|
|
|
|
|
|
static struct app_instance *app_find(void *app);
|
|
|
|
|
|
|
|
|
|
void draw_focus(void *app, struct Component *cpnt) {
|
|
|
|
|
app_draw_rect(app, COLOR_RGB(255, 0, 0), &RECT_XYWH(cpnt->rect.x, cpnt->rect.y, RECT_WIDTH(cpnt->rect), 1));
|
|
|
|
|
app_draw_rect(app, COLOR_RGB(255, 0, 0), &RECT_XYWH(cpnt->rect.x, cpnt->rect.y + RECT_HEIGHT(cpnt->rect) - 1, RECT_WIDTH(cpnt->rect), 1));
|
|
|
|
|
app_draw_rect(app, COLOR_RGB(255, 0, 0), &RECT_XYWH(cpnt->rect.x, cpnt->rect.y, 1, RECT_HEIGHT(cpnt->rect)));
|
|
|
|
|
app_draw_rect(app, COLOR_RGB(255, 0, 0), &RECT_XYWH(cpnt->rect.x + RECT_WIDTH(cpnt->rect) - 1, cpnt->rect.y, 1, RECT_HEIGHT(cpnt->rect)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void redraw(void *app, struct Component *cpnt) {
|
|
|
|
|
switch (cpnt->type) {
|
|
|
|
|
case CPNT_TYPE_TEXT_INPUT:
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(255), &cpnt->rect);
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(0), &RECT_XYWH(
|
|
|
|
|
cpnt->rect.x + 1,
|
|
|
|
|
cpnt->rect.y + 1,
|
|
|
|
|
RECT_WIDTH(cpnt->rect) - 2,
|
|
|
|
|
RECT_HEIGHT(cpnt->rect) - 2
|
|
|
|
|
));
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(255), &RECT_XYWH(
|
|
|
|
|
cpnt->rect.x + 2,
|
|
|
|
|
cpnt->rect.y + 2,
|
|
|
|
|
RECT_WIDTH(cpnt->rect) - 4,
|
|
|
|
|
RECT_HEIGHT(cpnt->rect) - 4
|
|
|
|
|
));
|
|
|
|
|
app_draw_text(app, cpnt->data.text_input.text, cpnt->rect.x + 3, cpnt->rect.y + 3, COLOR_LUMA(0), COLOR_LUMA(255));
|
|
|
|
|
break;
|
|
|
|
|
case CPNT_TYPE_BUTTON:
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(150), &cpnt->rect);
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(0), &RECT_XYWH(
|
|
|
|
|
cpnt->rect.x + 1,
|
|
|
|
|
cpnt->rect.y + 1,
|
|
|
|
|
RECT_WIDTH(cpnt->rect) - 2,
|
|
|
|
|
RECT_HEIGHT(cpnt->rect) - 2
|
|
|
|
|
));
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(150), &RECT_XYWH(
|
|
|
|
|
cpnt->rect.x + 2,
|
|
|
|
|
cpnt->rect.y + 2,
|
|
|
|
|
RECT_WIDTH(cpnt->rect) - 4,
|
|
|
|
|
RECT_HEIGHT(cpnt->rect) - 4
|
|
|
|
|
));
|
|
|
|
|
app_draw_text(app, cpnt->data.button.text, cpnt->rect.x + 3, cpnt->rect.y + 3, COLOR_LUMA(0), COLOR_LUMA(150));
|
|
|
|
|
break;
|
|
|
|
|
case CPNT_TYPE_LABEL:
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(255), &cpnt->rect);
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(0), &RECT_XYWH(
|
|
|
|
|
cpnt->rect.x + 1,
|
|
|
|
|
cpnt->rect.y + 1,
|
|
|
|
|
RECT_WIDTH(cpnt->rect) - 2,
|
|
|
|
|
RECT_HEIGHT(cpnt->rect) - 2
|
|
|
|
|
));
|
|
|
|
|
app_draw_rect(app, COLOR_LUMA(255), &RECT_XYWH(
|
|
|
|
|
cpnt->rect.x + 2,
|
|
|
|
|
cpnt->rect.y + 2,
|
|
|
|
|
RECT_WIDTH(cpnt->rect) - 4,
|
|
|
|
|
RECT_HEIGHT(cpnt->rect) - 4
|
|
|
|
|
));
|
|
|
|
|
app_draw_text(app, cpnt->data.label.text, cpnt->rect.x + 3, cpnt->rect.y + 3, COLOR_LUMA(0), COLOR_LUMA(255));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void on_click(void *self, struct Component *btn) {
|
|
|
|
|
struct MyApp *app = self;
|
|
|
|
|
uint64_t one_val;
|
|
|
|
|
uint64_t two_val;
|
|
|
|
|
const char *s;
|
|
|
|
|
s = app->one->data.text_input.text;
|
|
|
|
|
ASSERT(parse_u64(&s, &one_val));
|
|
|
|
|
s = app->two->data.text_input.text;
|
|
|
|
|
ASSERT(parse_u64(&s, &two_val));
|
|
|
|
|
char *out = app->out->data.label.text;
|
|
|
|
|
uint64_t result = one_val + two_val;
|
|
|
|
|
do {
|
|
|
|
|
*out++ = '0' + (result % 10);
|
|
|
|
|
result /= 10;
|
|
|
|
|
} while (result > 0);
|
|
|
|
|
*out = 0;
|
|
|
|
|
unsigned len = out - app->out->data.label.text;
|
|
|
|
|
out = app->out->data.label.text;
|
|
|
|
|
for (int i = 0; i < len/2; i++) {
|
|
|
|
|
char tmp = out[i];
|
|
|
|
|
out[i] = out[len - i - 1];
|
|
|
|
|
out[len - i - 1] = tmp;
|
|
|
|
|
}
|
|
|
|
|
redraw(self, app->out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct AppCreation my_app_create(size_t width, size_t height, void *arg) {
|
|
|
|
|
struct Component *one = slab_cache_alloc(&component_cache);
|
|
|
|
|
one->type = CPNT_TYPE_TEXT_INPUT;
|
|
|
|
|
one->data.text_input.text[0] = 0;
|
|
|
|
|
struct Component *two = slab_cache_alloc(&component_cache);
|
|
|
|
|
two->type = CPNT_TYPE_TEXT_INPUT;
|
|
|
|
|
two->data.text_input.text[0] = 0;
|
|
|
|
|
struct Component *btn = slab_cache_alloc(&component_cache);
|
|
|
|
|
btn->type = CPNT_TYPE_BUTTON;
|
|
|
|
|
btn->data.button.text = "calculate";
|
|
|
|
|
btn->data.button.on_click = on_click;
|
|
|
|
|
struct Component *out = slab_cache_alloc(&component_cache);
|
|
|
|
|
out->type = CPNT_TYPE_LABEL;
|
|
|
|
|
out->data.label.text[0] = 0;
|
|
|
|
|
one->next = two;
|
|
|
|
|
two->next = btn;
|
|
|
|
|
btn->next = out;
|
|
|
|
|
out->next = NULL;
|
|
|
|
|
my_app_instance.one = one;
|
|
|
|
|
my_app_instance.two = two;
|
|
|
|
|
my_app_instance.out = out;
|
|
|
|
|
return (struct AppCreation) {
|
|
|
|
|
.ptr = &my_app_instance,
|
|
|
|
|
.root = one,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct app_instance *app_find(void *app) {
|
|
|
|
|
|
|
|
|
|
if (app_root->app == app) {
|
|
|
|
|
@ -120,7 +255,6 @@ struct rect app_rect_local_to_global(struct app_instance *ins, const struct rect
|
|
|
|
|
return real_rect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO adapt to tex_blit interface (src and dst rect)
|
|
|
|
|
void app_draw_rect(void *self, struct color col, const struct rect *rect) {
|
|
|
|
|
struct app_instance *ins = app_find(self);
|
|
|
|
|
ASSERT(ins != NULL);
|
|
|
|
|
@ -193,8 +327,8 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
|
|
|
|
|
} else {
|
|
|
|
|
actual_pos = fb_rect();
|
|
|
|
|
}
|
|
|
|
|
void *app = template->create(RECT_WIDTH(actual_pos), RECT_HEIGHT(actual_pos), arg);
|
|
|
|
|
if (app == NULL) {
|
|
|
|
|
struct AppCreation creation = template->create(RECT_WIDTH(actual_pos), RECT_HEIGHT(actual_pos), arg);
|
|
|
|
|
if (creation.ptr == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// allocate framebuf
|
|
|
|
|
@ -208,13 +342,21 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
|
|
|
|
|
ASSERT(ram_alloc_buffer(&ppn, req));
|
|
|
|
|
void *fontbuf = slab_cache_alloc(&fontbuf_slab_cache);
|
|
|
|
|
ASSERT(fontbuf != NULL);
|
|
|
|
|
|
|
|
|
|
// layout
|
|
|
|
|
layout(creation.root);
|
|
|
|
|
|
|
|
|
|
if (app_root != NULL && app_root->component_focused) {
|
|
|
|
|
redraw(app_root->app, app_root->component_focused);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO this structure should be locked
|
|
|
|
|
struct app_instance *new_app = slab_cache_alloc(&app_slab_cache);
|
|
|
|
|
ASSERT(new_app != NULL);
|
|
|
|
|
*new_app = (struct app_instance){
|
|
|
|
|
.template = template,
|
|
|
|
|
.pos = actual_pos,
|
|
|
|
|
.app = app,
|
|
|
|
|
.app = creation.ptr,
|
|
|
|
|
.framebuf = TEX_CREATE(
|
|
|
|
|
RECT_WIDTH(actual_pos),
|
|
|
|
|
RECT_HEIGHT(actual_pos),
|
|
|
|
|
@ -225,6 +367,8 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
|
|
|
|
|
font_height(&app_font),
|
|
|
|
|
fontbuf
|
|
|
|
|
),
|
|
|
|
|
.component_root = creation.root,
|
|
|
|
|
.component_focused = NULL,
|
|
|
|
|
.next_app = app_root != NULL ? app_root : new_app,
|
|
|
|
|
.prev_app = app_root != NULL ? app_root->prev_app : new_app
|
|
|
|
|
};
|
|
|
|
|
@ -234,7 +378,12 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
|
|
|
|
|
}
|
|
|
|
|
app_root = new_app;
|
|
|
|
|
|
|
|
|
|
template->init(app);
|
|
|
|
|
for (struct Component *c = creation.root; c; c = c->next) {
|
|
|
|
|
redraw(creation.ptr, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (template->init)
|
|
|
|
|
template->init(creation.ptr);
|
|
|
|
|
fb_refresh();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@ -277,10 +426,10 @@ void app_translate(struct app_instance *ins, int dx, int dy) {
|
|
|
|
|
extern struct app_template app_launcher_template;
|
|
|
|
|
|
|
|
|
|
void app_key_event_listener(struct key_event event) {
|
|
|
|
|
if (app_root == NULL) {
|
|
|
|
|
struct app_instance *ins = app_top();
|
|
|
|
|
if (ins == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
struct app_instance *ins = app_top();
|
|
|
|
|
|
|
|
|
|
if (event.code == KEY_ARROW_LEFT && (event.mod & KEY_MOD_SHIFT)) {
|
|
|
|
|
if (event.pressed && ins->template != &app_launcher_template) {
|
|
|
|
|
@ -309,6 +458,11 @@ void app_key_event_listener(struct key_event event) {
|
|
|
|
|
if (event.code == KEY_TAB && (event.mod & KEY_MOD_SHIFT)) {
|
|
|
|
|
// select next app to be the current one now (natural rotation, easy for now)
|
|
|
|
|
if (event.pressed) {
|
|
|
|
|
// remove focus from the thing it's currently on
|
|
|
|
|
if (ins->component_focused) {
|
|
|
|
|
redraw(ins->app, ins->component_focused);
|
|
|
|
|
ins->component_focused = NULL;
|
|
|
|
|
}
|
|
|
|
|
app_root = app_root->next_app;
|
|
|
|
|
// redraw this new top window
|
|
|
|
|
struct tex fb_tex = fb_as_tex();
|
|
|
|
|
@ -328,89 +482,129 @@ void app_key_event_listener(struct key_event event) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ins->template->event_keyboard) {
|
|
|
|
|
ins->template->event_keyboard(ins->app, event);
|
|
|
|
|
if (event.code == KEY_TAB && event.pressed) {
|
|
|
|
|
struct Component *old_component = ins->component_focused;
|
|
|
|
|
if (ins->component_focused == NULL) {
|
|
|
|
|
ins->component_focused = ins->component_root;
|
|
|
|
|
} else {
|
|
|
|
|
if (ins->component_focused->next) {
|
|
|
|
|
ins->component_focused = ins->component_focused->next;
|
|
|
|
|
} else {
|
|
|
|
|
ins->component_focused = ins->component_root;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (old_component)
|
|
|
|
|
redraw(ins->app, old_component);
|
|
|
|
|
draw_focus(ins->app, ins->component_focused);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO text field input based on focused element
|
|
|
|
|
if (ins->component_focused) {
|
|
|
|
|
if (ins->component_focused->type == CPNT_TYPE_BUTTON) {
|
|
|
|
|
if (event.code == KEY_ENTER && event.pressed) {
|
|
|
|
|
ins->component_focused->data.button.on_click(ins->app, ins->component_focused);
|
|
|
|
|
}
|
|
|
|
|
} else if (ins->component_focused->type == CPNT_TYPE_TEXT_INPUT) {
|
|
|
|
|
if (event.code == KEY_BACKSPACE && event.pressed) {
|
|
|
|
|
uint8_t *start = (uint8_t*)ins->component_focused->data.text_input.text;
|
|
|
|
|
uint8_t *c = start;
|
|
|
|
|
while (*c != 0) {
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
if (c > start) {
|
|
|
|
|
*--c = 0;
|
|
|
|
|
redraw(ins->app, ins->component_focused);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event.printable && event.pressed) {
|
|
|
|
|
uint8_t *c = (uint8_t*)ins->component_focused->data.text_input.text;
|
|
|
|
|
while (*c != 0) {
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
utf8_write(c, event.printable);
|
|
|
|
|
redraw(ins->app, ins->component_focused);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern struct app_template app_kbdbg_template;
|
|
|
|
|
extern struct app_template snake_template;
|
|
|
|
|
extern struct app_template tron_template;
|
|
|
|
|
extern struct app_template app_kernmsg_template;
|
|
|
|
|
struct app_template my_app_template = {
|
|
|
|
|
.create = my_app_create,
|
|
|
|
|
.init = NULL,
|
|
|
|
|
.destroy = NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define KNOWN_APPS_SIZE 10
|
|
|
|
|
struct {
|
|
|
|
|
const char *name;
|
|
|
|
|
struct app_template *template;
|
|
|
|
|
} known_apps[KNOWN_APPS_SIZE] = {
|
|
|
|
|
} known_apps[] = {
|
|
|
|
|
{
|
|
|
|
|
"keyboard-debug",
|
|
|
|
|
&app_kbdbg_template,
|
|
|
|
|
"aaa",
|
|
|
|
|
&my_app_template,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"snake",
|
|
|
|
|
&snake_template,
|
|
|
|
|
"bbbb",
|
|
|
|
|
&my_app_template,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"tron",
|
|
|
|
|
&tron_template,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"kernmsg",
|
|
|
|
|
&app_kernmsg_template,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
size_t num_known_apps = 4;
|
|
|
|
|
#define NUM_KNOWN_APPS (sizeof(known_apps)/sizeof(known_apps[0]))
|
|
|
|
|
|
|
|
|
|
#define FONT_TEX_NUM_PIXELS 10*20
|
|
|
|
|
|
|
|
|
|
struct app_launcher {
|
|
|
|
|
int current_app;
|
|
|
|
|
struct color fg;
|
|
|
|
|
struct color bg;
|
|
|
|
|
struct Component *label;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void *app_launcher_create(size_t width, size_t height, void *arg) {
|
|
|
|
|
(void) arg;
|
|
|
|
|
struct app_launcher *app = ram_alloc_page_zeroed_asserted();
|
|
|
|
|
return app;
|
|
|
|
|
void button_next(void *self, struct Component *cpnt) {
|
|
|
|
|
struct app_launcher *app = self;
|
|
|
|
|
app->current_app = (app->current_app + 1) % NUM_KNOWN_APPS;
|
|
|
|
|
// TODO to we have strcpy?
|
|
|
|
|
const char *c = known_apps[app->current_app].name;
|
|
|
|
|
char *d = app->label->data.label.text;
|
|
|
|
|
while (*c) { *d++ = *c++; }
|
|
|
|
|
redraw(self, app->label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void app_launcher_init(void *self) {
|
|
|
|
|
void button_launch(void *self, struct Component *cpnt) {
|
|
|
|
|
struct app_launcher *app = self;
|
|
|
|
|
app_push(known_apps[app->current_app].template, NULL, &RECT_XYWH(100, 100, 400, 400));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct AppCreation app_launcher_create(size_t width, size_t height, void *arg) {
|
|
|
|
|
(void) arg;
|
|
|
|
|
struct app_launcher *app = ram_alloc_page_zeroed_asserted();
|
|
|
|
|
app->current_app = 0;
|
|
|
|
|
app->fg = COLOR_RGB(0, 255, 100);
|
|
|
|
|
app->bg = COLOR_LUMA(50);
|
|
|
|
|
app_draw_rect(self, app->bg, NULL);
|
|
|
|
|
app_draw_text(self, known_apps[app->current_app].name, 0, 0, app->fg, app->bg);
|
|
|
|
|
struct Component *label = slab_cache_alloc(&component_cache);
|
|
|
|
|
app->label = label;
|
|
|
|
|
label->type = CPNT_TYPE_LABEL;
|
|
|
|
|
// TODO to we have strcpy?
|
|
|
|
|
const char *c = known_apps[app->current_app].name;
|
|
|
|
|
char *d = label->data.label.text;
|
|
|
|
|
while (*c) { *d++ = *c++; }
|
|
|
|
|
|
|
|
|
|
struct Component *btn_next = slab_cache_alloc(&component_cache);
|
|
|
|
|
btn_next->type = CPNT_TYPE_BUTTON;
|
|
|
|
|
btn_next->data.button.text = "next";
|
|
|
|
|
btn_next->data.button.on_click = button_next;
|
|
|
|
|
struct Component *btn_launch = slab_cache_alloc(&component_cache);
|
|
|
|
|
btn_launch->type = CPNT_TYPE_BUTTON;
|
|
|
|
|
btn_launch->data.button.text = "launch";
|
|
|
|
|
btn_launch->data.button.on_click = button_launch;
|
|
|
|
|
label->next = btn_next;
|
|
|
|
|
btn_next->next = btn_launch;
|
|
|
|
|
btn_launch->next = NULL;
|
|
|
|
|
|
|
|
|
|
return (struct AppCreation) { app, label };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void app_launcher_destroy(void *self) {
|
|
|
|
|
// TODO free other stuff
|
|
|
|
|
ram_free(ppn_from_aligned_pa(pa_from_pointer(self)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void app_launcher_event_keyboard(void *self, struct key_event ev) {
|
|
|
|
|
struct app_launcher *app = self;
|
|
|
|
|
bool changed = false;
|
|
|
|
|
if (ev.code == KEY_ARROW_RIGHT && ev.pressed) {
|
|
|
|
|
app->current_app = (app->current_app + 1) % num_known_apps;
|
|
|
|
|
changed = true;
|
|
|
|
|
} else if (ev.code == KEY_ARROW_LEFT && ev.pressed) {
|
|
|
|
|
app->current_app = (app->current_app - 1) % num_known_apps;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
if (changed) {
|
|
|
|
|
app_draw_rect(app, app->bg, NULL);
|
|
|
|
|
app_draw_text(self, known_apps[app->current_app].name, 0, 0, app->fg, app->bg);
|
|
|
|
|
}
|
|
|
|
|
if (ev.code == KEY_ENTER && ev.pressed) {
|
|
|
|
|
app_push(known_apps[app->current_app].template, NULL, &RECT_XYWH(100, 100, 400, 400));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct app_template app_launcher_template = {
|
|
|
|
|
.create = app_launcher_create,
|
|
|
|
|
.init = app_launcher_init,
|
|
|
|
|
.init = NULL,
|
|
|
|
|
.destroy = app_launcher_destroy,
|
|
|
|
|
.event_keyboard = app_launcher_event_keyboard,
|
|
|
|
|
};
|
|
|
|
|
|