commit 700df2e2739b914fa2738404f949f791814cf7d4
parent 2845e91cce752793dfebfac761c4b1ae7c25b023
Author: lumidify <nobody@lumidify.org>
Date:   Wed,  6 Jan 2021 21:54:20 +0100
Add label widget
Diffstat:
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,
+	    <k_label_draw, NULL, <k_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"