URI: 
       tAdd label widget - ltk - Socket-based GUI for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 700df2e2739b914fa2738404f949f791814cf7d4
   DIR parent 2845e91cce752793dfebfac761c4b1ae7c25b023
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Wed,  6 Jan 2021 21:54:20 +0100
       
       Add label widget
       
       Diffstat:
         M .ltk/theme.ini                      |       4 ++++
         M LICENSE                             |       2 +-
         M Makefile                            |       2 +-
         M TODO                                |       2 ++
         M button.c                            |       1 +
         M color.h                             |       5 +++++
         M draw.c                              |       1 +
         M grid.c                              |       1 +
         A label.c                             |     155 +++++++++++++++++++++++++++++++
         A label.h                             |      44 +++++++++++++++++++++++++++++++
         M ltk.h                               |       5 +++--
         M ltkd.c                              |      29 +++++++++++++++++++++--------
         M strtonum.c                          |       1 +
         M text.h                              |       5 +++++
         M text_stb.c                          |       1 +
       
       15 files changed, 246 insertions(+), 12 deletions(-)
       ---
   DIR diff --git a/.ltk/theme.ini b/.ltk/theme.ini
       t@@ -17,3 +17,7 @@ border_active = #FFFFFF
        fill_active = #738194
        border_disabled = #FFFFFF
        fill_disabled = #292929
       +
       +[label]
       +text_color = #FFFFFF
       +pad = 5
   DIR diff --git a/LICENSE b/LICENSE
       t@@ -4,7 +4,7 @@ See khash.h, ini.*, stb_truetype.*, and strtonum.c for third-party licenses.
        MIT/X Consortium License
        
        The Lumidify ToolKit (LTK)
       -Copyright (c) 2016, 2017, 2018, 2019, 2020 lumidify <nobody@lumidify.org>
       +Copyright (c) 2016-2021 lumidify <nobody@lumidify.org>
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
   DIR diff --git a/Makefile b/Makefile
       t@@ -1,6 +1,6 @@
        include config.mk
        
       -OBJ += color.o util.o ltkd.o ini.o grid.o button.o draw.o
       +OBJ += color.o util.o ltkd.o ini.o grid.o button.o label.o draw.o
        
        all: ltkd ltkc
        
   DIR diff --git a/TODO b/TODO
       t@@ -1,3 +1,5 @@
       +Double-buffering; general improvements to rendering...
       +
        Convert points to pixels for stb rendering (currently, the size between
        pango and stb is completely different).
        
   DIR diff --git a/button.c b/button.c
       t@@ -30,6 +30,7 @@
        #include <X11/Xlib.h>
        #include <X11/Xutil.h>
        
       +#include "color.h"
        #include "ltk.h"
        #include "util.h"
        #include "text.h"
   DIR diff --git a/color.h b/color.h
       t@@ -1,5 +1,8 @@
        #include "defs.h"
        
       +#ifndef _LTK_COLOR_H_
       +#define _LTK_COLOR_H_
       +
        #ifdef USE_XFT
          #include <X11/Xft/Xft.h>
        #endif
       t@@ -10,3 +13,5 @@ typedef struct {
                XftColor xftcolor;
                #endif
        } LtkColor;
       +
       +#endif /* _LTK_COLOR_H_ */
   DIR diff --git a/draw.c b/draw.c
       t@@ -29,6 +29,7 @@
        #include <X11/Xlib.h>
        #include <X11/Xutil.h>
        
       +#include "color.h"
        #include "ltk.h"
        #include "util.h"
        #include "draw.h"
   DIR diff --git a/grid.c b/grid.c
       t@@ -31,6 +31,7 @@
        #include <X11/Xlib.h>
        #include <X11/Xutil.h>
        
       +#include "color.h"
        #include "ltk.h"
        #include "util.h"
        #include "grid.h"
   DIR diff --git a/label.c b/label.c
       t@@ -0,0 +1,155 @@
       +/*
       + * This file is part of the Lumidify ToolKit (LTK)
       + * Copyright (c) 2021 lumidify <nobody@lumidify.org>
       + *
       + * Permission is hereby granted, free of charge, to any person obtaining a copy
       + * of this software and associated documentation files (the "Software"), to deal
       + * in the Software without restriction, including without limitation the rights
       + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       + * copies of the Software, and to permit persons to whom the Software is
       + * furnished to do so, subject to the following conditions:
       + *
       + * The above copyright notice and this permission notice shall be included in all
       + * copies or substantial portions of the Software.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       + * SOFTWARE.
       + */
       +
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <stdint.h>
       +#include <string.h>
       +#include <stdarg.h>
       +
       +#include <X11/Xlib.h>
       +#include <X11/Xutil.h>
       +
       +#include "color.h"
       +#include "ltk.h"
       +#include "util.h"
       +#include "text.h"
       +#include "label.h"
       +
       +static void ltk_label_draw(ltk_label *label);
       +static ltk_label *ltk_label_create(ltk_window *window,
       +    const char *id, const char *text);
       +static void ltk_label_destroy(ltk_label *label, int shallow);
       +
       +static struct {
       +        LtkColor text_color;
       +        int pad;
       +} theme;
       +
       +void
       +ltk_label_setup_theme_defaults(ltk_window *window) {
       +        theme.pad = 5;
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#FFFFFF", &theme.text_color);
       +}
       +
       +void
       +ltk_label_ini_handler(ltk_window *window, const char *prop, const char *value) {
       +        if (strcmp(prop, "pad") == 0) {
       +                theme.pad = atoi(value);
       +        } else if (strcmp(prop, "text_color") == 0) {
       +                ltk_color_create(window->dpy, window->screen, window->cm,
       +                    value, &theme.text_color);
       +        } else {
       +                ltk_warn("Unknown property \"%s\" for label style.\n", prop);
       +        }
       +}
       +
       +static void
       +ltk_label_draw(ltk_label *label) {
       +        ltk_window *window = label->widget.window;
       +        ltk_rect rect = label->widget.rect;
       +
       +        int text_w, text_h;
       +        ltk_text_line_get_size(label->tl, &text_w, &text_h);
       +        int text_x = rect.x + (rect.w - text_w) / 2;
       +        int text_y = rect.y + (rect.h - text_h) / 2;
       +        ltk_text_line_draw(label->tl, window->gc, text_x, text_y);
       +}
       +
       +static ltk_label *
       +ltk_label_create(ltk_window *window, const char *id, const char *text) {
       +        char *text_copy;
       +        ltk_label *label = malloc(sizeof(ltk_label));
       +        if (!label) ltk_fatal_errno("Unable to allocate memory for ltk_label.\n");
       +
       +        ltk_fill_widget_defaults(&label->widget, id, window,
       +            &ltk_label_draw, NULL, &ltk_label_destroy, 1, LTK_LABEL);
       +        uint16_t font_size = window->theme.font_size;
       +        text_copy = strdup(text);
       +        if (!text_copy)
       +                ltk_fatal_errno("Unable to allocate label text.\n");
       +        label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
       +        int text_w, text_h;
       +        ltk_text_line_get_size(label->tl, &text_w, &text_h);
       +        label->widget.rect.w = text_w + theme.pad * 2;
       +        label->widget.rect.h = text_h + theme.pad * 2;
       +        ltk_text_line_render(label->tl, &window->theme.bg, &theme.text_color);
       +
       +        return label;
       +}
       +
       +static void
       +ltk_label_destroy(ltk_label *label, int shallow) {
       +        if (!label) {
       +                ltk_warn("Tried to destroy NULL label.\n");
       +                return;
       +        }
       +        ltk_text_line_destroy(label->tl);
       +        ltk_remove_widget(label->widget.window, label->widget.id);
       +        free(label->widget.id);
       +        free(label);
       +}
       +
       +/* label <label id> create <text> */
       +static int
       +ltk_label_cmd_create(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens,
       +    char **errstr) {
       +        ltk_label *label;
       +        if (num_tokens != 4) {
       +                *errstr = "Invalid number of arguments.\n";
       +                return 1;
       +        }
       +        if (!ltk_widget_id_free(tokens[1])) {
       +                *errstr = "Widget ID already taken.\n";
       +                return 1;
       +        }
       +        label = ltk_label_create(window, tokens[1], tokens[3]);
       +        ltk_set_widget(label, tokens[1]);
       +
       +        return 0;
       +}
       +
       +/* label <button id> <command> ... */
       +int
       +ltk_label_cmd(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens,
       +    char **errstr) {
       +        if (num_tokens < 3) {
       +                *errstr = "Invalid number of arguments.\n";
       +                return 1;
       +        }
       +        if (strcmp(tokens[2], "create") == 0) {
       +                return ltk_label_cmd_create(window, tokens, num_tokens, errstr);
       +        } else {
       +                *errstr = "Invalid command.\n";
       +                return 1;
       +        }
       +
       +        return 0;
       +}
   DIR diff --git a/label.h b/label.h
       t@@ -0,0 +1,44 @@
       +/*
       + * This file is part of the Lumidify ToolKit (LTK)
       + * Copyright (c) 2021 lumidify <nobody@lumidify.org>
       + *
       + * Permission is hereby granted, free of charge, to any person obtaining a copy
       + * of this software and associated documentation files (the "Software"), to deal
       + * in the Software without restriction, including without limitation the rights
       + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       + * copies of the Software, and to permit persons to whom the Software is
       + * furnished to do so, subject to the following conditions:
       + *
       + * The above copyright notice and this permission notice shall be included in all
       + * copies or substantial portions of the Software.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       + * SOFTWARE.
       + */
       +
       +#ifndef _LTK_LABEL_H_
       +#define _LTK_LABEL_H_
       +
       +/* Requires the following includes: <X11/Xlib.h>, "ltk.h", "color.h", "text.h" */
       +
       +typedef struct {
       +        ltk_widget widget;
       +        LtkTextLine *tl;
       +        Pixmap text_pixmap;
       +} ltk_label;
       +
       +void ltk_label_setup_theme_defaults(ltk_window *window);
       +void ltk_label_ini_handler(ltk_window *window, const char *prop, const char *value);
       +
       +int ltk_label_cmd(
       +    ltk_window *window,
       +    char **tokens,
       +    size_t num_tokens,
       +    char **errstr);
       +
       +#endif /* _LTK_LABEL_H_ */
   DIR diff --git a/ltk.h b/ltk.h
       t@@ -57,6 +57,7 @@ typedef enum {
                LTK_GRID,
                LTK_BUTTON,
                LTK_DRAW,
       +        LTK_LABEL,
                LTK_WIDGET
        } ltk_widget_type;
        
       t@@ -96,8 +97,8 @@ typedef struct {
                int border_width;
                uint16_t font_size;
                char *font;
       -        XColor fg;
       -        XColor bg;
       +        LtkColor fg;
       +        LtkColor bg;
        } ltk_window_theme;
        
        struct ltk_event_queue {
   DIR diff --git a/ltkd.c b/ltkd.c
       t@@ -1,6 +1,8 @@
       +/* FIXME: error checking in tokenizer (is this necessary?) */
       +/* FIXME: parsing doesn't work properly with bs? */
        /*
         * This file is part of the Lumidify ToolKit (LTK)
       - * Copyright (c) 2016, 2017, 2018, 2020 lumidify <nobody@lumidify.org>
       + * Copyright (c) 2016, 2017, 2018, 2020, 2021 lumidify <nobody@lumidify.org>
         *
         * Permission is hereby granted, free of charge, to any person obtaining a copy
         * of this software and associated documentation files (the "Software"), to deal
       t@@ -42,12 +44,14 @@
        #include "ini.h"
        #include "khash.h"
        
       +#include "color.h"
        #include "ltk.h"
        #include "util.h"
        #include "text.h"
        #include "grid.h"
        #include "draw.h"
        #include "button.h"
       +#include "label.h"
        
        #define MAX_SOCK_CONNS 20
        #define READ_BLK_SIZE 128
       t@@ -579,10 +583,10 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int 
                window->xwindow =
                    XCreateSimpleWindow(window->dpy, DefaultRootWindow(window->dpy), x, y,
                                        w, h, window->theme.border_width,
       -                                window->theme.fg.pixel, window->theme.bg.pixel);
       +                                window->theme.fg.xcolor.pixel, window->theme.bg.xcolor.pixel);
                window->gc = XCreateGC(window->dpy, window->xwindow, 0, 0);
       -        XSetForeground(window->dpy, window->gc, window->theme.fg.pixel);
       -        XSetBackground(window->dpy, window->gc, window->theme.bg.pixel);
       +        XSetForeground(window->dpy, window->gc, window->theme.fg.xcolor.pixel);
       +        XSetBackground(window->dpy, window->gc, window->theme.bg.xcolor.pixel);
                XSetStandardProperties(window->dpy, window->xwindow, title, NULL, None,
                                       NULL, 0, NULL);
                XSetWMProtocols(window->dpy, window->xwindow, &window->wm_delete_msg, 1);
       t@@ -639,9 +643,11 @@ ltk_window_ini_handler(ltk_window *window, const char *prop, const char *value) 
                if (strcmp(prop, "border_width") == 0) {
                        window->theme.border_width = atoi(value);
                } else if (strcmp(prop, "bg") == 0) {
       -                ltk_create_xcolor(window, value, &window->theme.bg);
       +                ltk_color_create(window->dpy, window->screen,
       +                    window->cm, value, &window->theme.bg);
                } else if (strcmp(prop, "fg") == 0) {
       -                ltk_create_xcolor(window, value, &window->theme.fg);
       +                ltk_color_create(window->dpy, window->screen,
       +                    window->cm, value, &window->theme.fg);
                } else if (strcmp(prop, "font") == 0) {
                        window->theme.font = strdup(value);
                        if (!window->theme.font)
       t@@ -657,6 +663,8 @@ ltk_ini_handler(void *window, const char *widget, const char *prop, const char *
                        ltk_window_ini_handler(window, prop, value);
                } else if (strcmp(widget, "button") == 0) {
                        ltk_button_ini_handler(window, prop, value);
       +        } else if (strcmp(widget, "label") == 0) {
       +                ltk_label_ini_handler(window, prop, value);
                } else {
                        return 0;
                }
       t@@ -668,8 +676,10 @@ ltk_window_setup_theme_defaults(ltk_window *window) {
                window->theme.border_width = 0;
                window->theme.font_size = 15;
                window->theme.font = "Liberation Mono";
       -        ltk_create_xcolor(window, "#000000", &window->theme.bg);
       -        ltk_create_xcolor(window, "#FFFFFF", &window->theme.fg);
       +        ltk_color_create(window->dpy, window->screen,
       +            window->cm, "#000000", &window->theme.bg);
       +        ltk_color_create(window->dpy, window->screen,
       +            window->cm, "#FFFFFF", &window->theme.fg);
        }
        
        static void
       t@@ -677,6 +687,7 @@ ltk_load_theme(ltk_window *window, const char *path) {
                /* FIXME: Error checking, especially when creating colors! */
                ltk_window_setup_theme_defaults(window);
                ltk_button_setup_theme_defaults(window);
       +        ltk_label_setup_theme_defaults(window);
                if (ini_parse(path, ltk_ini_handler, window) < 0) {
                        ltk_warn("Can't load theme.\n");
                }
       t@@ -1132,6 +1143,8 @@ process_commands(ltk_window *window, struct ltk_sock_info *sock) {
                                err = ltk_grid_cmd(window, tokens, num_tokens, &errstr);
                        } else if (strcmp(tokens[0], "button") == 0) {
                                err = ltk_button_cmd(window, tokens, num_tokens, &errstr);
       +                } else if (strcmp(tokens[0], "label") == 0) {
       +                        err = ltk_label_cmd(window, tokens, num_tokens, &errstr);
                        } else if (strcmp(tokens[0], "set-root-widget") == 0) {
                                err = ltk_set_root_widget_cmd(window, tokens, num_tokens, &errstr);
                        } else if (strcmp(tokens[0], "draw") == 0) {
   DIR diff --git a/strtonum.c b/strtonum.c
       t@@ -63,4 +63,5 @@ strtonum(const char *numstr, long long minval, long long maxval,
        
                return (ll);
        }
       +/* FIXME: What does this do? - lumidify */
        DEF_WEAK(strtonum);
   DIR diff --git a/text.h b/text.h
       t@@ -1,6 +1,9 @@
        #include "defs.h"
        #include "color.h"
        
       +#ifndef _LTK_TEXT_H_
       +#define _LTK_TEXT_H_
       +
        typedef struct LtkTextLine LtkTextLine;
        
        void ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap cm);
       t@@ -15,3 +18,5 @@ void ltk_text_line_destroy(LtkTextLine *tl);
        #ifdef USE_PANGO
          #include <pango/pangoxft.h>
        #endif
       +
       +#endif /* _LTK_TEXT_H_ */
   DIR diff --git a/text_stb.c b/text_stb.c
       t@@ -35,6 +35,7 @@
        #include "khash.h"
        #include "stb_truetype.h" /* http://nothings.org/stb/stb_truetype.h */
        
       +#include "color.h"
        #include "ltk.h"
        #include "util.h"
        #include "text.h"