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_VIEWPORTSLIDER):
42 case (CL_ENUM):
43 value = min(adj->max_value,max(adj->min_value,
44 adj->value + (adj->step * -direction)));
45 break;
46 case (CL_TOGGLE):
47 // value = adj->value ? 1.0 : 0.0;
48 break;
49 default:
50 break;
51 }
52 check_value_changed(adj, &value);
53 }
54 }
55
_toggle_event(Widget_t * wid)56 void _toggle_event(Widget_t * wid) {
57 Adjustment_t *adj = NULL;
58 if (wid->adj_y) {
59 adj = wid->adj_y;
60 } else if(wid->adj_x) {
61 adj = wid->adj_x;
62 }
63 if (adj && adj->type != CL_TOGGLE) {
64 adj_set_start_value(wid);
65 }
66 }
67
_check_enum(Widget_t * wid,XButtonEvent * xbutton)68 void _check_enum(Widget_t * wid, XButtonEvent *xbutton) {
69 if (wid->flags & HAS_POINTER && xbutton->button == Button1) {
70 Adjustment_t *adj = NULL;
71 if (wid->adj_y) {
72 adj = wid->adj_y;
73 } else if(wid->adj_x) {
74 adj = wid->adj_x;
75 }
76 if (adj && adj->type == CL_ENUM) {
77 float value = adj->value;
78 value = adj->value + 1.0;
79 if (value>adj->max_value) value = adj->min_value;
80 check_value_changed(adj, &value);
81 }
82 }
83 }
84
_button_press(Widget_t * wid,XButtonEvent * xbutton,void * user_data)85 void _button_press(Widget_t * wid, XButtonEvent *xbutton, void* user_data) {
86 switch(xbutton->button) {
87 case Button1:
88 wid->state = 2;
89 _has_pointer(wid, xbutton);
90 wid->pos_x = xbutton->x;
91 wid->pos_y = xbutton->y;
92 _toggle_event(wid);
93 wid->func.button_press_callback(wid, xbutton, user_data);
94 break;
95 case Button2:
96 debug_print("Button2 \n");
97 _has_pointer(wid, xbutton);
98 wid->func.button_press_callback(wid, xbutton, user_data);
99 break;
100 case Button3:
101 debug_print("Button3 \n");
102 _has_pointer(wid, xbutton);
103 wid->func.button_press_callback(wid, xbutton, user_data);
104 break;
105 case Button4:
106 _scroll_event(wid, 1);
107 break;
108 case Button5:
109 _scroll_event(wid, -1);
110 break;
111 default:
112 break;
113 }
114 }
115
_check_grab(Widget_t * wid,XButtonEvent * xbutton,Xputty * main)116 void _check_grab(Widget_t * wid, XButtonEvent *xbutton, Xputty *main) {
117 if(main->hold_grab != NULL) {
118 if (childlist_has_child(main->hold_grab->childlist)) {
119 Widget_t *slider = main->hold_grab->childlist->childs[1];
120 if (xbutton->window == slider->widget) {
121 return;
122 }
123 }
124 Widget_t *view_port = main->hold_grab->childlist->childs[0];
125 if(xbutton->button == Button1) {
126 //if (xbutton->window == view_port->widget) return;
127 XUngrabPointer(main->dpy,CurrentTime);
128 int i = view_port->childlist->elem-1;
129 for(;i>-1;i--) {
130 Widget_t *w = view_port->childlist->childs[i];
131 if (xbutton->window == w->widget) {
132 const char *l = view_port->childlist->childs[i]->label;
133 main->hold_grab->func.button_release_callback
134 (main->hold_grab, &i, &l);
135 break;
136 }
137 }
138 widget_hide(main->hold_grab);
139 main->hold_grab = NULL;
140
141 } /*else if(xbutton->button == Button4) {
142 _scroll_event(view_port, 1);
143 } else if(xbutton->button == Button5) {
144 _scroll_event(view_port, -1);
145 }*/ // done in _button_press() anyway
146 }
147 }
148
_check_submenu(Widget_t * wid,XButtonEvent * xbutton,Xputty * main)149 void _check_submenu(Widget_t * wid, XButtonEvent *xbutton, Xputty *main) {
150 if(main->submenu != NULL) {
151 Widget_t *view_port = main->submenu->childlist->childs[0];
152 if(xbutton->button == Button1) {
153 //if (xbutton->window == view_port->widget) return;
154 int i = view_port->childlist->elem-1;
155 for(;i>-1;i--) {
156 Widget_t *w = view_port->childlist->childs[i];
157 if (xbutton->window == w->widget) {
158 const char *l = view_port->childlist->childs[i]->label;
159 main->submenu->func.button_release_callback
160 (main->submenu, &i, &l);
161 break;
162 }
163 }
164 widget_hide(main->submenu);
165 main->submenu = NULL;
166
167 } else if(xbutton->button == Button4) {
168 _scroll_event(view_port, 1);
169 } else if(xbutton->button == Button5) {
170 _scroll_event(view_port, -1);
171 }
172 }
173 }
174
_propagate_child_expose(Widget_t * wid)175 void _propagate_child_expose(Widget_t *wid) {
176
177 if (childlist_has_child(wid->childlist)) {
178 int i = 0;
179 for(;i<wid->childlist->elem;i++) {
180 Widget_t *w = wid->childlist->childs[i];
181 if ( w->flags & NO_PROPAGATE) continue;
182 if (w->flags & USE_TRANSPARENCY) {
183 if(w->flags & FAST_REDRAW)
184 transparent_draw(w, NULL);
185 else expose_widget(w);
186 }
187 }
188 }
189 }
190
_check_keymap(void * w_,XKeyEvent xkey)191 void _check_keymap (void *w_ ,XKeyEvent xkey) {
192 Widget_t *wid = (Widget_t*)w_;
193 int n = 1;
194 int i = 0;
195 for(;i<wid->childlist->elem;i++) {
196 Widget_t *w = wid->childlist->childs[i];
197 if(w->flags & HAS_FOCUS && w->state != 4) {
198 wid=w;
199 break;
200 }
201 }
202 if(wid->app->hold_grab != NULL) {
203 wid = wid->app->hold_grab->childlist->childs[0];
204 n = -1;
205 }
206 int nk = key_mapping(wid->app->dpy, &xkey);
207 if (nk) {
208 switch (nk) {
209 case 3: _set_adj_value(wid, false, 1*n);
210 break;
211 case 4: _set_adj_value(wid, true, 1*n);
212 break;
213 case 5: _set_adj_value(wid, false, -1*n);
214 break;
215 case 6: _set_adj_value(wid, true, -1*n);
216 break;
217 case 10:
218 {
219 int i = 0;
220 for(;i<wid->childlist->elem;i++) {
221 Widget_t *w = wid->childlist->childs[i];
222 if(w->flags & HAS_FOCUS && w->state != 4) {
223 wid=w;
224 break;
225 }
226 }
227 send_button_press_event(wid);
228 send_button_release_event(wid);
229 }
230 break;
231 default:
232 break;
233 }
234 }
235 }
236
_hide_all_tooltips(Widget_t * wid)237 void _hide_all_tooltips(Widget_t *wid) {
238 int i = 0;
239 for(;i<wid->app->childlist->elem;i++) {
240 Widget_t *w = wid->app->childlist->childs[i];
241 if (w->flags & IS_TOOLTIP) {
242 widget_hide(w);
243 }
244 }
245 }
246
_has_pointer(Widget_t * w,XButtonEvent * button)247 void _has_pointer(Widget_t *w, XButtonEvent *button) {
248 XWindowAttributes attrs;
249 XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
250
251 if ((button->x<attrs.width && button->y<attrs.height) &&
252 (button->x>0 && button->y>0)){
253 w->flags |= HAS_POINTER;
254 } else {
255 w->flags &= ~HAS_POINTER;
256 }
257 }
258
_set_adj_value(void * w_,bool x,int direction)259 void _set_adj_value(void *w_, bool x, int direction) {
260 Widget_t *wid = (Widget_t*)w_;
261 Adjustment_t *adj = NULL;
262 if (x && wid->adj_x) {
263 adj = wid->adj_x;
264 } else if (!x && wid->adj_y) {
265 adj = wid->adj_y;
266 }
267 if (adj) {
268 float value = adj->value;
269 switch(adj->type) {
270 case (CL_VIEWPORT):
271 case (CL_VIEWPORTSLIDER):
272 value = min(adj->max_value,max(adj->min_value,
273 adj->value + (adj->step * -direction)));
274 break;
275 default:
276 value = min(adj->max_value,max(adj->min_value,
277 adj->value + (adj->step * direction)));
278 break;
279 }
280 check_value_changed(adj, &value);
281 }
282 }
283
_dummy1_callback(void * w_,void * _data,void * user_data)284 void _dummy1_callback(void *w_, void* _data, void* user_data) {
285 debug_print("Widget_t _dummy callback\n");
286 }
287
_dummy_callback(void * w_,void * user_data)288 void _dummy_callback(void *w_, void* user_data) {
289 debug_print("Widget_t _dummy callback\n");
290 }
291
_resize_surface(Widget_t * wid,int width,int height)292 void _resize_surface(Widget_t *wid, int width, int height) {
293 wid->width = width;
294 wid->height = height;
295 cairo_xlib_surface_set_size( wid->surface, wid->width, wid->height);
296 cairo_font_face_t *ff = cairo_get_font_face(wid->crb);
297 cairo_destroy(wid->crb);
298 cairo_surface_destroy(wid->buffer);
299 wid->buffer = cairo_surface_create_similar (wid->surface,
300 CAIRO_CONTENT_COLOR_ALPHA, width, height);
301 assert(cairo_surface_status(wid->buffer) == CAIRO_STATUS_SUCCESS);
302 wid->crb = cairo_create (wid->buffer);
303 cairo_set_font_face(wid->crb, ff);
304 }
305
_resize_childs(Widget_t * wid)306 void _resize_childs(Widget_t *wid) {
307 if(!childlist_has_child(wid->childlist)) return;
308 int i = 0;
309 for(;i<wid->childlist->elem;i++) {
310 Widget_t *w = wid->childlist->childs[i];
311 switch(w->scale.gravity) {
312 case(NORTHWEST):
313 XResizeWindow (wid->app->dpy, w->widget, max(1,
314 w->scale.init_width - (wid->scale.scale_x)),
315 max(1,w->scale.init_height - (wid->scale.scale_y)));
316 break;
317 case(NORTHEAST):
318 XResizeWindow (wid->app->dpy, w->widget, max(1,
319 w->scale.init_width - (wid->scale.scale_x)), w->height);
320 break;
321 case(SOUTHWEST):
322 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x-wid->scale.scale_x,
323 w->scale.init_y-wid->scale.scale_y);
324 break;
325 case(SOUTHEAST):
326 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x,
327 w->scale.init_y-wid->scale.scale_y);
328 case(SOUTHCENTER):
329 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x,
330 w->scale.init_y / wid->scale.cscale_y);
331 XResizeWindow (wid->app->dpy, w->widget, max(1,
332 w->scale.init_width - (wid->scale.scale_x)),
333 max(1,w->scale.init_height / (wid->scale.cscale_y)));
334 break;
335 case(EASTWEST):
336 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x,
337 w->scale.init_y-wid->scale.scale_y);
338 break;
339 case(EASTNORTH):
340 XResizeWindow (wid->app->dpy, w->widget, w->scale.init_width,
341 max(1,w->scale.init_height - (wid->scale.scale_y)));
342 break;
343 case(WESTNORTH):
344 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x-wid->scale.scale_x,
345 w->scale.init_y);
346 break;
347 case(WESTSOUTH):
348 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x-wid->scale.scale_x,
349 w->scale.init_y);
350 XResizeWindow (wid->app->dpy, w->widget, w->scale.init_width,
351 max(1,w->scale.init_height - (wid->scale.scale_y)));
352 break;
353 case(CENTER):
354 XMoveWindow(wid->app->dpy,w->widget,w->scale.init_x /
355 wid->scale.cscale_x,w->scale.init_y / wid->scale.cscale_y);
356 XResizeWindow (wid->app->dpy, w->widget, max(1,
357 w->scale.init_width / (wid->scale.cscale_x)),
358 max(1,w->scale.init_height / (wid->scale.cscale_y)));
359 break;
360 case(ASPECT):
361 XMoveWindow(wid->app->dpy,w->widget,(
362 (w->scale.init_x + w->scale.init_width*0.5) /
363 wid->scale.cscale_x) - w->width*0.5,
364 ((w->scale.init_y + w->scale.init_height*0.5) /
365 wid->scale.cscale_y)- w->height*0.5) ;
366 XResizeWindow (wid->app->dpy, w->widget, max(1,
367 w->scale.init_width / (wid->scale.ascale)),
368 max(1,w->scale.init_height / (wid->scale.ascale)));
369 break;
370 case(FIXEDSIZE):
371 XMoveWindow(wid->app->dpy,w->widget,(
372 (w->scale.init_x + w->scale.init_width*0.5) /
373 wid->scale.cscale_x) - w->width*0.5,
374 ((w->scale.init_y + w->scale.init_height*0.5) /
375 wid->scale.cscale_y)- w->height*0.5) ;
376 break;
377 case(MENUITEM):
378 XResizeWindow (wid->app->dpy, w->widget, max(1,
379 w->scale.init_width - (wid->scale.scale_x)-5), w->scale.init_height);
380 break;
381 case(NONE):
382 break;
383 default:
384 break;
385 }
386 w->func.configure_notify_callback(w,NULL);
387 }
388 }
389