diff options
Diffstat (limited to 'libs/libgui/gui.c')
-rw-r--r-- | libs/libgui/gui.c | 163 |
1 files changed, 138 insertions, 25 deletions
diff --git a/libs/libgui/gui.c b/libs/libgui/gui.c index 023bc98..859fb5a 100644 --- a/libs/libgui/gui.c +++ b/libs/libgui/gui.c @@ -17,13 +17,14 @@ struct gui_widget { struct list *children; struct { - void (*mousemove)(u32 widget_id, vec2 pos); - void (*mouseclick)(u32 widget_id, vec2 pos); + void (*mousemove)(struct gui_event_mouse *event); + void (*mouseclick)(struct gui_event_mouse *event); } event; }; struct gui_window { u32 id; + vec2 off; // fb offset vec2 pos; struct context ctx; struct list *widgets; @@ -190,6 +191,50 @@ void gui_load_image(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, v gui_load_image_filter(win_id, widget_id, layer, pos, size, GFX_FILTER_NONE, path); } +void gui_draw_rectangle(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos1, vec2 pos2, + u32 c) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + gui_error(ENOENT); + + if (layer == GUI_LAYER_BG) + gfx_draw_rectangle(&widget->bg, pos1, pos2, c); + else if (layer == GUI_LAYER_FG) + gfx_draw_rectangle(&widget->fg, pos1, pos2, c); + else + gui_error(EINVAL); +} + +void gui_draw_border(u32 win_id, u32 widget_id, enum gui_layer layer, u32 width, u32 c) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + gui_error(ENOENT); + + if (layer == GUI_LAYER_BG) + gfx_draw_border(&widget->bg, width, c); + else if (layer == GUI_LAYER_FG) + gfx_draw_border(&widget->fg, width, c); + else + gui_error(EINVAL); +} + +void gui_draw_line(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos1, vec2 pos2, u32 scale, + u32 c) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + gui_error(ENOENT); + + if (layer == GUI_LAYER_BG) + gfx_draw_line(&widget->bg, pos1, pos2, scale, c); + else if (layer == GUI_LAYER_FG) + gfx_draw_line(&widget->fg, pos1, pos2, scale, c); + else + gui_error(EINVAL); +} + /** * Widgets */ @@ -266,6 +311,7 @@ static void gui_sync_sub_widgets(struct gui_widget *widget) struct node *iterator = widget->children->head; while (iterator) { struct gui_widget *w = iterator->data; + gui_sync_sub_widgets(w); gfx_ctx_on_ctx(&widget->bg, &w->bg, w->pos, GFX_NON_ALPHA); gfx_ctx_on_ctx(&widget->fg, &w->fg, w->pos, GFX_NON_ALPHA); iterator = iterator->next; @@ -346,14 +392,14 @@ static vec2 gui_offset_widget(struct gui_widget *parent, struct gui_widget *chil static struct gui_widget *gui_new_plain_widget(vec2 pos, vec2 size, u8 bpp) { struct gui_widget *widget = zalloc(sizeof(*widget)); - struct context *bg = zalloc(sizeof(*bg)); - struct context *fg = zalloc(sizeof(*fg)); + struct context bg; + struct context fg; static u32 id = 0; widget->id = id++; widget->pos = pos; - widget->bg = *gfx_new_ctx(bg, size, bpp); - widget->fg = *gfx_new_ctx(fg, size, bpp); + widget->bg = *gfx_new_ctx(&bg, size, bpp); + widget->fg = *gfx_new_ctx(&fg, size, bpp); widget->children = list_new(); return widget; @@ -371,6 +417,41 @@ void gui_add_widget(u32 *widget, u32 win_id, u32 widget_id, vec2 pos, vec2 size) *widget = child->id; } +static void gui_destroy_widget(u32 win_id, u32 widget_id) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + return; + + struct node *iterator = widget->children->head; + while (iterator) { + struct gui_widget *sub = iterator->data; + gui_destroy_widget(win_id, sub->id); + iterator = iterator->next; + } + + list_destroy(widget->children); + free(widget->bg.fb); + free(widget->fg.fb); + free(widget); +} + +static void gui_destroy_widgets(u32 win_id) +{ + struct gui_window *win = gui_window_by_id(win_id); + + if (!win->widgets) + return; + + struct node *iterator = win->widgets->head; + while (iterator) { + struct gui_widget *widget = iterator->data; + gui_destroy_widget(win_id, widget->id); + iterator = iterator->next; + } + list_destroy(win->widgets); +} + void gui_new_widget(u32 *widget, u32 win_id, vec2 pos, vec2 size) { struct gui_window *win = gui_window_by_id(win_id); @@ -391,10 +472,10 @@ void gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u3 switch (listener) { case GUI_LISTEN_MOUSEMOVE: - widget->event.mousemove = (void (*)(u32, vec2))func; + widget->event.mousemove = (void (*)(struct gui_event_mouse *))func; break; case GUI_LISTEN_MOUSECLICK: - widget->event.mouseclick = (void (*)(u32, vec2))func; + widget->event.mouseclick = (void (*)(struct gui_event_mouse *))func; break; default: gui_error(ENOENT); @@ -404,7 +485,7 @@ void gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u3 void gui_redraw_widget(u32 win_id, u32 widget_id) { gui_sync_widget(win_id, widget_id); - gui_redraw_window(win_id); + gui_redraw_window_only(win_id); } /** @@ -467,6 +548,7 @@ void gui_new_custom_window(u32 *id, vec2 pos, vec2 size) if (msg_send(GUI_NEW_WINDOW, &msg, sizeof(msg)) > 0 && msg_receive(&msg, sizeof(msg)) > 0 && msg.header.type == (GUI_NEW_WINDOW | MSG_SUCCESS)) { win->id = msg.id; + win->off = msg.off; win->ctx = msg.ctx; win->pos = msg.pos; u32 buf_size; @@ -497,10 +579,8 @@ INLINE void gui_new_window(u32 *id) gui_new_custom_window(id, vec2(0, 0), vec2(0, 0)); } -void gui_redraw_window(u32 id) +void gui_redraw_window_only(u32 id) { - gui_sync_widgets(id); - struct message_redraw_window msg = { .id = id, .header.state = MSG_NEED_ANSWER }; gui_connect_wm(); if (msg_send(GUI_REDRAW_WINDOW, &msg, sizeof(msg)) > 0 && @@ -511,6 +591,37 @@ void gui_redraw_window(u32 id) gui_error(EINVAL); } +void gui_redraw_window(u32 id) +{ + gui_sync_widgets(id); + gui_redraw_window_only(id); +} + +static void gui_destroy_window(u32 id) +{ + gui_destroy_widgets(id); + + struct gui_window *win = gui_window_by_id(id); + u8 *fb = win->ctx.fb - (win->off.y * win->ctx.pitch); + assert(sys_free(fb) == EOK); + free(win); +} + +static void gui_destroy_all(void) +{ + struct node *iterator = windows->head; + while (iterator) { + struct gui_window *win = iterator->data; + struct message_destroy_window msg = { .id = win->id }; + gui_destroy_window(win->id); + gui_connect_wm(); + msg_send(GUI_DESTROY_WINDOW, &msg, sizeof(msg)); + iterator = iterator->next; + } + + list_destroy(windows); +} + /** * Message handling */ @@ -542,12 +653,23 @@ static void gui_handle_mouse(struct message_mouse *msg) struct gui_window *win = gui_window_by_id(msg->id); vec2 offset = gui_offset_widget(gui_main_widget(win), &widget); + vec2 pos = vec2_sub(msg->pos, offset); + + struct gui_event_mouse event = { + .win = win->id, + .widget = widget.id, + .pos = pos, + .scroll = msg->scroll, + .but.left = msg->but.left, + .but.right = msg->but.right, + .but.middle = msg->but.middle, + }; if (widget.event.mousemove) - widget.event.mousemove(widget.id, vec2_sub(msg->pos, offset)); + widget.event.mousemove(&event); - if (widget.event.mouseclick && msg->bits.click) - widget.event.mouseclick(widget.id, vec2_sub(msg->pos, offset)); + if (widget.event.mouseclick && msg->but.left) + widget.event.mouseclick(&event); } static void gui_handle_exit(void) @@ -555,16 +677,7 @@ static void gui_handle_exit(void) if (!windows) return; - struct node *iterator = windows->head; - while (iterator) { - struct gui_window *win = iterator->data; - struct message_destroy_window msg = { .id = win->id }; - gui_connect_wm(); - msg_send(GUI_DESTROY_WINDOW, &msg, sizeof(msg)); - iterator = iterator->next; - } - - list_destroy(windows); + gui_destroy_all(); } /** |