URI: 
       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 = &ltk_image_widget_draw,
           46         .destroy = &ltk_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", &ltk_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)