URI: 
       tlabel.c - 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
       ---
       tlabel.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)