ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 700df2e2739b914fa2738404f949f791814cf7d4
parent 2845e91cce752793dfebfac761c4b1ae7c25b023
Author: lumidify <nobody@lumidify.org>
Date:   Wed,  6 Jan 2021 21:54:20 +0100

Add label widget

Diffstat:
M.ltk/theme.ini | 4++++
MLICENSE | 2+-
MMakefile | 2+-
MTODO | 2++
Mbutton.c | 1+
Mcolor.h | 5+++++
Mdraw.c | 1+
Mgrid.c | 1+
Alabel.c | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alabel.h | 44++++++++++++++++++++++++++++++++++++++++++++
Mltk.h | 5+++--
Mltkd.c | 29+++++++++++++++++++++--------
Mstrtonum.c | 1+
Mtext.h | 5+++++
Mtext_stb.c | 1+
15 files changed, 246 insertions(+), 12 deletions(-)

diff --git a/.ltk/theme.ini b/.ltk/theme.ini @@ -17,3 +17,7 @@ border_active = #FFFFFF fill_active = #738194 border_disabled = #FFFFFF fill_disabled = #292929 + +[label] +text_color = #FFFFFF +pad = 5 diff --git a/LICENSE b/LICENSE @@ -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 diff --git a/Makefile b/Makefile @@ -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 diff --git a/TODO b/TODO @@ -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). diff --git a/button.c b/button.c @@ -30,6 +30,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include "color.h" #include "ltk.h" #include "util.h" #include "text.h" diff --git a/color.h b/color.h @@ -1,5 +1,8 @@ #include "defs.h" +#ifndef _LTK_COLOR_H_ +#define _LTK_COLOR_H_ + #ifdef USE_XFT #include <X11/Xft/Xft.h> #endif @@ -10,3 +13,5 @@ typedef struct { XftColor xftcolor; #endif } LtkColor; + +#endif /* _LTK_COLOR_H_ */ diff --git a/draw.c b/draw.c @@ -29,6 +29,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include "color.h" #include "ltk.h" #include "util.h" #include "draw.h" diff --git a/grid.c b/grid.c @@ -31,6 +31,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include "color.h" #include "ltk.h" #include "util.h" #include "grid.h" diff --git a/label.c b/label.c @@ -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; +} diff --git a/label.h b/label.h @@ -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_ */ diff --git a/ltk.h b/ltk.h @@ -57,6 +57,7 @@ typedef enum { LTK_GRID, LTK_BUTTON, LTK_DRAW, + LTK_LABEL, LTK_WIDGET } ltk_widget_type; @@ -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 { diff --git a/ltkd.c b/ltkd.c @@ -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 @@ -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 @@ -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); @@ -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) @@ -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; } @@ -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 @@ -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"); } @@ -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) { diff --git a/strtonum.c b/strtonum.c @@ -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); diff --git a/text.h b/text.h @@ -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); @@ -15,3 +18,5 @@ void ltk_text_line_destroy(LtkTextLine *tl); #ifdef USE_PANGO #include <pango/pangoxft.h> #endif + +#endif /* _LTK_TEXT_H_ */ diff --git a/text_stb.c b/text_stb.c @@ -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"