1 /*
2 * 0BSD
3 *
4 * BSD Zero Clause License
5 *
6 * Copyright (c) 2019 Hermann Meyer
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted.
10
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21
22 #include "xbutton_private.h"
23
24
_rounded_rectangle(cairo_t * cr,float x,float y,float width,float height)25 void _rounded_rectangle(cairo_t *cr,float x, float y, float width, float height) {
26 cairo_new_path (cr);
27 cairo_move_to (cr, x, (y + height)/2);
28 cairo_curve_to (cr, x ,y, x, y, (x + width)/2, y);
29 cairo_curve_to (cr, width, y, width, y, width, (y + height)/2);
30 cairo_curve_to (cr, width, height, width, height, (width + x)/2, height);
31 cairo_curve_to (cr, x, height, x, height, x, (y + height)/2);
32 cairo_close_path (cr);
33 }
34
_pattern_out(Widget_t * w,Color_state st,int height)35 void _pattern_out(Widget_t *w, Color_state st, int height) {
36 Colors *c = get_color_scheme(w->app,st);
37 if (!c) return;
38 cairo_pattern_t *pat = cairo_pattern_create_linear (2, 2, 2, height);
39 cairo_pattern_add_color_stop_rgba(pat, 0.0, c->light[0], c->light[1], c->light[2], c->light[3]);
40 cairo_pattern_add_color_stop_rgba(pat, 0.5, 0.0, 0.0, 0.0, 0.0);
41 cairo_pattern_add_color_stop_rgba(pat, 1.0, c->light[0], c->light[1], c->light[2], c->light[3]);
42 cairo_set_source(w->crb, pat);
43 cairo_pattern_destroy (pat);
44 }
45
_pattern_in(Widget_t * w,Color_state st,int height)46 void _pattern_in(Widget_t *w, Color_state st, int height) {
47 Colors *c = get_color_scheme(w->app,st);
48 if (!c) return;
49 cairo_pattern_t *pat = cairo_pattern_create_linear (2, 2, 2, height);
50 cairo_pattern_add_color_stop_rgba(pat, 0.0, 0.0, 0.0, 0.0, 0.0);
51 cairo_pattern_add_color_stop_rgba(pat, 0.5, c->light[0], c->light[1], c->light[2], c->light[3]);
52 cairo_pattern_add_color_stop_rgba(pat, 1.0, 0.0, 0.0, 0.0, 0.0);
53 cairo_set_source(w->crb, pat);
54 cairo_pattern_destroy (pat);
55 }
56
_draw_image_button(Widget_t * w,int width_t,int height_t,float offset)57 void _draw_image_button(Widget_t *w, int width_t, int height_t, float offset) {
58 int width = cairo_xlib_surface_get_width(w->image);
59 int height = cairo_xlib_surface_get_height(w->image);
60 double half_width = (width/height >=2) ? width*0.5 : width;
61 double x = (double)width_t/(double)(half_width);
62 double y = (double)height_t/(double)height;
63 double x1 = (double)height/(double)height_t;
64 double y1 = (double)(half_width)/(double)width_t;
65 double off_set = offset*x1;
66 double buttonstate = adj_get_state(w->adj);
67 int findex = (int)(((width/height)-1) * buttonstate) * (width/height >=2);
68 cairo_scale(w->crb, x,y);
69 cairo_set_source_surface (w->crb, w->image, -height*findex+off_set, off_set);
70 cairo_rectangle(w->crb,0, 0, height, height);
71 cairo_fill(w->crb);
72 cairo_scale(w->crb, x1,y1);
73 }
74
_draw_image_button_with_label(Widget_t * w,int width_t,int height_t)75 void _draw_image_button_with_label(Widget_t *w, int width_t, int height_t) {
76 int width = cairo_xlib_surface_get_width(w->image);
77 int height = cairo_xlib_surface_get_height(w->image);
78 double x = (double)width_t/(double)height;
79 double y = (double)height/(double)width_t;
80 double buttonstate = adj_get_state(w->adj);
81 int findex = (int)(((width/height)-1) * buttonstate);
82 cairo_scale(w->crb, x,x);
83 cairo_set_source_surface (w->crb, w->image, -height*findex, 0);
84 cairo_rectangle(w->crb,0, 0, height, height);
85 cairo_fill(w->crb);
86 cairo_scale(w->crb, y,y);
87 cairo_text_extents_t extents;
88 if(w->state==0) {
89 use_fg_color_scheme(w, NORMAL_);
90 } else if(w->state==1 && ! (int)w->adj_y->value) {
91 use_fg_color_scheme(w, PRELIGHT_);
92 } else if(w->state==1) {
93 use_fg_color_scheme(w, ACTIVE_);
94 } else if(w->state==2) {
95 use_fg_color_scheme(w, SELECTED_);
96 } else if(w->state==3) {
97 use_fg_color_scheme(w, ACTIVE_);
98 }
99
100 use_text_color_scheme(w, get_color_state(w));
101 cairo_set_font_size (w->crb,w->app->normal_font/w->scale.ascale);
102 if ((int)adj_get_value(w->adj) && strlen(w->input_label)) {
103 cairo_text_extents(w->crb,w->input_label , &extents);
104 cairo_move_to (w->crb, (width_t*0.5)-(extents.width/2), height_t-(extents.height/4));
105 cairo_show_text(w->crb, w->input_label);
106 } else {
107 cairo_text_extents(w->crb,w->label , &extents);
108 cairo_move_to (w->crb, (width_t*0.5)-(extents.width/2), height_t-(extents.height/4));
109 cairo_show_text(w->crb, w->label);
110 }
111 cairo_new_path (w->crb);
112 }
113
_draw_switch_image_button(void * w_,void * user_data)114 void _draw_switch_image_button(void *w_, void* user_data) {
115 Widget_t *w = (Widget_t*)w_;
116 if (!w) return;
117 XWindowAttributes attrs;
118 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
119 int width = attrs.width-2;
120 int height = attrs.height-2;
121 if (attrs.map_state != IsViewable) return;
122 if(strlen(w->label)) {
123 _draw_image_button_with_label(w, width, height);
124 } else {
125 _draw_image_button(w, width, height,0.0);
126 }
127 }
128
_draw_button_base(Widget_t * w,int width,int height)129 void _draw_button_base(Widget_t *w, int width, int height) {
130 if (!w->state && (int)w->adj_y->value) {
131 w->state = 3;
132 } else if (w->state == 3 && !(int)w->adj_y->value) {
133 w->state = 0;
134 }
135
136 _rounded_rectangle(w->crb,2.0, 2.0, width, height);
137
138 if(w->state==0) {
139 cairo_set_line_width(w->crb, 1.0);
140 _pattern_out(w, NORMAL_, height);
141 cairo_fill_preserve(w->crb);
142 use_frame_color_scheme(w, PRELIGHT_);
143 } else if(w->state==1) {
144 _pattern_out(w, PRELIGHT_, height);
145 cairo_fill_preserve(w->crb);
146 cairo_set_line_width(w->crb, 1.5);
147 use_frame_color_scheme(w, PRELIGHT_);
148 } else if(w->state==2) {
149 _pattern_in(w, SELECTED_, height);
150 cairo_fill_preserve(w->crb);
151 cairo_set_line_width(w->crb, 1.0);
152 use_frame_color_scheme(w, PRELIGHT_);
153 } else if(w->state==3) {
154 _pattern_in(w, ACTIVE_, height);
155 cairo_fill_preserve(w->crb);
156 cairo_set_line_width(w->crb, 1.0);
157 use_frame_color_scheme(w, PRELIGHT_);
158 }
159 cairo_stroke(w->crb);
160
161 if(w->state==2) {
162 _rounded_rectangle(w->crb,4.0, 4.0, width, height);
163 cairo_stroke(w->crb);
164 _rounded_rectangle(w->crb,3.0, 3.0, width, height);
165 cairo_stroke(w->crb);
166 } else if (w->state==3) {
167 _rounded_rectangle(w->crb,3.0, 3.0, width, height);
168 cairo_stroke(w->crb);
169 }
170 }
171
_draw_button(void * w_,void * user_data)172 void _draw_button(void *w_, void* user_data) {
173 Widget_t *w = (Widget_t*)w_;
174 if (!w) return;
175 XWindowAttributes attrs;
176 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
177 int width = attrs.width-2;
178 int height = attrs.height-2;
179 if (attrs.map_state != IsViewable) return;
180 _draw_button_base(w, width, height);
181
182 float offset = 0.0;
183 if(w->state==1 && ! (int)w->adj_y->value) {
184 offset = 1.0;
185 } else if(w->state==1) {
186 offset = 2.0;
187 } else if(w->state==2) {
188 offset = 2.0;
189 } else if(w->state==3) {
190 offset = 1.0;
191 }
192 if (w->image) {
193 if(strlen(w->label)) {
194 _draw_image_button_with_label(w, width, height);
195 } else {
196 _draw_image_button(w, width, height,offset);
197 }
198 } else {
199
200 cairo_text_extents_t extents;
201 use_text_color_scheme(w, get_color_state(w));
202 cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
203 cairo_text_extents(w->crb,w->label , &extents);
204 if(IS_UTF8(w->label[0])) {
205 cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
206 cairo_text_extents(w->crb,w->label , &extents);
207 }
208
209 cairo_move_to (w->crb, (width-extents.width)*0.5 +offset, (height+extents.height)*0.5 +offset);
210 cairo_show_text(w->crb, w->label);
211 cairo_new_path (w->crb);
212 }
213 }
214
_draw_on_off_button(void * w_,void * user_data)215 void _draw_on_off_button(void *w_, void* user_data) {
216 Widget_t *w = (Widget_t*)w_;
217 if (!w) return;
218 XWindowAttributes attrs;
219 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
220 int width = attrs.width-2;
221 int height = attrs.height-2;
222 if (attrs.map_state != IsViewable) return;
223
224 _draw_button_base(w, width, height);
225
226 float offset = 0.0;
227 cairo_text_extents_t extents;
228 if(w->state==1 && ! (int)w->adj_y->value) {
229 offset = 1.0;
230 } else if(w->state==1) {
231 offset = 2.0;
232 } else if(w->state==2) {
233 offset = 2.0;
234 } else if(w->state==3) {
235 offset = 1.0;
236 }
237 if((int)w->adj_y->value) {
238 w->label = "On";
239 } else {
240 w->label = "Off";
241 }
242
243 use_text_color_scheme(w, get_color_state(w));
244 cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
245 cairo_text_extents(w->crb,w->label , &extents);
246 if(IS_UTF8(w->label[0])) {
247 cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
248 cairo_text_extents(w->crb,w->label , &extents);
249 }
250
251 cairo_move_to (w->crb, (width-extents.width)*0.5 +offset, (height+extents.height)*0.5 +offset);
252 cairo_show_text(w->crb, w->label);
253 cairo_new_path (w->crb);
254
255 }
256
_draw_ti_button(void * w_,void * user_data)257 void _draw_ti_button(void *w_, void* user_data) {
258 Widget_t *w = (Widget_t*)w_;
259 if (!w) return;
260 XWindowAttributes attrs;
261 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
262 int width = attrs.width-2;
263 int height = attrs.height-2;
264 if (attrs.map_state != IsViewable) return;
265 _draw_button_base(w, width, height);
266 if (w->image) {
267 float offset = 0.0;
268 if(w->state==1 && ! (int)w->adj_y->value) {
269 offset = 1.0;
270 } else if(w->state==1) {
271 offset = 2.0;
272 } else if(w->state==2) {
273 offset = 2.0;
274 } else if(w->state==3) {
275 offset = 1.0;
276 }
277
278 _draw_image_button(w, width, height,offset);
279 }
280 }
281
_draw_check_button(void * w_,void * user_data)282 void _draw_check_button(void *w_, void* user_data) {
283 Widget_t *w = (Widget_t*)w_;
284 if (!w) return;
285 XWindowAttributes attrs;
286 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
287 int width = attrs.width-2;
288 int height = attrs.height-2;
289 if (attrs.map_state != IsViewable) return;
290 if (w->image) {
291 _draw_image_button(w, width, height,0.0);
292 } else {
293 _draw_button_base(w, width, height);
294
295 if(w->state==3) {
296 use_fg_color_scheme(w, get_color_state(w));
297 float offset = 1.0;
298 int wa = width/1.3;
299 int h = height/2.2;
300 int wa1 = width/2.2;
301 int h1 = height/1.3;
302 int wa2 = width/2.8;
303
304 cairo_set_line_width(w->crb, 2.5);
305 cairo_move_to(w->crb, wa+offset, h+offset);
306 cairo_line_to(w->crb, wa1+offset, h1+offset);
307 cairo_line_to(w->crb, wa2+offset, h+offset);
308 cairo_stroke(w->crb);
309 }
310
311 cairo_new_path (w->crb);
312 }
313 }
314
_draw_check_box(void * w_,void * user_data)315 void _draw_check_box(void *w_, void* user_data) {
316 Widget_t *w = (Widget_t*)w_;
317 if (!w) return;
318 XWindowAttributes attrs;
319 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
320 int height = attrs.height-2;
321 if (attrs.map_state != IsViewable) return;
322 if (w->image) {
323 _draw_image_button(w, height, height,0.0);
324 } else {
325 _draw_button_base(w, height, height);
326
327 if(adj_get_value(w->adj)) {
328 use_fg_color_scheme(w, get_color_state(w));
329 float offset = 1.0;
330 int wa = height/1.3;
331 int h = height/2.2;
332 int wa1 = height/2.2;
333 int h1 = height/1.3;
334 int wa2 = height/2.8;
335
336 cairo_set_line_width(w->crb, 2.5);
337 cairo_move_to(w->crb, wa+offset, h+offset);
338 cairo_line_to(w->crb, wa1+offset, h1+offset);
339 cairo_line_to(w->crb, wa2+offset, h+offset);
340 cairo_stroke(w->crb);
341 }
342
343 cairo_new_path (w->crb);
344
345 cairo_text_extents_t extents;
346 use_text_color_scheme(w, get_color_state(w));
347 cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
348 cairo_text_extents(w->crb,w->label , &extents);
349 cairo_move_to (w->crb, height+5 , (height+extents.height)*0.5 );
350 cairo_show_text(w->crb, w->label);
351 cairo_new_path (w->crb);
352 }
353 }
354
355 /*---------------------------------------------------------------------
356 -----------------------------------------------------------------------
357 button
358 -----------------------------------------------------------------------
359 ----------------------------------------------------------------------*/
360
_button_pressed(void * w_,void * button,void * user_data)361 void _button_pressed(void *w_, void* button, void* user_data) {
362 Widget_t *w = (Widget_t*)w_;
363 adj_set_value(w->adj_y, 1.0);
364 }
365
_button_released(void * w_,void * button_,void * user_data)366 void _button_released(void *w_, void* button_, void* user_data) {
367 Widget_t *w = (Widget_t*)w_;
368 if (w->flags & HAS_POINTER) w->state=1;
369 adj_set_value(w->adj_y, 0.0);
370 }
371
372 /*---------------------------------------------------------------------
373 -----------------------------------------------------------------------
374 toggle button
375 -----------------------------------------------------------------------
376 ----------------------------------------------------------------------*/
377
_toggle_button_pressed(void * w_,void * button,void * user_data)378 void _toggle_button_pressed(void *w_, void* button, void* user_data) {
379 Widget_t *w = (Widget_t*)w_;
380 expose_widget(w);
381 }
382
_toggle_button_released(void * w_,void * button_,void * user_data)383 void _toggle_button_released(void *w_, void* button_, void* user_data) {
384 Widget_t *w = (Widget_t*)w_;
385 XButtonEvent *xbutton = (XButtonEvent*)button_;
386 if (w->flags & HAS_POINTER) {
387 float value = w->adj->value;
388 if (xbutton->button == Button1) value = value ?
389 w->adj->min_value : w->adj->max_value;
390 if (xbutton->button == Button4) value = w->adj->max_value;
391 if (xbutton->button == Button5) value = w->adj->min_value;
392 adj_set_value(w->adj, value);
393 w->state = (int) w->adj->value ? 3 : 1;
394 } else {
395 w->state = (int) w->adj->value ? 3 : 0;
396 }
397 expose_widget(w);
398 }
399