Window stack
This commit is contained in:
parent
64ea01f46b
commit
703b2ec3f0
1 changed files with 67 additions and 50 deletions
117
src/app.c
117
src/app.c
|
|
@ -22,14 +22,20 @@ static struct tex fb_as_tex(void) {
|
|||
};
|
||||
}
|
||||
|
||||
#define APP_STACK_SIZE 10
|
||||
struct app_instance {
|
||||
struct app_template *template;
|
||||
struct rect pos;
|
||||
void *app;
|
||||
struct tex framebuf;
|
||||
} app_stack[10];
|
||||
size_t app_stack_size = 0;
|
||||
struct app_instance *next_app;
|
||||
struct app_instance *prev_app;
|
||||
};
|
||||
|
||||
// Soon dynamic allocation
|
||||
struct app_instance apps[32];
|
||||
size_t free_idx = 0;
|
||||
|
||||
struct app_instance *app_root = NULL;
|
||||
|
||||
struct tex app_background;
|
||||
|
||||
|
|
@ -75,41 +81,43 @@ void app_init_global(void) {
|
|||
}
|
||||
|
||||
static struct app_instance *app_find(void *app) {
|
||||
for (int i = (int)app_stack_size - 1; i >= 0; i--) {
|
||||
if (app_stack[i].app == app) {
|
||||
return app_stack + i;
|
||||
|
||||
if (app_root->app == app) {
|
||||
return app_root;
|
||||
}
|
||||
|
||||
for (struct app_instance *cursor = app_root->next_app; cursor != app_root; cursor = cursor->next_app) {
|
||||
if (cursor->app == app) {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void app_redraw_below(struct rect uncovered, size_t idx) {
|
||||
ASSERT(idx < app_stack_size);
|
||||
static void app_redraw_below(struct rect uncovered, struct app_instance *ins) {
|
||||
struct tex fb_tex = fb_as_tex();
|
||||
tex_blit(&fb_tex, &app_background, &uncovered, &uncovered);
|
||||
for (size_t i = 0; i < idx; i++) {
|
||||
struct app_instance *ins = &app_stack[i];
|
||||
for (struct app_instance *cursor = ins->next_app; cursor != ins; cursor = cursor->next_app) {
|
||||
struct rect local_src = uncovered;
|
||||
struct rect local_dst = uncovered;
|
||||
rect_clamp(&local_src, &ins->pos);
|
||||
rect_clamp(&local_dst, &ins->pos);
|
||||
rect_translate(&local_src, -ins->pos.x, -ins->pos.y);
|
||||
tex_blit(&fb_tex, &ins->framebuf, &local_src, &local_dst);
|
||||
rect_clamp(&local_src, &cursor->pos);
|
||||
rect_clamp(&local_dst, &cursor->pos);
|
||||
rect_translate(&local_src, -cursor->pos.x, -cursor->pos.y);
|
||||
tex_blit(&fb_tex, &cursor->framebuf, &local_src, &local_dst);
|
||||
}
|
||||
fb_damage(uncovered);
|
||||
}
|
||||
|
||||
static void app_redraw_above(struct rect uncovered, size_t idx) {
|
||||
ASSERT(idx < app_stack_size);
|
||||
static void app_redraw_above(struct rect uncovered, struct app_instance *ins) {
|
||||
ASSERT(ins != NULL);
|
||||
struct tex fb_tex = fb_as_tex();
|
||||
for (size_t i = idx + 1; i < app_stack_size; i++) {
|
||||
struct app_instance *ins = &app_stack[i];
|
||||
for (struct app_instance *cursor = ins->prev_app; cursor != ins; cursor = cursor->prev_app) {
|
||||
struct rect local_src = uncovered;
|
||||
struct rect local_dst = uncovered;
|
||||
rect_clamp(&local_src, &ins->pos);
|
||||
rect_clamp(&local_dst, &ins->pos);
|
||||
rect_translate(&local_src, -ins->pos.x, -ins->pos.y);
|
||||
tex_blit(&fb_tex, &ins->framebuf, &local_src, &local_dst);
|
||||
rect_clamp(&local_src, &cursor->pos);
|
||||
rect_clamp(&local_dst, &cursor->pos);
|
||||
rect_translate(&local_src, -cursor->pos.x, -cursor->pos.y);
|
||||
tex_blit(&fb_tex, &cursor->framebuf, &local_src, &local_dst);
|
||||
}
|
||||
fb_damage(uncovered);
|
||||
}
|
||||
|
|
@ -142,9 +150,8 @@ void app_draw_rect(void *self, struct color col, const struct rect *rect) {
|
|||
tex_fill_region(&my_view, col, rect);
|
||||
|
||||
struct rect rect_global = app_rect_local_to_global(ins, rect);
|
||||
size_t own_idx = (ins - app_stack);
|
||||
if (own_idx < app_stack_size - 1) {
|
||||
app_redraw_above(rect_global, own_idx);
|
||||
if (ins != app_root) {
|
||||
app_redraw_above(rect_global, ins);
|
||||
}
|
||||
fb_damage(rect_global);
|
||||
}
|
||||
|
|
@ -162,9 +169,8 @@ void app_draw_texture(void *self, const struct tex *tex, int x, int y) {
|
|||
|
||||
struct rect rect_local = RECT_XYWH(x, y, tex->width, tex->height);
|
||||
struct rect rect_global = app_rect_local_to_global(ins, &rect_local);
|
||||
size_t own_idx = (ins - app_stack);
|
||||
if (own_idx < app_stack_size - 1) {
|
||||
app_redraw_above(rect_global, own_idx);
|
||||
if (ins != app_root) {
|
||||
app_redraw_above(rect_global, ins);
|
||||
}
|
||||
fb_damage(rect_global);
|
||||
}
|
||||
|
|
@ -189,9 +195,10 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
|
|||
};
|
||||
struct ppn ppn;
|
||||
ASSERT(ram_alloc_buffer(&ppn, req));
|
||||
ASSERT(app_stack_size < APP_STACK_SIZE);
|
||||
// TODO this structure should be locked
|
||||
app_stack[app_stack_size++] = (struct app_instance){
|
||||
// 32 = length of apps[]
|
||||
ASSERT(free_idx < 32);
|
||||
apps[free_idx] = (struct app_instance){
|
||||
.template = template,
|
||||
.pos = actual_pos,
|
||||
.app = app,
|
||||
|
|
@ -200,14 +207,23 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
|
|||
RECT_HEIGHT(actual_pos),
|
||||
ppn_to_pointer(ppn)
|
||||
),
|
||||
.next_app = app_root != NULL ? app_root : &apps[free_idx],
|
||||
.prev_app = app_root != NULL ? app_root->prev_app : &apps[free_idx]
|
||||
};
|
||||
if (app_root != NULL) {
|
||||
app_root->prev_app->next_app = &apps[free_idx];
|
||||
app_root->prev_app = &apps[free_idx];
|
||||
}
|
||||
app_root = &apps[free_idx];
|
||||
free_idx++;
|
||||
|
||||
template->init(app);
|
||||
fb_refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
void *app_top(void) {
|
||||
return (app_stack_size == 0) ? NULL : app_stack + app_stack_size - 1;
|
||||
return app_root;
|
||||
}
|
||||
|
||||
void app_pop(void) {
|
||||
|
|
@ -219,64 +235,65 @@ void app_pop(void) {
|
|||
ins->template->destroy(ins->app);
|
||||
ram_free(ppn_from_aligned_pa(pa_from_pointer(ins->framebuf.data)));
|
||||
|
||||
// we know `app_stack_size` is at least 1 here, so the decrement is safe
|
||||
app_redraw_below(uncovered, app_stack_size - 1);
|
||||
app_stack_size--;
|
||||
app_redraw_below(uncovered, ins);
|
||||
if (ins == ins->next_app) {
|
||||
app_root = NULL;
|
||||
return;
|
||||
}
|
||||
ins->next_app->prev_app = ins->prev_app;
|
||||
ins->prev_app->next_app = ins->next_app;
|
||||
app_root = ins->next_app;
|
||||
}
|
||||
|
||||
void app_translate(size_t app_idx, int dx, int dy) {
|
||||
void app_translate(struct app_instance *ins, int dx, int dy) {
|
||||
// TODO could optimize the uncovered
|
||||
ASSERT(app_idx < app_stack_size);
|
||||
struct app_instance *ins = &app_stack[app_idx];
|
||||
const struct rect uncovered = ins->pos;
|
||||
rect_translate(&ins->pos, dx, dy);
|
||||
struct tex fb_tex = fb_as_tex();
|
||||
// draw everything below, and then the current window
|
||||
app_redraw_below(uncovered, app_idx);
|
||||
app_redraw_below(uncovered, ins);
|
||||
tex_blit(&fb_tex, &ins->framebuf, NULL, &ins->pos);
|
||||
fb_damage(ins->pos);
|
||||
}
|
||||
|
||||
void app_key_event_listener(struct key_event event) {
|
||||
if (app_stack_size == 0) {
|
||||
if (app_root == NULL) {
|
||||
return;
|
||||
}
|
||||
struct app_instance *ins = app_top();
|
||||
|
||||
if (event.code == KEY_ARROW_LEFT && (event.mod & KEY_MOD_SHIFT)) {
|
||||
if (event.pressed) {
|
||||
app_translate(app_stack_size - 1, -10, 0);
|
||||
app_translate(ins, -10, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.code == KEY_ARROW_RIGHT && (event.mod & KEY_MOD_SHIFT)) {
|
||||
if (event.pressed) {
|
||||
app_translate(app_stack_size - 1, 10, 0);
|
||||
app_translate(ins, 10, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.code == KEY_ARROW_UP && (event.mod & KEY_MOD_SHIFT)) {
|
||||
if (event.pressed) {
|
||||
app_translate(app_stack_size - 1, 0, -10);
|
||||
app_translate(ins, 0, -10);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.code == KEY_ARROW_DOWN && (event.mod & KEY_MOD_SHIFT)) {
|
||||
if (event.pressed) {
|
||||
app_translate(app_stack_size - 1, 0, 10);
|
||||
app_translate(ins, 0, 10);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.code == KEY_TAB && (event.mod & KEY_MOD_SHIFT)) {
|
||||
// select lowest app to be the current one now (natural rotation, easy for now)
|
||||
if (event.pressed && app_stack_size >= 2) {
|
||||
struct app_instance lowest = app_stack[0];
|
||||
memmove(app_stack, app_stack + 1, (app_stack_size - 1) * sizeof(struct app_instance));
|
||||
app_stack[app_stack_size - 1] = lowest;
|
||||
// select next app to be the current one now (natural rotation, easy for now)
|
||||
if (event.pressed) {
|
||||
app_root = app_root->next_app;
|
||||
// redraw this new top window
|
||||
struct tex fb_tex = fb_as_tex();
|
||||
tex_blit(&fb_tex, &lowest.framebuf, NULL, &lowest.pos);
|
||||
fb_damage(lowest.pos);
|
||||
tex_blit(&fb_tex, &app_root->framebuf, NULL, &app_root->pos);
|
||||
fb_damage(app_root->pos);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue