Commit Diff


commit - 94783f656eaf549437a61d52e2df97f28791e880
commit + 749e270c9e436c9e475d2ef00a30660ad7f1b12e
blob - aec9a0c7220e03ce9f502e4ec0c4777ea53660cc
blob + 7e285dc9cc7d37558104a0476578f5ec3960492c
--- TODO
+++ TODO
@@ -11,10 +11,21 @@
 - Implement groups styles (ex. VStack groups, HStack groups, Grid groups,
   etc.) with a set of flags (ex. Scrollable and clipping?)
 
-- Add font options (ex. color, size, etc) with flags (ex. multiline, text
-  wrapping)
+- Add a minimum size option for layouts so drawables are still visible
+  even if scaled down to the maximum.
 
-- Add a minimum size option for layouts
+- Get rid of xcb-render-util dependency. This is to reduce dependancies
+  mostly for FreeBSD as OpenBSD and NetBSD already come with X11R6 and
+  X11R7.
 
-- Fix issues happening in text rendering (noises that adds odd colors to
-  text and sometimes text from a dead program invading the new one)
+- Fix font line spacing in `mui_label`. When turning on setting the color
+  of the xcb_render picture in `context.c` there is a noticable gap at
+  the end of the texture. This is due to the layout height being multiplied
+  by 1.5 as a temporary hack.
+
+- Makefile for OpenBSD ports. The make command currently only create a
+  limbui.so file in the library folder. Change the makefile to install the
+  library on an OpenBSD system.
+
+- Add label partial font styling to have different styles inside the same
+  label. More customization to label in other world.
blob - 98401c97a40dd5fb6e56f4dbb3e0840c44a1750d
blob + 1a3f4838d6f15495ff8fcdc0c8b1becb22a91327
--- context.c
+++ context.c
@@ -188,7 +188,6 @@ ctx_load_font()
     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);
@@ -370,14 +369,13 @@ struct gheader {
 xcb_render_picture_t
 ctx_create_label(struct ctx_node *node)
 {
-    uint32_t mask;
-    uint32_t value;
     uint16_t width;
     uint16_t height;
+    xcb_rectangle_t rect;
     xcb_pixmap_t xcb_pixmap;
-    xcb_render_color_t color;
-    xcb_rectangle_t rectangle;
     xcb_render_picture_t xcb_picture;
+    xcb_render_color_t xcb_color;
+
     struct mui_label *label;
     struct mui_layout *layout;
 
@@ -387,50 +385,59 @@ ctx_create_label(struct ctx_node *node)
     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;
+    xcb_color.red   = 0;
+    xcb_color.green = 0;
+    xcb_color.blue  = 0;
+    xcb_color.alpha = 0;
 
-    color.red   = 0;
-    color.green = 0;
-    color.blue  = 0;
-    color.alpha = 0;
+    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, color, 1, &rectangle);
+    xcb_render_fill_rectangles(xcb.conn, XCB_RENDER_PICT_OP_SRC, xcb_picture, xcb_color, 1, &rect);
 
     /*
      * Actual drawing the text
      */
+    uint32_t                mask;
+    uint32_t                value;
     xcb_pixmap_t            gpixmap;
     xcb_render_picture_t    gpicture;
     struct gheader          header;
     uint32_t               *data;
     char                   *text;
+    struct                  mui_color m_color;
+    int                     tindex; /* Text index */
+    int                     last_width;
+    struct                  mui_gindice *ptr;
+    struct                  mui_gindice *last_indice;
 
+    m_color = mui_get_label_color(label);
+
     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;
+    header.dy = 0;
 
     width = 1;
     height = 1;
-    rectangle.x = 0;
-    rectangle.y = 0;
-    rectangle.width = width;
-    rectangle.height = height;
+    rect.x = 0;
+    rect.y = 0;
+    rect.width = width;
+    rect.height = height;
 
-    color.red = 0;
-    color.green = 0;
-    color.blue = 0;
-    color.alpha = 0xffff;
+    xcb_color.red = m_color.r * 0xffff;
+    xcb_color.green = m_color.g * 0xffff;
+    xcb_color.blue = m_color.b * 0xffff;
+    xcb_color.alpha = m_color.a * 0xffff;
 
     mask = XCB_RENDER_CP_REPEAT;
     value = XCB_RENDER_REPEAT_NORMAL;
@@ -438,29 +445,52 @@ ctx_create_label(struct ctx_node *node)
     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_create_pixmap(xcb.conn, 32, gpixmap, xcb.screen->root, 1, 1);
     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);
