1 /*
2 * Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of ZToolkit
5 *
6 * ZToolkit is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * ZToolkit is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Affero Public License
17 * along with ZToolkit. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <ztoolkit/ztk.h>
24 #include "pugl.h"
25
26 static void
button_draw_cb(ZtkWidget * widget,cairo_t * cr,ZtkRect * draw_rect,void * data)27 button_draw_cb (
28 ZtkWidget * widget,
29 cairo_t * cr,
30 ZtkRect * draw_rect,
31 void * data)
32 {
33 ZtkButton * self = (ZtkButton *) widget;
34
35 ZtkWidgetState state = widget->state;
36 if (self->has_bg_colors)
37 {
38 if ((state & ZTK_WIDGET_STATE_PRESSED) ||
39 (self->is_toggle &&
40 self->toggled_getter (
41 self, widget->user_data)))
42 {
43 ztk_color_set_for_cairo (
44 &self->clicked_color, cr);
45 }
46 else if (state & ZTK_WIDGET_STATE_HOVERED)
47 {
48 ztk_color_set_for_cairo (
49 &self->hovered_color, cr);
50 }
51 else
52 {
53 ztk_color_set_for_cairo (
54 &self->normal_color, cr);
55 }
56 cairo_rectangle (
57 cr, widget->rect.x, widget->rect.y,
58 widget->rect.width, widget->rect.height);
59 cairo_fill (cr);
60 }
61 else if (self->bg_draw_cb)
62 {
63 self->bg_draw_cb (
64 widget, cr, draw_rect, data);
65 }
66
67 #define DRAW_SVG(svg) \
68 ZtkRect rect = { \
69 widget->rect.x + self->hpadding, \
70 widget->rect.y + self->vpadding, \
71 widget->rect.width - self->hpadding * 2, \
72 widget->rect.height - self->vpadding * 2 }; \
73 ztk_rsvg_draw ( \
74 self->svg, cr, &rect)
75
76 switch (self->type)
77 {
78 case ZTK_BTN_LBL:
79 /* TODO draw label */
80 break;
81 #ifdef HAVE_RSVG
82 case ZTK_BTN_SVG:
83 if ((state & ZTK_WIDGET_STATE_PRESSED) ||
84 (self->is_toggle &&
85 self->toggled_getter (
86 self, widget->user_data)))
87 {
88 DRAW_SVG (clicked_svg);
89 }
90 else if (state & ZTK_WIDGET_STATE_HOVERED)
91 {
92 DRAW_SVG (hover_svg);
93 }
94 else
95 {
96 DRAW_SVG (normal_svg);
97 }
98 break;
99 #endif
100 case ZTK_BTN_CUSTOM:
101 self->custom_draw_cb (
102 widget, cr, draw_rect, data);
103 break;
104 default:
105 break;
106 }
107
108 #undef DRAW_SVG
109 }
110
111 static void
update_cb(ZtkWidget * w,void * data)112 update_cb (
113 ZtkWidget * w,
114 void * data)
115 {
116 }
117
118 static int
on_button_event(ZtkWidget * w,const PuglEventButton * btn,void * data)119 on_button_event (
120 ZtkWidget * w,
121 const PuglEventButton * btn,
122 void * data)
123 {
124 ZtkButton * self = (ZtkButton *) w;
125
126 ZtkWidgetState state = w->state;
127 if (state & ZTK_WIDGET_STATE_PRESSED)
128 {
129 if (ztk_widget_is_hit (w, btn->x, btn->y))
130 {
131 self->was_pressed = 1;
132 }
133 }
134 else
135 {
136 if (self->was_pressed)
137 {
138 self->activate_cb (w, data);
139 }
140 self->was_pressed = 0;
141 }
142
143 return 1;
144 }
145
146 static void
free_cb(ZtkWidget * widget,void * data)147 free_cb (
148 ZtkWidget * widget,
149 void * data)
150 {
151 ZtkButton * self = (ZtkButton *) widget;
152
153 free (self);
154 }
155
156 /**
157 * Creates a new ZtkButton.
158 *
159 * This must then be set to its type using the setters
160 * below.
161 */
162 ZtkButton *
ztk_button_new(ZtkRect * rect,ZtkWidgetActivateCallback activate_cb,void * user_data)163 ztk_button_new (
164 ZtkRect * rect,
165 ZtkWidgetActivateCallback activate_cb,
166 void * user_data)
167 {
168 ZtkButton * self = calloc (1, sizeof (ZtkButton));
169 ZtkWidget * widget = (ZtkWidget *) self;
170 ztk_widget_init (
171 (ZtkWidget *) self, ZTK_WIDGET_TYPE_BUTTON, rect,
172 update_cb, button_draw_cb, free_cb);
173
174 self->activate_cb = activate_cb;
175
176 widget->button_event_cb = on_button_event;
177 widget->user_data = user_data;
178
179 return self;
180 }
181
182 void
ztk_button_make_toggled(ZtkButton * self,ZtkButtonToggledGetter toggled_getter)183 ztk_button_make_toggled (
184 ZtkButton * self,
185 ZtkButtonToggledGetter toggled_getter)
186 {
187 self->is_toggle = 1;
188 self->toggled_getter = toggled_getter;
189 }
190
191 /**
192 * Makes a button with a label.
193 */
194 void
ztk_button_make_labeled(ZtkButton * self,const char * label)195 ztk_button_make_labeled (
196 ZtkButton * self,
197 const char * label)
198 {
199 self->type = ZTK_BTN_LBL;
200
201 strcpy (self->lbl, label);
202 }
203
204 #ifdef HAVE_RSVG
205 /**
206 * Makes a button with SVGs.
207 */
208 void
ztk_button_make_svged(ZtkButton * self,int hpadding,int vpadding,ZtkRsvgHandle * svg_normal,ZtkRsvgHandle * svg_hover,ZtkRsvgHandle * svg_clicked)209 ztk_button_make_svged (
210 ZtkButton * self,
211 int hpadding,
212 int vpadding,
213 ZtkRsvgHandle * svg_normal,
214 ZtkRsvgHandle * svg_hover,
215 ZtkRsvgHandle * svg_clicked)
216 {
217 self->type = ZTK_BTN_SVG;
218
219 self->hpadding = hpadding;
220 self->vpadding = vpadding;
221 self->normal_svg = svg_normal;
222 self->hover_svg = svg_hover;
223 self->clicked_svg = svg_clicked;
224 }
225 #endif
226
227 /**
228 * Makes a customly drawn button.
229 */
230 void
ztk_button_make_custom(ZtkButton * self,ZtkWidgetDrawCallback draw_cb)231 ztk_button_make_custom (
232 ZtkButton * self,
233 ZtkWidgetDrawCallback draw_cb)
234 {
235 self->type = ZTK_BTN_CUSTOM;
236
237 self->custom_draw_cb = draw_cb;
238 }
239
240 void
ztk_button_set_background_colors(ZtkButton * self,ZtkColor * normal,ZtkColor * hovered,ZtkColor * clicked)241 ztk_button_set_background_colors (
242 ZtkButton * self,
243 ZtkColor * normal,
244 ZtkColor * hovered,
245 ZtkColor * clicked)
246 {
247 self->has_bg_colors = 1;
248
249 self->normal_color = * normal;
250 self->hovered_color = * hovered;
251 self->clicked_color = * clicked;
252 }
253
254 /**
255 * Add callback for drawing the background.
256 */
257 void
ztk_button_add_background_callback(ZtkButton * self,ZtkWidgetDrawCallback draw_cb)258 ztk_button_add_background_callback (
259 ZtkButton * self,
260 ZtkWidgetDrawCallback draw_cb)
261 {
262 self->bg_draw_cb = draw_cb;
263 }
264