URI: 
       button.c - ltkx - GUI toolkit for X11 (old)
  HTML git clone git://lumidify.org/ltkx.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/ltkx.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltkx.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       button.c (7256B)
       ---
            1 /*
            2  * This file is part of the Lumidify ToolKit (LTK)
            3  * Copyright (c) 2016, 2017, 2018 lumidify <nobody@lumidify.org>
            4  *
            5  * Permission is hereby granted, free of charge, to any person obtaining a copy
            6  * of this software and associated documentation files (the "Software"), to deal
            7  * in the Software without restriction, including without limitation the rights
            8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
            9  * copies of the Software, and to permit persons to whom the Software is
           10  * furnished to do so, subject to the following conditions:
           11  *
           12  * The above copyright notice and this permission notice shall be included in all
           13  * copies or substantial portions of the Software.
           14  *
           15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
           16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
           17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
           18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
           19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
           20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
           21  * SOFTWARE.
           22  */
           23 
           24 #include <stdio.h>
           25 #include <stdint.h>
           26 #include <X11/Xlib.h>
           27 #include <X11/Xutil.h>
           28 #include "khash.h"
           29 #include "ltk.h"
           30 #include "stb_truetype.h"
           31 #include <fribidi.h>
           32 #include <harfbuzz/hb.h>
           33 #include <fontconfig/fontconfig.h>
           34 #include "text_common.h"
           35 #include "array.h"
           36 #include "text_buffer.h"
           37 #include "button.h"
           38 
           39 void
           40 ltk_button_ini_handler(LtkTheme *theme, const char *prop, const char *value) {
           41         if (theme->button == NULL) {
           42                 theme->button = malloc(sizeof(LtkButtonTheme));
           43         }
           44         if (strcmp(prop, "border_width") == 0) {
           45                 theme->button->border_width = atoi(value);
           46         } else if (strcmp(prop, "font_size") == 0) {
           47                 theme->button->font_size = atoi(value);
           48         } else if (strcmp(prop, "pad") == 0) {
           49                 theme->button->pad = atoi(value);
           50         } else if (strcmp(prop, "border") == 0) {
           51                 theme->button->border = ltk_create_xcolor(value);
           52         } else if (strcmp(prop, "fill") == 0) {
           53                 theme->button->fill = ltk_create_xcolor(value);
           54         } else if (strcmp(prop, "border_hover") == 0) {
           55                 theme->button->border_hover = ltk_create_xcolor(value);
           56         } else if (strcmp(prop, "fill_hover") == 0) {
           57                 theme->button->fill_hover = ltk_create_xcolor(value);
           58         } else if (strcmp(prop, "border_pressed") == 0) {
           59                 theme->button->border_pressed = ltk_create_xcolor(value);
           60         } else if (strcmp(prop, "fill_pressed") == 0) {
           61                 theme->button->fill_pressed = ltk_create_xcolor(value);
           62         } else if (strcmp(prop, "border_active") == 0) {
           63                 theme->button->border_active = ltk_create_xcolor(value);
           64         } else if (strcmp(prop, "fill_active") == 0) {
           65                 theme->button->fill_active = ltk_create_xcolor(value);
           66         } else if (strcmp(prop, "border_disabled") == 0) {
           67                 theme->button->border_disabled = ltk_create_xcolor(value);
           68         } else if (strcmp(prop, "fill_disabled") == 0) {
           69                 theme->button->fill_disabled = ltk_create_xcolor(value);
           70         } else if (strcmp(prop, "text_color") == 0) {
           71                 theme->button->text_color = ltk_create_xcolor(value);
           72         } else {
           73                 (void)printf("WARNING: Unknown property \"%s\" for button style.\n");
           74         }
           75 }
           76 
           77 void
           78 ltk_button_draw(LtkButton *button) {
           79         LtkTheme *global_theme = ltk_get_theme();
           80         LtkButtonTheme *theme = global_theme->button;
           81         LtkWindow *window = button->widget.window;
           82         LtkRect rect = button->widget.rect;
           83         int bw = theme->border_width;
           84         XColor border;
           85         XColor fill;
           86         XImage *img;
           87         int text_x, text_y;
           88         switch (button->widget.state) {
           89         case LTK_NORMAL:
           90                 border = theme->border;
           91                 fill = theme->fill;
           92                 img = button->text;
           93                 break;
           94         case LTK_HOVERACTIVE:
           95         case LTK_HOVER:
           96                 border = theme->border_hover;
           97                 fill = theme->fill_hover;
           98                 img = button->text_hover;
           99                 break;
          100         case LTK_PRESSED:
          101                 border = theme->border_pressed;
          102                 fill = theme->fill_pressed;
          103                 img = button->text_pressed;
          104                 break;
          105         case LTK_ACTIVE:
          106                 border = theme->border_active;
          107                 fill = theme->fill_active;
          108                 img = button->text_active;
          109                 break;
          110         case LTK_DISABLED:
          111                 border = theme->border_disabled;
          112                 fill = theme->fill_disabled;
          113                 img = button->text_disabled;
          114                 break;
          115         default:
          116                 ltk_fatal("No style found for button!\n");
          117         }
          118         Display *display = ltk_get_display();
          119         Colormap colormap = ltk_get_colormap();
          120         XSetForeground(display, window->gc, fill.pixel);
          121         XFillRectangle(display, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h);
          122         /* FIXME: Why did I do this? */
          123         if (bw < 1) return;
          124         XSetForeground(display, window->gc, border.pixel);
          125         XSetLineAttributes(display, window->gc, bw, LineSolid, CapButt, JoinMiter);
          126         XDrawRectangle(display, window->xwindow, window->gc, rect.x + bw / 2, rect.y + bw / 2, rect.w - bw, rect.h - bw);
          127         if (!img) {
          128                 img = ltk_text_line_render(button->tl, display, window->xwindow, window->gc, colormap, theme->text_color, fill);
          129                 /* FIXME: any nicer way to do this? */
          130                 switch (button->widget.state) {
          131                         case LTK_NORMAL:
          132                                 button->text = img;
          133                                 break;
          134                         case LTK_HOVERACTIVE:
          135                         case LTK_HOVER:
          136                                 button->text_hover = img;
          137                                 break;
          138                         case LTK_PRESSED:
          139                                 button->text_pressed = img;
          140                                 break;
          141                         case LTK_ACTIVE:
          142                                 button->text_active = img;
          143                                 break;
          144                         case LTK_DISABLED:
          145                                 button->text_disabled = img;
          146                                 break;
          147                 }
          148         }
          149         text_x = rect.x + (rect.w - button->tl->w) / 2;
          150         text_y = rect.y + (rect.h - button->tl->h) / 2;
          151         XPutImage(display, window->xwindow, window->gc, img, 0, 0, text_x, text_y, button->tl->w, button->tl->h);
          152 }
          153 
          154 LtkButton *
          155 ltk_button_create(LtkWindow *window, const char *text, void (*callback) (void *, XEvent, void *), void *data) {
          156         LtkButton *button = malloc(sizeof(LtkButton));
          157 
          158         if (button == NULL) {
          159                 ltk_fatal("ERROR: Unable to allocate memory for LtkButton.\n");
          160         }
          161 
          162         ltk_fill_widget_defaults(&button->widget, window, &ltk_button_draw, &ltk_button_destroy, 1);
          163         button->widget.mouse_release = &ltk_button_mouse_release;
          164 
          165         button->callback = callback;
          166         button->data = data;
          167         LtkTheme *theme = ltk_get_theme();
          168         button->tl = ltk_text_line_create(theme->button->font_size);
          169         /* FIXME: support font size */
          170         ltk_text_line_insert_utf8(button->tl, 0, text);
          171         ltk_text_line_wrap(button->tl, -1);
          172         button->widget.rect.w = button->tl->w + (theme->button->border_width + theme->button->pad) * 2;
          173         button->widget.rect.h = button->tl->h + (theme->button->border_width + theme->button->pad) * 2;
          174         button->text = NULL;
          175         button->text_pressed = NULL;
          176         button->text_hover = NULL;
          177         button->text_disabled = NULL;
          178         button->text_active = NULL;
          179 
          180         return button;
          181 }
          182 
          183 void
          184 ltk_button_destroy(LtkButton *button) {
          185         if (!button) {
          186                 (void)printf("WARNING: Tried to destroy NULL button.\n");
          187         }
          188         if (button->text) XDestroyImage(button->text);
          189         if (button->text_hover) XDestroyImage(button->text_hover);
          190         if (button->text_pressed) XDestroyImage(button->text_pressed);
          191         if (button->text_active) XDestroyImage(button->text_active);
          192         if (button->text_disabled) XDestroyImage(button->text_disabled);
          193         ltk_text_line_destroy(button->tl);
          194         free(button);
          195 }
          196 
          197 /* FIXME: is the fixme below supposed to be for the function above? */
          198 /* FIXME: ungrid button if gridded */
          199 void
          200 ltk_button_mouse_release(LtkButton *button, XEvent event) {
          201         if (button->widget.state == LTK_HOVERACTIVE && button->callback) {
          202                 button->callback(button, event, button->data);
          203         }
          204 }