image_widget.c (4835B)
1 /* 2 * Copyright (c) 2023 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 "image_widget.h" 31 #include "graphics.h" 32 #include "cmd.h" 33 34 /* FIXME: add padding, etc. */ 35 36 static void ltk_image_widget_draw( 37 ltk_widget *self, ltk_surface *draw_surf, int x, int y, ltk_rect clip 38 ); 39 static ltk_image_widget *ltk_image_widget_create( 40 ltk_window *window, const char *id, const char *path, const char *data, size_t len 41 ); 42 static void ltk_image_widget_destroy(ltk_widget *self, int shallow); 43 44 static struct ltk_widget_vtable vtable = { 45 .draw = <k_image_widget_draw, 46 .destroy = <k_image_widget_destroy, 47 .hide = NULL, 48 .resize = NULL, 49 .change_state = NULL, 50 .child_size_change = NULL, 51 .remove_child = NULL, 52 .get_child_at_pos = NULL, 53 .key_press = NULL, 54 .key_release = NULL, 55 .mouse_press = NULL, 56 .mouse_release = NULL, 57 .motion_notify = NULL, 58 .mouse_leave = NULL, 59 .mouse_enter = NULL, 60 .type = LTK_WIDGET_IMAGE, 61 .flags = LTK_NEEDS_REDRAW | LTK_ACTIVATABLE_SPECIAL, 62 }; 63 64 static void 65 ltk_image_widget_draw(ltk_widget *self, ltk_surface *draw_surf, int x, int y, ltk_rect clip) { 66 ltk_image_widget *img = (ltk_image_widget *)self; 67 ltk_rect lrect = self->lrect; 68 ltk_rect clip_final = ltk_rect_intersect(clip, (ltk_rect){0, 0, lrect.w, lrect.h}); 69 if (clip_final.w <= 0 || clip_final.h <= 0) 70 return; 71 /* FIXME: maybe replace with integer operations */ 72 double scalex = self->ideal_w / (double)lrect.w; 73 double scaley = self->ideal_h / (double)lrect.h; 74 int src_x = (int)(clip_final.x * scalex); 75 int src_y = (int)(clip_final.y * scaley); 76 int src_w = (int)(clip_final.w * scalex); 77 int src_h = (int)(clip_final.h * scaley); 78 ltk_image_draw_cropped_scaled( 79 img->img, draw_surf, src_x, src_y, src_w, src_h, 80 x + clip_final.x, y + clip_final.y, clip_final.w, clip_final.h 81 ); 82 } 83 84 static ltk_image_widget * 85 ltk_image_widget_create(ltk_window *window, const char *id, const char *path, const char *data, size_t len) { 86 ltk_image_widget *img = ltk_malloc(sizeof(ltk_image_widget)); 87 img->img = ltk_image_create_from_mem(path, data, len); 88 if (!img->img) 89 return NULL; 90 int w = ltk_image_get_width(img->img); 91 int h = ltk_image_get_height(img->img); 92 ltk_fill_widget_defaults(&img->widget, id, window, &vtable, w, h); 93 img->widget.ideal_w = w; 94 img->widget.ideal_h = h; 95 96 return img; 97 } 98 99 static void 100 ltk_image_widget_destroy(ltk_widget *self, int shallow) { 101 (void)shallow; 102 ltk_image_widget *img = (ltk_image_widget *)self; 103 if (!img) { 104 ltk_warn("Tried to destroy NULL image widget.\n"); 105 return; 106 } 107 ltk_image_destroy(img->img); 108 ltk_free(img); 109 } 110 111 /* image <image id> create <filename> <data> */ 112 static int 113 ltk_image_widget_cmd_create( 114 ltk_window *window, 115 ltk_image_widget *img_unneeded, 116 ltk_cmd_token *tokens, 117 size_t num_tokens, 118 ltk_error *err) { 119 (void)img_unneeded; 120 ltk_cmdarg_parseinfo cmd[] = { 121 {.type = CMDARG_IGNORE, .optional = 0}, 122 {.type = CMDARG_STRING, .optional = 0}, 123 {.type = CMDARG_IGNORE, .optional = 0}, 124 {.type = CMDARG_STRING, .optional = 0}, 125 {.type = CMDARG_DATA, .optional = 0}, 126 }; 127 if (ltk_parse_cmd(window, tokens, num_tokens, cmd, LENGTH(cmd), err)) 128 return 1; 129 if (!ltk_widget_id_free(cmd[1].val.str)) { 130 err->type = ERR_WIDGET_ID_IN_USE; 131 err->arg = 1; 132 return 1; 133 } 134 ltk_image_widget *img = ltk_image_widget_create(window, cmd[1].val.str, cmd[3].val.str, cmd[4].val.data, cmd[4].len); 135 if (!img) { 136 /* FIXME: more sensible error name */ 137 err->type = ERR_UNKNOWN; 138 err->arg = -1; 139 return 1; 140 } 141 ltk_set_widget((ltk_widget *)img, cmd[1].val.str); 142 143 return 0; 144 } 145 146 static struct image_widget_cmd { 147 char *name; 148 int (*func)(ltk_window *, ltk_image_widget *, ltk_cmd_token *, size_t, ltk_error *); 149 int needs_all; 150 } image_widget_cmds[] = { 151 {"create", <k_image_widget_cmd_create, 1}, 152 }; 153 154 GEN_CMD_HELPERS(ltk_image_widget_cmd, LTK_WIDGET_IMAGE, ltk_image_widget, image_widget_cmds, struct image_widget_cmd)