+    xcb_render_fill_rectangles(xcb.conn, XCB_RENDER_PICT_OP_OVER, gpicture, xcb_color, 1, &rect);
 
+    ptr = NULL;
+    tindex = 0;
+    last_width = 0;
+    last_indice = NULL;
+    while ((ptr = mui_get_label_next_indice(label, ptr))) {
+        header.dy += xcb.fonts[ptr->gs]->height;
 
-    void *line;
-    line = NULL;
+        /*
+         * This is in a case the current pointer has the same line number
+         * as the last one.
+         *
+         * This line will offset properly the xcb_picture
+         */
+        if (last_indice) {
+            if (last_indice->lnum == ptr->lnum) {
+                header.dx = last_width;
+                header.dy -= xcb.fonts[ptr->gs]->height;
+            } else {
+                last_width = 0;
+                header.dx = 0;
+            }
+        }
 
-    header.count = mui_get_label_len(label);
+        header.count = ptr->len;
+        text = mui_get_label_text(label);
 
-    text = mui_get_label_text(label);
-    data = malloc(sizeof(uint32_t) * header.count + sizeof(header));
+        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];
+        for (int i = 0; i < header.count; i++) {
+            data[i + sizeof(header) / sizeof(uint32_t)] = text[tindex + i];
+            last_width += xcb.fonts[ptr->gs]->widths[text[tindex + i]];
+        }
 
-    memcpy(data, &header, sizeof(header));
+        memcpy(data, &header, sizeof(header));
+        tindex += ptr->len;
 
-    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);
+        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);
+        last_indice = ptr;
+    }
 
-    free(data);
-
     xcb_render_free_picture(xcb.conn, gpicture);
     xcb_free_pixmap(xcb.conn, gpixmap);
     xcb_free_pixmap(xcb.conn, xcb_pixmap);
blob - 9f1c515482dc202e4a3c6a404e7d50de332466f0
blob + 1cbab7f2dd6cff54abf9d07ee00db76a9458e912
--- demo/image/main.c
+++ demo/image/main.c
@@ -43,7 +43,7 @@ main(void)
 
     data = load_image_data("../common/fish.raw");
     image = mui_create_image(data, 200, 200);
-    label = mui_create_label("The Fish", 8);
+    label = mui_create_label("The Fish");
     layout = mui_get_image_layout(image);
     layint = mui_get_label_layout(label);
 
blob - 54dd7ff5de77607479a727ae6c1491c06daab714
blob + 1c9fac3bbc67c9dd9f7c24349f0b5e23c2a18b85
--- demo/text/main.c
+++ demo/text/main.c
@@ -10,27 +10,25 @@ static struct {
 } window;
 
 
-char notice[] = "OpenBSD - The secure OS";
+char notice[] = 
+"OpenBSD - Free, Functional and secure\n\n"
+"NetBSD- Free, Fast, Secure and highly portable Unix-like Open Source operating system\n\n"
+"FreeBSD - The Power to Serve\n\n"
+"DragonflyBSD";
 
 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.mw = mui_create_window("text.ex", 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);
