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

label.c (6148B)


      1 /*
      2  * Copyright (c) 2021, 2022 lumidify <nobody@lumidify.org>
      3  *
      4  * Permission to use, copy, modify, and/or distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <stdint.h>
     20 #include <string.h>
     21 #include <stdarg.h>
     22 
     23 #include "event.h"
     24 #include "memory.h"
     25 #include "color.h"
     26 #include "rect.h"
     27 #include "widget.h"
     28 #include "ltk.h"
     29 #include "util.h"
     30 #include "text.h"
     31 #include "label.h"
     32 #include "graphics.h"
     33 #include "surface_cache.h"
     34 #include "theme.h"
     35 #include "cmd.h"
     36 
     37 #define MAX_LABEL_PADDING 500
     38 
     39 static void ltk_label_draw(ltk_widget *self, ltk_surface *draw_surf, int x, int y, ltk_rect clip);
     40 static ltk_label *ltk_label_create(ltk_window *window,
     41     const char *id, char *text);
     42 static void ltk_label_destroy(ltk_widget *self, int shallow);
     43 static void ltk_label_redraw_surface(ltk_label *label, ltk_surface *s);
     44 
     45 static struct ltk_widget_vtable vtable = {
     46 	.draw = &ltk_label_draw,
     47 	.destroy = &ltk_label_destroy,
     48 	.hide = NULL,
     49 	.resize = NULL,
     50 	.change_state = NULL,
     51 	.child_size_change = NULL,
     52 	.remove_child = NULL,
     53 	.get_child_at_pos = NULL,
     54 	.key_press = NULL,
     55 	.key_release = NULL,
     56 	.mouse_press = NULL,
     57 	.mouse_release = NULL,
     58 	.motion_notify = NULL,
     59 	.mouse_leave = NULL,
     60 	.mouse_enter = NULL,
     61 	.type = LTK_WIDGET_LABEL,
     62 	.flags = LTK_NEEDS_REDRAW | LTK_ACTIVATABLE_SPECIAL,
     63 };
     64 
     65 static struct {
     66 	ltk_color text_color;
     67 	ltk_color bg_color;
     68 	ltk_color bg_color_active;
     69 	int pad;
     70 } theme;
     71 
     72 int parseinfo_sorted = 0;
     73 
     74 static ltk_theme_parseinfo parseinfo[] = {
     75 	{"bg-color", THEME_COLOR, {.color = &theme.bg_color}, {.color = "#000000"}, 0, 0, 0},
     76 	{"bg-color-active", THEME_COLOR, {.color = &theme.bg_color_active}, {.color = "#222222"}, 0, 0, 0},
     77 	{"pad", THEME_INT, {.i = &theme.pad}, {.i = 5}, 0, MAX_LABEL_PADDING, 0},
     78 	{"text-color", THEME_COLOR, {.color = &theme.text_color}, {.color = "#FFFFFF"}, 0, 0, 0},
     79 };
     80 
     81 int
     82 ltk_label_ini_handler(ltk_window *window, const char *prop, const char *value) {
     83 	return ltk_theme_handle_value(window, "label", prop, value, parseinfo, LENGTH(parseinfo), &parseinfo_sorted);
     84 }
     85 
     86 int
     87 ltk_label_fill_theme_defaults(ltk_window *window) {
     88 	return ltk_theme_fill_defaults(window, "label", parseinfo, LENGTH(parseinfo));
     89 }
     90 
     91 void
     92 ltk_label_uninitialize_theme(ltk_window *window) {
     93 	ltk_theme_uninitialize(window, parseinfo, LENGTH(parseinfo));
     94 }
     95 
     96 static void
     97 ltk_label_draw(ltk_widget *self, ltk_surface *draw_surf, int x, int y, ltk_rect clip) {
     98 	ltk_label *label = (ltk_label *)self;
     99 	ltk_rect lrect = self->lrect;
    100 	ltk_rect clip_final = ltk_rect_intersect(clip, (ltk_rect){0, 0, lrect.w, lrect.h});
    101 	if (clip_final.w <= 0 || clip_final.h <= 0)
    102 		return;
    103 	ltk_surface *s;
    104 	ltk_surface_cache_request_surface_size(label->key, lrect.w, lrect.h);
    105 	if (!ltk_surface_cache_get_surface(label->key, &s) || self->dirty)
    106 		ltk_label_redraw_surface(label, s);
    107 	ltk_surface_copy(s, draw_surf, clip_final, x + clip_final.x, y + clip_final.y);
    108 }
    109 
    110 static void
    111 ltk_label_redraw_surface(ltk_label *label, ltk_surface *s) {
    112 	ltk_rect r = label->widget.lrect;
    113 	r.x = 0;
    114 	r.y = 0;
    115 	ltk_surface_fill_rect(s, (label->widget.state & LTK_ACTIVE) ? &theme.bg_color_active : &theme.bg_color, r);
    116 
    117 	int text_w, text_h;
    118 	ltk_text_line_get_size(label->tl, &text_w, &text_h);
    119 	int text_x = (r.w - text_w) / 2;
    120 	int text_y = (r.h - text_h) / 2;
    121 	ltk_text_line_draw(label->tl, s, &theme.text_color, text_x, text_y);
    122 }
    123 
    124 static ltk_label *
    125 ltk_label_create(ltk_window *window, const char *id, char *text) {
    126 	ltk_label *label = ltk_malloc(sizeof(ltk_label));
    127 
    128 	uint16_t font_size = window->theme->font_size;
    129 	label->tl = ltk_text_line_create(window->text_context, font_size, text, 0, -1);
    130 	int text_w, text_h;
    131 	ltk_text_line_get_size(label->tl, &text_w, &text_h);
    132 	/* FIXME: what was I even thinking here? label->widget.ideal_{w,h} isn't even initialized here */
    133 	ltk_fill_widget_defaults(&label->widget, id, window, &vtable, label->widget.ideal_w, label->widget.ideal_h);
    134 	label->widget.ideal_w = text_w + theme.pad * 2;
    135 	label->widget.ideal_h = text_h + theme.pad * 2;
    136 	label->key = ltk_surface_cache_get_unnamed_key(window->surface_cache, label->widget.ideal_w, label->widget.ideal_h);
    137 
    138 	return label;
    139 }
    140 
    141 static void
    142 ltk_label_destroy(ltk_widget *self, int shallow) {
    143 	(void)shallow;
    144 	ltk_label *label = (ltk_label *)self;
    145 	if (!label) {
    146 		ltk_warn("Tried to destroy NULL label.\n");
    147 		return;
    148 	}
    149 	ltk_surface_cache_release_key(label->key);
    150 	ltk_text_line_destroy(label->tl);
    151 	ltk_free(label);
    152 }
    153 
    154 /* label <label id> create <text> */
    155 static int
    156 ltk_label_cmd_create(
    157     ltk_window *window,
    158     ltk_label *label_unneeded,
    159     ltk_cmd_token *tokens,
    160     size_t num_tokens,
    161     ltk_error *err) {
    162 	(void)label_unneeded;
    163 	ltk_cmdarg_parseinfo cmd[] = {
    164 		{.type = CMDARG_IGNORE, .optional = 0},
    165 		{.type = CMDARG_STRING, .optional = 0},
    166 		{.type = CMDARG_IGNORE, .optional = 0},
    167 		{.type = CMDARG_STRING, .optional = 0},
    168 	};
    169 	if (ltk_parse_cmd(window, tokens, num_tokens, cmd, LENGTH(cmd), err))
    170 		return 1;
    171 	if (!ltk_widget_id_free(cmd[1].val.str)) {
    172 		err->type = ERR_WIDGET_ID_IN_USE;
    173 		err->arg = 1;
    174 		return 1;
    175 	}
    176 	ltk_label *label = ltk_label_create(window, cmd[1].val.str, cmd[3].val.str);
    177 	ltk_set_widget((ltk_widget *)label, cmd[1].val.str);
    178 
    179 	return 0;
    180 }
    181 
    182 static struct label_cmd {
    183 	char *name;
    184 	int (*func)(ltk_window *, ltk_label *, ltk_cmd_token *, size_t, ltk_error *);
    185 	int needs_all;
    186 } label_cmds[] = {
    187 	{"create", &ltk_label_cmd_create, 1},
    188 };
    189 
    190 GEN_CMD_HELPERS(ltk_label_cmd, LTK_WIDGET_LABEL, ltk_label, label_cmds, struct label_cmd)