libxputty  0.1
A damn tiny abstraction Layer to create X11 window/widgets with cairo surfaces
xbutton_private.c
Go to the documentation of this file.
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 
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 
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 
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 
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 
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) {
90  } else if(w->state==1 && ! (int)w->adj_y->value) {
92  } else if(w->state==1) {
94  } else if(w->state==2) {
96  } else if(w->state==3) {
98  }
99 
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 
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 
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);
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);
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);
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);
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 
172 int _remove_low_dash(char *str) {
173 
174  char *src;
175  char *dst;
176  int i = 0;
177  int r = 0;
178  for (src = dst = str; *src != '\0'; src++) {
179  *dst = *src;
180  if (*dst != '_') {
181  dst++;
182  } else {
183  r = i;
184  }
185  i++;
186  }
187  *dst = '\0';
188  return r;
189 }
190 
191 void _draw_button(void *w_, void* user_data) {
192  Widget_t *w = (Widget_t*)w_;
193  if (!w) return;
194  XWindowAttributes attrs;
195  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
196  int width = attrs.width-2;
197  int height = attrs.height-2;
198  if (attrs.map_state != IsViewable) return;
199  _draw_button_base(w, width, height);
200 
201  float offset = 0.0;
202  if(w->state==1 && ! (int)w->adj_y->value) {
203  offset = 1.0;
204  } else if(w->state==1) {
205  offset = 2.0;
206  } else if(w->state==2) {
207  offset = 2.0;
208  } else if(w->state==3) {
209  offset = 1.0;
210  }
211  if (w->image) {
212  if(strlen(w->label)) {
213  _draw_image_button_with_label(w, width, height);
214  } else {
215  _draw_image_button(w, width, height,offset);
216  }
217  } else {
218 
219  cairo_text_extents_t extents;
221  cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
222 
223  if (strstr(w->label, "_")) {
224  cairo_text_extents(w->crb, "--", &extents);
225  double underline = extents.width;
226  strcpy(w->input_label,w->label);
227  int pos = _remove_low_dash(w->input_label);
228  cairo_text_extents(w->crb,w->input_label , &extents);
229  cairo_move_to (w->crb, (width-extents.width)*0.5 +offset, (height+extents.height)*0.5 +offset);
230  cairo_show_text(w->crb, w->input_label);
231  cairo_set_line_width(w->crb, 1.0);
232  cairo_move_to (w->crb, (width-extents.width)*0.5 +offset + (pos * underline), (height+extents.height)*0.55 +offset);
233  cairo_line_to(w->crb,(width-extents.width)*0.5 +offset + ((pos+1) * underline), (height+extents.height)*0.55 +offset);
234  cairo_stroke(w->crb);
235  } else {
236  cairo_text_extents(w->crb,w->label , &extents);
237  cairo_move_to (w->crb, (width-extents.width)*0.5 +offset, (height+extents.height)*0.5 +offset);
238  cairo_show_text(w->crb, w->label);
239  }
240  }
241 }
242 
243 void _draw_on_off_button(void *w_, void* user_data) {
244  Widget_t *w = (Widget_t*)w_;
245  if (!w) return;
246  XWindowAttributes attrs;
247  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
248  int width = attrs.width-2;
249  int height = attrs.height-2;
250  if (attrs.map_state != IsViewable) return;
251 
252  _draw_button_base(w, width, height);
253 
254  float offset = 0.0;
255  cairo_text_extents_t extents;
256  if(w->state==1 && ! (int)w->adj_y->value) {
257  offset = 1.0;
258  } else if(w->state==1) {
259  offset = 2.0;
260  } else if(w->state==2) {
261  offset = 2.0;
262  } else if(w->state==3) {
263  offset = 1.0;
264  }
265  if((int)w->adj_y->value) {
266  w->label = "On";
267  } else {
268  w->label = "Off";
269  }
270 
272  cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
273  cairo_text_extents(w->crb,w->label , &extents);
274  if(IS_UTF8(w->label[0])) {
275  cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
276  cairo_text_extents(w->crb,w->label , &extents);
277  }
278 
279  cairo_move_to (w->crb, (width-extents.width)*0.5 +offset, (height+extents.height)*0.5 +offset);
280  cairo_show_text(w->crb, w->label);
281  cairo_new_path (w->crb);
282 
283 }
284 
285 void _draw_ti_button(void *w_, void* user_data) {
286  Widget_t *w = (Widget_t*)w_;
287  if (!w) return;
288  XWindowAttributes attrs;
289  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
290  int width = attrs.width-2;
291  int height = attrs.height-2;
292  if (attrs.map_state != IsViewable) return;
293  _draw_button_base(w, width, height);
294  if (w->image) {
295  float offset = 0.0;
296  if(w->state==1 && ! (int)w->adj_y->value) {
297  offset = 1.0;
298  } else if(w->state==1) {
299  offset = 2.0;
300  } else if(w->state==2) {
301  offset = 2.0;
302  } else if(w->state==3) {
303  offset = 1.0;
304  }
305 
306  _draw_image_button(w, width, height,offset);
307  }
308 }
309 
310 void _draw_check_button(void *w_, void* user_data) {
311  Widget_t *w = (Widget_t*)w_;
312  if (!w) return;
313  XWindowAttributes attrs;
314  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
315  int width = attrs.width-2;
316  int height = attrs.height-2;
317  if (attrs.map_state != IsViewable) return;
318  if (w->image) {
319  _draw_image_button(w, width, height,0.0);
320  } else {
321  _draw_button_base(w, width, height);
322 
323  if(w->state==3) {
325  float offset = 1.0;
326  int wa = width/1.3;
327  int h = height/2.2;
328  int wa1 = width/2.2;
329  int h1 = height/1.3;
330  int wa2 = width/2.8;
331 
332  cairo_set_line_width(w->crb, 2.5);
333  cairo_move_to(w->crb, wa+offset, h+offset);
334  cairo_line_to(w->crb, wa1+offset, h1+offset);
335  cairo_line_to(w->crb, wa2+offset, h+offset);
336  cairo_stroke(w->crb);
337  }
338 
339  cairo_new_path (w->crb);
340  }
341 }
342 
343 void _draw_check_box(void *w_, void* user_data) {
344  Widget_t *w = (Widget_t*)w_;
345  if (!w) return;
346  XWindowAttributes attrs;
347  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
348  int height = attrs.height-2;
349  if (attrs.map_state != IsViewable) return;
350  if (w->image) {
351  _draw_image_button(w, height, height,0.0);
352  } else {
353  _draw_button_base(w, height, height);
354 
355  if(adj_get_value(w->adj)) {
357  float offset = 1.0;
358  int wa = height/1.3;
359  int h = height/2.2;
360  int wa1 = height/2.2;
361  int h1 = height/1.3;
362  int wa2 = height/2.8;
363 
364  cairo_set_line_width(w->crb, 2.5);
365  cairo_move_to(w->crb, wa+offset, h+offset);
366  cairo_line_to(w->crb, wa1+offset, h1+offset);
367  cairo_line_to(w->crb, wa2+offset, h+offset);
368  cairo_stroke(w->crb);
369  }
370 
371  cairo_new_path (w->crb);
372 
373  cairo_text_extents_t extents;
375  cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
376  cairo_text_extents(w->crb,w->label , &extents);
377  cairo_move_to (w->crb, height+5 , (height+extents.height)*0.5 );
378  cairo_show_text(w->crb, w->label);
379  cairo_new_path (w->crb);
380  }
381 }
382 
383 /*---------------------------------------------------------------------
384 -----------------------------------------------------------------------
385  button
386 -----------------------------------------------------------------------
387 ----------------------------------------------------------------------*/
388 
389 void _button_pressed(void *w_, void* button, void* user_data) {
390  Widget_t *w = (Widget_t*)w_;
391  adj_set_value(w->adj_y, 1.0);
392 }
393 
394 void _button_released(void *w_, void* button_, void* user_data) {
395  Widget_t *w = (Widget_t*)w_;
396  if (w->flags & HAS_POINTER) w->state=1;
397  adj_set_value(w->adj_y, 0.0);
398 }
399 
400 /*---------------------------------------------------------------------
401 -----------------------------------------------------------------------
402  toggle button
403 -----------------------------------------------------------------------
404 ----------------------------------------------------------------------*/
405 
406 void _toggle_button_pressed(void *w_, void* button, void* user_data) {
407  Widget_t *w = (Widget_t*)w_;
408  expose_widget(w);
409 }
410 
411 void _toggle_button_released(void *w_, void* button_, void* user_data) {
412  Widget_t *w = (Widget_t*)w_;
413  XButtonEvent *xbutton = (XButtonEvent*)button_;
414  if (w->flags & HAS_POINTER) {
415  float value = w->adj->value;
416  if (xbutton->button == Button1) value = value ?
417  w->adj->min_value : w->adj->max_value;
418  if (xbutton->button == Button4) value = w->adj->max_value;
419  if (xbutton->button == Button5) value = w->adj->min_value;
420  adj_set_value(w->adj, value);
421  w->state = (int) w->adj->value ? 3 : 1;
422  } else {
423  w->state = (int) w->adj->value ? 3 : 0;
424  }
425  expose_widget(w);
426 }
use_text_color_scheme
void use_text_color_scheme(Widget_t *w, Color_state st)
use_text_color_scheme - use text Colors to paint on Widget_t
Definition: xcolor.c:199
_draw_check_button
void _draw_check_button(void *w_, void *user_data)
_draw_check_button - internal draw the button to the buffer
Definition: xbutton_private.c:310
expose_widget
void expose_widget(Widget_t *w)
expose_widgets - send a expose event (EXPOSE) to a Widget_t
Definition: xwidget.c:461
Widget_t::image
cairo_surface_t * image
Definition: xwidget.h:320
adj_get_state
float adj_get_state(Adjustment_t *adj)
adj_get_state - get the current state of the Adjustment_t
Definition: xadjustment.c:148
Adjustment_t::value
float value
Definition: xadjustment.h:86
_draw_ti_button
void _draw_ti_button(void *w_, void *user_data)
_draw_ti_button - internal draw the button to the buffer
Definition: xbutton_private.c:285
_draw_image_button_with_label
void _draw_image_button_with_label(Widget_t *w, int width_t, int height_t)
Definition: xbutton_private.c:75
_pattern_out
void _pattern_out(Widget_t *w, Color_state st, int height)
_pattern_in - a little pattern to make press state more visible
Definition: xbutton_private.c:35
get_color_state
Color_state get_color_state(Widget_t *wid)
get_color_state - get the Color_state to use in relation to the Widget_t state
Definition: xcolor.c:155
_toggle_button_released
void _toggle_button_released(void *w_, void *button_, void *user_data)
_toggle_button_released - redraw the button and send state via user_callback
Definition: xbutton_private.c:411
Xputty::normal_font
int normal_font
Definition: xputty.h:191
_pattern_in
void _pattern_in(Widget_t *w, Color_state st, int height)
_pattern_in - a little pattern to make press state more visible
Definition: xbutton_private.c:46
adj_get_value
float adj_get_value(Adjustment_t *adj)
adj_get_value - get the current value of the Adjustment_t
Definition: xadjustment.c:154
HAS_POINTER
@ HAS_POINTER
Definition: xwidget.h:247
Widget_t::crb
cairo_t * crb
Definition: xwidget.h:318
_toggle_button_pressed
void _toggle_button_pressed(void *w_, void *button, void *user_data)
_toggle_button_pressed - redraw the button and send state via user_callback
Definition: xbutton_private.c:406
Widget_t::flags
long long flags
Definition: xwidget.h:324
_draw_on_off_button
void _draw_on_off_button(void *w_, void *user_data)
_draw_on_off_button - internal draw the on/off button to the buffer
Definition: xbutton_private.c:243
adj_set_value
void adj_set_value(Adjustment_t *adj, float value)
adj_set_value - set the current value to the Adjustment_t
Definition: xadjustment.c:163
Widget_t::adj
Adjustment_t * adj
Definition: xwidget.h:334
_draw_button
void _draw_button(void *w_, void *user_data)
_draw_button - internal draw the button to the buffer
Definition: xbutton_private.c:191
use_fg_color_scheme
void use_fg_color_scheme(Widget_t *w, Color_state st)
use_fg_color_scheme - use forground Colors to paint on Widget_t
Definition: xcolor.c:178
Widget_t::scale
Resize_t scale
Definition: xwidget.h:356
_rounded_rectangle
void _rounded_rectangle(cairo_t *cr, float x, float y, float width, float height)
_rounded_rectangle - internal draw a rounded button
Definition: xbutton_private.c:25
_button_released
void _button_released(void *w_, void *button_, void *user_data)
_button_released - redraw the button and send state via user_callback
Definition: xbutton_private.c:394
_remove_low_dash
int _remove_low_dash(char *str)
Definition: xbutton_private.c:172
Widget_t::app
Xputty * app
Definition: xwidget.h:300
Xputty::dpy
Display * dpy
Definition: xputty.h:181
use_frame_color_scheme
void use_frame_color_scheme(Widget_t *w, Color_state st)
use_frame_color_scheme - use frame Colors to paint on Widget_t
Definition: xcolor.c:213
_draw_image_button
void _draw_image_button(Widget_t *w, int width_t, int height_t, float offset)
Definition: xbutton_private.c:57
Widget_t::state
int state
Definition: xwidget.h:342
Colors
Color_t - struct used to set cairo color for Widget_t.
Definition: xcolor.h:73
Resize_t::ascale
float ascale
Definition: xwidget.h:214
ACTIVE_
@ ACTIVE_
Definition: xcolor.h:42
_button_pressed
void _button_pressed(void *w_, void *button, void *user_data)
_button_pressed - redraw the button and send state via user_callback
Definition: xbutton_private.c:389
Widget_t::widget
Window widget
Definition: xwidget.h:302
Widget_t
Widget_t - struct to hold the basic Widget_t info.
Definition: xwidget.h:298
NORMAL_
@ NORMAL_
Definition: xcolor.h:39
PRELIGHT_
@ PRELIGHT_
Definition: xcolor.h:40
xbutton_private.h
Adjustment_t::max_value
float max_value
Definition: xadjustment.h:90
IS_UTF8
#define IS_UTF8(c)
IS_UTF8 - check if a char contain UTF 8 formated signs.
Definition: xputty.h:99
Widget_t::input_label
char input_label[32]
Definition: xwidget.h:328
Widget_t::adj_y
Adjustment_t * adj_y
Definition: xwidget.h:332
_draw_button_base
void _draw_button_base(Widget_t *w, int width, int height)
Definition: xbutton_private.c:129
get_color_scheme
Colors * get_color_scheme(Xputty *main, Color_state st)
get_color_scheme - get pointer to the Colors struct to use in relation to the Color_state
Definition: xcolor.c:130
_draw_switch_image_button
void _draw_switch_image_button(void *w_, void *user_data)
draw switch_image_button - internal draw the button to the buffer
Definition: xbutton_private.c:114
SELECTED_
@ SELECTED_
Definition: xcolor.h:41
Widget_t::label
const char * label
Definition: xwidget.h:326
Colors::light
double light[4]
Definition: xcolor.h:80
Adjustment_t::min_value
float min_value
Definition: xadjustment.h:88
Color_state
Color_state
Color_state - select color mode to use on Widget_t.
Definition: xcolor.h:38
_draw_check_box
void _draw_check_box(void *w_, void *user_data)
_draw_check_box - internal draw the check box to the buffer
Definition: xbutton_private.c:343