-
+    label = mui_create_label(notice);
+    mui_set_label_flags(label, MUI_TEXT_WRAPPED | MUI_TEXT_MULTILINE);
     mui_group_add(window.group, MUI_LABEL, label);
 
     while ((event = mui_pop_event(window.handler)).type != MUI_EVENT_QUIT) {
blob - 90108fc2a236a4cf13c5c1d62990b01aae977805
blob + 31d3d95df9965d8d0bdb58d7ab0a3ae82384dff4
--- group.c
+++ group.c
@@ -9,9 +9,12 @@ struct member {
 };
 
 struct mui_group {
+    uint16_t        type;
     struct          mui_ctx *ctx;
     struct          mui_layout *layout;
 
+    struct { uint16_t cols, rows; } grid;
+
     TAILQ_HEAD(mem_head, member) head;
 };
 
@@ -23,6 +26,7 @@ mui_create_group()
 
     group = malloc(sizeof(*group));
     group->layout = mui_create_layout(MUI_GROUP, group);
+    group->type = MUI_UNDEF;
     group->ctx = NULL;
 
     TAILQ_INIT(&group->head);
@@ -30,6 +34,19 @@ mui_create_group()
     return group;
 }
 
+struct mui_group*
+mui_create_grid(uint16_t cols, uint16_t rows)
+{
+    struct mui_group *group;
+
+    group = mui_create_group();
+    group->type = MUI_GRID;
+    group->grid.cols = cols;
+    group->grid.rows = rows;
+
+    return group;
+}
+
 void
 mui_delete_group(struct mui_group *group)
 {
blob - 3170b3ca351bb8f97c1fd0b9d812ca430198e11b
blob + 27be9d05366f4aba761b51139b2701a9ca1877e5
--- label.c
+++ label.c
@@ -2,28 +2,35 @@
 
 struct mui_label {
     int         len;
+    int         vlen;
     char       *text;
     int         flags;
     int         font_id;
+    struct      mui_color color;
     struct      mui_group *group;
     struct      mui_layout *layout;
+
+    TAILQ_HEAD(mui_gindice_h, mui_gindice) head;
 };
 
 struct mui_label*
-mui_create_label(char *text, int len)
+mui_create_label(char *text)
 {
     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->len = strlen(text);
+    label->text = malloc(label->len + 1);
+    memcpy(label->text, text, label->len);
+    label->text[label->len] = '\0';
     label->font_id = 0;
 
     label->group = NULL;
+    label->color = (struct mui_color) { 0, 0, 0, 1.0 };
     label->layout = mui_create_layout(MUI_LABEL, label);
 
+    TAILQ_INIT(&label->head);
+
     return label;
 }
 
@@ -68,53 +75,182 @@ mui_get_label_text(struct mui_label *label)
     return label->text;
 }
 
+struct mui_color
+mui_get_label_color(struct mui_label *label)
+{
+    return label->color;
+}
+
 void
-mui_get_label_lines(struct mui_label *label, int *line_count, int *rwidth, int *rheight)
+mui_set_label_color(struct mui_label *label, float r, float g, float b, float a)
 {
-    char      **lines;
-    uint16_t    width;
-    uint16_t    lwidth;
-    int         lindex;
-    uint16_t    swidth;
-    int         sindex;
-    char       *line;
-    int         len;
-    struct      mui_layout *layout;
+    label->color = (struct mui_color) { r, g, b, a };
+    if (label->group)
+        mui_update_group_member_node(label->group, mui_in_group(label->group, MUI_LABEL, label));
+}
 
