label.c (4690B)
1 /* 2 * Copyright (c) 2021-2024 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 <stddef.h> 18 19 #include "config.h" 20 #include "memory.h" 21 #include "color.h" 22 #include "rect.h" 23 #include "widget.h" 24 #include "ltk.h" 25 #include "util.h" 26 #include "text.h" 27 #include "label.h" 28 #include "graphics.h" 29 30 #define MAX_LABEL_PADDING 50000 31 32 static void ltk_label_draw(ltk_widget *self, ltk_surface *draw_surf, int x, int y, ltk_rect clip); 33 static void ltk_label_destroy(ltk_widget *self, int shallow); 34 static void ltk_label_recalc_ideal_size(ltk_widget *self); 35 36 static struct ltk_widget_vtable vtable = { 37 .draw = <k_label_draw, 38 .destroy = <k_label_destroy, 39 .hide = NULL, 40 .resize = NULL, 41 .change_state = NULL, 42 .child_size_change = NULL, 43 .remove_child = NULL, 44 .get_child_at_pos = NULL, 45 .key_press = NULL, 46 .key_release = NULL, 47 .mouse_press = NULL, 48 .mouse_release = NULL, 49 .motion_notify = NULL, 50 .mouse_leave = NULL, 51 .mouse_enter = NULL, 52 .recalc_ideal_size = <k_label_recalc_ideal_size, 53 .type = LTK_WIDGET_LABEL, 54 .flags = LTK_NEEDS_REDRAW | LTK_ACTIVATABLE_SPECIAL, 55 .invalid_signal = LTK_LABEL_SIGNAL_INVALID 56 }; 57 58 static struct { 59 ltk_color *text_color; 60 ltk_color *bg_color; 61 ltk_color *bg_color_active; 62 char *font; 63 ltk_size pad; 64 ltk_size font_size; 65 } theme; 66 67 static ltk_theme_parseinfo parseinfo[] = { 68 {"bg-color", THEME_COLOR, {.color = &theme.bg_color}, {.color = "#000000"}, 0, 0, 0}, 69 {"bg-color-active", THEME_COLOR, {.color = &theme.bg_color_active}, {.color = "#222222"}, 0, 0, 0}, 70 {"pad", THEME_SIZE, {.size = &theme.pad}, {.size = {.val = 100, .unit = LTK_UNIT_MM}}, 0, MAX_LABEL_PADDING, 0}, 71 {"text-color", THEME_COLOR, {.color = &theme.text_color}, {.color = "#FFFFFF"}, 0, 0, 0}, 72 {"font-size", THEME_SIZE, {.size = &theme.font_size}, {.size = {.val = 1200, .unit = LTK_UNIT_PT}}, 0, 20000, 0}, 73 {"font", THEME_STRING, {.str = &theme.font}, {.str = "Monospace"}, 0, 0, 0}, 74 }; 75 76 void 77 ltk_label_get_theme_parseinfo(ltk_theme_parseinfo **p, size_t *len) { 78 *p = parseinfo; 79 *len = LENGTH(parseinfo); 80 } 81 82 static void 83 ltk_label_draw(ltk_widget *self, ltk_surface *draw_surf, int x, int y, ltk_rect clip) { 84 ltk_label *label = LTK_CAST_LABEL(self); 85 ltk_rect lrect = self->lrect; 86 ltk_rect clip_final = ltk_rect_intersect(clip, (ltk_rect){0, 0, lrect.w, lrect.h}); 87 if (clip_final.w <= 0 || clip_final.h <= 0) 88 return; 89 ltk_rect draw_clip = {x + clip_final.x, y + clip_final.y, clip_final.w, clip_final.h}; 90 ltk_surface_fill_rect(draw_surf, (self->state & LTK_ACTIVE) ? theme.bg_color_active : theme.bg_color, draw_clip); 91 92 int text_w, text_h; 93 ltk_text_line_get_size(label->tl, &text_w, &text_h); 94 int text_x = x + (lrect.w - text_w) / 2; 95 int text_y = y + (lrect.h - text_h) / 2; 96 ltk_text_line_draw_clipped(label->tl, draw_surf, theme.text_color, text_x, text_y, draw_clip); 97 } 98 99 static void 100 recalc_ideal_size(ltk_label *label) { 101 int text_w, text_h; 102 ltk_text_line_get_size(label->tl, &text_w, &text_h); 103 int pad = ltk_size_to_pixel(theme.pad, LTK_CAST_WIDGET(label)->last_dpi); 104 label->widget.ideal_w = text_w + pad * 2; 105 label->widget.ideal_h = text_h + pad * 2; 106 } 107 108 static void 109 ltk_label_recalc_ideal_size(ltk_widget *self) { 110 ltk_label *label = LTK_CAST_LABEL(self); 111 int font_size = ltk_size_to_pixel(theme.font_size, self->last_dpi); 112 ltk_text_line_set_font_size(label->tl, font_size); 113 recalc_ideal_size(label); 114 } 115 116 ltk_label * 117 ltk_label_create(ltk_window *window, const char *text) { 118 ltk_label *label = ltk_malloc(sizeof(ltk_label)); 119 120 ltk_fill_widget_defaults(LTK_CAST_WIDGET(label), window, &vtable, 0, 0); 121 label->tl = ltk_text_line_create_const_text_default( 122 theme.font, ltk_size_to_pixel(theme.font_size, label->widget.last_dpi), text, -1 123 ); 124 recalc_ideal_size(label); 125 126 return label; 127 } 128 129 static void 130 ltk_label_destroy(ltk_widget *self, int shallow) { 131 (void)shallow; 132 ltk_label *label = LTK_CAST_LABEL(self); 133 if (!label) { 134 ltk_warn("Tried to destroy NULL label.\n"); 135 return; 136 } 137 ltk_text_line_destroy(label->tl); 138 ltk_free(label); 139 }