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 #include "xwidget_private.h"
22 
23 
_scroll_event(Widget_t * wid,int direction)24 void _scroll_event(Widget_t * wid, int direction) {
25     Adjustment_t *adj = NULL;
26     if (wid->adj_y) {
27         adj = wid->adj_y;
28     } else if(wid->adj_x) {
29         adj = wid->adj_x;
30     }
31     if (adj) {
32         float value = adj->value;
33         switch(adj->type) {
34             case (CL_LOGSCALE):
35             case (CL_LOGARITHMIC):
36             case (CL_CONTINUOS):
37                 value = min(adj->max_value,max(adj->min_value,
38                                 adj->value + (adj->step * direction)));
39             break;
40             case (CL_VIEWPORT):
41             case (CL_ENUM):
42                 value = min(adj->max_value,max(adj->min_value,
43                                 adj->value + (adj->step * -direction)));
44             break;
45             case (CL_TOGGLE):
46                // value = adj->value ? 1.0 : 0.0;
47             break;
48             default:
49             break;
50         }
51         check_value_changed(adj, &value);
52     }
53 }
54 
_toggle_event(Widget_t * wid)55 void _toggle_event(Widget_t * wid) {
56     Adjustment_t *adj = NULL;
57     if (wid->adj_y) {
58         adj = wid->adj_y;
59     } else if(wid->adj_x) {
60         adj = wid->adj_x;
61     }
62     if (adj && adj->type != CL_TOGGLE) {
63         adj_set_start_value(wid);
64     }
65 }
66 
_check_enum(Widget_t * wid,XButtonEvent * xbutton)67 void _check_enum(Widget_t * wid, XButtonEvent *xbutton) {
68     if (wid->flags & HAS_POINTER && xbutton->button == Button1) {
69         Adjustment_t *adj = NULL;
70         if (wid->adj_y) {
71             adj = wid->adj_y;
72         } else if(wid->adj_x) {
73             adj = wid->adj_x;
74         }
75         if (adj && adj->type == CL_ENUM) {
76             float value = adj->value;
77             value = adj->value + 1.0;
78             if (value>adj->max_value) value = adj->min_value;
79             check_value_changed(adj, &value);
80         }
81     }
82 }
83 
_button_press(Widget_t * wid,XButtonEvent * xbutton,void * user_data)84 void _button_press(Widget_t * wid, XButtonEvent *xbutton, void* user_data) {
85     switch(xbutton->button) {
86         case Button1:
87             wid->state = 2;
88             _has_pointer(wid, xbutton);
89             wid->pos_x = xbutton->x;
90             wid->pos_y = xbutton->y;
91             _toggle_event(wid);
92             wid->func.button_press_callback(wid, xbutton, user_data);
93         break;
94         case Button2:
95             debug_print("Button2 \n");
96         break;
97         case Button3:
98             debug_print("Button3 \n");
99             wid->func.button_press_callback(wid, xbutton, user_data);
100         break;
101         case  Button4:
102             _scroll_event(wid, 1);
103         break;
104         case Button5:
105             _scroll_event(wid, -1);
106         break;
107         default:
108         break;
109     }
110 }
111 
_check_grab(Widget_t * wid,XButtonEvent * xbutton,Xputty * main)112 void _check_grab(Widget_t * wid, XButtonEvent *xbutton, Xputty *main) {
113     if(main->hold_grab != NULL) {
114         Widget_t *view_port = main->hold_grab->childlist->childs[0];
115         if(xbutton->button == Button1) {
116             //if (xbutton->window == view_port->widget) return;
117             XUngrabPointer(main->dpy,CurrentTime);
118             int i = view_port->childlist->elem-1;
119             for(;i>-1;i--) {
120                 Widget_t *w = view_port->childlist->childs[i];
121                 if (xbutton->window == w->widget) {
122                     const char *l = view_port->childlist->childs[i]->label;
123                     main->hold_grab->func.button_release_callback
124                         (main->hold_grab, &i, &l);
125                     break;
126                 }
127             }
128             widget_hide(main->hold_grab);
129             main->hold_grab = NULL;
130 
131         } else if(xbutton->button == Button4) {
132             _scroll_event(view_port, 1);
133         } else if(xbutton->button == Button5) {
134             _scroll_event(view_port, -1);
135         }
136     }
137 }
138 
_propagate_child_expose(Widget_t * wid)139 void _propagate_child_expose(Widget_t *wid) {
140 
141     if (childlist_has_child(wid->childlist)) {
142         int i = 0;
143         for(;i<wid->childlist->elem;i++) {
144             Widget_t *w = wid->childlist->childs[i];
145             if (w->flags & USE_TRANSPARENCY) {
146                 if(w->flags & FAST_REDRAW)
147                     transparent_draw(w, NULL);
148                 else expose_widget(w);
149             }
150         }
151     }
152 }
153 
_check_keymap(void * w_,XKeyEvent xkey)154 void _check_keymap (void *w_ ,XKeyEvent xkey) {
155     Widget_t *wid = (Widget_t*)w_;
156     int n = 1;
157     int i = 0;
158     for(;i<wid->childlist->elem;i++) {
159         Widget_t *w = wid->childlist->childs[i];
160         if(w->flags & HAS_FOCUS && w->state != 4) {
161              wid=w;
162             break;
163         }
164     }
165     if(wid->app->hold_grab != NULL) {
166         wid = wid->app->hold_grab->childlist->childs[0];
167         n = -1;
168     }
169     int nk = key_mapping(wid->app->dpy, &xkey);
170     if (nk) {
171         switch (nk) {
172             case 3: _set_adj_value(wid, false, 1*n);
173             break;
174             case 4: _set_adj_value(wid, true, 1*n);
175             break;
176             case 5: _set_adj_value(wid, false, -1*n);
177             break;
178             case 6: _set_adj_value(wid, true, -1*n);
179             break;
180             case 10:
181             {
182                 int i = 0;
183                 for(;i<wid->childlist->elem;i++) {
184                     Widget_t *w = wid->childlist->childs[i];
185                     if(w->flags & HAS_FOCUS && w->state != 4) {
186                          wid=w;
187                         break;
188                     }
189                 }
190                 send_button_press_event(wid);
191                 send_button_release_event(wid);
192             }
193             break;
194             default:
195             break;
196         }
197     }
198 }
199 
_hide_all_tooltips(Widget_t * wid)200 void _hide_all_tooltips(Widget_t *wid) {
201     int i = 0;
202     for(;i<wid->app->childlist->elem;i++) {
203         Widget_t *w = wid->app->childlist->childs[i];
204         if (w->flags & IS_TOOLTIP) {
205             widget_hide(w);
206         }
207     }
208 }
209 
_has_pointer(Widget_t * w,XButtonEvent * button)210 void _has_pointer(Widget_t *w, XButtonEvent *button) {
211     XWindowAttributes attrs;
212     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
213 
214     if ((button->x<attrs.width && button->y<attrs.height) &&
215                                 (button->x>0 && button->y>0)){
216         w->flags |= HAS_POINTER;
217     } else {
218         w->flags &= ~HAS_POINTER;
219     }
220 }
221 
_set_adj_value(void * w_,bool x,int direction)222 void _set_adj_value(void *w_, bool x, int direction) {
223     Widget_t *wid = (Widget_t*)w_;
224     Adjustment_t *adj = NULL;
225     if (x && wid->adj_x) {
226         adj = wid->adj_x;
227     } else if (!x && wid->adj_y) {
228         adj = wid->adj_y;
229     }
230     if (adj) {
231         float value = min(adj->max_value,max(adj->min_value,
232         adj->value + (adj->step * direction)));
233         check_value_changed(adj, &value);
234     }
235 }
236 
_dummy1_callback(void * w_,void * _data,void * user_data)237 void _dummy1_callback(void *w_, void* _data, void* user_data) {
238     debug_print("Widget_t _dummy callback\n");
239 }
240 
_dummy_callback(void * w_,void * user_data)241 void _dummy_callback(void *w_, void* user_data) {
242     debug_print("Widget_t _dummy callback\n");
243 }
244 
_resize_surface(Widget_t * wid,int width,int height)245 void _resize_surface(Widget_t *wid, int width, int height) {
246     wid->width = width;
247     wid->height = height;
248     cairo_xlib_surface_set_size( wid->surface, wid->width, wid->height);
249     cairo_font_face_t *ff = cairo_get_font_face(wid->crb);
250     cairo_destroy(wid->crb);
251     cairo_surface_destroy(wid->buffer);
252     wid->buffer = cairo_surface_create_similar (wid->surface,
253                         CAIRO_CONTENT_COLOR_ALPHA, width, height);
254     assert(cairo_surface_status(wid->buffer) == CAIRO_STATUS_SUCCESS);
255     wid->crb = cairo_create (wid->buffer);
256     cairo_set_font_face(wid->crb, ff);
257 }
258 
_resize_childs(Widget_t * wid)259 void _resize_childs(Widget_t *wid) {
260     if(!childlist_has_child(wid->childlist)) return;
261     int i = 0;
262     for(;i<wid->childlist->elem;i++) {
263         Widget_t *w = wid->childlist->childs[i];
264         switch(w->scale.gravity) {
265             case(NORTHWEST):
266                 XResizeWindow (wid->app->dpy, w->widget, max(1,
267                     w->scale.init_width - (wid->scale.scale_x)),
268                     max(1,w->scale.init_height - (wid->scale.scale_y)));
269             break;
270             case(NORTHEAST):
271                 XResizeWindow (wid->app->dpy, w->widget, max(1,
272                     w->scale.init_width - (wid->scale.scale_x)), w->height);
273             break;
274             case(SOUTHWEST):
275                 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x-wid->scale.scale_x,
276                                         w->scale.init_y-wid->scale.scale_y);
277 
278             break;
279             case(SOUTHEAST):
280                 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x,
281                                             w->scale.init_y-wid->scale.scale_y);
282             break;
283             case(CENTER):
284                 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x /
285                     wid->scale.cscale_x,w->scale.init_y / wid->scale.cscale_y);
286                 XResizeWindow (wid->app->dpy, w->widget, max(1,
287                     w->scale.init_width / (wid->scale.cscale_x)),
288                     max(1,w->scale.init_height / (wid->scale.cscale_y)));
289             break;
290             case(ASPECT):
291                 XMoveWindow(wid->app->dpy,w->widget,(
292                     (w->scale.init_x + w->scale.init_width/2.0) /
293                     wid->scale.cscale_x) - w->width/2.0,
294                     ((w->scale.init_y + w->scale.init_height/2.0) /
295                     wid->scale.cscale_y)- w->height/2.0) ;
296                 XResizeWindow (wid->app->dpy, w->widget, max(1,
297                     w->scale.init_width / (wid->scale.ascale)),
298                     max(1,w->scale.init_height / (wid->scale.ascale)));
299 
300             break;
301             case(MENUITEM):
302                 XResizeWindow (wid->app->dpy, w->widget, max(1,
303                     w->scale.init_width - (wid->scale.scale_x)-5), w->scale.init_height);
304             break;
305             case(NONE):
306             break;
307             default:
308             break;
309         }
310         w->func.configure_notify_callback(w,NULL);
311     }
312 }
313