-    *line_count = 1;
-    layout = mui_get_label_layout(label);
-    width = mui_get_layout_width(layout);
+struct mui_gindice*
+mui_get_label_next_indice(struct mui_label *label, struct mui_gindice *ptr)
+{
+    if (ptr == NULL)
+        return TAILQ_FIRST(&label->head);
 
-    *rwidth = *rheight = 0;
+    struct mui_gindice *curr;
+    struct mui_gindice *next;
 
-    for (int i = 0; i < label->len; i++) {
+    curr = (struct mui_gindice *)ptr;
+    next = TAILQ_NEXT(curr, entries);
 
-        lindex = i;
-        lwidth = 0;
+    return (curr == next) ? NULL : next;
+}
 
-        for (; lwidth < width && i < label->len && label->text[i] != '\n'; i++) {
-            if (label->text[i] == ' ') {
-                swidth = lwidth;
-                sindex = i;
+/*
+ * Text is stored in an easy to read format to help render properly 
+ * on the context. This is done using the `mui_gindice` struct which
+ * has the line number, the glyphset and the number of characters.
+ *
+ * You can vien it in this way :
+ *
+ * { {0, 1, 50} , {1, 0, 25} }
+ *
+ * In this example there are two lines where the first line has 50
+ * character and uses the font id 1 and the second has 25 lines
+ *
+ * This function also allows implementation of flags such as 
+ * `MUI_MULTILINE` and `MUI_TEXT_WRAP`
+ */
+
+void
+mui_format_label(struct mui_label *label)
+{
+    uint8_t len;
+    int last_space;
+    uint16_t width;
+    uint16_t height;
+    uint16_t twidth;
+    uint16_t lwidth;
+    uint32_t gs, lnum;
+    struct mui_gindice *np;
+    struct mui_layout *layout;
+
+    /* Cleanup */
+    while ((np = TAILQ_FIRST(&label->head))) {
+        TAILQ_REMOVE(&label->head, np, entries);
+        free(np);
+    }
+
+    layout = mui_get_group_layout(label->group);
+    lwidth = mui_get_layout_width(layout);
+
+    gs = len = lnum = 0;
+    width = height = 0;
+    last_space = 0;
+    twidth = 0;
+
+    /* Appending */
+    for (int i = 0; i < label->len + 1; i++) {
+        len++;
+
+        twidth += mui_ctx_get_glyph_width(label->text[i], label->font_id);
+
+        if (label->text[i] == ' ')
+            last_space = i;
+
+        if (twidth > lwidth && last_space > 0 && label->flags & MUI_TEXT_WRAPPED) {
+            /* Checking in current indice for last line */
+            if (last_space > i - len) {
+                np = malloc(sizeof(*np));
+                np->len = (last_space - (i - len));
+                np->gs = 0;
+                np->lnum = lnum++;
+                width = (width < lwidth) ? lwidth : width;
+                height += mui_ctx_get_font_height(label->font_id);
+
+
+                TAILQ_INSERT_TAIL(&label->head, np, entries);
+                i = last_space;
+                last_space = 0;
+                twidth = 0;
+                len = 0;
+                continue;
+
+            /* Checking for previous indices for and cleaning after */
+            } else {
+                int cindex;
+                struct mui_gindice *curr;
+                struct mui_gindice *next;
+
+                cindex = i - len;
+                curr = TAILQ_LAST(&label->head, mui_gindice_h);
+
+                while (cindex - curr->len > last_space) {
+                    cindex -= curr->len;
+                    curr = TAILQ_PREV(curr, mui_gindice_h, entries);
+                }
+
+                while ((next = TAILQ_NEXT(curr, entries))) {
+                    TAILQ_REMOVE(&label->head, next, entries);
+                    free(next);
+                }
+
+                i = cindex - curr->len;
+                curr->len = last_space - i;
+                width = (width < lwidth) ? lwidth : width;
+
+                i = last_space;
+                last_space = 0;
+                twidth = 0;
+                lnum++;
+                len = 0;
+
+                continue;
             }
         }
 
-        if (lwidth > width) {
-            lwidth = swidth;
-            i = sindex;
+        if (i == label->len) {
+            np = malloc(sizeof(*np));
+            np->len = len;
+            np->gs = 0;
+            np->lnum = lnum;
+            width = (width < twidth) ? twidth : width;
+            height += mui_ctx_get_font_height(label->font_id);
+
+            TAILQ_INSERT_TAIL(&label->head, np, entries);
+            break;
         }
 
-        len = i - lindex;
-        line = malloc(len + 1);
-        memcpy(line, label->text + lindex, len);
-        line[len] = '\0';
+        /*
+         * XCB only accept up to 254 glyphs being composited at once. Hence
+         * why a `mui_gindice` is limited to this amount
+         */
+        if (len == 254) {
+            np = malloc(sizeof(*np));
+            np->lnum = lnum;
+            np->len = len;
+            np->gs = 0;
 
-        *rwidth = (*rwidth > lwidth) ? *rwidth : lwidth;
-        *rheight += mui_ctx_get_font_height(label->font_id);
+            len = 0;
+            TAILQ_INSERT_TAIL(&label->head, np, entries);
+            printf("{%d, %d, %d}, ", np->lnum, np->gs, np->len);
+        }
 
-        free(line);
+        if (label->text[i] == '\n' && label->flags & MUI_TEXT_MULTILINE) {
+            np = malloc(sizeof(*np));
+            np->len = len;
+            np->gs = 0;
+            np->lnum = lnum++;
 
+            width = (width < twidth) ? twidth : width;
+            height += mui_ctx_get_font_height(label->font_id);
+            twidth = 0;
+
+            TAILQ_INSERT_TAIL(&label->head, np, entries);
+
+            len = 0;
+            twidth = 0;
+        }
     }
+    mui_resize_layout(label->layout, width, height);
 }
 
 void
@@ -135,13 +271,15 @@ mui_set_label_group(struct mui_label *label, struct mu
     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_format_label(label);
 
         mui_group_add(group, MUI_LABEL, label);
         mui_resize_layout(layout, mui_get_layout_width(layout), mui_get_layout_height(layout));
     }
 }
+
+void
+mui_set_label_flags(struct mui_label *label, int flags)
+{
+    label->flags = flags;
+}
blob - ce6f83d61a7141b265272ee276b83e3d79851a72
blob + daa50e1a8b330d153dcdaa012f2f6343b9e805b1
--- mui.h
+++ mui.h
@@ -19,6 +19,14 @@
 
 /* BASIC TYPES */
 
+struct mui_gindice {
+    uint8_t     len;
+    uint32_t    gs;
+    uint32_t    lnum;
+
+    TAILQ_ENTRY(mui_gindice) entries;
+};
+
 struct mui_label;
 
 struct mui_shape;
@@ -45,8 +53,8 @@ enum mui_layout_flags {
     MUI_ALIGN_BOTTOM = 1024,
     MUI_ALIGN_CENTER_X = 2048,
     MUI_ALIGN_CENTER_Y = 4096,
-    MUI_EXPAND_X = 8192,
-    MUI_EXPAND_Y = 16384
+    MUI_FILL_X = 8192,
+    MUI_FILL_Y = 16384
 };
 
 struct mui_layout;
@@ -131,7 +139,7 @@ void                                mui_set_shape_colo
 
 /* LABEL FUNCTIONS */
 
-struct mui_label                   *mui_create_label(char *text, int len);
+struct mui_label                   *mui_create_label(char *text);
 
 void                                mui_delete_label(struct mui_label *label);
 
@@ -145,12 +153,12 @@ char                               *mui_get_label_text
 
 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);
+struct mui_color                    mui_get_label_color(struct mui_label *label);
 
+struct mui_gindice                 *mui_get_label_next_indice(struct mui_label *label, struct mui_gindice *ptr);
+
+void                                mui_set_label_color(struct mui_label *label, float r, float g, float b, float a);
+
 void                                mui_set_label_flags(struct mui_label *label, int flags);
 
 void                                mui_set_label_group(struct mui_label *label, struct mui_group *group);
@@ -228,6 +236,8 @@ void                                mui_print_layout_m
 
 struct mui_group                   *mui_create_group(void);
 
+struct mui_group                   *mui_create_grid(uint16_t cols, uint16_t rows);
+
 void                                mui_draw_group_nodes(struct mui_group *group);
 
 void                                mui_set_group_ctx(struct mui_group *group, struct mui_ctx *ctx);
blob - ae3e6a466b9b02b4d8ac140933a1af8bb7b8f830
blob + 05ae5884ee29a157f5cd46af0859bc04b7f9075a
--- window.c
+++ window.c
@@ -19,7 +19,7 @@ mui_create_window(const char *name, uint16_t width, ui
     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);
+    mui_set_layout_flags(layout, MUI_SCALE_X | MUI_SCALE_Y);
     mw->handler = mui_create_event_handler(mw);
 
     mw->name = malloc(strlen(name)+1);