commit - 94783f656eaf549437a61d52e2df97f28791e880
commit + 749e270c9e436c9e475d2ef00a30660ad7f1b12e
blob - aec9a0c7220e03ce9f502e4ec0c4777ea53660cc
blob + 7e285dc9cc7d37558104a0476578f5ec3960492c
--- TODO
+++ TODO
- 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
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);
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;
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;
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
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
} 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
};
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;
};
group = malloc(sizeof(*group));
group->layout = mui_create_layout(MUI_GROUP, group);
+ group->type = MUI_UNDEF;
group->ctx = NULL;
TAILQ_INIT(&group->head);
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
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;
}
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
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
/* 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;
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;
/* 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);
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);
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
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);