diff options
author | Marvin Borner | 2021-05-21 15:25:42 +0200 |
---|---|---|
committer | Marvin Borner | 2021-05-21 15:25:42 +0200 |
commit | a69af1e2cc219f2f4010a6231dd32416a18437f2 (patch) | |
tree | 822571c69cc924adff0ec2c98c88f7bf928b43d5 | |
parent | 5c27101d27a6fe9005ce4b95075d1dea5117d190 (diff) |
Major GUI refactoring
-rw-r--r-- | apps/chess/main.c | 26 | ||||
-rw-r--r-- | apps/wm/main.c | 73 | ||||
-rw-r--r-- | boot/grub.cfg | 4 | ||||
-rw-r--r-- | libs/libc/inc/vec.h | 2 | ||||
-rw-r--r-- | libs/libgui/gfx.c | 42 | ||||
-rw-r--r-- | libs/libgui/gfx.h | 11 | ||||
-rw-r--r-- | libs/libgui/gui.c | 265 | ||||
-rw-r--r-- | libs/libgui/gui.h | 33 | ||||
-rw-r--r-- | libs/libgui/msg.h | 3 | ||||
-rwxr-xr-x | run | 3 |
10 files changed, 265 insertions, 197 deletions
diff --git a/apps/chess/main.c b/apps/chess/main.c index 94739ef..e5a8799 100644 --- a/apps/chess/main.c +++ b/apps/chess/main.c @@ -57,15 +57,15 @@ static vec2 selected = { -1, -1 }; // Selected tile static void load_image(struct piece *tile) { - assert(gui_clear(win, tile->widget, GUI_LAYER_FG) == EOK); + gui_clear(win, tile->widget, GUI_LAYER_FG); char icon[48] = { 0 }; snprintf(icon, sizeof(icon), "/icons/chess-%s-%d.png", tile->name, TILE); enum gfx_filter filter = IS_COLOR(tile->piece, BLACK) ? GFX_FILTER_NONE : GFX_FILTER_INVERT; /* assert(gui_fill(win, tile->widget, GUI_LAYER_FG, 0) == EOK); */ - assert(gui_load_image_filter(win, tile->widget, GUI_LAYER_FG, vec2(0, 0), vec2(TILE, TILE), - filter, icon) == EOK); + gui_load_image_filter(win, tile->widget, GUI_LAYER_FG, vec2(0, 0), vec2(TILE, TILE), filter, + icon); } static void mouseclick(u32 widget_id, vec2 pos) @@ -92,14 +92,14 @@ static void mouseclick(u32 widget_id, vec2 pos) strlcpy(clicked_piece->name, selected_piece->name, sizeof(clicked_piece->name)); selected_piece->name[0] = '\0'; - assert(gui_clear(win, selected_piece->widget, GUI_LAYER_FG) == EOK); + gui_clear(win, selected_piece->widget, GUI_LAYER_FG); load_image(clicked_piece); - assert(gui_redraw_window(win) == EOK); + gui_redraw_window(win); selected = vec2(-1, -1); } else if (clicked_piece->piece) { - assert(gui_redraw_widget(win, clicked_piece->widget) == EOK); + gui_redraw_widget(win, clicked_piece->widget); selected = clicked; } } @@ -216,20 +216,18 @@ static void draw_board(void) { for (u8 x = 0; x < 8; x++) { for (u8 y = 0; y < 8; y++) { - u32 widget = - gui_new_widget(win, vec2(TILE, TILE), vec2(TILE * x, TILE * y)); + u32 widget; + gui_new_widget(&widget, win, vec2(TILE * x, TILE * y), vec2(TILE, TILE)); assert((signed)widget > 0); u8 colored = (x + y + 1) % 2 == 0; #if !WHITE_STARTS colored = !colored; #endif - assert(gui_fill(win, widget, GUI_LAYER_BG, - colored ? DARK_COLOR : LIGHT_COLOR) == EOK); + gui_fill(win, widget, GUI_LAYER_BG, colored ? DARK_COLOR : LIGHT_COLOR); struct piece *tile = &tiles[x][y]; - assert(gui_listen_widget(win, widget, GUI_LISTEN_MOUSECLICK, - (u32)mouseclick) == EOK); + gui_listen_widget(win, widget, GUI_LISTEN_MOUSECLICK, (u32)mouseclick); tile->widget = widget; @@ -238,12 +236,12 @@ static void draw_board(void) } } - assert(gui_redraw_window(win) == EOK); + gui_redraw_window(win); } int main(void) { - assert(gui_new_window(&win) == EOK); + gui_new_custom_window(&win, vec2(0, 0), vec2(TILE * 8, TILE * 8)); fen_parse(START_FEN); draw_board(); diff --git a/apps/wm/main.c b/apps/wm/main.c index 0d00427..0e47af4 100644 --- a/apps/wm/main.c +++ b/apps/wm/main.c @@ -13,8 +13,6 @@ #include <rand.h> #include <sys.h> -#define WINDOW_MOVE_TIMEOUT 20 - struct client { u32 conn; // Bus conn }; @@ -223,9 +221,9 @@ static struct window *window_new(struct client client, struct vec2 pos, struct v win->id = id++; win->ctx.size = size; win->ctx.bpp = screen.bpp; - win->ctx.pitch = size.x * bypp; + win->ctx.pitch = win->ctx.size.x * bypp; win->ctx.bytes = win->ctx.pitch * win->ctx.size.y; - if ((flags & WF_NO_FB) != 0) { + if (flags & WF_NO_FB) { win->ctx.fb = NULL; } else { assert(shalloc(win->ctx.bytes, (u32 *)&win->ctx.fb, &win->shid) == EOK); @@ -347,6 +345,13 @@ static void window_redraw(struct window *win) window_redraw_non_alpha(win); } +static void window_move(struct window *win, vec2 pos) +{ + win->pos_prev = win->pos; + win->pos = pos; + window_redraw(win); +} + // TODO: Fix strange artifacts after destroying static void window_destroy(struct window *win) { @@ -358,6 +363,37 @@ static void window_destroy(struct window *win) } /** + * Window bar + */ + +#define BAR_HEIGHT 32 +#define BAR_CLOSE_SIZE 24 +#define BAR_MARGIN GFX_CENTER_IN(BAR_HEIGHT, BAR_CLOSE_SIZE) +#define BAR_BUTTONS_WIDTH (BAR_MARGIN * 2 + BAR_CLOSE_SIZE) + +static void window_bar_mousemove(struct window *win, struct event_mouse *event, vec2 pos, + vec2 mouse_pos) +{ + if (pos.y > BAR_HEIGHT) + return; + + if (pos.x >= win->ctx.size.x - BAR_BUTTONS_WIDTH && event->but.left) + window_destroy(win); + else if (event->but.left) + window_move(win, vec2_sub(mouse_pos, vec2(win->ctx.size.x / 2, BAR_HEIGHT / 2))); +} + +static void window_bar_draw(struct window *win) +{ + if (!(win->flags & WF_BAR)) + return; + + gfx_load_image_filter(&win->ctx, + vec2(win->ctx.size.x - BAR_CLOSE_SIZE - BAR_MARGIN, BAR_MARGIN), + GFX_FILTER_INVERT, "/icons/close-" STRINGIFY(BAR_CLOSE_SIZE) ".png"); +} + +/** * Event handlers */ @@ -389,7 +425,6 @@ static void handle_event_keyboard(struct event_keyboard *event) UNUSED(ch); } -static struct timer mouse_timer = { 0 }; static void handle_event_mouse(struct event_mouse *event) { if (event->magic != MOUSE_MAGIC) { @@ -428,14 +463,7 @@ static void handle_event_mouse(struct event_mouse *event) focused = win; if (focused && !(focused->flags & WF_NO_DRAG) && event->but.left && special_keys.alt) { - struct timer timer = { 0 }; - io_read(IO_TIMER, &timer, 0, sizeof(timer)); - if (timer.time - mouse_timer.time > WINDOW_MOVE_TIMEOUT) { - focused->pos_prev = focused->pos; - focused->pos = mouse.pos; - window_redraw(focused); - mouse_timer = timer; - } + window_move(win, mouse.pos); return; } else if (!vec2_eq(cursor->pos, cursor->pos_prev)) { window_redraw(cursor); @@ -444,10 +472,20 @@ static void handle_event_mouse(struct event_mouse *event) if (!win) return; + vec2 relative_pos = vec2_sub(mouse.pos, win->pos); + if (win->flags & WF_BAR) { + if (relative_pos.y <= BAR_HEIGHT) { + window_bar_mousemove(win, event, relative_pos, mouse.pos); + return; + } else { + relative_pos.y -= BAR_HEIGHT; + } + } + struct message_mouse msg = { 0 }; msg.header.state = MSG_GO_ON; msg.id = win->id; - msg.pos = vec2_sub(mouse.pos, win->pos); + msg.pos = relative_pos; msg.bits.click = event->but.left; if (msg_connect_conn(win->client.conn) == EOK) @@ -462,9 +500,12 @@ static void handle_event_mouse(struct event_mouse *event) static void handle_message_new_window(struct message_new_window *msg) { - struct window *win = window_new((struct client){ .conn = msg->header.bus.conn }, - vec2(500, 600), vec2(600, 400), 0); + struct window *win = window_new((struct client){ .conn = msg->header.bus.conn }, msg->pos, + vec2_add(msg->size, vec2(0, BAR_HEIGHT)), WF_BAR); + window_bar_draw(win); + msg->ctx = win->ctx; + msg->off = vec2(0, BAR_HEIGHT); msg->shid = win->shid; msg->id = win->id; diff --git a/boot/grub.cfg b/boot/grub.cfg index 7f310e9..277ca5c 100644 --- a/boot/grub.cfg +++ b/boot/grub.cfg @@ -2,11 +2,11 @@ set timeout=0 set default=0 menuentry "Melvix with logging" { - multiboot /boot/melvix log + multiboot /boot/melvix boot } menuentry "Melvix without logging" { - multiboot /boot/melvix + multiboot /boot/melvix nolog boot } diff --git a/libs/libc/inc/vec.h b/libs/libc/inc/vec.h index a036931..bcd4cca 100644 --- a/libs/libc/inc/vec.h +++ b/libs/libc/inc/vec.h @@ -21,6 +21,7 @@ typedef struct vec3 { #define vec2_div(a, b) ((vec2){ a.x / (b), a.y / (b) }) #define vec2_dot(a, b) ((u32)(a.x * b.x + a.y * b.y)) #define vec2_eq(a, b) (a.x == b.x && a.y == b.y) +#define vec2_sum(a) ((u32)(a.x + a.y)) #define vec3(x, y, z) ((vec3){ (x), (y), (z) }) #define vec3to2(a) ((vec2){ a.x, a.y }) @@ -32,5 +33,6 @@ typedef struct vec3 { #define vec3_eq(a, b) (a.x == b.x && a.y == b.y && a.z == c.z) #define vec3_cross(a, b) \ ((vec3){ a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }) +#define vec3_sum(a) ((u32)(a.x + a.y + a.z)) #endif diff --git a/libs/libgui/gfx.c b/libs/libgui/gfx.c index 3ed8375..d963a1b 100644 --- a/libs/libgui/gfx.c +++ b/libs/libgui/gfx.c @@ -92,22 +92,6 @@ static void write_char(struct context *ctx, vec2 pos, struct font *font, u32 c, } } -static void draw_rectangle(struct context *ctx, vec2 pos1, vec2 pos2, u32 c) -{ - assert(pos1.x <= pos2.x && pos1.y <= pos2.y); - int bypp = ctx->bpp >> 3; - u8 *draw = &ctx->fb[pos1.x * bypp + pos1.y * ctx->pitch]; - for (u32 i = 0; i < pos2.y - pos1.y; i++) { - for (u32 j = 0; j < pos2.x - pos1.x; j++) { - draw[bypp * j] = GET_BLUE(c); - draw[bypp * j + 1] = GET_GREEN(c); - draw[bypp * j + 2] = GET_RED(c); - draw[bypp * j + 3] = GET_ALPHA(c); - } - draw += ctx->pitch; - } -} - struct context *gfx_new_ctx(struct context *ctx, vec2 size, u8 bpp) { ctx->size = size; @@ -222,7 +206,6 @@ static void gfx_image_cache_save(const char *path, struct bmp *bmp) void gfx_load_image_filter(struct context *ctx, vec2 pos, enum gfx_filter filter, const char *path) { - // TODO: Support x, y // TODO: Detect image type struct bmp *bmp = gfx_image_cache_get(path); @@ -245,7 +228,7 @@ void gfx_load_image_filter(struct context *ctx, vec2 pos, enum gfx_filter filter u8 bypp = bmp->bpp >> 3; /* u8 *srcfb = &bmp->data[bypp + (bmp->size.y - 1) * bmp->pitch]; */ u8 *srcfb = bmp->data; - u8 *destfb = &ctx->fb[bypp]; + u8 *destfb = &ctx->fb[pos.x * bypp + pos.y * ctx->pitch]; for (u32 cy = 0; cy < bmp->size.y && cy + pos.y < ctx->size.y; cy++) { int diff = 0; for (u32 cx = 0; cx < bmp->size.x && cx + pos.x < ctx->size.x; cx++) { @@ -279,6 +262,22 @@ void gfx_load_wallpaper(struct context *ctx, const char *path) gfx_load_image(ctx, vec2(0, 0), path); } +void gfx_draw_rectangle(struct context *ctx, vec2 pos1, vec2 pos2, u32 c) +{ + assert(pos1.x <= pos2.x && pos1.y <= pos2.y); + int bypp = ctx->bpp >> 3; + u8 *draw = &ctx->fb[pos1.x * bypp + pos1.y * ctx->pitch]; + for (u32 i = 0; i < pos2.y - pos1.y; i++) { + for (u32 j = 0; j < pos2.x - pos1.x; j++) { + draw[bypp * j] = GET_BLUE(c); + draw[bypp * j + 1] = GET_GREEN(c); + draw[bypp * j + 2] = GET_RED(c); + draw[bypp * j + 3] = GET_ALPHA(c); + } + draw += ctx->pitch; + } +} + void gfx_copy(struct context *dest, struct context *src, vec2 pos, vec2 size) { int bypp = dest->bpp >> 3; @@ -323,11 +322,6 @@ void gfx_ctx_on_ctx(struct context *dest, struct context *src, vec2 pos, u8 alph } } -void gfx_draw_rectangle(struct context *ctx, vec2 pos1, vec2 pos2, u32 c) -{ - draw_rectangle(ctx, pos1, pos2, c); -} - void gfx_clear(struct context *ctx) { memset(ctx->fb, 0, ctx->bytes); @@ -335,7 +329,7 @@ void gfx_clear(struct context *ctx) void gfx_fill(struct context *ctx, u32 c) { - draw_rectangle(ctx, vec2(0, 0), vec2(ctx->size.x, ctx->size.y), c); + gfx_draw_rectangle(ctx, vec2(0, 0), vec2(ctx->size.x, ctx->size.y), c); } void gfx_border(struct context *ctx, u32 c, u32 width) diff --git a/libs/libgui/gfx.h b/libs/libgui/gfx.h index 1dfa96d..eb98578 100644 --- a/libs/libgui/gfx.h +++ b/libs/libgui/gfx.h @@ -43,10 +43,13 @@ #define WF_NO_FB (1 << 3) #define WF_NO_WINDOW (1 << 4) #define WF_ALPHA (1 << 5) +#define WF_BAR (1 << 6) #define GFX_NON_ALPHA 0 #define GFX_ALPHA 1 +#define GFX_CENTER_IN(a, b) (ABS((a) - (b)) / 2) + enum font_type { FONT_8, FONT_12, FONT_16, FONT_24, FONT_32, FONT_64 }; enum gfx_filter { GFX_FILTER_NONE, @@ -89,12 +92,4 @@ void gfx_border(struct context *ctx, u32 c, u32 width) NONNULL; int gfx_font_height(enum font_type); int gfx_font_width(enum font_type); -/** - * Wrappers - */ - -/* #define gfx_redraw() \ */ -/* (msg_send(pidof(WM_PATH), GFX_REDRAW, NULL)) // TODO: Partial redraw (optimization) */ -/* #define gfx_redraw_focused() (msg_send(pidof(WM_PATH), GFX_REDRAW_FOCUSED, NULL)) */ - #endif diff --git a/libs/libgui/gui.c b/libs/libgui/gui.c index 891a0e4..023bc98 100644 --- a/libs/libgui/gui.c +++ b/libs/libgui/gui.c @@ -24,12 +24,16 @@ struct gui_widget { struct gui_window { u32 id; + vec2 pos; struct context ctx; struct list *widgets; }; struct list *windows = NULL; +#define gui_error(error) \ + err(1, "%s:%d in %s: GUI Error: %s\n", __FILE__, __LINE__, __func__, strerror(error)) + /** * Resolve/find stuff */ @@ -120,71 +124,80 @@ static void gui_connect_wm(void) * GFX wrappers */ -res gui_clear(u32 win_id, u32 widget_id, enum gui_layer layer) +void gui_clear(u32 win_id, u32 widget_id, enum gui_layer layer) { struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); if (!widget) - return_errno(ENOENT); + gui_error(ENOENT); if (layer == GUI_LAYER_BG) gfx_clear(&widget->bg); else if (layer == GUI_LAYER_FG) gfx_clear(&widget->fg); else - return_errno(EINVAL); - - return_errno(EOK); + gui_error(EINVAL); } -res gui_fill(u32 win_id, u32 widget_id, enum gui_layer layer, u32 c) +void gui_fill(u32 win_id, u32 widget_id, enum gui_layer layer, u32 c) { struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); if (!widget) - return_errno(ENOENT); + gui_error(ENOENT); if (layer == GUI_LAYER_BG) gfx_fill(&widget->bg, c); else if (layer == GUI_LAYER_FG) gfx_fill(&widget->fg, c); else - return_errno(EINVAL); + gui_error(EINVAL); +} + +void gui_write(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, enum font_type font_type, + u32 c, const char *text) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + gui_error(ENOENT); - return_errno(EOK); + if (layer == GUI_LAYER_BG) + gfx_write(&widget->bg, pos, font_type, c, text); + else if (layer == GUI_LAYER_FG) + gfx_write(&widget->fg, pos, font_type, c, text); + else + gui_error(EINVAL); } -res gui_load_image_filter(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, - enum gfx_filter filter, const char *path) +void gui_load_image_filter(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, + enum gfx_filter filter, const char *path) { UNUSED(size); // TODO: Add image scaling struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); if (!widget) - return_errno(ENOENT); + gui_error(ENOENT); if (layer == GUI_LAYER_BG) gfx_load_image_filter(&widget->bg, pos, filter, path); else if (layer == GUI_LAYER_FG) gfx_load_image_filter(&widget->fg, pos, filter, path); else - return_errno(EINVAL); - - return_errno(EOK); + gui_error(EINVAL); } -res gui_load_image(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, - const char *path) +void gui_load_image(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, + const char *path) { - return gui_load_image_filter(win_id, widget_id, layer, pos, size, GFX_FILTER_NONE, path); + gui_load_image_filter(win_id, widget_id, layer, pos, size, GFX_FILTER_NONE, path); } /** * Widgets */ -static res gui_sub_widget_at(struct gui_widget *widget, vec2 pos, struct gui_widget *buf) +static u8 gui_sub_widget_at(struct gui_widget *widget, vec2 pos, struct gui_widget *buf) { if (!widget || !widget->children || !buf) - return_errno(EFAULT); + gui_error(EFAULT); struct gui_widget *ret = NULL; struct gui_widget sub = { 0 }; @@ -196,32 +209,29 @@ static res gui_sub_widget_at(struct gui_widget *widget, vec2 pos, struct gui_wid pos.y <= w->pos.y + w->bg.size.y) ret = w; - if (w->children->head) { - if (gui_sub_widget_at(w, pos, &sub) == EOK) - ret = ⊂ - } + if (w->children->head && gui_sub_widget_at(w, pos, &sub)) + ret = ⊂ iterator = iterator->next; } - if (ret) { - *buf = *ret; - return_errno(EOK); - } else { - return_errno(ENOENT); - } + if (!ret) + return 0; + + *buf = *ret; + return 1; } -static res gui_widget_at(u32 win_id, vec2 pos, struct gui_widget *widget) +static u8 gui_widget_at(u32 win_id, vec2 pos, struct gui_widget *widget) { if (!widget) - return_errno(EFAULT); + gui_error(EFAULT); struct gui_window *win = gui_window_by_id(win_id); if (!win) - return_errno(ENOENT); + gui_error(ENOENT); if (!win->widgets) - return_errno(EOK); + return 1; struct gui_widget *ret = NULL; struct gui_widget sub = { 0 }; @@ -233,28 +243,25 @@ static res gui_widget_at(u32 win_id, vec2 pos, struct gui_widget *widget) pos.y <= w->pos.y + w->bg.size.y) ret = w; - if (w->children->head) { - if (gui_sub_widget_at(w, pos, &sub) == EOK) - ret = ⊂ - } + if (w->children->head && gui_sub_widget_at(w, pos, &sub)) + ret = ⊂ iterator = iterator->next; } - if (ret) { - *widget = *ret; - return_errno(EOK); - } else { - return_errno(ENOENT); - } + if (!ret) + return 0; + + *widget = *ret; + return 1; } -static res gui_sync_sub_widgets(struct gui_widget *widget) +static void gui_sync_sub_widgets(struct gui_widget *widget) { if (!widget) - return_errno(EFAULT); + gui_error(EFAULT); if (!widget->children) - return_errno(EOK); + return; struct node *iterator = widget->children->head; while (iterator) { @@ -263,32 +270,28 @@ static res gui_sync_sub_widgets(struct gui_widget *widget) gfx_ctx_on_ctx(&widget->fg, &w->fg, w->pos, GFX_NON_ALPHA); iterator = iterator->next; } - - return_errno(EOK); } -static res gui_sync_widget(u32 win_id, u32 widget_id) +static void gui_sync_widget(u32 win_id, u32 widget_id) { struct gui_window *win = gui_window_by_id(win_id); struct gui_widget *widget = gui_widget_in_win(win, widget_id); if (!widget) - return_errno(ENOENT); + gui_error(ENOENT); gui_sync_sub_widgets(widget); gfx_ctx_on_ctx(&win->ctx, &widget->bg, widget->pos, GFX_ALPHA); gfx_ctx_on_ctx(&win->ctx, &widget->fg, widget->pos, GFX_ALPHA); - - return_errno(EOK); } -static res gui_sync_widgets(u32 win_id) +static void gui_sync_widgets(u32 win_id) { struct gui_window *win = gui_window_by_id(win_id); if (!win) - return_errno(ENOENT); + gui_error(ENOENT); if (!win->widgets) - return_errno(EOK); + return; struct node *iterator = win->widgets->head; while (iterator) { @@ -298,15 +301,20 @@ static res gui_sync_widgets(u32 win_id) gfx_ctx_on_ctx(&win->ctx, &widget->fg, widget->pos, GFX_ALPHA); iterator = iterator->next; } - - return_errno(EOK); } -static struct gui_widget *gui_win_main_widget(struct gui_window *win) +static struct gui_widget *gui_main_widget(struct gui_window *win) { + assert(win && win->widgets && win->widgets->head); return win->widgets->head->data; } +static u32 gui_main_widget_id(struct gui_window *win) +{ + assert(win && win->widgets && win->widgets->head); + return ((struct gui_widget *)win->widgets->head->data)->id; +} + // TODO: This is very recursive and inefficient -> improve! static vec2 gui_offset_widget(struct gui_widget *parent, struct gui_widget *child) { @@ -335,7 +343,7 @@ static vec2 gui_offset_widget(struct gui_widget *parent, struct gui_widget *chil return offset; } -static struct gui_widget *gui_new_plain_widget(vec2 size, vec2 pos, u8 bpp) +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)); @@ -351,39 +359,35 @@ static struct gui_widget *gui_new_plain_widget(vec2 size, vec2 pos, u8 bpp) return widget; } -res gui_add_widget(u32 win_id, u32 widget_id, vec2 size, vec2 pos) +void gui_add_widget(u32 *widget, u32 win_id, u32 widget_id, vec2 pos, vec2 size) { struct gui_widget *parent = gui_widget_by_id(win_id, widget_id); if (!parent) - return_errno(ENOENT); + gui_error(ENOENT); - struct gui_widget *child = gui_new_plain_widget(size, pos, parent->bg.bpp); + struct gui_widget *child = gui_new_plain_widget(pos, size, parent->bg.bpp); list_add(parent->children, child); - return child->id; + *widget = child->id; } -res gui_new_widget(u32 win_id, vec2 size, vec2 pos) +void gui_new_widget(u32 *widget, u32 win_id, vec2 pos, vec2 size) { struct gui_window *win = gui_window_by_id(win_id); if (!win) - return_errno(ENOENT); + gui_error(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); + gui_add_widget(widget, win->id, gui_main_widget(win)->id, pos, size); } -res gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func) +void gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func) { if (!func) - return_errno(EFAULT); + gui_error(EFAULT); struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); if (!widget) - return_errno(ENOENT); + gui_error(ENOENT); switch (listener) { case GUI_LISTEN_MOUSEMOVE: @@ -393,21 +397,38 @@ res gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 widget->event.mouseclick = (void (*)(u32, vec2))func; break; default: - return_errno(ENOENT); + gui_error(ENOENT); } +} - return_errno(EOK); +void gui_redraw_widget(u32 win_id, u32 widget_id) +{ + gui_sync_widget(win_id, widget_id); + gui_redraw_window(win_id); } -res gui_redraw_widget(u32 win_id, u32 widget_id) +/** + * Popups/alerts + */ + +#define POPUP_WIDTH 200 +#define POPUP_HEIGHT 100 + +void gui_popup(const char *text) { - if (gui_sync_widget(win_id, widget_id) != EOK) - return errno; + vec2 pos = vec2(200, 200); + + u32 popup; + gui_new_custom_window(&popup, pos, vec2(POPUP_WIDTH, POPUP_HEIGHT)); + struct gui_window *win = gui_window_by_id(popup); + gui_fill(popup, gui_main_widget_id(win), GUI_LAYER_BG, COLOR_WHITE); - if (gui_redraw_window(win_id) != EOK) - return errno; + u32 widget; + gui_new_widget(&widget, popup, vec2(0, 0), vec2(POPUP_WIDTH, 32)); + gui_fill(popup, widget, GUI_LAYER_BG, COLOR_WHITE); + gui_write(popup, widget, GUI_LAYER_FG, vec2(0, 0), FONT_32, COLOR_BLACK, text); - return_errno(EOK); + gui_redraw_window(popup); } /** @@ -418,7 +439,7 @@ vec2 gui_window_size(u32 win_id) { struct gui_window *win = gui_window_by_id(win_id); if (!win) - return vec2(0, 0); + gui_error(ENOENT); return win->ctx.size; } @@ -426,97 +447,107 @@ vec2 gui_window_size(u32 win_id) * Window manager interfaces */ -res gui_new_window(u32 *id) +void gui_new_custom_window(u32 *id, vec2 pos, vec2 size) { if (!windows) windows = list_new(); + if (vec2_sum(pos) == 0) + pos = vec2(200, 200); + + if (vec2_sum(size) == 0) + size = vec2(600, 400); + struct gui_window *win = zalloc(sizeof(*win)); + struct message_new_window msg = { .header.state = MSG_NEED_ANSWER, + .pos = pos, + .size = size }; - struct message_new_window msg = { .header.state = MSG_NEED_ANSWER }; gui_connect_wm(); 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->ctx = msg.ctx; - u32 size; - res ret = shaccess(msg.shid, (u32 *)&win->ctx.fb, &size); + win->pos = msg.pos; + u32 buf_size; + res ret = shaccess(msg.shid, (u32 *)&win->ctx.fb, &buf_size); if (ret < 0 || !win->ctx.fb) - return_errno(-MIN(ret, -EFAULT)); + gui_error(-MIN(ret, -EFAULT)); + + // Apply offset + win->ctx.size = vec2_sub(win->ctx.size, msg.off); + win->ctx.bytes -= msg.off.y * msg.ctx.pitch; + win->ctx.fb += msg.off.y * msg.ctx.pitch; + list_add(windows, win); win->widgets = list_new(); + list_add(win->widgets, + gui_new_plain_widget(vec2(0, 0), win->ctx.size, win->ctx.bpp)); + *id = win->id; - return_errno(EOK); + return; } - return_errno(EINVAL); + gui_error(EINVAL); } -res gui_redraw_window(u32 id) +INLINE void gui_new_window(u32 *id) { - res ret = gui_sync_widgets(id); - if (ret != 0) - return_errno(ENOENT); + gui_new_custom_window(id, vec2(0, 0), vec2(0, 0)); +} + +void gui_redraw_window(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 && msg_receive(&msg, sizeof(msg)) > 0 && msg.header.type == (GUI_REDRAW_WINDOW | MSG_SUCCESS)) - return EOK; + return; - return_errno(EINVAL); + gui_error(EINVAL); } /** * Message handling */ -static res gui_handle_error(const char *op, res code) -{ - log("GUI error at '%s': %s (%d)\n", op, strerror(code), code); - return code; -} - -static res gui_handle_ping(struct message_ping *msg) +static void gui_handle_ping(struct message_ping *msg) { if (msg->ping != MSG_PING_SEND) - return gui_handle_error("ping", EINVAL); + gui_error(EINVAL); msg->header.type |= MSG_SUCCESS; msg->ping = MSG_PING_RECV; if (msg_connect_conn(msg->header.bus.conn) == EOK && msg_send(GUI_PING, msg, sizeof(msg)) == EOK) - return EOK; - else - return errno; + return; + gui_error(errno); } -static res gui_handle_mouse(struct message_mouse *msg) +static void gui_handle_mouse(struct message_mouse *msg) { if (msg->header.state == MSG_NEED_ANSWER) { if (msg_connect_conn(msg->header.bus.conn) == EOK && msg_send(msg->header.type | MSG_SUCCESS, msg, sizeof(msg)) == EOK) - return EOK; - else - return errno; + return; + gui_error(errno); } struct gui_widget widget = { 0 }; - if (gui_widget_at(msg->id, msg->pos, &widget) != EOK) - return_errno(EOK); + gui_widget_at(msg->id, msg->pos, &widget); struct gui_window *win = gui_window_by_id(msg->id); - vec2 offset = gui_offset_widget(gui_win_main_widget(win), &widget); + vec2 offset = gui_offset_widget(gui_main_widget(win), &widget); if (widget.event.mousemove) widget.event.mousemove(widget.id, vec2_sub(msg->pos, offset)); if (widget.event.mouseclick && msg->bits.click) widget.event.mouseclick(widget.id, vec2_sub(msg->pos, offset)); - - return_errno(EOK); } static void gui_handle_exit(void) @@ -559,7 +590,7 @@ void gui_loop(void) break; default: // TODO: Fix random unknown msg types - gui_handle_error("loop", EINVAL); + gui_error(EINVAL); } } diff --git a/libs/libgui/gui.h b/libs/libgui/gui.h index 9473bd9..c7dc24f 100644 --- a/libs/libgui/gui.h +++ b/libs/libgui/gui.h @@ -18,20 +18,25 @@ enum gui_layer { GUI_LAYER_FG, }; -res gui_new_window(u32 *id); -res gui_redraw_window(u32 id); - -res gui_clear(u32 win_id, u32 widget_id, enum gui_layer layer); -res gui_fill(u32 win_id, u32 widget_id, enum gui_layer layer, u32 c); -res gui_load_image(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, - const char *path) NONNULL; -res gui_load_image_filter(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, - enum gfx_filter filter, const char *path) NONNULL; - -res gui_add_widget(u32 win_id, u32 widget_id, vec2 size, vec2 pos); -res gui_new_widget(u32 win_id, vec2 size, vec2 pos); -res gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func); -res gui_redraw_widget(u32 win_id, u32 widget_id); +void gui_new_custom_window(u32 *id, vec2 pos, vec2 size); +void gui_new_window(u32 *id); +void gui_redraw_window(u32 id); + +void gui_clear(u32 win_id, u32 widget_id, enum gui_layer layer); +void gui_fill(u32 win_id, u32 widget_id, enum gui_layer layer, u32 c); +void gui_write(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, enum font_type font_type, + u32 c, const char *text); +void gui_load_image(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, + const char *path) NONNULL; +void gui_load_image_filter(u32 win_id, u32 widget_id, enum gui_layer layer, vec2 pos, vec2 size, + enum gfx_filter filter, const char *path) NONNULL; + +void gui_add_widget(u32 *widget, u32 win_id, u32 widget_id, vec2 pos, vec2 size); +void gui_new_widget(u32 *widget, u32 win_id, vec2 pos, vec2 size); +void gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func); +void gui_redraw_widget(u32 win_id, u32 widget_id); + +void gui_popup(const char *text); vec2 gui_window_size(u32 win_id); diff --git a/libs/libgui/msg.h b/libs/libgui/msg.h index 857042c..b29d0c8 100644 --- a/libs/libgui/msg.h +++ b/libs/libgui/msg.h @@ -35,6 +35,9 @@ struct message_new_window { struct message_header header; u32 id; u32 shid; + vec2 off; + vec2 size; + vec2 pos; struct context ctx; }; @@ -107,8 +107,7 @@ make_disk() { rm -rf "spleen-$VERSION"* cd ../../ - icons="cursor-default - cursor-default-outline + icons="close chess-bishop chess-king chess-knight |