commit - /dev/null
commit + cb5e051aec61c8910f1a8335320b6dd435005c1d
blob - /dev/null
blob + 6ac7bd351e23a9d3c253521d1db27fec0488bf12 (mode 644)
--- /dev/null
+++ LICENSE
+Copyright (c) 2025 Onana Onana Xavier Manuel <xavier@onana.net>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
blob - /dev/null
blob + 2224ddef2b331222a6301be020522753cdebd389 (mode 644)
--- /dev/null
+++ Makefile
+CFLAGS = -fPIC -std=c99
+
+PREFIX=/usr/local
+
+INCS=-I ./ -I /usr/X11R6/include -I /usr/X11R6/include/freetype2
+
+LIBS=-L /usr/X11R6/lib -lxcb -lxcb-render -lxcb-render-util -lxcb-image -lfreetype -lm -lfontconfig
+
+SRCS= window.c layout.c group.c context.c shape.c event.c label.c image.c
+
+OBJS=${SRCS:.c=.o}
+
+
+all: mui
+
+.c.o:
+ ${CC} -c ${CFLAGS} ${INCS} $< -o $@
+
+
+mui: ${OBJS}
+ ${CC} -shared -Wl,-soname,libmui.so -o libmui.so ${OBJS} ${LIBS}
+
+clean:
+ rm -rf ${OBJS} libmui.so
+
+.PHONY: all mui clean fonts uninstall
blob - /dev/null
blob + c5e9a12c1ea1174ea41c329c59240654e68ae840 (mode 644)
--- /dev/null
+++ README
+mui stands for minimal UI
blob - /dev/null
blob + 2fde96a624cd67966672ed3bfcb09cb4d96e552c (mode 644)
--- /dev/null
+++ TODO
+Event targets
+
+Debug macro
+
+Complete man `mui.1` for demos
+
+Complete man `mui.3`
+
+Nested groups
+
+Groups styles (Scroll, VStack, HStack, Grid)
+
+Group clipping
+
+Font faces (color, size, style)
+
+Minimum layout dimensions
+
+Multiline support text rendering
+
+Man page
+
+Fix image rendering and text rendering on FreeBSD and NetBSD (DONE)
+
+Fix issue when text render with noise when having a small len (DONE?)
+
+Cleanup functions aka delete functions (DONE)
+
+Fix alignment to update when added to group (DONE)
+
+New flag 'MUI_SCALE_X' and 'MUI_SCALE_Y' which will be actual scale of
+the layout while 'MUI_EXPAND_X' and 'MUI_EXPAND_Y' will be the actual
+width and height. (DONE)
+
+Proper scale matrix for xcb_render (DONE)
+
+Layout anchoring (DONE)
+
+Change shape color after adding to group (DONE)
+
+Events (KeyPress and KeyRelease) (DONE)
+
+Fix issue when shape changes color but isn't visible until update (DONE)
+
+Image rendering (DONE)
+
+Text rendering (the hardest) (DONE)
blob - /dev/null
blob + c6cd2ed28ae61171708a3e79ed1c71dc0464f649 (mode 755)
--- /dev/null
+++ cleanup.sh
+#!/bin/sh
+
+# Run this script before pushing
+
+make clean
+
+for folder in demo/*; do
+ [ -d $folder ] && [ -f $folder/Makefile ] && make -C $folder clean
+done
blob - /dev/null
blob + 98401c97a40dd5fb6e56f4dbb3e0840c44a1750d (mode 644)
--- /dev/null
+++ context.c
+#include "mui.h"
+
+#include <xcb/xcb.h>
+#include <xcb/render.h>
+#include <xcb/xcb_image.h>
+#include <xcb/xcb_renderutil.h>
+
+#include <ft2build.h>
+#include <freetype/freetype.h>
+#include <fontconfig/fontconfig.h>
+
+#define MAX_FONTS 100
+#define MAX_UINT16 65536
+
+struct ctx_node {
+ void *ptr;
+ uint16_t type;
+ xcb_render_picture_t picture;
+ xcb_render_transform_t transform;
+};
+
+struct ctx_font {
+ char *path;
+ int height;
+ int widths[128]; /* Latin Characters */
+ xcb_render_glyphset_t gs;
+};
+
+struct {
+ xcb_connection_t *conn;
+ const xcb_setup_t *setup;
+ xcb_screen_t *screen;
+
+ uint32_t fmt_normal;
+ uint32_t fmt_alpha8;
+ uint32_t fmt_argb32;
+
+ struct ctx_font *fonts[MAX_FONTS];
+ FT_Library ft_library;
+
+ /*
+ * Linked list used to keep track on existing
+ * contexes for operations such as distributing
+ * events among windows
+ */
+ LIST_HEAD(, mui_ctx) ctx_head;
+} xcb;
+
+
+struct mui_ctx {
+ xcb_window_t window;
+ xcb_gcontext_t gc;
+ xcb_pixmap_t pixmap;
+ xcb_render_picture_t picture;
+ xcb_intern_atom_reply_t *wm_delete_window;
+
+ struct mui_window *mw;
+ LIST_ENTRY(mui_ctx) entries;
+};
+
+void
+ctx_create_bg(struct mui_ctx *ctx)
+{
+ uint32_t mask;
+ uint16_t width;
+ uint16_t height;
+ uint32_t values[2];
+ struct mui_group *group;
+ struct mui_layout *layout;
+
+ if (ctx->pixmap) xcb_free_pixmap(xcb.conn, ctx->pixmap);
+ if (ctx->picture) xcb_render_free_picture(xcb.conn, ctx->picture);
+
+ group = mui_get_window_group(ctx->mw);
+ layout = mui_get_group_layout(group);
+
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout);
+
+ ctx->pixmap = xcb_generate_id(xcb.conn);
+ ctx->picture = xcb_generate_id(xcb.conn);
+
+ xcb_create_pixmap(xcb.conn, xcb.screen->root_depth, ctx->pixmap, xcb.screen->root,
+ width, height);
+
+ mask = XCB_RENDER_CP_POLY_MODE | XCB_RENDER_CP_POLY_EDGE;
+ values[0] = XCB_RENDER_POLY_MODE_IMPRECISE;
+ values[1] = XCB_RENDER_POLY_EDGE_SMOOTH;
+
+ xcb_render_create_picture(xcb.conn, ctx->picture, ctx->pixmap, xcb.fmt_normal, mask,
+ values);
+}
+
+void
+ctx_load_formats(void)
+{
+ xcb_render_query_pict_formats_cookie_t cookie =
+ xcb_render_query_pict_formats_unchecked(xcb.conn);
+
+ xcb_render_query_pict_formats_reply_t *reply =
+ xcb_render_query_pict_formats_reply(xcb.conn, cookie, NULL);
+
+ xcb.fmt_normal = xcb_render_util_find_visual_format(reply,
+ xcb.screen->root_visual)->format;
+
+ xcb.fmt_argb32 = xcb_render_util_find_standard_format(reply,
+ XCB_PICT_STANDARD_ARGB_32)->id;
+
+ xcb.fmt_alpha8 = xcb_render_util_find_standard_format(reply,
+ XCB_PICT_STANDARD_A_8)->id;
+
+}
+
+static void
+ctx_load_glyph(struct ctx_font *font, FT_Face face, int charcode)
+{
+ int gindx;
+ uint32_t gid;
+ FT_Bitmap *bitmap;
+ xcb_render_glyphinfo_t ginfo;
+
+ FT_Select_Charmap(face, ft_encoding_unicode);
+ gindx = FT_Get_Char_Index(face, charcode);
+
+ FT_Load_Glyph(face, gindx, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
+
+ bitmap = &face->glyph->bitmap;
+ ginfo.x = -face->glyph->bitmap_left;
+ ginfo.y = face->glyph->bitmap_top;
+ ginfo.width = bitmap->width;
+ ginfo.height = bitmap->rows;
+ ginfo.x_off = face->glyph->advance.x / 64;
+ ginfo.y_off = face->glyph->advance.y / 64;
+
+ gid = charcode;
+
+ int y;
+ int stride = (ginfo.width+3)&~3;
+ uint8_t tmp_bitmap[stride * ginfo.height];
+
+ for (y = 0; y < ginfo.height; y++)
+ memcpy(tmp_bitmap + y * stride, bitmap->buffer + y * ginfo.width, ginfo.width);
+
+ int height = face->glyph->metrics.height / 64;
+ font->height = (font->height < height) ? height : font->height;
+ font->widths[charcode] = face->glyph->advance.x / 64;
+
+ xcb_render_add_glyphs(xcb.conn, font->gs, 1, &gid, &ginfo, stride * ginfo.height, tmp_bitmap);
+}
+
+struct ctx_font*
+ctx_load_font()
+{
+ FT_Face face;
+ FcChar8 *fpath;
+ FcConfig *config;
+ FcPattern *pattern;
+ FcPattern *matched;
+ FcResult result;
+ struct ctx_font *font;
+ int font_size;
+
+ if (FT_Init_FreeType(&xcb.ft_library)) {
+ exit(1);
+ }
+
+ font = calloc(1, sizeof(*font));
+ config = FcInitLoadConfigAndFonts();
+
+ if (!config) {
+ printf("Failed to load font config and fonts\n");
+ exit(1);
+ }
+
+ pattern = FcPatternCreate();
+ FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *)"sans-serif");
+
+ FcDefaultSubstitute(pattern);
+ matched = FcFontMatch(config, pattern, &result);
+
+ if (!matched)
+ exit(1);
+
+ if (FcPatternGetString(matched, FC_FILE, 0, &fpath) == FcResultMatch) {
+
+ }
+
+ font_size = 16;
+ font->gs = xcb_generate_id(xcb.conn);
+ xcb_render_create_glyph_set(xcb.conn, font->gs, xcb.fmt_alpha8);
+ printf("%s\n", fpath);
+
+ if (FT_New_Face(xcb.ft_library, fpath, 0, &face)) {
+ exit(1);
+ }
+
+ FT_Set_Char_Size(face, 0, font_size * 64, 90, 90);
+
+ for (int n = 32; n < 128; n++)
+ ctx_load_glyph(font, face, n);
+
+ FT_Done_Face(face);
+
+ return font;
+}
+
+struct mui_group*
+ctx_get_node_group(struct ctx_node *node)
+{
+ switch (node->type) {
+ case MUI_SHAPE:
+ return mui_get_shape_group(node->ptr);
+ case MUI_LABEL:
+ return mui_get_label_group(node->ptr);
+ case MUI_IMAGE:
+ return mui_get_image_group(node->ptr);
+ }
+ return NULL;
+}
+
+
+struct mui_ctx*
+mui_create_ctx(struct mui_window *mw)
+{
+ uint32_t mask;
+ uint32_t values[2];
+ uint16_t width;
+ uint16_t height;
+ struct mui_ctx *ctx;
+ struct mui_group *group;
+ struct mui_layout *layout;
+ xcb_intern_atom_reply_t *reply;
+ xcb_intern_atom_cookie_t cookie1, cookie2;
+
+ if (xcb.conn == NULL) {
+ xcb.conn = xcb_connect(NULL, NULL);
+
+ xcb.setup = xcb_get_setup(xcb.conn);
+ xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb.setup);
+ xcb.screen = iter.data;
+
+ ctx_load_formats();
+ xcb.fonts[0] = ctx_load_font();
+ LIST_INIT(&xcb.ctx_head);
+ }
+
+
+ ctx = calloc(1, sizeof(*ctx));
+ ctx->mw = mw;
+
+ mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
+ values[0] = xcb.screen->white_pixel;
+ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION |
+ XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+
+ group = mui_get_window_group(mw);
+ layout = mui_get_group_layout(group);
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout);
+ ctx->window = xcb_generate_id(xcb.conn);
+
+ xcb_create_window(xcb.conn,
+ XCB_COPY_FROM_PARENT,
+ ctx->window,
+ xcb.screen->root,
+ 0, 0,
+ width,
+ height,
+ 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ xcb.screen->root_visual,
+ mask,
+ values
+ );
+
+ mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
+ values[0] = 0xcbcbcb | 0xff000000;
+ values[1] = 0;
+
+ const xcb_change_window_attributes_value_list_t cw = { 0 };
+ xcb_change_window_attributes(xcb.conn, ctx->window, XCB_CW_BACK_PIXMAP, &cw);
+
+ ctx->gc = xcb_generate_id(xcb.conn);
+ xcb_create_gc(xcb.conn, ctx->gc, ctx->window, mask, values);
+
+ ctx_create_bg(ctx);
+
+ cookie1 = xcb_intern_atom(xcb.conn, 1, 12, "WM_PROTOCOLS");
+ cookie2 = xcb_intern_atom(xcb.conn, 1, 16, "WM_DELETE_WINDOW");
+
+ reply = xcb_intern_atom_reply(xcb.conn, cookie1, 0);
+ ctx->wm_delete_window = xcb_intern_atom_reply(xcb.conn, cookie2, 0);
+
+ xcb_change_property(xcb.conn, XCB_PROP_MODE_REPLACE, ctx->window, reply->atom,
+ 4, 32, 1, &(ctx->wm_delete_window->atom));
+ xcb_change_property(xcb.conn, XCB_PROP_MODE_REPLACE, ctx->window,
+ XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(mui_get_window_name(ctx->mw)),
+ mui_get_window_name(ctx->mw));
+
+
+ xcb_map_window(xcb.conn, ctx->window);
+ xcb_flush(xcb.conn);
+
+ LIST_INSERT_HEAD(&xcb.ctx_head, ctx, entries);
+ return ctx;
+}
+
+void
+mui_delete_ctx(struct mui_ctx *ctx)
+{
+
+}
+
+xcb_render_picture_t
+ctx_create_shape(struct ctx_node *node)
+{
+ uint16_t width;
+ uint16_t height;
+ xcb_rectangle_t rect;
+ xcb_pixmap_t xcb_pixmap;
+ xcb_render_picture_t xcb_picture;
+ xcb_render_color_t xcb_color;
+
+ struct mui_shape *shape;
+ struct mui_layout *layout;
+ struct mui_color color;
+
+ shape = (struct mui_shape *)node->ptr;
+ layout = mui_get_shape_layout(shape);
+ color = mui_get_shape_color(shape);
+
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout);
+
+ xcb_color.red = color.r * 0xffff;
+ xcb_color.green = color.g * 0xffff;
+ xcb_color.blue = color.b * 0xffff;
+ xcb_color.alpha = color.a * 0xffff;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+
+ xcb_pixmap = xcb_generate_id(xcb.conn);
+ xcb_picture = xcb_generate_id(xcb.conn);
+
+ xcb_create_pixmap(xcb.conn, 32, xcb_pixmap, xcb.screen->root, width, height);
+ xcb_render_create_picture(xcb.conn, xcb_picture, xcb_pixmap, xcb.fmt_argb32, 0, NULL);
+ xcb_render_fill_rectangles(xcb.conn, XCB_RENDER_PICT_OP_OVER, xcb_picture, xcb_color, 1, &rect);
+ xcb_free_pixmap(xcb.conn, xcb_pixmap);
+ return xcb_picture;
+}
+
+
+/*
+ * This creates a picture that contains glyphs that will be then
+ * composited to the context picture
+ */
+
+struct gheader {
+ uint8_t count;
+ uint8_t pad[3];
+ uint16_t dx;
+ uint16_t dy;
+};
+
+xcb_render_picture_t
+ctx_create_label(struct ctx_node *node)
+{
+ uint32_t mask;
+ uint32_t value;
+ uint16_t width;
+ uint16_t height;
+ xcb_pixmap_t xcb_pixmap;
+ xcb_render_color_t color;
+ xcb_rectangle_t rectangle;
+ xcb_render_picture_t xcb_picture;
+ struct mui_label *label;
+ struct mui_layout *layout;
+
+ label = (struct mui_label *)node->ptr;
+ layout = mui_get_label_layout(label);
+
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout) * 1.5;
+
+ rectangle.x = 0;
+ rectangle.y = 0;
+ rectangle.width = width;
+ rectangle.height = height;
+
+ color.red = 0;
+ color.green = 0;
+ color.blue = 0;
+ color.alpha = 0;
+
+ xcb_pixmap = xcb_generate_id(xcb.conn);
+ xcb_picture = xcb_generate_id(xcb.conn);
+
+ xcb_create_pixmap(xcb.conn, 32, xcb_pixmap, xcb.screen->root, width, height);
+ xcb_render_create_picture(xcb.conn, xcb_picture, xcb_pixmap, xcb.fmt_argb32, 0, NULL);
+ xcb_render_fill_rectangles(xcb.conn, XCB_RENDER_PICT_OP_OVER, xcb_picture, color, 1, &rectangle);
+
+ /*
+ * Actual drawing the text
+ */
+ xcb_pixmap_t gpixmap;
+ xcb_render_picture_t gpicture;
+ struct gheader header;
+ uint32_t *data;
+ char *text;
+
+ header.count = mui_get_label_len(label);
+ header.pad[0] = 0;
+ header.pad[1] = 0;
+ header.pad[2] = 0;
+ header.dx = 0;
+ header.dy = xcb.fonts[0]->height;
+
+ width = 1;
+ height = 1;
+ rectangle.x = 0;
+ rectangle.y = 0;
+ rectangle.width = width;
+ rectangle.height = height;
+
+ color.red = 0;
+ color.green = 0;
+ color.blue = 0;
+ color.alpha = 0xffff;
+
+ mask = XCB_RENDER_CP_REPEAT;
+ value = XCB_RENDER_REPEAT_NORMAL;
+
+ gpixmap = xcb_generate_id(xcb.conn);
+ gpicture = xcb_generate_id(xcb.conn);
+
+ xcb_create_pixmap(xcb.conn, 32, gpixmap, xcb.screen->root, width, height);
+ xcb_render_create_picture(xcb.conn, gpicture, gpixmap, xcb.fmt_argb32, mask, &value);
+ xcb_render_fill_rectangles(xcb.conn, XCB_RENDER_PICT_OP_OVER, gpicture, color, 1, &rectangle);
+
+
+ void *line;
+ line = NULL;
+
+ header.count = mui_get_label_len(label);
+
+ text = mui_get_label_text(label);
+ data = malloc(sizeof(uint32_t) * header.count + sizeof(header));
+
+ for (int i = 0; i < header.count; i++)
+ data[i + sizeof(header) / sizeof(uint32_t)] = text[i];
+
+ memcpy(data, &header, sizeof(header));
+
+ xcb_render_composite_glyphs_32(xcb.conn, XCB_RENDER_PICT_OP_OVER, gpicture, xcb_picture, 0,
+ xcb.fonts[0]->gs, 0, 0, sizeof(header) + header.count * sizeof(uint32_t), (uint8_t *)data);
+
+ free(data);
+
+ xcb_render_free_picture(xcb.conn, gpicture);
+ xcb_free_pixmap(xcb.conn, gpixmap);
+ xcb_free_pixmap(xcb.conn, xcb_pixmap);
+
+ return xcb_picture;
+}
+
+xcb_render_picture_t
+ctx_create_image(struct ctx_node *node)
+{
+ uint8_t *data;
+ uint16_t width;
+ uint16_t height;
+ xcb_image_t *xcb_image;
+ xcb_pixmap_t xcb_pixmap;
+ xcb_gcontext_t gc;
+ xcb_render_picture_t xcb_picture;
+ struct mui_layout *layout;
+ struct mui_group *group;
+
+ data = (uint8_t *)mui_get_image_data(node->ptr);
+ group = mui_get_image_group(node->ptr);
+ layout = mui_get_image_layout(node->ptr);
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout);
+
+ xcb_pixmap = xcb_generate_id(xcb.conn);
+ xcb_picture = xcb_generate_id(xcb.conn);
+
+ xcb_create_pixmap(xcb.conn, 32, xcb_pixmap, xcb.screen->root, width, height);
+ xcb_image = xcb_image_create_native(xcb.conn, width, height, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 32, NULL, 0, data);
+
+ xcb_render_create_picture(xcb.conn, xcb_picture, xcb_pixmap, xcb.fmt_argb32, 0, NULL);
+
+ gc = xcb_generate_id(xcb.conn);
+ xcb_create_gc(xcb.conn, gc, xcb_pixmap, 0, NULL);
+ xcb_image_put(xcb.conn, xcb_pixmap, gc, xcb_image, 0, 0, 0);
+
+ xcb_free_gc(xcb.conn, gc);
+ xcb_image_destroy(xcb_image);
+ xcb_free_pixmap(xcb.conn, xcb_pixmap);
+
+ return xcb_picture;
+}
+
+void*
+mui_ctx_create_node(struct mui_ctx *ctx, uint16_t type, void *data)
+{
+ struct ctx_node *node;
+
+ node = malloc(sizeof(*node));
+ node->type = type;
+ node->ptr = data;
+
+ switch (type) {
+ case MUI_SHAPE:
+ node->picture = ctx_create_shape(node);
+ mui_ctx_transform_node(ctx, node);
+ break;
+
+ case MUI_LABEL:
+ node->picture = ctx_create_label(node);
+ mui_ctx_transform_node(ctx, node);
+ break;
+
+ case MUI_IMAGE:
+ node->picture = ctx_create_image(node);
+ mui_ctx_transform_node(ctx, node);
+ break;
+ }
+ return node;
+}
+
+void
+mui_ctx_delete_node(void *node)
+{
+ struct ctx_node *ctx_node;
+
+ ctx_node = (struct ctx_node *)node;
+ xcb_render_free_picture(xcb.conn, ctx_node->picture);
+ free(node);
+}
+
+
+void
+ctx_draw(struct mui_ctx *ctx)
+{
+ uint16_t width;
+ uint16_t height;
+ struct mui_group *group;
+ struct mui_layout *layout;
+
+ group = mui_get_window_group(ctx->mw);
+ layout = mui_get_group_layout(group);
+
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout);
+
+ xcb_render_fill_rectangles(xcb.conn, XCB_RENDER_PICT_OP_OVER, ctx->picture,
+ (xcb_render_color_t) { 0xcbcb, 0xcbcb, 0xcbcb, 0xffff }, 1,
+ &(xcb_rectangle_t) { 0, 0, width, height });
+
+ mui_draw_group_nodes(group);
+
+ xcb_copy_area(xcb.conn, ctx->pixmap, ctx->window, ctx->gc, 0, 0, 0, 0, width, height);
+ xcb_flush(xcb.conn);
+}
+
+void
+mui_ctx_transform_node(struct mui_ctx *ctx, void *node)
+{
+ float *matrix;
+ struct ctx_node *ctx_node;
+ struct mui_layout *layout;
+
+ ctx_node = (struct ctx_node *)node;
+
+ switch (ctx_node->type) {
+ case MUI_SHAPE:
+ layout = mui_get_shape_layout(ctx_node->ptr);
+ break;
+
+ case MUI_LABEL:
+ layout = mui_get_label_layout(ctx_node->ptr);
+ break;
+
+ case MUI_IMAGE:
+ layout = mui_get_image_layout(ctx_node->ptr);
+ break;
+ }
+
+ matrix = mui_get_layout_matrix(layout);
+
+ ctx_node->transform.matrix11 = MAX_UINT16 * matrix[0];
+ ctx_node->transform.matrix12 = MAX_UINT16 * matrix[1];
+ ctx_node->transform.matrix13 = MAX_UINT16 * matrix[2];
+ ctx_node->transform.matrix21 = MAX_UINT16 * matrix[3];
+ ctx_node->transform.matrix22 = MAX_UINT16 * matrix[4];
+ ctx_node->transform.matrix23 = MAX_UINT16 * matrix[5];
+ ctx_node->transform.matrix31 = MAX_UINT16 * matrix[6];
+ ctx_node->transform.matrix32 = MAX_UINT16 * matrix[7];
+ ctx_node->transform.matrix33 = MAX_UINT16 * matrix[8];
+
+ free(matrix);
+ ctx_draw(ctx);
+}
+
+
+void
+mui_ctx_draw_node(struct mui_ctx *ctx, void *node)
+{
+ if (node == NULL)
+ return;
+
+ uint16_t width;
+ uint16_t height;
+ struct mui_group *group;
+ struct mui_layout *layout;
+ struct ctx_node *ctx_node;
+
+ ctx_node = (struct ctx_node *)node;
+ group = ctx_get_node_group(ctx_node);
+ layout = mui_get_group_layout(group);
+ width = mui_get_layout_width(layout);
+ height = mui_get_layout_height(layout);
+
+ xcb_render_set_picture_transform(xcb.conn, ctx_node->picture, ctx_node->transform);
+
+ xcb_render_composite(xcb.conn, XCB_RENDER_PICT_OP_OVER, ctx_node->picture,
+ 0, ctx->picture, 0, 0, 0, 0, 0, 0, width, height);
+}
+
+struct mui_ctx*
+ctx_find_from_window(xcb_window_t xcb_window)
+{
+ struct mui_ctx *np;
+ LIST_FOREACH(np, &xcb.ctx_head, entries) {
+ if (np->window == xcb_window)
+ return np;
+ }
+ return NULL;
+}
+
+int
+mui_ctx_get_glyph_width(char glyph, int font_id)
+{
+ return xcb.fonts[font_id]->widths[glyph];
+}
+
+int
+mui_ctx_get_font_height(int font_id)
+{
+ return xcb.fonts[font_id]->height;
+}
+
+void
+mui_ctx_process_event()
+{
+ xcb_generic_event_t *event;
+ xcb_expose_event_t *expose;
+ xcb_client_message_event_t *client_message;
+ xcb_button_press_event_t *button_press;
+ xcb_button_release_event_t *button_release;
+ xcb_motion_notify_event_t *motion_notify;
+ xcb_key_press_event_t *key_press;
+ xcb_key_release_event_t *key_release;
+ xcb_configure_notify_event_t *configure_notify;
+
+ struct mui_ctx *ctx;
+ struct mui_group *group;
+ struct mui_layout *layout;
+ struct mui_event_handler *handler;
+
+ while ((event = xcb_poll_for_event(xcb.conn))) {
+ switch (event->response_type & ~0x80) {
+ case XCB_EXPOSE:
+ xcb_flush(xcb.conn);
+ break;
+
+ case XCB_CLIENT_MESSAGE:
+ client_message = (xcb_client_message_event_t *)event;
+ ctx = ctx_find_from_window(client_message->window);
+ handler = mui_get_window_event_handler(ctx->mw);
+
+ if (client_message->data.data32[0] == ctx->wm_delete_window->atom)
+ mui_push_event(handler, &(struct mui_event) { .type = MUI_EVENT_QUIT });
+ break;
+
+ case XCB_BUTTON_PRESS:
+ button_press = (xcb_button_press_event_t *)event;
+ ctx = ctx_find_from_window(button_press->event);
+ handler = mui_get_window_event_handler(ctx->mw);
+
+ mui_push_event(handler, &(struct mui_event) { .type = MUI_EVENT_MOUSE_PRESS,
+ .mouse_press = {
+ .button = button_press->detail,
+ .x = button_press->event_x,
+ .y = button_press->event_y
+ }
+ });
+ break;
+
+ case XCB_BUTTON_RELEASE:
+ button_release = (xcb_button_release_event_t *)event;
+ ctx = ctx_find_from_window(button_release->event);
+ handler = mui_get_window_event_handler(ctx->mw);
+
+ mui_push_event(handler, &(struct mui_event) { .type = MUI_EVENT_MOUSE_RELEASE,
+ .mouse_release = {
+ .button = button_release->detail,
+ .x = button_release->event_x,
+ .y = button_release->event_y
+ }
+ });
+ break;
+
+ case XCB_MOTION_NOTIFY:
+ motion_notify = (xcb_motion_notify_event_t *)event;
+ ctx = ctx_find_from_window(motion_notify->event);
+ handler = mui_get_window_event_handler(ctx->mw);
+
+ mui_push_event(handler, &(struct mui_event) { .type = MUI_EVENT_MOUSE_MOTION,
+ .mouse_motion = {
+ .x = motion_notify->event_x,
+ .y = motion_notify->event_y
+ }
+ });
+ break;
+
+ case XCB_KEY_PRESS:
+ key_press = (xcb_key_press_event_t *)event;
+ ctx = ctx_find_from_window(key_press->event);
+ handler = mui_get_window_event_handler(ctx->mw);
+
+
+ mui_push_event(handler, &(struct mui_event) { .type = MUI_EVENT_KEY_PRESS,
+ .key_press = {
+ .key = key_press->detail,
+ }
+ });
+ break;
+
+ case XCB_KEY_RELEASE:
+ key_release = (xcb_key_release_event_t *)event;
+ ctx = ctx_find_from_window(key_release->event);
+ handler = mui_get_window_event_handler(ctx->mw);
+
+ mui_push_event(handler, &(struct mui_event) { .type = MUI_EVENT_KEY_RELEASE,
+ .key_release = {
+ .key = key_release->detail
+ }
+ });
+ break;
+
+ case XCB_CONFIGURE_NOTIFY:
+ configure_notify = (xcb_configure_notify_event_t *)event;
+ ctx = ctx_find_from_window(configure_notify->window);
+ group = mui_get_window_group(ctx->mw);
+ layout = mui_get_group_layout(group);
+
+ /*
+ * Resize the window layout here then proceed
+ * to redraw the contex with the new values
+ */
+ if (mui_get_layout_width(layout) != configure_notify->width ||
+ mui_get_layout_height(layout) != configure_notify->height) {
+
+ mui_resize_layout(layout, configure_notify->width, configure_notify->height);
+ ctx_create_bg(ctx);
+
+ }
+
+ ctx_draw(ctx);
+ break;
+ }
+ free(event);
+ }
+}
blob - /dev/null
blob + 5b823fd26ce57b28b0e2b525da790bab22b41c92 (mode 644)
Binary files /dev/null and demo/common/fish.raw differ
blob - /dev/null
blob + b38610dd68f45e3855a0b7a1c0ed8de241ebb0d2 (mode 644)
Binary files /dev/null and demo/common/flag.raw differ
blob - /dev/null
blob + 3ff5ea8b0ea946d3b5df94cfb36ae72da49356b3 (mode 644)
--- /dev/null
+++ demo/image/Makefile
+SRCS=main.c
+LIBDIR=../..
+INCS= -I ${LIBDIR}
+LIBS=-Wl,-rpath=${LIBDIR} -L ${LIBDIR} -lmui
+
+all:
+ make MUI_DEBUG=1 -C ${LIBDIR}
+ ${CC} ${SRCS} -o bin ${INCS} ${LIBS}
+
+clean:
+ rm -rf bin bin.core
blob - /dev/null
blob + 9f1c515482dc202e4a3c6a404e7d50de332466f0 (mode 644)
--- /dev/null
+++ demo/image/main.c
+#include <unistd.h>
+
+#include "mui.h"
+
+static struct {
+ struct mui_window *mw;
+ struct mui_group *group;
+ struct mui_layout *layout;
+ struct mui_event_handler *handler;
+} window;
+
+char*
+load_image_data(char *fpath)
+{
+ int c;
+ FILE *fp;
+ long fsize;
+ char *buffer;
+
+ c = 0;
+ fp = fopen(fpath, "rb");
+ buffer = malloc(200 * 200 * 4);
+
+ fseek(fp, 0, SEEK_END);
+ fsize = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ for (int i = 0; i < (200 * 200 * 4) && c != EOF; i++) {
+ c = fgetc(fp);
+ buffer[i] = c;
+ }
+ return buffer;
+}
+
+int
+main(void)
+{
+ char *data;
+ struct mui_image *image;
+ struct mui_label *label;
+ struct mui_layout *layout;
+ struct mui_layout *layint;
+
+ data = load_image_data("../common/fish.raw");
+ image = mui_create_image(data, 200, 200);
+ label = mui_create_label("The Fish", 8);
+ layout = mui_get_image_layout(image);
+ layint = mui_get_label_layout(label);
+
+ window.mw = mui_create_window("Puffy", 320, 240);
+ window.group = mui_get_window_group(window.mw);
+ window.handler = mui_get_window_event_handler(window.mw);
+
+
+ mui_set_layout_flags(layout, MUI_ALIGN_CENTER_X | MUI_ALIGN_CENTER_Y |
+ MUI_ANCHOR_CENTER_X | MUI_ANCHOR_CENTER_Y);
+ mui_set_layout_flags(layint, MUI_ALIGN_RIGHT | MUI_ALIGN_BOTTOM | MUI_ANCHOR_RIGHT
+ | MUI_ANCHOR_BOTTOM);
+ mui_group_add(window.group, MUI_IMAGE, image);
+ mui_group_add(window.group, MUI_LABEL, label);
+
+ while ((mui_pop_event(window.handler)).type != MUI_EVENT_QUIT) {
+ mui_update();
+ }
+
+ mui_delete_image(image);
+ mui_delete_label(label);
+ mui_delete_window(window.mw);
+
+ return 0;
+}
blob - /dev/null
blob + 3ff5ea8b0ea946d3b5df94cfb36ae72da49356b3 (mode 644)
--- /dev/null
+++ demo/shape/Makefile
+SRCS=main.c
+LIBDIR=../..
+INCS= -I ${LIBDIR}
+LIBS=-Wl,-rpath=${LIBDIR} -L ${LIBDIR} -lmui
+
+all:
+ make MUI_DEBUG=1 -C ${LIBDIR}
+ ${CC} ${SRCS} -o bin ${INCS} ${LIBS}
+
+clean:
+ rm -rf bin bin.core
blob - /dev/null
blob + f1e0f61e2989ee60003ac6436ae3fa4f6dcf12be (mode 644)
--- /dev/null
+++ demo/shape/main.c
+/*********************************************************/
+/*
+ * This demo shows some layout transformation in response
+ * to the window being resized
+ */
+/*********************************************************/
+
+#include <unistd.h>
+
+#include "mui.h"
+
+static struct {
+ struct mui_window *mw;
+ struct mui_group *group;
+ struct mui_layout *layout;
+ struct mui_event_handler *handler;
+} window;
+
+int
+main(void)
+{
+ struct mui_event event;
+ struct mui_shape *shape[3];
+ struct mui_layout *slayout[3];
+
+
+ shape[0] = mui_create_rectangle(120, 30);
+ shape[1] = mui_create_rectangle(120, 30);
+ shape[2] = mui_create_rectangle(100, 100);
+
+ slayout[0] = mui_get_shape_layout(shape[0]);
+ slayout[1] = mui_get_shape_layout(shape[1]);
+ slayout[2] = mui_get_shape_layout(shape[2]);
+
+ mui_set_layout_flags(slayout[0], MUI_SCALE_X);
+
+ mui_set_layout_flags(slayout[1], MUI_SCALE_X | MUI_ANCHOR_RIGHT |
+ MUI_ANCHOR_BOTTOM | MUI_ALIGN_RIGHT | MUI_ALIGN_BOTTOM);
+
+ mui_set_layout_flags(slayout[2], MUI_KEEP_RATIO | MUI_ANCHOR_CENTER_X |
+ MUI_ANCHOR_CENTER_Y | MUI_ALIGN_CENTER_X | MUI_ALIGN_CENTER_Y);
+
+
+ window.mw = mui_create_window("Alignment", 320, 240);
+ window.group = mui_get_window_group(window.mw);
+ window.layout = mui_get_group_layout(window.group);
+ window.handler = mui_get_window_event_handler(window.mw);
+
+ mui_group_add(window.group, MUI_SHAPE, shape[2]);
+ mui_group_add(window.group, MUI_SHAPE, shape[1]);
+ mui_group_add(window.group, MUI_SHAPE, shape[0]);
+
+ while ((event = mui_pop_event(window.handler)).type != MUI_EVENT_QUIT) {
+ mui_rotate_layout(slayout[2], 0.01);
+ mui_update();
+ usleep(1000);
+ }
+
+ mui_delete_shape(shape[2]);
+ mui_delete_shape(shape[1]);
+ mui_delete_shape(shape[0]);
+ mui_delete_window(window.mw);
+
+ return 0;
+}
blob - /dev/null
blob + 3ff5ea8b0ea946d3b5df94cfb36ae72da49356b3 (mode 644)
--- /dev/null
+++ demo/text/Makefile
+SRCS=main.c
+LIBDIR=../..
+INCS= -I ${LIBDIR}
+LIBS=-Wl,-rpath=${LIBDIR} -L ${LIBDIR} -lmui
+
+all:
+ make MUI_DEBUG=1 -C ${LIBDIR}
+ ${CC} ${SRCS} -o bin ${INCS} ${LIBS}
+
+clean:
+ rm -rf bin bin.core
blob - /dev/null
blob + 54dd7ff5de77607479a727ae6c1491c06daab714 (mode 644)
--- /dev/null
+++ demo/text/main.c
+#include <unistd.h>
+
+#include "mui.h"
+
+static struct {
+ struct mui_window *mw;
+ struct mui_group *group;
+ struct mui_layout *layout;
+ struct mui_event_handler *handler;
+} window;
+
+
+char notice[] = "OpenBSD - The secure OS";
+
+int
+main(void)
+{
+ int count;
+ struct mui_event event;
+ struct mui_label *label;
+ struct mui_layout *layout;
+
+ window.mw = mui_create_window("Text", 320, 240);
+ window.group = mui_get_window_group(window.mw);
+ window.layout = mui_get_group_layout(window.group);
+ window.handler = mui_get_window_event_handler(window.mw);
+
+ label = mui_create_label(notice, strlen(notice));
+ layout = mui_get_label_layout(label);
+
+ mui_set_layout_flags(layout, MUI_ALIGN_CENTER_X | MUI_ALIGN_CENTER_Y |
+ MUI_ANCHOR_CENTER_X | MUI_ANCHOR_CENTER_Y | MUI_KEEP_RATIO);
+
+ mui_group_add(window.group, MUI_LABEL, label);
+
+ while ((event = mui_pop_event(window.handler)).type != MUI_EVENT_QUIT) {
+ mui_update();
+ usleep(1000);
+ }
+
+ mui_delete_label(label);
+ mui_delete_window(window.mw);
+
+ return 0;
+}
blob - /dev/null
blob + 0bb4a83133f20cb4b6e2c7fea8df799d4a47cc52 (mode 644)
--- /dev/null
+++ event.c
+#include "mui.h"
+
+struct mui_event_handler {
+ uint8_t count;
+ TAILQ_HEAD(ev_list, mui_event) head;
+};
+
+
+struct mui_event_handler*
+mui_create_event_handler()
+{
+ struct mui_event_handler *handler;
+
+ handler = calloc(1, sizeof(*handler));
+ TAILQ_INIT(&handler->head);
+ handler->count = 0;
+
+ return handler;
+}
+
+void
+mui_push_event(struct mui_event_handler *handler, struct mui_event *event)
+{
+ struct mui_event *current;
+
+ if (handler->count == MUI_EVENT_MAX) {
+ struct mui_event *tail;
+
+ tail = TAILQ_LAST(&handler->head, ev_list);
+ TAILQ_REMOVE(&handler->head, tail, entries);
+ handler->count--;
+ free(tail);
+ }
+
+ current = calloc(1, sizeof(*current));
+ memcpy(current, event, sizeof(struct mui_event));
+ TAILQ_INSERT_HEAD(&handler->head, current, entries);
+
+ handler->count++;
+}
+
+struct mui_event
+mui_pop_event(struct mui_event_handler *handler)
+{
+ struct mui_event event;
+ struct mui_event *head;
+
+ event.type = MUI_EVENT_NONE;
+
+ if (handler->count == 0)
+ return event;
+
+ head = TAILQ_FIRST(&handler->head);
+
+ memcpy(&event, head, sizeof(event));
+ TAILQ_REMOVE(&handler->head, head, entries);
+ free(head);
+
+ handler->count--;
+ return event;
+}
+
+void
+mui_event_set_target(struct mui_window *mw, struct mui_event *event)
+{
+ struct mui_event_handler *handler;
+}
blob - /dev/null
blob + 90108fc2a236a4cf13c5c1d62990b01aae977805 (mode 644)
--- /dev/null
+++ group.c
+#include "mui.h"
+
+struct member {
+ unsigned int type;
+ void *ctx_node;
+ void *ptr;
+
+ TAILQ_ENTRY(member) entries;
+};
+
+struct mui_group {
+ struct mui_ctx *ctx;
+ struct mui_layout *layout;
+
+ TAILQ_HEAD(mem_head, member) head;
+};
+
+
+struct mui_group*
+mui_create_group()
+{
+ struct mui_group *group;
+
+ group = malloc(sizeof(*group));
+ group->layout = mui_create_layout(MUI_GROUP, group);
+ group->ctx = NULL;
+
+ TAILQ_INIT(&group->head);
+
+ return group;
+}
+
+void
+mui_delete_group(struct mui_group *group)
+{
+ struct member *np;
+
+ TAILQ_FOREACH(np, &group->head, entries) {
+ mui_group_remove(group, np->type, np->ptr);
+ }
+}
+
+void
+mui_set_group_ctx(struct mui_group *group, struct mui_ctx *ctx)
+{
+ struct member *np;
+
+ TAILQ_FOREACH(np, &group->head, entries) {
+ mui_ctx_delete_node(np->ctx_node);
+
+ if (np->type == MUI_GROUP) {
+ mui_set_group_ctx(group, ctx);
+ continue;
+ }
+ np->ctx_node = mui_ctx_create_node(ctx, np->type, np->ptr);
+ }
+
+ group->ctx = ctx;
+}
+
+struct mui_layout*
+mui_get_group_layout(struct mui_group *group)
+{
+ return group->layout;
+}
+
+
+void
+mui_group_add(struct mui_group *group, uint16_t type, void *data)
+{
+ struct mui_label *d_label;
+ struct mui_shape *d_shape;
+ struct mui_image *d_image;
+ struct mui_group *d_group;
+
+ struct member *member;
+ struct mui_group *current_group;
+
+ switch (type) {
+ case MUI_SHAPE:
+ d_shape = (struct mui_shape *)data;
+ current_group = mui_get_shape_group(d_shape);
+
+ if (current_group != group) {
+ mui_set_shape_group(d_shape, group);
+ return;
+ }
+ break;
+
+ case MUI_LABEL:
+ d_label = (struct mui_label *)data;
+ current_group = mui_get_label_group(d_label);
+
+ if (current_group != group) {
+ mui_set_label_group(d_label, group);
+ return;
+ }
+ break;
+
+ case MUI_IMAGE:
+ d_image = (struct mui_image *)data;
+ current_group = mui_get_image_group(d_image);
+
+ if (current_group != group) {
+ mui_set_image_group(d_image, group);
+ return;
+ }
+ break;
+
+ case MUI_GROUP:
+ d_group = (struct mui_group *)data;
+
+ /* Don't add a group within itself */
+ if (d_group == group)
+ return;
+
+ mui_set_group_ctx(d_group, group->ctx);
+ break;
+
+ default:
+ break;
+ }
+
+ if (mui_in_group(group, type, data)) {
+ printf("Already in group!\n");
+ return;
+ }
+
+
+ member = malloc(sizeof(*member));
+ member->type = type;
+ member->ptr = data;
+ member->ctx_node = (group->ctx && type != MUI_GROUP) ?
+ mui_ctx_create_node(group->ctx, type, data) : NULL;
+
+ TAILQ_INSERT_TAIL(&group->head, member, entries);
+}
+
+
+void
+mui_group_remove(struct mui_group *group, uint16_t type, void *data)
+{
+ struct mui_label *d_label;
+ struct mui_shape *d_shape;
+ struct mui_image *d_image;
+ struct mui_group *d_group;
+
+ struct member *member;
+ struct mui_group *current_group;
+
+ switch (type) {
+ case MUI_SHAPE:
+ d_shape = (struct mui_shape *)data;
+ current_group = mui_get_shape_group(d_shape);
+
+ if (current_group == group) {
+ mui_set_shape_group(d_shape, NULL);
+ return;
+ }
+ break;
+
+ case MUI_LABEL:
+ d_label = (struct mui_label *)data;
+ current_group = mui_get_label_group(d_label);
+
+ if (current_group == group) {
+ mui_set_label_group(d_label, NULL);
+ return;
+ }
+
+ case MUI_IMAGE:
+ d_image = (struct mui_image *)data;
+ current_group = mui_get_image_group(d_image);
+
+ if (current_group == group) {
+ mui_set_image_group(d_image, NULL);
+ return;
+ }
+
+ default:
+ break;
+ }
+
+
+ struct member *np;
+
+ TAILQ_FOREACH(np, &group->head, entries) {
+ if (np->ptr == data) {
+ TAILQ_REMOVE(&group->head, np, entries);
+ return;
+ }
+ }
+}
+
+void*
+mui_in_group(struct mui_group *group, uint16_t type, void *data)
+{
+ struct member *np;
+
+ TAILQ_FOREACH(np, &group->head, entries) {
+ if (np->ptr == data) return np;
+ }
+ return NULL;
+}
+
+void
+mui_draw_group_nodes(struct mui_group *group)
+{
+ if (group->ctx == NULL)
+ return;
+
+ struct member *member;
+
+ TAILQ_FOREACH(member, &group->head, entries) {
+ if (member->type == MUI_GROUP) {
+ mui_draw_group_nodes(member->ptr);
+ continue;
+ }
+ mui_ctx_draw_node(group->ctx, member->ctx_node);
+ }
+}
+
+
+void*
+mui_get_group_next_member(struct mui_group *group, void *ptr)
+{
+ if (ptr == NULL)
+ return TAILQ_FIRST(&group->head);
+
+ struct member *curr;
+ struct member *next;
+
+ curr = (struct member *)ptr;
+ next = TAILQ_NEXT(curr, entries);
+
+ return (curr == next) ? NULL : next;
+}
+
+uint16_t
+mui_get_group_member_type(void *ptr)
+{
+ return ((struct member*)ptr)->type;
+}
+
+void*
+mui_get_group_member_data(void *ptr)
+{
+ return ((struct member*)ptr)->ptr;
+}
+
+void
+mui_update_group_member(struct mui_group *group, void *ptr)
+{
+ mui_ctx_transform_node(group->ctx, ((struct member *)ptr)->ctx_node);
+}
+
+void
+mui_update_group_member_node(struct mui_group *group, void *ptr)
+{
+ struct member *member;
+
+ member = (struct member*)ptr;
+ mui_ctx_delete_node(member->ctx_node);
+
+ /*
+ * If ctx_node is not set to NULL, mui_ctx_draw_node will fail
+ * with a Segmentation Fault as it will try to draw a new node
+ * before it is assigned
+ */
+ member->ctx_node = NULL;
+ member->ctx_node = mui_ctx_create_node(group->ctx, member->type, member->ptr);
+
+ /* Force to use this function to live update */
+ mui_ctx_transform_node(group->ctx, member->ctx_node);
+}
blob - /dev/null
blob + 885188fd016951a9134caa650aec5b47ad23d5bb (mode 644)
--- /dev/null
+++ image.c
+#include "mui.h"
+
+struct mui_image {
+ char *data;
+ uint8_t fmt;
+ uint16_t width;
+ uint16_t height;
+ struct mui_group *group;
+ struct mui_layout *layout;
+};
+
+uint32_t
+u8_to_u32(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+{
+ uint8_t rgba[4];
+ uint32_t result;
+
+ rgba[0] = (float) r / 255 * a;
+ rgba[1] = (float) g / 255 * a;
+ rgba[2] = (float) b / 255 *a;
+
+ result = (rgba[0] << 24) + (rgba[1] << 16) + (rgba[2] << 8) + a;
+ return result;
+}
+
+/*
+ * This is necessary as xcb_xrender images stores them in BGRA format
+ */
+void
+rgba_to_bgra(char *data, uint16_t width, uint16_t height)
+{
+ int start;
+ uint32_t rgba;
+ int r, g, b, a;
+
+ for (int i = 0; i < width * height; i++) {
+ start = i * 4;
+ rgba = u8_to_u32(data[start + 0],
+ data[start + 1],
+ data[start + 2],
+ data[start + 3]);
+
+ r = (rgba & 0xff000000) >> 24;
+ g = (rgba & 0x00ff0000) >> 16;
+ b = (rgba & 0x0000ff00) >> 8;
+
+ data[start + 0] = b;
+ data[start + 1] = g;
+ data[start + 2] = r;
+ data[start + 3] = data[start + 3]; /* um... */
+ }
+}
+
+
+struct mui_image*
+mui_create_image(char *data, uint16_t width, uint16_t height)
+{
+ struct mui_image *image;
+
+ image = calloc(1, sizeof(*image));
+ image->width = width;
+ image->height = height;
+ image->fmt = 4;
+ image->layout = mui_create_layout(MUI_IMAGE, image);
+
+ image->data = malloc(width * height * image->fmt);
+ memcpy(image->data, data, width * height * image->fmt);
+ mui_resize_layout(image->layout, width, height);
+
+ rgba_to_bgra(image->data, width, height);
+
+ return image;
+}
+
+void
+mui_delete_image(struct mui_image *image)
+{
+ if (image->group)
+ mui_group_remove(image->group, MUI_IMAGE, image);
+
+ mui_delete_layout(image->layout);
+ free(image->data);
+ free(image);
+}
+
+struct mui_group*
+mui_get_image_group(struct mui_image *image)
+{
+ return image->group;
+}
+
+struct mui_layout*
+mui_get_image_layout(struct mui_image *image)
+{
+ return image->layout;
+}
+
+char*
+mui_get_image_data(struct mui_image *image)
+{
+ return image->data;
+}
+
+void
+mui_set_image_group(struct mui_image *image, struct mui_group *group)
+{
+ struct mui_group *current;
+ struct mui_layout *layout;
+
+ current = image->group;
+ image->group = group;
+
+ if (current != NULL)
+ mui_group_remove(current, MUI_IMAGE, image);
+
+ if (group) {
+ layout = mui_get_group_layout(group);
+ mui_group_add(group, MUI_IMAGE, image);
+ mui_resize_layout(layout, mui_get_layout_width(layout), mui_get_layout_height(layout));
+ }
+}
blob - /dev/null
blob + 3170b3ca351bb8f97c1fd0b9d812ca430198e11b (mode 644)
--- /dev/null
+++ label.c
+#include "mui.h"
+
+struct mui_label {
+ int len;
+ char *text;
+ int flags;
+ int font_id;
+ struct mui_group *group;
+ struct mui_layout *layout;
+};
+
+struct mui_label*
+mui_create_label(char *text, int len)
+{
+ struct mui_label *label;
+
+ label = calloc(1, sizeof(*label));
+ label->text = malloc(len + 1);
+ memcpy(label->text, text, len);
+ label->text[len] = '\0';
+ label->len = len;
+ label->font_id = 0;
+
+ label->group = NULL;
+ label->layout = mui_create_layout(MUI_LABEL, label);
+
+ return label;
+}
+
+void
+mui_delete_label(struct mui_label *label)
+{
+ if (label->group)
+ mui_group_remove(label->group, MUI_LABEL, label);
+
+ mui_delete_layout(label->layout);
+ free(label->text);
+ free(label);
+}
+
+struct mui_group*
+mui_get_label_group(struct mui_label *label)
+{
+ return label->group;
+}
+
+struct mui_layout*
+mui_get_label_layout(struct mui_label *label)
+{
+ return label->layout;
+}
+
+int
+mui_get_label_font_id(struct mui_label *label)
+{
+ return label->font_id;
+}
+
+int
+mui_get_label_len(struct mui_label *label)
+{
+ return label->len;
+}
+
+char*
+mui_get_label_text(struct mui_label *label)
+{
+ return label->text;
+}
+
+void
+mui_get_label_lines(struct mui_label *label, int *line_count, int *rwidth, int *rheight)
+{
+ char **lines;
+ uint16_t width;
+ uint16_t lwidth;
+ int lindex;
+ uint16_t swidth;
+ int sindex;
+ char *line;
+ int len;
+ struct mui_layout *layout;
+
+ *line_count = 1;
+ layout = mui_get_label_layout(label);
+ width = mui_get_layout_width(layout);
+
+ *rwidth = *rheight = 0;
+
+ for (int i = 0; i < label->len; i++) {
+
+ lindex = i;
+ lwidth = 0;
+
+ for (; lwidth < width && i < label->len && label->text[i] != '\n'; i++) {
+ if (label->text[i] == ' ') {
+ swidth = lwidth;
+ sindex = i;
+ }
+ }
+
+ if (lwidth > width) {
+ lwidth = swidth;
+ i = sindex;
+ }
+
+ len = i - lindex;
+ line = malloc(len + 1);
+ memcpy(line, label->text + lindex, len);
+ line[len] = '\0';
+
+ *rwidth = (*rwidth > lwidth) ? *rwidth : lwidth;
+ *rheight += mui_ctx_get_font_height(label->font_id);
+
+ free(line);
+
+ }
+}
+
+void
+mui_set_label_group(struct mui_label *label, struct mui_group *group)
+{
+ uint16_t width;
+ uint16_t height;
+ struct mui_group *current;
+ struct mui_layout *layout;
+
+ current = label->group;
+ label->group = group;
+ width = 0;
+
+ if (current != NULL)
+ mui_group_remove(current, MUI_LABEL, label);
+
+ if (group) {
+ layout = mui_get_group_layout(group);
+
+ /* Initial dimensions when group changes */
+ for (int i = 0; i < label->len; i++)
+ width += mui_ctx_get_glyph_width(label->text[i], label->font_id);
+ height = mui_ctx_get_font_height(label->font_id);
+ mui_resize_layout(label->layout, width, height);
+
+ mui_group_add(group, MUI_LABEL, label);
+ mui_resize_layout(layout, mui_get_layout_width(layout), mui_get_layout_height(layout));
+ }
+}
blob - /dev/null
blob + 0c08902f9ccd746d7c575b6b0492f8a71e309c01 (mode 644)
--- /dev/null
+++ layout.c
+#include "mui.h"
+
+struct mui_layout {
+ uint16_t width;
+ uint16_t height;
+
+ uint32_t flags;
+ uint8_t type;
+ void *ptr;
+
+ /* Pairs of translation, scale
+ and rotation */
+ float x;
+ float y;
+ float scale_x;
+ float scale_y;
+ float align_x;
+ float align_y;
+ float rotation;
+};
+
+
+void
+matrix_identity(float *matrix)
+{
+ matrix[0] = 1.0; matrix[1] = 0.0; matrix[2] = 0.0;
+ matrix[3] = 0.0; matrix[4] = 1.0; matrix[5] = 0.0;
+ matrix[6] = 0.0; matrix[7] = 0.0; matrix[8] = 1.0;
+}
+
+/*
+ * Multiply a 3x3 matrix by a 3x3 matrix and push the data in the
+ * src pointer
+ */
+void
+matrix_multiply(float *src, float *scale)
+{
+ float dst[9];
+
+ dst[0] = src[0] * scale[0] + src[1] * scale[3] + src[2] * scale[6];
+ dst[1] = src[0] * scale[1] + src[1] * scale[4] + src[2] * scale[7];
+ dst[2] = src[0] * scale[2] + src[1] * scale[5] + src[2] * scale[8];
+
+ dst[3] = src[3] * scale[0] + src[4] * scale[3] + src[5] * scale[6];
+ dst[4] = src[3] * scale[1] + src[4] * scale[4] + src[5] * scale[7];
+ dst[5] = src[3] * scale[2] + src[4] * scale[5] + src[5] * scale[8];
+
+ dst[6] = src[6] * scale[0] + src[7] * scale[3] + src[8] * scale[6];
+ dst[7] = src[6] * scale[1] + src[7] * scale[4] + src[8] * scale[7];
+ dst[8] = src[6] * scale[2] + src[7] * scale[5] + src[8] * scale[8];
+
+ memcpy(src, dst, sizeof(dst));
+}
+
+void
+matrix_translate(float *matrix, float x, float y)
+{
+ matrix[2] += x;
+ matrix[5] += y;
+}
+
+void
+matrix_rotate(float *matrix, float r)
+{
+ float m[]= { cos(r), sin(r), 0,
+ -sin(r), cos(r), 0,
+ 0, 0, 1};
+
+ matrix_multiply(matrix, m);
+}
+
+void
+matrix_scale(float *matrix, float sx, float sy)
+{
+ float scale[] = { sx, 0, 0, 0, sy, 0, 0, 0, 1};
+ matrix_multiply(matrix, scale);
+}
+
+struct mui_group*
+get_layout_group(struct mui_layout *layout)
+{
+ switch (layout->type) {
+ case MUI_IMAGE:
+ return mui_get_image_group(layout->ptr);
+ case MUI_LABEL:
+ return mui_get_label_group(layout->ptr);
+ case MUI_SHAPE:
+ return mui_get_shape_group(layout->ptr);
+ default:
+ return NULL;
+ }
+}
+
+
+struct mui_layout*
+mui_create_layout(uint8_t type, void *ptr)
+{
+ struct mui_layout *layout;
+
+ layout = calloc(1, sizeof(*layout));
+
+ layout->flags = 0;
+ layout->width = 0;
+ layout->height = 0;
+ layout->type = type;
+ layout->ptr = ptr;
+
+ layout->x = 0.0;
+ layout->y = 0.0;
+ layout->scale_x = 1.0;
+ layout->scale_y = 1.0;
+ layout->rotation = 0.0;
+
+ return layout;
+}
+
+void
+mui_delete_layout(struct mui_layout *layout)
+{
+ free(layout);
+}
+
+void
+resize_group_layout(struct mui_layout *layout, uint16_t width, uint16_t height)
+{
+ void *ptr;
+ uint16_t type;
+ float scale_x, scale_y;
+ float align_x, align_y;
+ uint16_t owidth, oheight;
+ struct mui_group *group;
+
+ struct mui_label *label;
+ struct mui_shape *shape;
+ struct mui_image *image;
+ struct mui_layout *m_layout;
+
+ ptr = NULL;
+ group = (struct mui_group *)layout->ptr;
+
+ owidth = layout->width;
+ oheight = layout->height;
+
+ layout->width = width;
+ layout->height = height;
+
+ while ((ptr = mui_get_group_next_member(group, ptr))) {
+ m_layout = NULL;
+ type = mui_get_group_member_type(ptr);
+
+ switch (type) {
+ case MUI_SHAPE:
+ shape = mui_get_group_member_data(ptr);
+ m_layout = mui_get_shape_layout(shape);
+
+ break;
+
+ case MUI_LABEL:
+ label = mui_get_group_member_data(ptr);
+ m_layout = mui_get_label_layout(label);
+ break;
+
+ case MUI_IMAGE:
+ image = mui_get_group_member_data(ptr);
+ m_layout = mui_get_image_layout(image);
+
+ default:
+ break;
+ }
+
+ if (!m_layout) continue;
+
+ scale_x = (m_layout->width * m_layout->scale_x + (width - owidth)) /
+ (m_layout->width * m_layout->scale_x);
+
+ scale_y = (m_layout->height * m_layout->scale_y + (height - oheight)) /
+ (float) (m_layout->height * m_layout->scale_y);
+
+
+ align_x = align_y = 0;
+
+ if (m_layout->flags & MUI_ALIGN_BOTTOM)
+ align_y = layout->height;
+
+ if (m_layout->flags & MUI_ALIGN_RIGHT)
+ align_x = layout->width;
+
+ if (m_layout->flags & MUI_ALIGN_CENTER_X)
+ align_x = layout->width / 2.0;
+
+ if (m_layout->flags & MUI_ALIGN_CENTER_Y)
+ align_y = layout->height / 2.0;
+
+ m_layout->align_x = align_x;
+ m_layout->align_y = align_y;
+
+ mui_scale_layout(m_layout, scale_x, scale_y);
+
+ }
+}
+
+void
+mui_resize_layout(struct mui_layout *layout, uint16_t width, uint16_t height)
+{
+ switch (layout->type) {
+ case MUI_GROUP:
+ resize_group_layout(layout, width, height);
+ break;
+
+ case MUI_SHAPE:
+ layout->width = width;
+ layout->height = height;
+ break;
+
+ case MUI_LABEL:
+ layout->width = width;
+ layout->height = height;
+ break;
+
+ case MUI_IMAGE:
+ layout->width = width;
+ layout->height = height;
+ break;
+ }
+}
+
+void
+mui_scale_layout(struct mui_layout *layout, float scale_x, float scale_y)
+{
+ struct mui_group *l_group;
+ float l_scale_x, l_scale_y;
+
+ l_group = get_layout_group(layout);
+
+ l_scale_x = layout->scale_x;
+ l_scale_y = layout->scale_y;
+
+ if (layout->flags & MUI_SCALE_X)
+ l_scale_x = layout->scale_x * scale_x;
+
+ if (layout->flags & MUI_SCALE_Y)
+ l_scale_y = layout->scale_y * scale_y;
+
+ if (layout->flags & MUI_KEEP_RATIO) {
+ l_scale_x = layout->scale_y * scale_y;
+ l_scale_y = layout->scale_y * scale_y;
+ }
+
+ layout->scale_x = l_scale_x;
+ layout->scale_y = l_scale_y;
+
+ if (l_group) mui_update_group_member(l_group, mui_in_group(l_group, layout->type, layout->ptr));
+}
+
+void
+mui_rotate_layout(struct mui_layout *layout, float rot)
+{
+ struct mui_group *l_group;
+
+ layout->rotation += rot;
+ l_group = get_layout_group(layout);
+
+ if (l_group) mui_update_group_member(l_group, mui_in_group(l_group, layout->type, layout->ptr));
+}
+
+void
+mui_translate_layout(struct mui_layout *layout, float dx, float dy)
+{
+ struct mui_group *l_group;
+
+ layout->x += dx;
+ layout->y += dy;
+ l_group = get_layout_group(layout);
+
+ if (l_group) mui_update_group_member(l_group, mui_in_group(l_group, layout->type, layout->ptr));
+}
+
+uint16_t
+mui_get_layout_width(struct mui_layout *layout)
+{
+ return layout->width;
+}
+
+uint16_t
+mui_get_layout_height(struct mui_layout *layout)
+{
+ return layout->height;
+}
+
+void
+mui_set_layout_flags(struct mui_layout *layout, uint32_t flags)
+{
+ layout->flags = flags;
+}
+
+uint32_t
+mui_get_layout_flags(struct mui_layout *layout)
+{
+ return layout->flags;
+}
+
+/*
+ * VERY important function for XCB as it sets up a matrix for
+ * transforming the image to match the current layout that
+ * works with XCB.
+ *
+ * Very weird scaling operations in this function
+ */
+
+float*
+mui_get_layout_matrix(struct mui_layout *layout)
+{
+ float *matrix;
+ float dx, dy;
+ float m_align1[9];
+ float m_align2[9];
+
+ dy = dx = 0;
+
+ matrix_identity(m_align1);
+ matrix_identity(m_align2);
+
+ if (layout->flags & MUI_ANCHOR_RIGHT)
+ dx = layout->width * layout->scale_x;
+
+ if (layout->flags & MUI_ANCHOR_CENTER_X)
+ dx = layout->width / 2.0 * layout->scale_x;
+
+ if (layout->flags & MUI_ANCHOR_CENTER_Y)
+ dy = layout->height / 2.0 * layout->scale_y;
+
+ if (layout->flags & MUI_ANCHOR_BOTTOM)
+ dy = layout->height * layout->scale_y;
+
+ matrix = calloc(9, sizeof(*matrix));
+ matrix_identity(matrix);
+
+ /*
+ * In an ideal world the matrix should be set to zero. However,
+ * as we are using XCB, it needs to be infinity
+ */
+ if (layout->scale_x < 0.0 || layout->scale_y < 0.0) {
+ matrix[0] = 1 / 0.0;
+ matrix[4] = 1 / 0.0;
+ return matrix;
+ }
+
+ m_align1[2] = -layout->x - layout->align_x;
+ m_align1[5] = -layout->y - layout->align_y;
+ m_align2[2] = -m_align1[2];
+ m_align2[5] = -m_align1[5];
+
+ matrix_scale(matrix, 1 / layout->scale_x, 1 / layout->scale_y);
+ matrix_multiply(matrix, m_align2);
+ matrix_rotate(matrix, layout->rotation);
+ matrix_multiply(matrix, m_align1);
+ matrix_translate(matrix, (-layout->x + dx - layout->align_x) / layout->scale_x,
+ (-layout->y + dy - layout->align_y) / layout->scale_y);
+
+ return matrix;
+}
+
+float
+mui_get_layout_rotation(struct mui_layout *layout)
+{
+ return layout->rotation;
+}
+
+void
+mui_print_layout_matrix(float *matrix)
+{
+ printf("Matrix:\n%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n",
+ matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5],
+ matrix[6], matrix[7], matrix[8]);
+}
+
+float
+mui_get_layout_scale_x(struct mui_layout *layout)
+{
+ return layout->scale_x;
+}
+
+float
+mui_get_layout_scale_y(struct mui_layout *layout)
+{
+ return layout->scale_y;
+}
blob - /dev/null
blob + 13b3cc23fd96597022a53dc61d2f6b811e1915f7 (mode 644)
--- /dev/null
+++ mui.7
+.Dd $Mdocdate: September 07 2025 $
+.Dt MUI 7
+.Os
+.Sh NAME
+.Nm mui
+.Nd General information
+.Sh DESCRIPTION
+mui is a library with very few modules to focuse on maintainability
+and simplicity. It is made of drawables, groups, layouts and a
+context tied to the used backend.
+.Sh DRAWABLES
+Drawables are instances that can be displayed on a window. There are
+3 types of drawables: images, shapes and labels.
+.sp
+.Sh GROUPS
+Groups are the only container of mui which can contain drawables or
+other groups. They define how drawables should be organized.
+.sp
+.Sh LAYOUTS
+Layouts are instances that are attached to groups and drawables. They
+define the transformations that occure in them.
+.sp
+.Sh CONTEXES
+Contexes are a way of communication between mui and the backend
+currently beeing used. This provides a layer of abstraction so
+the developer can create a GUI in a simple maner. This implementation
+of mui uses XCB to create a context.
+.sp
+The context can be reimplemented to be based on OpenGL or other graphics
+backend by editing the source code.
+.sp
+.Sh BASICS
+A mui program needs a display to render its drawable but not to create
+them. A general application follows these steps: create a window, get
+the window group, add instances and update mui in a loop.
+.sp
+.Sh SEE ALSO
+queue(3), mui(1)
+.Sh AUTHORS
+Onana Onana Xavier Manuel
+.Em xavier@onana.net
blob - /dev/null
blob + 31472cc2453fa7899fee5ba80af4de7efa9e60ec (mode 644)
--- /dev/null
+++ mui.h
+/***********************************************************/
+/* MUI LIBRARY
+ *
+ * This file can be used as a reference to understand the
+ * library API
+ */
+/***********************************************************/
+
+#ifndef _MUI_H_
+#define _MUI_H_
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <sys/queue.h>
+
+/* BASIC TYPES */
+
+struct mui_label;
+
+struct mui_shape;
+
+struct mui_image;
+
+struct mui_group;
+
+struct mui_color { float r, g, b, a; };
+
+/* The layout type is used by all the basic types in mui */
+
+enum mui_layout_flags {
+ MUI_SCALE_X = 1,
+ MUI_SCALE_Y = 2,
+ MUI_KEEP_RATIO = 4,
+ MUI_ANCHOR_LEFT = 8,
+ MUI_ANCHOR_RIGHT = 16,
+ MUI_ANCHOR_TOP = 32,
+ MUI_ANCHOR_BOTTOM = 64,
+ MUI_ANCHOR_CENTER_X = 128,
+ MUI_ANCHOR_CENTER_Y = 256,
+ MUI_ALIGN_RIGHT = 512,
+ MUI_ALIGN_BOTTOM = 1024,
+ MUI_ALIGN_CENTER_X = 2048,
+ MUI_ALIGN_CENTER_Y = 4096,
+ MUI_EXPAND_X = 8192,
+ MUI_EXPAND_Y = 16384
+};
+
+struct mui_layout;
+
+struct mui_window;
+
+struct mui_ctx;
+
+#define MUI_EVENT_MAX 32
+
+enum {
+ MUI_EVENT_NONE,
+ MUI_EVENT_QUIT,
+ MUI_EVENT_RESIZE,
+ MUI_EVENT_KEY_PRESS,
+ MUI_EVENT_KEY_RELEASE,
+ MUI_EVENT_MOUSE_PRESS,
+ MUI_EVENT_MOUSE_MOTION,
+ MUI_EVENT_MOUSE_RELEASE
+};
+
+struct mui_event_key_press { int key; };
+
+struct mui_event_key_release { int key; };
+
+struct mui_event_button_press { int key; };
+
+struct mui_event_button_release { int key; };
+
+struct mui_event_mouse_press { int button, x, y; };
+
+struct mui_event_mouse_release { int button, x, y; };
+
+struct mui_event_mouse_motion { int x, y; };
+
+struct mui_event {
+ uint8_t type;
+
+ struct mui_event_key_press key_press;
+ struct mui_event_key_release key_release;
+ struct mui_event_mouse_press mouse_press;
+ struct mui_event_mouse_motion mouse_motion;
+ struct mui_event_mouse_release mouse_release;
+ TAILQ_ENTRY(mui_event) entries;
+
+ struct { uint8_t id; void *ptr; } target;
+};
+
+
+struct mui_event_handler;
+
+struct mui_event_handler *mui_create_event_handler(void);
+
+void mui_push_event(struct mui_event_handler *handler, struct mui_event *event);
+
+struct mui_event mui_pop_event(struct mui_event_handler *handler);
+
+/*
+ * This function is very important and should be placed
+ * in the main loop of you GUI program
+ */
+void mui_update(void);
+
+/* SHAPE FUNCTIONS */
+
+struct mui_shape *mui_create_rectangle(uint16_t width, uint16_t height);
+
+void mui_delete_shape(struct mui_shape *shape);
+
+struct mui_group *mui_get_shape_group(struct mui_shape *shape);
+
+struct mui_layout *mui_get_shape_layout(struct mui_shape *shape);
+
+struct mui_color mui_get_shape_color(struct mui_shape *shape);
+
+void mui_set_shape_group(struct mui_shape *shape, struct mui_group *group);
+
+void mui_set_shape_color(struct mui_shape *shape, float r, float g, float b, float a);
+
+
+/* LABEL FUNCTIONS */
+
+struct mui_label *mui_create_label(char *text, int len);
+
+void mui_delete_label(struct mui_label *label);
+
+struct mui_group *mui_get_label_group(struct mui_label *label);
+
+struct mui_layout *mui_get_label_layout(struct mui_label *label);
+
+int mui_get_label_font_id(struct mui_label *label);
+
+char *mui_get_label_text(struct mui_label *label);
+
+int mui_get_label_len(struct mui_label *label);
+
+/*
+ * Returns the line count, width and height of a label
+ * based on its parent.
+ */
+void mui_get_label_lines(struct mui_label *label, int *line_count, int *rwidth, int *rheight);
+
+void mui_set_label_flags(struct mui_label *label, int flags);
+
+void mui_set_label_group(struct mui_label *label, struct mui_group *group);
+
+/* IMAGE FUNCTIONS */
+
+struct mui_image *mui_create_image(char *data, uint16_t width, uint16_t height);
+
+void mui_delete_image(struct mui_image *image);
+
+struct mui_group *mui_get_image_group(struct mui_image *image);
+
+struct mui_layout *mui_get_image_layout(struct mui_image *image);
+
+char *mui_get_image_data(struct mui_image *image);
+
+void mui_set_image_group(struct mui_image *image, struct mui_group *group);
+
+
+/* WINDOW FUNCTIONS */
+
+struct mui_window *mui_create_window(const char *name, uint16_t width, uint16_t height);
+
+void mui_delete_window(struct mui_window *window);
+
+struct mui_group *mui_get_window_group(struct mui_window *window);
+
+char *mui_get_window_name(struct mui_window *window);
+
+struct mui_event_handler *mui_get_window_event_handler(struct mui_window *mw);
+
+
+/* LAYOUT FUNCTIONS */
+
+struct mui_layout *mui_create_layout(uint8_t type, void *ptr);
+
+void mui_delete_layout(struct mui_layout *layout);
+
+void mui_resize_layout(struct mui_layout *layout, uint16_t width, uint16_t height);
+
+void mui_scale_layout(struct mui_layout *layout, float scale_x, float scale_y);
+
+void mui_rotate_layout(struct mui_layout *layout, float rot);
+
+void mui_translate_layout(struct mui_layout *layout, float dx, float dy);
+
+void mui_set_layout_flags(struct mui_layout *layout, uint32_t flags);
+
+uint32_t mui_get_layout_flags(struct mui_layout *layout);
+
+uint16_t mui_get_layout_width(struct mui_layout *layout);
+
+uint16_t mui_get_layout_height(struct mui_layout *layout);
+
+float *mui_get_layout_transform(struct mui_layout *layout);
+
+float *mui_get_layout_matrix(struct mui_layout *layout);
+
+float mui_get_layout_rotation(struct mui_layout *layout);
+
+float mui_get_layout_scale_x(struct mui_layout *layout);
+
+float mui_get_layout_scale_y(struct mui_layout *layout);
+
+/*
+ * This function should be removed later and replaced with a
+ * debugging marcro
+ */
+void mui_print_layout_matrix(float *matrix);
+
+
+/* GROUP FUNCTIONS */
+
+struct mui_group *mui_create_group(void);
+
+void mui_draw_group_nodes(struct mui_group *group);
+
+void mui_set_group_ctx(struct mui_group *group, struct mui_ctx *ctx);
+
+void mui_delete_group(struct mui_group *group);
+
+struct mui_layout *mui_get_group_layout(struct mui_group *group);
+
+void mui_group_add(struct mui_group *group, uint16_t type, void *data);
+
+void mui_group_remove(struct mui_group *group, uint16_t type, void *data);
+
+void *mui_in_group(struct mui_group *group, uint16_t type, void *data);
+
+void mui_update_group_member(struct mui_group *group, void *ptr);
+
+void mui_update_group_member_node(struct mui_group *group, void *ptr);
+
+/*
+ * Returns the next member in a group. If NULL is passed as `ptr`, the
+ * first element of the group will be returned
+ */
+void *mui_get_group_next_member(struct mui_group *group, void *ptr);
+
+uint16_t mui_get_group_member_type(void *ptr);
+
+void *mui_get_group_member_data(void *ptr);
+
+
+
+/* CONTEXT FUNCTIONS (for XCB)
+ *
+ * These functions can be used but it is not recommended. They
+ * are more dedicated to the library.
+*/
+
+struct mui_ctx *mui_create_ctx(struct mui_window *mw);
+
+void mui_delete_ctx(struct mui_ctx *ctx);
+
+void *mui_ctx_create_node(struct mui_ctx *ctx, uint16_t type, void *data);
+
+void mui_ctx_draw_node(struct mui_ctx *ctx, void *node);
+
+void mui_ctx_delete_node(void *node);
+
+void mui_ctx_transform_node(struct mui_ctx *ctx, void *node);
+
+void mui_ctx_process_event(void);
+
+int mui_ctx_get_glyph_width(char glyph, int font_id);
+
+int mui_ctx_get_font_height(int font_id);
+
+
+/* TYPES */
+
+#define MUI_UNDEF 0
+#define MUI_SHAPE 1
+#define MUI_LABEL 2
+#define MUI_IMAGE 3
+#define MUI_GROUP 4
+
+/* LABEL FLAGS */
+
+#define MUI_TEXT_WRAPPED 1
+#define MUI_TEXT_MULTILINE 2
+
+/* KEY CODES
+ *
+ * This is a list of keys based on an US keyboard on OpenBSD. It will be modified
+ * later when my knowledge gets better upon this section of XCB
+ */
+
+#define MUI_KEY_Q 24
+#define MUI_KEY_W 25
+#define MUI_KEY_E 26
+#define MUI_KEY_R 27
+#define MUI_KEY_T 28
+#define MUI_KEY_Y 29
+#define MUI_KEY_U 30
+#define MUI_KEY_I 31
+#define MUI_KEY_O 32
+#define MUI_KEY_P 33
+#define MUI_KEY_A 38
+#define MUI_KEY_S 39
+#define MUI_KEY_D 40
+#define MUI_KEY_F 41
+#define MUI_KEY_G 42
+#define MUI_KEY_H 43
+#define MUI_KEY_J 44
+#define MUI_KEY_K 45
+#define MUI_KEY_L 46
+#define MUI_KEY_Z 52
+#define MUI_KEY_X 53
+#define MUI_KEY_C 54
+#define MUI_KEY_V 55
+#define MUI_KEY_B 56
+#define MUI_KEY_N 57
+#define MUI_KEY_M 58
+
+
+/* DEBUGGING FUNCTIONS
+ *
+ * These macros are used when defining MUI_DEBUG while
+ * compiling. They can help pinpoint an error.
+*/
+
+
+#endif
blob - /dev/null
blob + 63b4038912507151fd9d32e04563f3aebfa06b2b (mode 644)
--- /dev/null
+++ shape.c
+#include "mui.h"
+
+struct mui_shape {
+ uint8_t type;
+ struct mui_color color;
+ struct mui_group *group;
+ struct mui_layout *layout;
+};
+
+
+struct mui_shape*
+mui_create_rectangle(uint16_t width, uint16_t height)
+{
+ struct mui_shape *shape;
+
+ shape = malloc(sizeof(*shape));
+ shape->group = NULL;
+ shape->layout = mui_create_layout(MUI_SHAPE, shape);
+ shape->color.r = 0.5;
+ shape->color.g = 0.5;
+ shape->color.b = 0.5;
+ shape->color.a = 1.0;
+ mui_resize_layout(shape->layout, width, height);
+
+ return shape;
+}
+
+void
+mui_delete_shape(struct mui_shape *shape)
+{
+ if (shape->group)
+ mui_group_remove(shape->group, MUI_SHAPE, shape);
+
+ mui_delete_layout(shape->layout);
+ free(shape);
+}
+
+struct mui_group*
+mui_get_shape_group(struct mui_shape *shape)
+{
+ return shape->group;
+}
+
+struct mui_layout*
+mui_get_shape_layout(struct mui_shape *shape)
+{
+ return shape->layout;
+}
+
+struct mui_color
+mui_get_shape_color(struct mui_shape *shape)
+{
+ return shape->color;
+}
+
+void
+mui_set_shape_color(struct mui_shape *shape, float r, float g, float b, float a)
+{
+ shape->color.r = r;
+ shape->color.g = g;
+ shape->color.b = b;
+ shape->color.a = a;
+
+ if (shape->group) {
+ mui_update_group_member_node(shape->group, mui_in_group(shape->group, MUI_SHAPE, shape));
+ }
+}
+
+void
+mui_set_shape_group(struct mui_shape *shape, struct mui_group *group)
+{
+ struct mui_group *current;
+ struct mui_layout *layout;
+
+ current = shape->group;
+ shape->group = group;
+
+ if (current != NULL)
+ mui_group_remove(current, MUI_SHAPE, shape);
+
+ if (group) {
+ layout = mui_get_group_layout(group);
+ mui_group_add(group, MUI_SHAPE, shape);
+
+ mui_resize_layout(layout, mui_get_layout_width(layout), mui_get_layout_height(layout));
+ }
+}
blob - /dev/null
blob + 5e964f11bdc556ab55781c50157a885f462f5f94 (mode 644)
--- /dev/null
+++ window.c
+#include "mui.h"
+
+struct mui_window {
+ struct mui_event_handler *handler;
+ struct mui_group *group;
+ struct mui_ctx *ctx;
+ char *name;
+};
+
+
+
+struct mui_window*
+mui_create_window(const char *name, uint16_t width, uint16_t height)
+{
+ struct mui_window *mw;
+ struct mui_layout *layout;
+
+ mw = malloc(sizeof(*mw));
+ mw->group = mui_create_group();
+ layout = mui_get_group_layout(mw->group);
+ mui_resize_layout(layout, width, height);
+ mui_set_layout_flags(layout, MUI_EXPAND_X | MUI_EXPAND_Y);
+ mw->handler = mui_create_event_handler();
+
+ mw->name = malloc(strlen(name)+1);
+ memcpy(mw->name, name, strlen(name));
+ mw->name[strlen(name)] = '\0';
+
+ mw->ctx = mui_create_ctx(mw);
+ mui_set_group_ctx(mw->group, mw->ctx);
+
+ return mw;
+}
+
+void
+mui_delete_window(struct mui_window *mw)
+{
+
+}
+
+
+struct mui_group*
+mui_get_window_group(struct mui_window *mw)
+{
+ return mw->group;
+}
+
+char*
+mui_get_window_name(struct mui_window *mw)
+{
+ return mw->name;
+}
+
+struct mui_event_handler*
+mui_get_window_event_handler(struct mui_window *mw)
+{
+ return mw->handler;
+}
+
+void
+mui_update()
+{
+ mui_ctx_process_event();
+}