ltkx

GUI toolkit for X11 (old)
git clone git://lumidify.org/ltkx.git (fast, but not encrypted)
git clone https://lumidify.org/ltkx.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltkx.git (over tor)
Log | Files | Refs | README | 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 }