aboutsummaryrefslogtreecommitdiff
path: root/libs/libgui/gui.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libgui/gui.c')
-rw-r--r--libs/libgui/gui.c240
1 files changed, 225 insertions, 15 deletions
diff --git a/libs/libgui/gui.c b/libs/libgui/gui.c
index d8435e6..2c6221a 100644
--- a/libs/libgui/gui.c
+++ b/libs/libgui/gui.c
@@ -7,44 +7,241 @@
#include <libgui/msg.h>
#include <list.h>
#include <print.h>
+#include <random.h>
#define WM_PATH "/bin/wm"
+struct gui_widget {
+ u32 id;
+ vec2 pos;
+ struct context ctx;
+ struct list *children;
+
+ struct {
+ void (*mousemove)(vec2 pos);
+ } event;
+};
+
struct gui_window {
u32 id;
struct context ctx;
+ struct list *widgets;
};
struct list *windows = NULL;
-static struct gui_window *win_by_id(u32 id)
+/**
+ * Resolve/find stuff
+ */
+
+static struct gui_window *win_by_id(u32 win_id)
{
assert(windows);
struct node *iterator = windows->head;
while (iterator) {
struct gui_window *win = iterator->data;
- if (win->id == id)
+ if (win->id == win_id)
+ return iterator->data;
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+static struct gui_widget *widget_in_widget(struct gui_widget *parent, u32 widget_id)
+{
+ if (parent->id == widget_id)
+ return parent;
+
+ if (!parent->children)
+ return NULL;
+
+ struct node *iterator = parent->children->head;
+ while (iterator) {
+ struct gui_widget *widget = iterator->data;
+ if (widget->id == widget_id)
return iterator->data;
+
+ struct gui_widget *sub = widget_in_widget(widget, widget_id);
+ if (sub && sub->id == widget_id)
+ return sub;
+
iterator = iterator->next;
}
+
return NULL;
}
+static struct gui_widget *widget_in_win(struct gui_window *win, u32 widget_id)
+{
+ assert(win->widgets);
+ struct node *iterator = win->widgets->head;
+ while (iterator) {
+ struct gui_widget *widget = iterator->data;
+ if (widget->id == widget_id)
+ return iterator->data;
+
+ struct gui_widget *sub = widget_in_widget(widget, widget_id);
+ if (sub && sub->id == widget_id)
+ return sub;
+
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+static struct gui_widget *widget_by_id(u32 win_id, u32 widget_id)
+{
+ struct gui_window *win = win_by_id(win_id);
+ return widget_in_win(win, widget_id);
+}
+
/**
* GFX wrappers
*/
-static res fill(u32 id, u32 c)
+res gui_fill(u32 win_id, u32 widget_id, u32 c)
+{
+ struct gui_widget *widget = widget_by_id(win_id, widget_id);
+ if (!widget)
+ return_errno(ENOENT);
+
+ gfx_fill(&widget->ctx, c);
+
+ return_errno(EOK);
+}
+
+/**
+ * Widgets
+ */
+
+static res gui_widget_at(u32 win_id, vec2 pos, struct gui_widget *widget)
+{
+ struct gui_window *win = win_by_id(win_id);
+ if (!win)
+ return_errno(ENOENT);
+
+ struct gui_widget *ret = NULL;
+
+ struct node *iterator = win->widgets->head;
+ while (iterator) {
+ struct gui_widget *w = iterator->data;
+ if (pos.x >= w->pos.x && pos.x <= w->pos.x + w->ctx.size.x && pos.y >= w->pos.y &&
+ pos.y <= w->pos.y + w->ctx.size.y)
+ ret = widget;
+ // TODO: Search in children
+ iterator = iterator->next;
+ }
+
+ if (widget) {
+ *widget = *ret;
+ return_errno(EOK);
+ } else {
+ return_errno(ENOENT);
+ }
+}
+
+static res gui_sync_widget(u32 win_id, u32 widget_id)
+{
+ struct gui_window *win = win_by_id(win_id);
+ struct gui_widget *widget = widget_in_win(win, widget_id);
+ if (!widget)
+ return_errno(ENOENT);
+
+ gfx_ctx_on_ctx(&win->ctx, &widget->ctx, widget->pos);
+
+ return_errno(EOK);
+}
+
+static struct gui_widget *gui_win_main_widget(struct gui_window *win)
+{
+ return win->widgets->head->data;
+}
+
+static struct gui_widget *gui_new_plain_widget(vec2 size, vec2 pos, u8 bpp)
+{
+ struct gui_widget *widget = zalloc(sizeof(*widget));
+ struct context *ctx = zalloc(sizeof(*ctx));
+
+ widget->id = rand();
+ widget->pos = pos;
+ widget->ctx = *gfx_new_ctx(ctx, size, bpp);
+ widget->children = list_new();
+
+ return widget;
+}
+
+res gui_add_widget(u32 win_id, u32 widget_id, vec2 size, vec2 pos)
+{
+ struct gui_widget *parent = widget_by_id(win_id, widget_id);
+ if (!parent)
+ return_errno(ENOENT);
+
+ struct gui_widget *child = gui_new_plain_widget(size, pos, parent->ctx.bpp);
+ list_add(parent->children, child);
+
+ return child->id;
+}
+
+res gui_new_widget(u32 win_id, vec2 size, vec2 pos)
+{
+ struct gui_window *win = win_by_id(win_id);
+ if (!win)
+ return_errno(ENOENT);
+
+ if (!win->widgets->head)
+ list_add(win->widgets,
+ gui_new_plain_widget(win->ctx.size, vec2(0, 0), win->ctx.bpp));
+
+ return gui_add_widget(win->id, gui_win_main_widget(win)->id, size, pos);
+}
+
+res gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func)
+{
+ if (!func)
+ return_errno(EFAULT);
+
+ struct gui_widget *widget = widget_by_id(win_id, widget_id);
+ if (!widget)
+ return_errno(ENOENT);
+
+ switch (listener) {
+ case GUI_LISTEN_MOUSEMOVE:
+ widget->event.mousemove = (void (*)(vec2))func;
+ break;
+ default:
+ return_errno(ENOENT);
+ }
+
+ return_errno(EOK);
+}
+
+res gui_redraw_widget(u32 win_id, u32 widget_id)
+{
+ if (gui_sync_widget(win_id, widget_id) != EOK)
+ return errno;
+
+ if (gui_redraw_window(win_id) != EOK)
+ return errno;
+
+ return_errno(EOK);
+}
+
+/**
+ * Window data getters
+ */
+
+vec2 gui_window_size(u32 win_id)
{
- struct gui_window *win = win_by_id(id);
+ struct gui_window *win = win_by_id(win_id);
if (!win)
- return -ENOENT;
- gfx_fill(&win->ctx, c);
- return EOK;
+ return vec2(0, 0);
+ return win->ctx.size;
}
/**
- * Program interface
+ * Window manager interfaces
*/
res gui_new_window(void)
@@ -63,13 +260,14 @@ res gui_new_window(void)
u32 size;
res ret = shaccess(msg.shid, (u32 *)&win->ctx.fb, &size);
if (ret < 0 || !win->ctx.fb)
- return MIN(ret, -EFAULT);
+ return_errno(-MIN(ret, -EFAULT));
list_add(windows, win);
- assert(fill(win->id, COLOR_BLACK) == EOK);
- gui_redraw_window(win->id);
+ win->widgets = list_new();
+
return win->id;
}
- return -EINVAL;
+
+ return_errno(EINVAL);
}
res gui_redraw_window(u32 id)
@@ -79,7 +277,8 @@ res gui_redraw_window(u32 id)
msg_receive(&msg, sizeof(msg)) > 0 &&
msg.header.type == (GUI_REDRAW_WINDOW | MSG_SUCCESS))
return id;
- return -EINVAL;
+
+ return_errno(EINVAL);
}
/**
@@ -106,10 +305,21 @@ static res handle_ping(struct message_ping *msg)
static res handle_mouse(struct message_mouse *msg)
{
- if (msg->header.state == MSG_NEED_ANSWER)
+ if (msg->header.state == MSG_NEED_ANSWER) {
msg_send(msg->header.src, msg->header.type | MSG_SUCCESS, msg, sizeof(*msg));
- return errno;
+ if (errno != EOK)
+ return errno;
+ }
+
+ struct gui_widget widget = { 0 };
+ if (gui_widget_at(msg->id, msg->pos, &widget) != EOK)
+ return_errno(EOK);
+
+ if (widget.event.mousemove)
+ widget.event.mousemove(msg->pos);
+
+ return_errno(EOK);
}
static void handle_exit(void)