timage_widget.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
---
timage_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)