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, <k_button_draw, <k_button_destroy, 1);
163 button->widget.mouse_release = <k_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 }