1 // widget-helper.c
2 // LiVES
3 // (c) G. Finch 2012 - 2020 <salsaman+lives@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING or www.gnu.org for licensing details
6 
7 #define NEED_DEF_WIDGET_OPTS
8 
9 #include "main.h"
10 
11 // The idea here is to replace toolkit specific functions with generic ones
12 
13 // TODO - replace as much code in the other files with these functions as possible
14 
15 // TODO - add for other toolkits, e.g. qt
16 
17 // static defns
18 
19 #define EV_LIM 64
20 
21 static void set_child_colour_internal(LiVESWidget *, livespointer set_allx);
22 static void set_child_alt_colour_internal(LiVESWidget *, livespointer set_allx);
23 static boolean governor_loop(livespointer data) GNU_RETURNS_TWICE;
24 static void async_sig_handler(livespointer instance, livespointer data);
25 
26 typedef void (*bifunc)(livespointer, livespointer);
27 typedef boolean(*trifunc)(livespointer, livespointer, livespointer);
28 static void sigdata_free(livespointer, LiVESWidgetClosure *);
29 
30 static boolean show_css = FALSE;
31 
32 #ifdef GUI_GTK
33 boolean set_css_value_direct(LiVESWidget *, LiVESWidgetState state, const char *selector,
34                              const char *detail, const char *value);
35 #endif
36 
37 #define NSLEEP_TIME 500
38 
39 /// internal data keys
40 #define STD_KEY "_wh_is_standard"
41 #define BACCL_GROUP_KEY "_wh_baccl_group"
42 #define BACCL_ACCL_KEY "_wh_baccl_accl"
43 #define TTIPS_KEY "_wh_lives_tooltips"
44 #define TTIPS_OVERRIDE_KEY "_wh_lives_tooltips_override"
45 #define TTIPS_HIDE_KEY "_wh_lives_tooltips_hide"
46 #define HAS_TTIPS_IMAGE_KEY "_wh_has_ttips_image"
47 #define TTIPS_IMAGE_KEY "_wh_ttips_image"
48 #define WARN_IMAGE_KEY "_wh_warn_image"
49 #define SHOWALL_OVERRIDE_KEY "_wh_lives_showall_override"
50 #define SHOWHIDE_CONTROLLER_KEY "_wh_lives_showhide_controller"
51 #define ROWS_KEY "_wh_rows"
52 #define COLS_KEY "_wh_cols"
53 #define CDEF_KEY "_wh_current_default"
54 #define DEFBUTTON_KEY "_wh_default_button"
55 #define DEFOVERRIDE_KEY "_wh_default_override"
56 #define EXP_LIST_KEY "_wh_expansion_list"
57 #define LROW_KEY "_wh_layout_row"
58 #define EXPANSION_KEY "_wh_expansion"
59 #define JUST_KEY "_wh_justification"
60 #define WADDED_KEY "_wh_widgets_added"
61 #define NWIDTH_KEY "_wh_normal_width"
62 #define FBUTT_KEY "_wh_first_button"
63 #define ISLOCKED_KEY "_wh_is_locked"
64 #define CBUTTON_KEY "_wh_cbutton"
65 #define SPRED_KEY "_wh_sp_red"
66 #define SPGREEN_KEY "_wh_sp_green"
67 #define SPBLUE_KEY "_wh_sp_blue"
68 #define SPALPHA_KEY "_wh_sp_alpha"
69 #define THEME_KEY "_wh_theme"
70 
71 #define SBUTT_SURFACE_KEY "_sbutt_surf"
72 #define SBUTT_TXT_KEY "_sbutt_txt"
73 #define SBUTT_LAYOUT_KEY "_sbutt_layout"
74 #define SBUTT_LW_KEY "_sbutt_lw"
75 #define SBUTT_LH_KEY "_sbutt_lh"
76 #define SBUTT_PIXBUF_KEY "_sbutt_pixbuf"
77 #define SBUTT_FORCEIMG_KEY "_sbutt_forceimg"
78 #define SBUTT_FAKEDEF_KEY "_sbutt_fakedef"
79 
80 static LiVESWindow *modalw = NULL;
81 
82 #if 0
83 weed_plant_t *LiVESWidgetObject_to_weed_plant(LiVESWidgetObject *o) {
84   int nprops;
85   GParamSpec **pspec;
86   GObjectClass oclass;
87   weed_plant_t *plant;
88 
89   if (!o || !G_IS_OBJECT(o)) return NULL;
90 
91   plant = weed_plant_new(WEED_PLANT_LIVES);
92   weed_set_int_value(plant, WEED_LEAF_LIVES_SUBTYPE, LIVES_WEED_SUBTYPE_WIDGET);
93 
94   oclass = G_OBJECT_GET_CLASS(o);
95 
96   // get all the properties
97   pspec = g_object_class_list_properties(oclass, &nprops);
98   // also g_object_interface_list_properties
99 
100   if (nprops > 0) {
101     GType gtype;
102     weed_plant_t **params = (weed_plant_t **)lives_malloc(nprops * sizeof(weed_plant_t *));
103     for (i = 0; i < nprops; i++) {
104       // check pspec[i]->flags (G_PARAM_READABLE, G_PARAM_WRITABLE...)
105       // if (!G_PARAM_EXPLICIT_NOTIFY), we can hook to the notify signal to shadow it
106       //
107 
108       params[i] = weed_plant_new(WEED_PLANT_PARAMETER);
109       weed_set_string_value(params[i], WEED_LEAF_NAME, g_param_spec_get_name(pspec[i]));
110       gtype = G_PARAM_SPEC_VALUE_TYPE(pspec[i]);
111       switch (gtype) {
112       case G_TYPE_STRING:
113       case G_TYPE_CHAR:
114       case G_TYPE_UCHAR:
115         // WEED_SEED_STRING
116         break;
117       case G_TYPE_FLOAT:
118       case G_TYPE_DOUBLE:
119         // WEED_SEED_DOUBLE
120         break;
121       case G_TYPE_INT:
122       case G_TYPE_FLAGS:
123       case G_TYPE_ENUM:
124       case G_TYPE_UINT: {
125         int ival;
126         g_object_get(o, name, &ival, NULL);
127         //g_object_set(o, name, ival, NULL);
128         weed_set_int_value(params[i], WEED_LEAF_VALUE, ival);
129         break;
130       }
131       case G_TYPE_BOOLEAN:
132         // WEED_SEED_BOOLEAN
133         break;
134       case G_TYPE_INT64:
135       case G_TYPE_UINT64:
136       case G_TYPE_LONG:
137       case G_TYPE_ULONG:
138         // WEED_SEED_INT64
139         break;
140       case G_TYPE_POINTER:
141         // WEED_SEED_VOIDPTR
142         break;
143       default:
144         break;
145       }
146     }
147     params[num_params] = NULL;
148     weed_set_plantptr_array(plant, WEED_LEAF_IN_PARAMETERS, nprops, params);
149   }
150 }
151 #endif
152 
153 
is_standard_widget(LiVESWidget * widget)154 WIDGET_HELPER_GLOBAL_INLINE boolean is_standard_widget(LiVESWidget *widget) {
155   livespointer val;
156   if (!(val = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), STD_KEY))) return FALSE;
157   return (LIVES_POINTER_TO_INT(val));
158 }
159 
set_standard_widget(LiVESWidget * widget,boolean is)160 WIDGET_HELPER_LOCAL_INLINE void set_standard_widget(LiVESWidget *widget, boolean is) {
161   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), STD_KEY, LIVES_INT_TO_POINTER(is));
162 }
163 
164 
edit_state_cb(LiVESWidgetObject * object,livespointer pspec,livespointer user_data)165 static void edit_state_cb(LiVESWidgetObject *object, livespointer pspec, livespointer user_data) {
166   LiVESWidget *entry = LIVES_WIDGET(object);
167   if (lives_entry_get_editable(LIVES_ENTRY(object))) {
168     lives_widget_apply_theme3(entry, LIVES_WIDGET_STATE_NORMAL);
169   } else {
170     lives_widget_apply_theme2(entry, LIVES_WIDGET_STATE_NORMAL, TRUE);
171   }
172 }
173 
174 
175 #if !GTK_CHECK_VERSION(3, 16, 0)
widget_state_cb(LiVESWidgetObject * object,livespointer pspec,livespointer user_data)176 static boolean widget_state_cb(LiVESWidgetObject *object, livespointer pspec, livespointer user_data) {
177   // This callback is here because:
178   //
179   // a) cannot alter the text colour of a button after the initial draw of a button
180   // this is because it doesnt have a proper label widget
181   // we can only change the background colour, so here we change the border colour via updating the parent container
182 
183   // note: if we need a button with changable text colour we must use a toolbar button instead !
184   //
185   // b) CSS appears broken in gtk+ 3.18.9 and possibly other versions, preventing seeting of colours for
186   // non-default states (e.g. insensitive)
187   // thus we need to set a callback to listen to "sensitive" changes, and update the colours in response
188   //
189   // c) it is also easier just to set the CSS colours when the widget state changes than to figure out ahead of time
190   //     what the colours should be for each state. Hopefully it doesn't add too much overhead listening for sensitivity
191   //     changes and then updating the CSS manually.
192   //
193   LiVESWidget *widget = (LiVESWidget *)object;
194   LiVESWidgetState state;
195   int woat = widget_opts.apply_theme;
196 
197   if (LIVES_IS_PLAYING || !mainw->is_ready) return FALSE;
198 
199   widget_opts.apply_theme = 1;
200 
201   state = lives_widget_get_state(widget);
202 
203   if (LIVES_IS_TOOL_BUTTON(widget)) {
204     LiVESWidget *label;
205     LiVESWidget *icon = gtk_tool_button_get_icon_widget(LIVES_TOOL_BUTTON(widget));
206     if (icon) {
207       // if we have an icon (no label) just update the border
208       lives_tool_button_set_border_color(widget, state, &palette->menu_and_bars);
209       widget_opts.apply_theme = woat;
210       return FALSE;
211     }
212     label = gtk_tool_button_get_label_widget(LIVES_TOOL_BUTTON(widget));
213     if (label) {
214       float dimval;
215       LiVESWidgetColor dimmed_fg;
216       LiVESList *list, *olist;
217       // if we have a label we CAN set the text colours for TOOL_buttons
218       // as well as the outline colour
219       if (!lives_widget_is_sensitive(widget)) {
220         dimval = (0.2 * 65535.);
221         lives_widget_color_copy(&dimmed_fg, &palette->normal_fore);
222         lives_widget_color_mix(&dimmed_fg, &palette->normal_back, (float)dimval / 65535.);
223         lives_tool_button_set_border_color(widget, state, &dimmed_fg);
224         lives_widget_apply_theme_dimmed2(label, state, BUTTON_DIM_VAL);
225       } else {
226         dimval = (0.6 * 65535.);
227         lives_widget_color_copy(&dimmed_fg, &palette->normal_fore);
228         lives_widget_color_mix(&dimmed_fg, &palette->normal_back, (float)dimval / 65535.);
229         lives_tool_button_set_border_color(widget, state, &dimmed_fg);
230         lives_widget_apply_theme2(label, state, TRUE);
231       }
232       // menutoolbuttons will also have an arrow
233       // since CSS selectors are borked we have to find it by brute force
234       olist = list = lives_container_get_children(LIVES_CONTAINER(widget));
235       while (list) {
236         widget = (LiVESWidget *)list->data;
237         if (LIVES_IS_VBOX(widget)) {
238           lives_widget_set_bg_color(widget, state, &palette->menu_and_bars);
239         }
240         list = list->next;
241       }
242       lives_list_free(olist);
243       widget_opts.apply_theme = woat;
244       return FALSE;
245     }
246   }
247 
248   if (LIVES_IS_LABEL(widget)) {
249     // other widgets get dimmed text
250     int themetype = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), THEME_KEY));
251     if (themetype == 2) {
252       if (!lives_widget_is_sensitive(widget)) {
253         set_child_dimmed_colour2(widget, BUTTON_DIM_VAL); // insens, themecols 1, child only
254       } else set_child_alt_colour(widget, TRUE);
255     } else {
256       if (!lives_widget_is_sensitive(widget)) {
257         set_child_dimmed_colour(widget, BUTTON_DIM_VAL); // insens, themecols 1, child only
258       } else set_child_colour(widget, TRUE);
259     }
260   }
261 
262   if (LIVES_IS_ENTRY(widget) || LIVES_IS_COMBO(widget)) {
263     // other widgets get dimmed text
264     if (!lives_widget_is_sensitive(widget)) {
265       set_child_dimmed_colour2(widget, BUTTON_DIM_VAL); // insens, themecols 1, child only
266       lives_widget_apply_theme_dimmed2(widget, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
267     } else {
268       if (LIVES_IS_ENTRY(widget) && !LIVES_IS_SPIN_BUTTON(widget))
269         edit_state_cb(LIVES_WIDGET_OBJECT(widget), NULL, NULL);
270       else {
271         if (LIVES_IS_COMBO(widget)) {
272           LiVESWidget *entry = lives_combo_get_entry(LIVES_COMBO(widget));
273           lives_widget_apply_theme2(entry, LIVES_WIDGET_STATE_NORMAL, TRUE);
274           lives_widget_apply_theme2(widget, LIVES_WIDGET_STATE_NORMAL, TRUE);
275         } else set_child_colour(widget, TRUE);
276       }
277     }
278   }
279   widget_opts.apply_theme = woat;
280   return FALSE;
281 }
282 #endif
283 
284 
lives_widget_object_set_data_auto(LiVESWidgetObject * obj,const char * key,livespointer data)285 WIDGET_HELPER_GLOBAL_INLINE void lives_widget_object_set_data_auto(LiVESWidgetObject *obj, const char *key, livespointer data) {
286   lives_widget_object_set_data_full(obj, key, data, lives_free);
287 }
288 
289 /// needed because lives_list_free() is a macro
lives_list_free_cb(livespointer list)290 static void lives_list_free_cb(livespointer list) {lives_list_free((LiVESList *)list);}
291 
lives_widget_object_set_data_list(LiVESWidgetObject * obj,const char * key,LiVESList * list)292 WIDGET_HELPER_GLOBAL_INLINE void lives_widget_object_set_data_list(LiVESWidgetObject *obj, const char *key, LiVESList *list) {
293   lives_widget_object_set_data_full(obj, key, list, lives_list_free_cb);
294 }
295 
lives_widget_object_unref_cb(livespointer obj)296 static void lives_widget_object_unref_cb(livespointer obj) {lives_widget_object_unref((LiVESWidgetObject *)obj);}
297 
lives_widget_object_set_data_widget_object(LiVESWidgetObject * obj,const char * key,livespointer other)298 WIDGET_HELPER_GLOBAL_INLINE void lives_widget_object_set_data_widget_object(LiVESWidgetObject *obj, const char *key,
299     livespointer other) {
300   lives_widget_object_set_data_full(obj, key, other, lives_widget_object_unref_cb);
301 }
302 
303 
304 // basic functions
305 
306 ////////////////////////////////////////////////////
307 //lives_painter functions
308 
lives_painter_create_from_surface(lives_painter_surface_t * target)309 WIDGET_HELPER_GLOBAL_INLINE lives_painter_t *lives_painter_create_from_surface(lives_painter_surface_t *target) {
310   lives_painter_t *cr = NULL;
311 #ifdef LIVES_PAINTER_IS_CAIRO
312   cr = cairo_create(target);
313 #endif
314 #ifdef PAINTER_QPAINTER
315   cr = new lives_painter_t(target);
316 #endif
317   return cr;
318 }
319 
320 
lives_painter_set_source_pixbuf(lives_painter_t * cr,const LiVESPixbuf * pixbuf,double pixbuf_x,double pixbuf_y)321 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_source_pixbuf(lives_painter_t *cr, const LiVESPixbuf *pixbuf,
322     double pixbuf_x,
323     double pixbuf_y) {
324   // blit pixbuf to cairo at x,y
325 #ifdef LIVES_PAINTER_IS_CAIRO
326   gdk_cairo_set_source_pixbuf(cr, pixbuf, pixbuf_x, pixbuf_y);
327   return TRUE;
328 #endif
329 #ifdef PAINTER_QPAINTER
330   QPointF qp(pixbuf_x, pixbuf_y);
331   const QImage *qi = (const QImage *)pixbuf;
332   cr->drawImage(qp, *qi);
333   return TRUE;
334 #endif
335   return FALSE;
336 }
337 
338 
lives_painter_set_source_surface(lives_painter_t * cr,lives_painter_surface_t * surface,double x,double y)339 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_source_surface(lives_painter_t *cr, lives_painter_surface_t *surface,
340     double x,
341     double y) {
342 #ifdef LIVES_PAINTER_IS_CAIRO
343   cairo_set_source_surface(cr, surface, x, y);
344   return TRUE;
345 #endif
346 #ifdef PAINTER_QPAINTER
347   QPointF qp(x, y);
348   cr->drawImage(qp, *surface);
349   return TRUE;
350 #endif
351   return FALSE;
352 }
353 
354 
lives_painter_paint(lives_painter_t * cr)355 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_paint(lives_painter_t *cr) {
356 #ifdef LIVES_PAINTER_IS_CAIRO
357   cairo_paint(cr);
358   return TRUE;
359 #endif
360 #ifdef PAINTER_QPAINTER
361   return TRUE;
362 #endif
363   return FALSE;
364 }
365 
366 
lives_painter_fill(lives_painter_t * cr)367 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_fill(lives_painter_t *cr) {
368 #ifdef LIVES_PAINTER_IS_CAIRO
369   cairo_fill(cr);
370   return TRUE;
371 #endif
372 #ifdef PAINTER_QPAINTER
373   cr->fillPath(*(cr->p), cr->pen.color());
374   delete cr->p;
375   cr->p = new QPainterPath;
376   return TRUE;
377 #endif
378   return FALSE;
379 }
380 
381 
lives_painter_stroke(lives_painter_t * cr)382 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_stroke(lives_painter_t *cr) {
383 #ifdef LIVES_PAINTER_IS_CAIRO
384   cairo_stroke(cr);
385   return TRUE;
386 #endif
387 #ifdef PAINTER_QPAINTER
388   cr->strokePath(*(cr->p), cr->pen);
389   delete cr->p;
390   cr->p = new QPainterPath;
391   return TRUE;
392 #endif
393   return FALSE;
394 }
395 
396 
lives_painter_clip(lives_painter_t * cr)397 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_clip(lives_painter_t *cr) {
398 #ifdef LIVES_PAINTER_IS_CAIRO
399   cairo_clip(cr);
400   return TRUE;
401 #endif
402 #ifdef PAINTER_QPAINTER
403   cr->setClipPath(*(cr->p), Qt::IntersectClip);
404   delete cr->p;
405   cr->p = new QPainterPath;
406   return TRUE;
407 #endif
408   return FALSE;
409 }
410 
411 
lives_painter_destroy(lives_painter_t * cr)412 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_destroy(lives_painter_t *cr) {
413 #ifdef LIVES_PAINTER_IS_CAIRO
414   cairo_destroy(cr);
415   return TRUE;
416 #endif
417 #ifdef PAINTER_QPAINTER
418   cr->end();
419   delete cr;
420   return TRUE;
421 #endif
422   return FALSE;
423 }
424 
425 
lives_painter_render_background(LiVESWidget * widget,lives_painter_t * cr,double x,double y,double width,double height)426 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_render_background(LiVESWidget *widget, lives_painter_t *cr, double x,
427     double y, double width, double height) {
428 #ifdef LIVES_PAINTER_IS_CAIRO
429   if (widget == mainw->play_image && mainw->multitrack) {
430     if (prefs->dev_show_dabg)
431       lives_painter_set_source_rgb_from_lives_widget_color(cr, &palette->dark_orange);
432     else
433       lives_painter_set_source_rgb_from_lives_widget_color(cr, &palette->black);
434   } else {
435     if (LIVES_IS_PLAYING && mainw->faded) {
436       if (prefs->dev_show_dabg)
437         lives_painter_set_source_rgb_from_lives_widget_color(cr, &palette->light_green);
438       else
439         lives_painter_set_source_rgb_from_lives_widget_color(cr, &palette->fade_colour);
440     } else {
441       if (prefs->dev_show_dabg)
442         lives_painter_set_source_rgb_from_lives_widget_color(cr, &palette->dark_red);
443       else
444         lives_painter_set_source_rgb_from_lives_widget_color(cr, &palette->normal_back);
445     }
446   }
447   lives_painter_rectangle(cr, x, y, width, height);
448   lives_painter_fill(cr);
449   lives_widget_queue_draw(widget);
450   return TRUE;
451 #endif /// painter cairo
452   return FALSE;
453 }
454 
455 
456 
lives_painter_surface_destroy(lives_painter_surface_t * surf)457 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_surface_destroy(lives_painter_surface_t *surf) {
458 #ifdef LIVES_PAINTER_IS_CAIRO
459   cairo_surface_destroy(surf);
460   return TRUE;
461 #endif
462 #ifdef PAINTER_QPAINTER
463   surf->dec_refcount();
464   return TRUE;
465 #endif
466   return FALSE;
467 }
468 
469 
lives_painter_surface_reference(lives_painter_surface_t * surf)470 WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t *lives_painter_surface_reference(lives_painter_surface_t *surf) {
471 #ifdef LIVES_PAINTER_IS_CAIRO
472   return cairo_surface_reference(surf);
473 #endif
474   return NULL;
475 }
476 
477 
lives_painter_new_path(lives_painter_t * cr)478 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_new_path(lives_painter_t *cr) {
479 #ifdef LIVES_PAINTER_IS_CAIRO
480   cairo_new_path(cr);
481   return TRUE;
482 #endif
483 #ifdef PAINTER_QPAINTER
484   delete cr->p;
485   cr->p = new QPainterPath;
486   return TRUE;
487 #endif
488   return FALSE;
489 }
490 
491 
lives_painter_translate(lives_painter_t * cr,double x,double y)492 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_translate(lives_painter_t *cr, double x, double y) {
493 #ifdef LIVES_PAINTER_IS_CAIRO
494   cairo_translate(cr, x, y);
495   return TRUE;
496 #endif
497 #ifdef PAINTER_QPAINTER
498   QTransform qt;
499   qt.translate(x, y);
500   cr->setTransform(qt, true);
501   return TRUE;
502 #endif
503   return FALSE;
504 }
505 
506 
lives_painter_set_line_width(lives_painter_t * cr,double width)507 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_line_width(lives_painter_t *cr, double width) {
508 #ifdef LIVES_PAINTER_IS_CAIRO
509   cairo_set_line_width(cr, width);
510   return TRUE;
511 #endif
512 #ifdef PAINTER_QPAINTER
513   cr->pen.setWidthF(width);
514   return TRUE;
515 #endif
516   return FALSE;
517 }
518 
519 
lives_painter_move_to(lives_painter_t * cr,double x,double y)520 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_move_to(lives_painter_t *cr, double x, double y) {
521 #ifdef LIVES_PAINTER_IS_CAIRO
522   cairo_move_to(cr, x, y);
523   return TRUE;
524 #endif
525 #ifdef PAINTER_QPAINTER
526   cr->p->moveTo(x, y);
527   return TRUE;
528 #endif
529   return FALSE;
530 }
531 
532 
lives_painter_line_to(lives_painter_t * cr,double x,double y)533 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_line_to(lives_painter_t *cr, double x, double y) {
534 #ifdef LIVES_PAINTER_IS_CAIRO
535   cairo_line_to(cr, x, y);
536   return TRUE;
537 #endif
538 #ifdef PAINTER_QPAINTER
539   cr->p->lineTo(x, y);
540   return TRUE;
541 #endif
542   return FALSE;
543 }
544 
545 
lives_painter_close_path(lives_painter_t * cr)546 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_close_path(lives_painter_t *cr) {
547 #ifdef LIVES_PAINTER_IS_CAIRO
548   cairo_close_path(cr);
549   return TRUE;
550 #endif
551   return FALSE;
552 }
553 
554 
lives_painter_rectangle(lives_painter_t * cr,double x,double y,double width,double height)555 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_rectangle(lives_painter_t *cr, double x, double y, double width,
556     double height) {
557 #ifdef LIVES_PAINTER_IS_CAIRO
558   cairo_rectangle(cr, x, y, width, height);
559   return TRUE;
560 #endif
561 #ifdef PAINTER_QPAINTER
562   cr->p->addRect(x, y, width, height);
563   return TRUE;
564 #endif
565   return FALSE;
566 }
567 
568 
lives_painter_arc(lives_painter_t * cr,double xc,double yc,double radius,double angle1,double angle2)569 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_arc(lives_painter_t *cr, double xc, double yc, double radius, double angle1,
570     double angle2) {
571 #ifdef LIVES_PAINTER_IS_CAIRO
572   cairo_arc(cr, xc, yc, radius, angle1, angle2);
573   return TRUE;
574 #endif
575 #ifdef PAINTER_QPAINTER
576   double l = xc - radius;
577   double t = yc - radius;
578   double w = radius * 2, h = w;
579   angle1 = angle1 / M_PI * 180.;
580   angle2 = angle2 / M_PI * 180.;
581   cr->p->arcTo(l, t, w, h, angle1, angle2 - angle1);
582   return TRUE;
583 #endif
584   return FALSE;
585 }
586 
587 
lives_painter_set_operator(lives_painter_t * cr,lives_painter_operator_t op)588 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_operator(lives_painter_t *cr, lives_painter_operator_t op) {
589   // if op was not LIVES_PAINTER_OPERATOR_DEFAULT, and FALSE is returned, then the operation failed,
590   // and op was set to the default
591 #ifdef LIVES_PAINTER_IS_CAIRO
592   cairo_set_operator(cr, op);
593   if (op == LIVES_PAINTER_OPERATOR_UNKNOWN) return FALSE;
594   return TRUE;
595 #endif
596 #ifdef PAINTER_QPAINTER
597   cr->setCompositionMode(op);
598   return TRUE;
599 #endif
600   return FALSE;
601 }
602 
603 
lives_painter_set_source_rgb(lives_painter_t * cr,double red,double green,double blue)604 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_source_rgb(lives_painter_t *cr, double red, double green, double blue) {
605   // r,g,b values 0.0 -> 1.0
606 #ifdef LIVES_PAINTER_IS_CAIRO
607   cairo_set_source_rgb(cr, red, green, blue);
608   return TRUE;
609 #endif
610 #ifdef PAINTER_QPAINTER
611   QColor qc(red * 255., green * 255., blue * 255.);
612   cr->pen.setColor(qc);
613   return TRUE;
614 #endif
615   return FALSE;
616 }
617 
618 
lives_painter_set_source_rgba(lives_painter_t * cr,double red,double green,double blue,double alpha)619 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_source_rgba(lives_painter_t *cr, double red, double green, double blue,
620     double alpha) {
621   // r,g,b,a values 0.0 -> 1.0
622 #ifdef LIVES_PAINTER_IS_CAIRO
623   cairo_set_source_rgba(cr, red, green, blue, alpha);
624   return TRUE;
625 #endif
626 #ifdef PAINTER_QPAINTER
627   QColor qc(red * 255., green * 255., blue * 255., alpha * 255.);
628   cr->pen.setColor(qc);
629   return TRUE;
630 #endif
631   return FALSE;
632 }
633 
634 
lives_painter_set_fill_rule(lives_painter_t * cr,lives_painter_fill_rule_t fill_rule)635 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_set_fill_rule(lives_painter_t *cr, lives_painter_fill_rule_t fill_rule) {
636 #ifdef LIVES_PAINTER_IS_CAIRO
637   cairo_set_fill_rule(cr, fill_rule);
638   return TRUE;
639 #endif
640 #ifdef PAINTER_QPAINTER
641   cr->p->setFillRule(fill_rule);
642   return TRUE;
643 #endif
644   return FALSE;
645 }
646 
647 
lives_painter_surface_flush(lives_painter_surface_t * surf)648 WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_surface_flush(lives_painter_surface_t *surf) {
649 #ifdef LIVES_PAINTER_IS_CAIRO
650   cairo_surface_flush(surf);
651   return TRUE;
652 #endif
653 #ifdef PAINTER_QPAINTER
654   return TRUE;
655 #endif
656   return FALSE;
657 }
658 
659 
lives_painter_image_surface_create_for_data(uint8_t * data,lives_painter_format_t format,int width,int height,int stride)660 WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t *lives_painter_image_surface_create_for_data(uint8_t *data,
661     lives_painter_format_t format,
662     int width, int height, int stride) {
663   lives_painter_surface_t *surf = NULL;
664 #ifdef LIVES_PAINTER_IS_CAIRO
665   surf = cairo_image_surface_create_for_data(data, format, width, height, stride);
666 #endif
667 #ifdef PAINTER_QPAINTER
668   surf = new lives_painter_surface_t(data, format, width, height, stride);
669 #endif
670   return surf;
671 }
672 
673 
lives_painter_image_surface_create(lives_painter_format_t format,int width,int height)674 WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t *lives_painter_image_surface_create(lives_painter_format_t format,
675     int width,
676     int height) {
677   lives_painter_surface_t *surf = NULL;
678 #ifdef LIVES_PAINTER_IS_CAIRO
679   surf = cairo_image_surface_create(format, width, height);
680 #endif
681 #ifdef PAINTER_QPAINTER
682   surf = new lives_painter_surface_t(width, height, format);
683 #endif
684   return surf;
685 }
686 
687 
688 WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t
lives_xwindow_create_similar_surface(LiVESXWindow * window,lives_painter_content_t cont,int width,int height)689 *lives_xwindow_create_similar_surface(LiVESXWindow *window, lives_painter_content_t cont,
690                                       int width, int height) {
691   lives_painter_surface_t *surf = gdk_window_create_similar_surface(window, cont, width, height);
692   lives_painter_t *cr = lives_painter_create_from_surface(surf);
693   lives_painter_set_source_rgb(cr, 0., 0., 0.);
694   lives_painter_paint(cr);
695   lives_painter_destroy(cr);
696   return surf;
697 }
698 
699 
lives_widget_create_painter_surface(LiVESWidget * widget)700 WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t *lives_widget_create_painter_surface(LiVESWidget *widget) {
701   if (widget)
702     return lives_xwindow_create_similar_surface(lives_widget_get_xwindow(widget),
703            LIVES_PAINTER_CONTENT_COLOR,
704            lives_widget_get_allocation_width(widget),
705            lives_widget_get_allocation_height(widget));
706   return NULL;
707 }
708 
709 ////////////////////////// painter info funcs
710 
lives_painter_get_target(lives_painter_t * cr)711 WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t *lives_painter_get_target(lives_painter_t *cr) {
712   lives_painter_surface_t *surf = NULL;
713 #ifdef LIVES_PAINTER_IS_CAIRO
714   surf = cairo_get_target(cr);
715 #endif
716 #ifdef PAINTER_QPAINTER
717   surf = cr->target;
718 #endif
719   return surf;
720 }
721 
722 
lives_painter_format_stride_for_width(lives_painter_format_t form,int width)723 WIDGET_HELPER_GLOBAL_INLINE int lives_painter_format_stride_for_width(lives_painter_format_t form, int width) {
724   int stride = -1;
725 #ifdef LIVES_PAINTER_IS_CAIRO
726   stride = cairo_format_stride_for_width(form, width);
727 #endif
728 #ifdef PAINTER_QPAINTER
729   stride = width * 4; //TODO !!
730 #endif
731   return stride;
732 }
733 
734 
lives_painter_image_surface_get_data(lives_painter_surface_t * surf)735 WIDGET_HELPER_GLOBAL_INLINE uint8_t *lives_painter_image_surface_get_data(lives_painter_surface_t *surf) {
736   uint8_t *data = NULL;
737 #ifdef LIVES_PAINTER_IS_CAIRO
738   data = cairo_image_surface_get_data(surf);
739 #endif
740 #ifdef PAINTER_QPAINTER
741   data = (uint8_t *)surf->bits();
742 #endif
743   return data;
744 }
745 
746 
lives_painter_image_surface_get_width(lives_painter_surface_t * surf)747 WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_width(lives_painter_surface_t *surf) {
748   int width = 0;
749 #ifdef LIVES_PAINTER_IS_CAIRO
750   width = cairo_image_surface_get_width(surf);
751 #endif
752 #ifdef PAINTER_QPAINTER
753   width = ((QImage *)surf)->width();
754 #endif
755   return width;
756 }
757 
758 
lives_painter_image_surface_get_height(lives_painter_surface_t * surf)759 WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_height(lives_painter_surface_t *surf) {
760   int height = 0;
761 #ifdef LIVES_PAINTER_IS_CAIRO
762   height = cairo_image_surface_get_height(surf);
763 #endif
764 #ifdef PAINTER_QPAINTER
765   height = ((QImage *)surf)->height();
766 #endif
767   return height;
768 }
769 
770 
lives_painter_image_surface_get_stride(lives_painter_surface_t * surf)771 WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_stride(lives_painter_surface_t *surf) {
772   int stride = 0;
773 #ifdef LIVES_PAINTER_IS_CAIRO
774   stride = cairo_image_surface_get_stride(surf);
775 #endif
776 #ifdef PAINTER_QPAINTER
777   stride = ((QImage *)surf)->bytesPerLine();
778 #endif
779   return stride;
780 }
781 
782 
lives_painter_image_surface_get_format(lives_painter_surface_t * surf)783 WIDGET_HELPER_GLOBAL_INLINE lives_painter_format_t lives_painter_image_surface_get_format(lives_painter_surface_t *surf) {
784   lives_painter_format_t format = (lives_painter_format_t)0;
785 #ifdef LIVES_PAINTER_IS_CAIRO
786   format = cairo_image_surface_get_format(surf);
787 #endif
788 #ifdef PAINTER_QPAINTER
789   format = ((QImage *)surf)->format();
790 #endif
791   return format;
792 }
793 
794 
795 ////////////////////////////////////////////////////////
796 
lives_widget_object_ref(livespointer object)797 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_ref(livespointer object) {
798 #ifdef GUI_GTK
799   if (LIVES_IS_WIDGET_OBJECT(object)) g_object_ref(object);
800   else {
801     LIVES_WARN("Ref of non-object");
802     break_me("ref of nomobj");
803     return FALSE;
804   }
805   return TRUE;
806 #endif
807 #ifdef GUI_QT
808   static_cast<LiVESWidgetObject *>(object)->inc_refcount();
809   return TRUE;
810 #endif
811   return FALSE;
812 }
813 
814 
lives_widget_object_unref(livespointer object)815 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_unref(livespointer object) {
816 #ifdef GUI_GTK
817   if (LIVES_IS_WIDGET_OBJECT(object)) g_object_unref(object);
818   else {
819     LIVES_WARN("Unref of non-object");
820     break_me("unref of nonobj");
821     return FALSE;
822   }
823   return TRUE;
824 #endif
825 #ifdef GUI_QT
826   static_cast<LiVESWidgetObject *>(object)->dec_refcount();
827   return TRUE;
828 #endif
829   return FALSE;
830 }
831 
832 
833 #ifdef GUI_GTK
834 #if GTK_CHECK_VERSION(3, 0, 0)
lives_widget_object_ref_sink(livespointer object)835 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_ref_sink(livespointer object) {
836   if (!LIVES_IS_WIDGET_OBJECT(object)) {
837     LIVES_WARN("Ref_sink of non-object");
838     break_me("ref sink of nonobj");
839     return FALSE;
840   }
841   g_object_ref_sink(object);
842   return TRUE;
843 }
844 #else
lives_widget_object_ref_sink(livespointer object)845 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_ref_sink(livespointer object) {
846   GtkObject *gtkobject;
847   if (!LIVES_IS_WIDGET_OBJECT(object)) {
848     LIVES_WARN("Ref_sink of non-object");
849     return FALSE;
850   }
851   gtkobject = (GtkObject *)object;
852   gtk_object_sink(gtkobject);
853   return TRUE;
854 }
855 #endif
856 #endif
857 
858 #ifdef GUI_QT
lives_widget_object_ref_sink(livespointer object)859 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_ref_sink(livespointer object) {
860   static_cast<LiVESWidgetObject *>(object)->ref_sink();
861   return TRUE;
862 }
863 #endif
864 
865 /// signal handling
866 
867 typedef struct {
868   livespointer instance;
869   lives_funcptr_t callback;
870   livespointer user_data;
871   volatile boolean swapped;
872   unsigned long funcid;
873   char *detsig;
874   boolean is_timer;
875   boolean added;
876   lives_proc_thread_t proc;
877 } lives_sigdata_t;
878 
879 static LiVESList *active_sigdets = NULL;
880 
async_notify_redirect_handler(LiVESWidgetObject * object,livespointer pspec,livespointer user_data)881 static void async_notify_redirect_handler(LiVESWidgetObject *object, livespointer pspec,
882     livespointer user_data) {
883   /// async shim to convert "notify::xxx" to some other signal
884   async_sig_handler(object, user_data);
885 }
886 
notify_redirect_handler(LiVESWidgetObject * object,livespointer pspec,livespointer user_data)887 static void notify_redirect_handler(LiVESWidgetObject *object, livespointer pspec,
888                                     livespointer user_data) {
889   /// shim to convert "notify::xxx" to some other signal
890   lives_sigdata_t *sigdata = (lives_sigdata_t *)user_data;
891   LiVESWidget *widget = (LiVESWidget *)object;
892   if (!sigdata->swapped)
893     (*((bifunc)sigdata->callback))(widget, sigdata->user_data);
894   else
895     (*((bifunc)sigdata->callback))(sigdata->user_data, widget);
896 }
897 
lives_signal_connect_sync(livespointer instance,const char * detailed_signal,LiVESGuiCallback c_handler,livespointer data,LiVESConnectFlags flags)898 unsigned long lives_signal_connect_sync(livespointer instance, const char *detailed_signal,
899                                         LiVESGuiCallback c_handler, livespointer data,
900                                         LiVESConnectFlags flags) {
901   unsigned long func_id;
902 #if LIVES_HAS_SWITCH_WIDGET
903   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))
904       && !strcmp(detailed_signal, LIVES_WIDGET_TOGGLED_SIGNAL)) {
905     /// to make switch and checkbutton interchangeable,
906     /// we substitue the "toggled" signal for a switch with "notify::active"
907     /// and then redirect it back to the desired callback
908     lives_sigdata_t *sigdata = lives_calloc(1, sizeof(lives_sigdata_t));
909     sigdata->instance = instance;
910     sigdata->callback = (lives_funcptr_t)c_handler;
911     sigdata->user_data = data;
912     sigdata->swapped = (flags & LIVES_CONNECT_SWAPPED) ? TRUE : FALSE;
913     sigdata->detsig = lives_strdup(LIVES_WIDGET_TOGGLED_SIGNAL);
914     sigdata->funcid = g_signal_connect_data(instance, LIVES_WIDGET_NOTIFY_SIGNAL "active",
915                                             LIVES_GUI_CALLBACK(notify_redirect_handler),
916                                             sigdata, sigdata_free, (flags & LIVES_CONNECT_AFTER));
917     active_sigdets = lives_list_prepend(active_sigdets, (livespointer)sigdata);
918     return sigdata->funcid;
919   }
920 #endif
921   if (!flags)
922     func_id = g_signal_connect(instance, detailed_signal, c_handler, data);
923   else {
924     if (flags & LIVES_CONNECT_AFTER)
925       func_id = g_signal_connect_after(instance, detailed_signal, c_handler, data);
926     else
927       func_id = g_signal_connect_swapped(instance, detailed_signal, c_handler, data);
928   }
929   return func_id;
930 }
931 
932 
lives_signal_handler_block(livespointer instance,unsigned long handler_id)933 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_block(livespointer instance, unsigned long handler_id) {
934 #ifdef GUI_GTK
935   g_signal_handler_block(instance, handler_id);
936   return TRUE;
937 #endif
938 #ifdef GUI_QT
939   LiVESWidgetObject *obj = static_cast<LiVESWidgetObject *>(instance);
940   obj->block_signal(handler_id);
941   return TRUE;
942 #endif
943   return FALSE;
944 }
945 
946 
lives_signal_handler_unblock(livespointer instance,unsigned long handler_id)947 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_unblock(livespointer instance, unsigned long handler_id) {
948 #ifdef GUI_GTK
949   g_signal_handler_unblock(instance, handler_id);
950   return TRUE;
951 #endif
952 #ifdef GUI_QT
953   LiVESWidgetObject *obj = static_cast<LiVESWidgetObject *>(instance);
954   obj->unblock_signal(handler_id);
955   return TRUE;
956 #endif
957   return FALSE;
958 }
959 
960 
lives_signal_handler_disconnect(livespointer instance,unsigned long handler_id)961 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_disconnect(livespointer instance, unsigned long handler_id) {
962 #ifdef GUI_GTK
963   g_signal_handler_disconnect(instance, handler_id);
964   return TRUE;
965 #endif
966 #ifdef GUI_QT
967   LiVESWidgetObject *obj = static_cast<LiVESWidgetObject *>(instance);
968   obj->disconnect_signal(handler_id);
969   return TRUE;
970 #endif
971   return FALSE;
972 }
973 
974 
lives_signal_stop_emission_by_name(livespointer instance,const char * detailed_signal)975 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_stop_emission_by_name(livespointer instance, const char *detailed_signal) {
976 #ifdef GUI_GTK
977   g_signal_stop_emission_by_name(instance, detailed_signal);
978   return TRUE;
979 #endif
980   return FALSE;
981 }
982 
983 
984 static volatile boolean gov_running = FALSE;
985 static volatile LiVESResponseType dlgresp = LIVES_RESPONSE_NONE;
986 static volatile boolean was_dest = FALSE;
987 static volatile lives_proc_thread_t lpttorun = NULL;
988 static volatile void *lpt_result = NULL;
989 static volatile void *lpt_retval = NULL;
990 
sigdata_free(livespointer data,LiVESWidgetClosure * cl)991 static void sigdata_free(livespointer data, LiVESWidgetClosure *cl) {
992   lives_sigdata_t *sigdata = (lives_sigdata_t *)data;
993   if (cl) active_sigdets = lives_list_remove(active_sigdets, sigdata);
994 
995   //if (sigdata->proc) weed_plant_free(sigdata->proc);
996 
997   if (sigdata->detsig) lives_free(sigdata->detsig);
998   lives_free(sigdata);
999 }
1000 
1001 static boolean timer_running = FALSE;
1002 
1003 static LiVESList *task_list = NULL;
1004 
tasks_running(void)1005 static lives_sigdata_t *tasks_running(void) {
1006   LiVESList *list;
1007   lives_sigdata_t *sigdata;
1008   list = task_list;
1009   if (!list) return NULL;
1010   sigdata = (lives_sigdata_t *)list->data;
1011   if (lives_proc_thread_check(sigdata->proc)) {
1012     task_list = task_list->next;
1013     if (task_list) task_list->prev = NULL;
1014     list->next = NULL;
1015     list->data = NULL;
1016     lives_list_free(list);
1017     if (!task_list) return sigdata;
1018     if (sigdata->proc) lives_proc_thread_dontcare(sigdata->proc);
1019     sigdata_free(sigdata, NULL);
1020   }
1021   return NULL;
1022 }
1023 
governor_loop(livespointer data)1024 static boolean governor_loop(livespointer data) {
1025   volatile boolean clutch;
1026   static boolean lpt_recurse = FALSE;
1027   static boolean lpt_recurse2 = FALSE;
1028   boolean is_timer = FALSE;
1029   lives_sigdata_t *sigdata = NULL;
1030   lives_sigdata_t *new_sigdata = (lives_sigdata_t *)data;
1031   /// this loop runs in the main thread while callbacks are being run in bg.
1032 reloop:
1033 
1034   if (g_main_depth() > 1) {
1035     mainw->clutch = TRUE;
1036     return TRUE;
1037   }
1038   if (mainw->is_exiting) return FALSE;
1039 
1040   if (lpt_recurse2) return TRUE;
1041 
1042   if (!new_sigdata) {
1043     // here we ar either re-entering as an idlefunc, or we are in a timer and looped back
1044     if (lpttorun) {
1045       // check if there is a foreground task to run
1046       lpt_recurse2 = TRUE;
1047       lpt_result = fg_run_func(lpttorun, (void *)lpt_retval);
1048       if (!is_timer) {
1049         lpttorun = NULL;
1050         lpt_recurse2 = FALSE;
1051         if (!lpt_recurse) {
1052           return FALSE;
1053         } else {
1054           //gov_running = FALSE;
1055           lpt_recurse = FALSE;
1056           return TRUE;
1057         }
1058       }
1059       /* if (!lpttorun) */
1060       /*   while (lives_widget_context_iteration(NULL, FALSE)); */
1061       lpttorun = NULL;
1062       lpt_recurse = FALSE;
1063       lpt_recurse2 = FALSE;
1064     }
1065 
1066     if (timer_running) {
1067       mainw->clutch = FALSE;
1068       return TRUE;
1069     }
1070   }
1071 
1072   // this is a shared variable which can be reset to interrupt us
1073   mainw->clutch = TRUE;
1074 
1075   if (!new_sigdata || !lives_proc_thread_check(new_sigdata->proc)) {
1076     // either we rentered as an idle, or reloop for timer, or adding a new task
1077 
1078     // sigdata will be set if the last task on the stack completed
1079     if (!(sigdata = tasks_running()) || new_sigdata) {
1080       // either a task is still running, or else we are adding a new one
1081 
1082       if (sigdata && new_sigdata) {
1083         // handle the case where the last task finished, and we need to add a new one
1084         if (sigdata->is_timer) {
1085           // this is complicated, We need to return to caller so it can exit with correct value
1086           // but we need to return to run the new task
1087           lives_idle_add_simple(governor_loop, new_sigdata);
1088           return FALSE;
1089         }
1090       }
1091       // signal that ww are in the loop
1092       gov_running = TRUE;
1093 
1094       if (new_sigdata) {
1095         // push a new task to the stack
1096         // signal bg that it can start now...
1097         lives_proc_thread_sync_ready(new_sigdata->proc);
1098         task_list = lives_list_prepend(task_list, new_sigdata);
1099         new_sigdata = NULL;
1100         goto reloop;
1101       }
1102 
1103       clutch = mainw->clutch;
1104       while (task_list && !lpttorun && clutch && !mainw->is_exiting && !(sigdata = tasks_running())) {
1105         // while any signal handler is running in the bg, we just loop here until either:
1106         // the task completes, the task wants to run a main loop cycle, or the app exits
1107         lives_nanosleep(NSLEEP_TIME);
1108         /* if (lives_proc_thread_signalled(sigdata->proc)) { */
1109         /*   g_print("Thread %lu received signal %d\n", lives_proc_thread_signalled_idx(sigdata->proc), */
1110         /*           lives_proc_thread_signalled(sigdata->proc)); */
1111         /* } */
1112         //sched_yield();
1113         clutch = mainw->clutch;
1114       }
1115     }
1116   }
1117   //else sigdata = new_sigdata;
1118 
1119   if (mainw->is_exiting) return FALSE; // app exit
1120 
1121   if (!task_list && !lpttorun && !sigdata) {
1122     gov_running = FALSE;
1123     return FALSE;
1124   }
1125 
1126   if (lpttorun || (!mainw->clutch && !sigdata)) {
1127     int count = 0;
1128     // a thread wants to wiggle the widgets...
1129     if (task_list) sigdata = (lives_sigdata_t *)lives_list_last(task_list)->data;
1130     if (sigdata && sigdata->is_timer) {
1131       // this is also complicated. We are running in a timer and we need to run mainloop
1132       is_timer = TRUE;
1133       /* if (!lpttorun) */
1134       while (!lives_proc_thread_check(sigdata->proc) && lives_widget_context_iteration(NULL, FALSE));
1135       sigdata = NULL;
1136       goto reloop;
1137     }
1138     if (lpttorun) lpt_recurse = TRUE;
1139     while (count++ < EV_LIM && !(sigdata && lives_proc_thread_check(sigdata->proc))
1140            && lives_widget_context_iteration(NULL, FALSE));
1141     lives_idle_add_simple(governor_loop, NULL);
1142     gov_running = FALSE;
1143     return FALSE;
1144   }
1145 
1146   /// something else might have removed the clutch, so check again
1147   if (!lives_proc_thread_check(sigdata->proc)) goto reloop;
1148 
1149   /// something else might have removed the clutch, so check again
1150   //if (!lives_proc_thread_check(sigdata->proc)) goto reloop;
1151   //if (!(sigdata = tasks_running())) goto reloop;
1152 
1153   // bg handler finished
1154   gov_running = FALSE;
1155   // if a timer, set sigdata->swapped
1156   if (sigdata->is_timer) {
1157     if (sigdata) sigdata->swapped = TRUE;
1158     /// timer handler will free sigdata
1159   } else {
1160     lives_proc_thread_dontcare(sigdata->proc);
1161     sigdata_free(sigdata, NULL);
1162   }
1163   return FALSE;
1164 }
1165 
1166 
async_sig_handler(livespointer instance,livespointer data)1167 static void async_sig_handler(livespointer instance, livespointer data) {
1168   lives_thread_attr_t attr = LIVES_THRDATTR_WAIT_SYNC;
1169   lives_sigdata_t *sigdata = lives_calloc(1, sizeof(lives_sigdata_t));
1170   lives_memcpy(sigdata, data, sizeof(lives_sigdata_t));
1171   sigdata->detsig = NULL;
1172 
1173   // possible values: [gtk+] gdk_frame_clock_paint_idle
1174   // GDK X11 Event source (:0.0)
1175   // [gio] complete_in_idle_cb
1176   // null
1177   // g_print("SOURCE is %s\n", g_source_get_name(g_main_current_source()));
1178   if (sigdata->instance != instance) return;
1179 
1180   /* ctx = lives_widget_context_get_thread_default(); */
1181   /* if (!gov_running && (!ctx || ctx == lives_widget_context_default())) { */
1182 
1183   //mainw->clutch = TRUE;
1184   if (sigdata->swapped) {
1185     sigdata->proc = lives_proc_thread_create(attr, (lives_funcptr_t)sigdata->callback, -1, "vv", sigdata->user_data, instance);
1186   } else {
1187     sigdata->proc = lives_proc_thread_create(attr, (lives_funcptr_t)sigdata->callback, -1, "vv", instance, sigdata->user_data);
1188   }
1189   governor_loop(sigdata);
1190 }
1191 
1192 
async_sig_handler3(livespointer instance,livespointer extra,livespointer data)1193 static void async_sig_handler3(livespointer instance, livespointer extra, livespointer data) {
1194   lives_sigdata_t *sigdata = lives_calloc(1, sizeof(lives_sigdata_t));
1195   lives_thread_attr_t attr = LIVES_THRDATTR_WAIT_SYNC;
1196   lives_memcpy(sigdata, data, sizeof(lives_sigdata_t));
1197   sigdata->detsig = NULL;
1198   if (sigdata->swapped)
1199     sigdata->proc = lives_proc_thread_create(attr, sigdata->callback, -1, "vvv", sigdata->user_data,
1200                     extra, instance);
1201   else
1202     sigdata->proc = lives_proc_thread_create(attr, sigdata->callback, -1, "vvv", instance, extra,
1203                     sigdata->user_data);
1204   governor_loop((livespointer)sigdata);
1205 }
1206 
1207 
async_timer_handler(livespointer data)1208 static boolean async_timer_handler(livespointer data) {
1209   if (mainw->is_exiting) return FALSE;
1210   else {
1211     lives_sigdata_t *sigdata = lives_calloc(1, sizeof(lives_sigdata_t));
1212     lives_memcpy(sigdata, data, sizeof(lives_sigdata_t));
1213     sigdata->detsig = NULL;
1214     sigdata->is_timer = TRUE;
1215     //g_print("SOURCE is %s\n", g_source_get_name(g_main_current_source())); // NULL for timer, GIdleSource for idle
1216     //g_print("hndling %p %s %p\n", sigdata, sigdata->detsig, (void *)sigdata->detsig);
1217 
1218     if (!sigdata->added) {
1219       lives_thread_attr_t attr = LIVES_THRDATTR_WAIT_SYNC;
1220       mainw->clutch = FALSE;
1221       sigdata->swapped = FALSE;
1222       sigdata->proc = lives_proc_thread_create(attr, (lives_funcptr_t)sigdata->callback, WEED_SEED_BOOLEAN,
1223                       "v", sigdata->user_data);
1224     }
1225 
1226     while (1) {
1227       int count = 0;
1228       if (!governor_loop(sigdata->added ? NULL : (livespointer)sigdata)) {
1229         if (sigdata->proc) lives_proc_thread_dontcare(sigdata->proc);
1230         sigdata_free(sigdata, NULL);
1231         break;
1232       }
1233       sigdata->added = TRUE;
1234       if (sigdata->swapped) {
1235         // task finished
1236         // get bool result and return
1237         boolean res = lives_proc_thread_join_boolean(sigdata->proc);
1238         if (sigdata->proc) weed_plant_free(sigdata->proc);
1239         sigdata_free(sigdata, NULL);
1240         return res;
1241       }
1242       timer_running = TRUE;
1243       while (count++ < EV_LIM && !mainw->is_exiting && lives_widget_context_pending(NULL)) {
1244         //while (lives_widget_context_iteration(NULL, FALSE)) {
1245         //LiVESXEvent *ev = lives_widgets_get_current_event();
1246         //if (ev) g_print("ev was %d\n", ev->type);
1247         //else g_print("NULL event\n");
1248         lives_widget_context_iteration(NULL, FALSE);
1249         //lives_nanosleep(NSLEEP_TIME);
1250       }
1251       timer_running = FALSE;
1252     }
1253   }
1254   return FALSE;
1255 }
1256 
1257 
lives_signal_connect_async(livespointer instance,const char * detailed_signal,LiVESGuiCallback c_handler,livespointer data,LiVESConnectFlags flags)1258 unsigned long lives_signal_connect_async(livespointer instance, const char *detailed_signal, LiVESGuiCallback c_handler,
1259     livespointer data, LiVESConnectFlags flags) {
1260   static size_t notilen = -1;
1261   lives_sigdata_t *sigdata;
1262   uint32_t nvals;
1263   GSignalQuery sigq;
1264 
1265 #if LIVES_HAS_SWITCH_WIDGET
1266   boolean swtog = FALSE;
1267   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))
1268       && !strcmp(detailed_signal, LIVES_WIDGET_TOGGLED_SIGNAL)) swtog = TRUE;
1269   else {
1270 #endif
1271 
1272     if (notilen == -1) notilen = lives_strlen(LIVES_WIDGET_NOTIFY_SIGNAL);
1273     if (!lives_strncmp(detailed_signal, LIVES_WIDGET_NOTIFY_SIGNAL, notilen)) {
1274       return lives_signal_connect_sync(instance, detailed_signal, c_handler, data, flags);
1275     }
1276 
1277     g_signal_query(g_signal_lookup(detailed_signal, G_OBJECT_TYPE(instance)), &sigq);
1278     if (sigq.return_type != 4) {
1279       return lives_signal_connect_sync(instance, detailed_signal, c_handler, data, flags);
1280     }
1281 
1282     nvals = sigq.n_params + 2; // add instance, user_data
1283 
1284     if (nvals != 2 && nvals != 3) {
1285       return lives_signal_connect_sync(instance, detailed_signal, c_handler, data, flags);
1286     }
1287 
1288 #if LIVES_HAS_SWITCH_WIDGET
1289   }
1290 #endif
1291 
1292   sigdata = (lives_sigdata_t *)lives_calloc(1, sizeof(lives_sigdata_t));
1293   sigdata->instance = instance;
1294   sigdata->callback = (lives_funcptr_t)c_handler;
1295   sigdata->user_data = data;
1296   sigdata->swapped = (flags & LIVES_CONNECT_SWAPPED) ? TRUE : FALSE;
1297   active_sigdets = lives_list_prepend(active_sigdets, (livespointer)sigdata);
1298 
1299 #if LIVES_HAS_SWITCH_WIDGET
1300   if (swtog) {
1301     /// to make switch and checkbutton interchangeable,
1302     /// we substitue the "toggled" signal for a switch with "notify::active"
1303     /// and then redirect it back to the desired callback
1304     sigdata->detsig = lives_strdup(LIVES_WIDGET_TOGGLED_SIGNAL);
1305     sigdata->funcid = g_signal_connect_data(instance, LIVES_WIDGET_NOTIFY_SIGNAL "active",
1306                                             LIVES_GUI_CALLBACK(async_notify_redirect_handler),
1307                                             sigdata, sigdata_free, (flags & LIVES_CONNECT_AFTER));
1308     return sigdata->funcid;
1309   }
1310 #endif
1311 
1312   sigdata->detsig = lives_strdup(detailed_signal);
1313 
1314   if (nvals == 2) {
1315     sigdata->funcid = g_signal_connect_data(instance, detailed_signal,
1316                                             LIVES_GUI_CALLBACK(async_sig_handler),
1317                                             sigdata, sigdata_free, (flags & LIVES_CONNECT_AFTER));
1318   } else {
1319     sigdata->funcid = g_signal_connect_data(instance, detailed_signal,
1320                                             LIVES_GUI_CALLBACK(async_sig_handler3),
1321                                             sigdata, sigdata_free, (flags & LIVES_CONNECT_AFTER));
1322   }
1323   return sigdata->funcid;
1324 }
1325 
find_sigdata(livespointer instance,LiVESGuiCallback func,livespointer data)1326 static lives_sigdata_t *find_sigdata(livespointer instance, LiVESGuiCallback func, livespointer data) {
1327   LiVESList *list = active_sigdets;
1328   for (; list; list = list->next) {
1329     lives_sigdata_t *sigdata = (lives_sigdata_t *)list->data;
1330     if (sigdata->instance == instance && sigdata->callback == (lives_funcptr_t)func
1331         && sigdata->user_data == data) return sigdata;
1332   }
1333   return NULL;
1334 }
1335 
lives_signal_handlers_sync_disconnect_by_func(livespointer instance,LiVESGuiCallback func,livespointer data)1336 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handlers_sync_disconnect_by_func(livespointer instance,
1337     LiVESGuiCallback func, livespointer data) {
1338 #ifdef GUI_GTK
1339 #if LIVES_HAS_SWITCH_WIDGET
1340   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))) {
1341     /// to make switch and checkbutton interchangeable,
1342     /// we substitue the "toggled" signal for a switch with "notify::active"
1343     /// and then redirect it back to the desired callback
1344     lives_sigdata_t *sigdata = find_sigdata(instance, LIVES_GUI_CALLBACK(func), data);
1345     if (sigdata) {
1346       g_signal_handler_disconnect(instance, sigdata->funcid);
1347       return TRUE;
1348     }
1349   }
1350 #endif
1351   g_signal_handlers_disconnect_by_func(instance, func, data);
1352   return TRUE;
1353 #endif
1354   return FALSE;
1355 }
1356 
lives_signal_handlers_sync_block_by_func(livespointer instance,LiVESGuiCallback func,livespointer data)1357 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handlers_sync_block_by_func(livespointer instance,
1358     LiVESGuiCallback func, livespointer data) {
1359 #ifdef GUI_GTK
1360 #if LIVES_HAS_SWITCH_WIDGET
1361   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))) {
1362     /// to make switch and checkbutton interchangeable,
1363     /// we substitue the "toggled" signal for a switch with "notify::active"
1364     /// and then redirect it back to the desired callback
1365     lives_sigdata_t *sigdata = find_sigdata(instance, LIVES_GUI_CALLBACK(func), data);
1366     if (sigdata) {
1367       g_signal_handler_block(instance, sigdata->funcid);
1368       return TRUE;
1369     }
1370   }
1371 #endif
1372   g_signal_handlers_block_by_func(instance, func, data);
1373   return TRUE;
1374 #endif
1375   return FALSE;
1376 }
1377 
lives_signal_handlers_sync_unblock_by_func(livespointer instance,LiVESGuiCallback func,livespointer data)1378 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handlers_sync_unblock_by_func(livespointer instance,
1379     LiVESGuiCallback func, livespointer data) {
1380 #ifdef GUI_GTK
1381 #if LIVES_HAS_SWITCH_WIDGET
1382   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))) {
1383     /// to make switch and checkbutton interchangeable,
1384     /// we substitue the "toggled" signal for a switch with "notify::active"
1385     /// and then redirect it back to the desired callback
1386     lives_sigdata_t *sigdata = find_sigdata(instance, LIVES_GUI_CALLBACK(func), data);
1387     if (sigdata) {
1388       g_signal_handler_unblock(instance, sigdata->funcid);
1389       return TRUE;
1390     }
1391   }
1392 #endif
1393   g_signal_handlers_unblock_by_func(instance, func, data);
1394   return TRUE;
1395 #endif
1396   return FALSE;
1397 }
1398 
lives_signal_handlers_disconnect_by_func(livespointer instance,LiVESGuiCallback func,livespointer data)1399 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handlers_disconnect_by_func(livespointer instance,
1400     LiVESGuiCallback func, livespointer data) {
1401 #if LIVES_HAS_SWITCH_WIDGET
1402   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))) {
1403     return lives_signal_handlers_sync_disconnect_by_func(instance, func, data);
1404   } else {
1405 #endif
1406     lives_sigdata_t *sigdata = find_sigdata(instance, LIVES_GUI_CALLBACK(func), data);
1407     if (sigdata) {
1408       lives_signal_handler_disconnect(instance, sigdata->funcid);
1409       return TRUE;
1410     }
1411     return lives_signal_handlers_sync_disconnect_by_func(instance, func, data);
1412 #if LIVES_HAS_SWITCH_WIDGET
1413   }
1414 #endif
1415 }
1416 
lives_signal_handlers_block_by_func(livespointer instance,LiVESGuiCallback func,livespointer data)1417 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handlers_block_by_func(livespointer instance,
1418     LiVESGuiCallback func, livespointer data) {
1419 #if LIVES_HAS_SWITCH_WIDGET
1420   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))) {
1421     return lives_signal_handlers_sync_block_by_func(instance, func, data);
1422   } else {
1423 #endif
1424     lives_sigdata_t *sigdata = find_sigdata(instance, LIVES_GUI_CALLBACK(func), data);
1425     if (sigdata) {
1426       lives_signal_handler_block(instance, sigdata->funcid);
1427       return TRUE;
1428     }
1429     return lives_signal_handlers_sync_block_by_func(instance, func, data);
1430 #if LIVES_HAS_SWITCH_WIDGET
1431   }
1432 #endif
1433 }
1434 
lives_signal_handlers_unblock_by_func(livespointer instance,LiVESGuiCallback func,livespointer data)1435 WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handlers_unblock_by_func(livespointer instance,
1436     LiVESGuiCallback func, livespointer data) {
1437 #if LIVES_HAS_SWITCH_WIDGET
1438   if (LIVES_IS_WIDGET(instance) && LIVES_IS_SWITCH(LIVES_WIDGET(instance))) {
1439     return lives_signal_handlers_sync_unblock_by_func(instance, func, data);
1440   } else {
1441 #endif
1442     lives_sigdata_t *sigdata = find_sigdata(instance, LIVES_GUI_CALLBACK(func), data);
1443     if (sigdata) {
1444       lives_signal_handler_unblock(instance, sigdata->funcid);
1445       return TRUE;
1446     }
1447     return lives_signal_handlers_sync_unblock_by_func(instance, func, data);
1448 #if LIVES_HAS_SWITCH_WIDGET
1449   }
1450 #endif
1451 }
1452 
1453 
lives_grab_add(LiVESWidget * widget)1454 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grab_add(LiVESWidget *widget) {
1455 #ifdef GUI_GTK
1456   gtk_grab_add(widget);
1457   return TRUE;
1458 #endif
1459   return FALSE;
1460 }
1461 
lives_grab_remove(LiVESWidget * widget)1462 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grab_remove(LiVESWidget *widget) {
1463 #ifdef GUI_GTK
1464   gtk_grab_remove(widget);
1465   return TRUE;
1466 #endif
1467   return FALSE;
1468 }
1469 
1470 
_lives_widget_set_sensitive_cb(LiVESWidget * w,void * pstate)1471 static void _lives_widget_set_sensitive_cb(LiVESWidget *w, void *pstate) {
1472   boolean state = (boolean)LIVES_POINTER_TO_INT(pstate);
1473   lives_widget_set_sensitive(w, state);
1474 }
1475 
1476 
lives_widget_set_sensitive(LiVESWidget * widget,boolean state)1477 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive(LiVESWidget *widget, boolean state) {
1478   if (!GTK_IS_WIDGET(widget)) break_me("non widget in set_sensitive");
1479 #ifdef GUI_GTK
1480   gtk_widget_set_sensitive(widget, state);
1481 #ifdef GTK_SUBMENU_SENS_BUG
1482   if (GTK_IS_MENU_ITEM(widget)) {
1483     LiVESWidget *sub = lives_menu_item_get_submenu(LIVES_MENU_ITEM(widget));
1484     if (sub) {
1485       lives_container_foreach(LIVES_CONTAINER(sub), _lives_widget_set_sensitive_cb,
1486                               LIVES_INT_TO_POINTER(state));
1487       gtk_widget_set_sensitive(sub, state);
1488     }
1489   }
1490 #endif
1491   return TRUE;
1492 #endif
1493   return FALSE;
1494 }
1495 
1496 
lives_widget_get_sensitive(LiVESWidget * widget)1497 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_sensitive(LiVESWidget *widget) {
1498 #ifdef GUI_GTK
1499   return gtk_widget_get_sensitive(widget);
1500 #endif
1501   return FALSE;
1502 }
1503 
1504 
lives_widget_show(LiVESWidget * widget)1505 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show(LiVESWidget *widget) {
1506 #ifdef GUI_GTK
1507   gtk_widget_show(widget);
1508   return TRUE;
1509 #endif
1510   return FALSE;
1511 }
1512 
1513 
lives_widget_hide(LiVESWidget * widget)1514 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_hide(LiVESWidget *widget) {
1515 #ifdef GUI_GTK
1516   gtk_widget_hide(widget);
1517   return TRUE;
1518 #endif
1519   return FALSE;
1520 }
1521 
1522 
lives_widget_show_all(LiVESWidget * widget)1523 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget) {
1524 #ifdef GUI_GTK
1525   gtk_widget_show_all(widget);
1526 
1527   // recommended to center the window again after adding all its widgets
1528   if (LIVES_IS_DIALOG(widget) && mainw->mgeom) lives_window_center(LIVES_WINDOW(widget));
1529 
1530   return TRUE;
1531 #endif
1532   return FALSE;
1533 }
1534 
lives_widget_show_all_from_bg(LiVESWidget * widget)1535 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all_from_bg(LiVESWidget *widget) {
1536   // run in main thread as it seems to give a smoother result
1537   boolean ret;
1538   main_thread_execute((lives_funcptr_t)lives_widget_show_all, WEED_SEED_BOOLEAN, &ret, "v", widget);
1539   return ret;
1540   //return lives_widget_show_all(widget);
1541 }
1542 
1543 
lives_widget_show_now(LiVESWidget * widget)1544 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_now(LiVESWidget *widget) {
1545 #ifdef GUI_GTK
1546   gtk_widget_show_now(widget);
1547   return TRUE;
1548 #endif
1549   return FALSE;
1550 }
1551 
1552 
lives_widget_destroy(LiVESWidget * widget)1553 LIVES_GLOBAL_INLINE boolean lives_widget_destroy(LiVESWidget *widget) {
1554 #ifdef GUI_GTK
1555   if (GTK_IS_WIDGET(widget))
1556     gtk_widget_destroy(widget);
1557   return TRUE;
1558 #endif
1559   return FALSE;
1560 }
1561 
1562 
_lives_widget_destroy(LiVESWidget * widget)1563 WIDGET_HELPER_LOCAL_INLINE boolean _lives_widget_destroy(LiVESWidget *widget) {
1564   /* boolean ret; */
1565   /* main_thread_execute((lives_funcptr_t)_lives_widget_destroy, WEED_SEED_BOOLEAN, &ret, "v", widget); */
1566   /* return ret; */
1567   return lives_widget_destroy(widget);
1568 }
1569 
1570 
lives_widget_realize(LiVESWidget * widget)1571 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_realize(LiVESWidget *widget) {
1572 #ifdef GUI_GTK
1573   gtk_widget_realize(widget);
1574   return TRUE;
1575 #endif
1576   return FALSE;
1577 }
1578 
1579 
lives_widget_queue_draw(LiVESWidget * widget)1580 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw(LiVESWidget *widget) {
1581 #ifdef GUI_GTK
1582   if (!GTK_IS_WIDGET(widget)) {
1583     LIVES_WARN("Draw queue invalid widget");
1584     return FALSE;
1585   }
1586   gtk_widget_queue_draw(widget);
1587   return TRUE;
1588 #endif
1589   return FALSE;
1590 }
1591 
1592 
lives_widget_queue_draw_area(LiVESWidget * widget,int x,int y,int width,int height)1593 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw_area(LiVESWidget *widget, int x, int y, int width, int height) {
1594 #ifdef GUI_GTK
1595 #if GTK_CHECK_VERSION(3, 0, 0)
1596   gtk_widget_queue_draw_area(widget, x, y, width, height);
1597 #else
1598   gtk_widget_queue_draw(widget);
1599 #endif
1600 #endif
1601   return FALSE;
1602 }
1603 
1604 
lives_widget_queue_resize(LiVESWidget * widget)1605 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_resize(LiVESWidget *widget) {
1606 #ifdef GUI_GTK
1607   gtk_widget_queue_resize(widget);
1608   return TRUE;
1609 #endif
1610   return FALSE;
1611 }
1612 
1613 
lives_widget_set_size_request(LiVESWidget * widget,int width,int height)1614 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_size_request(LiVESWidget *widget, int width, int height) {
1615 #ifdef GUI_GTK
1616   if (LIVES_IS_WINDOW(widget)) lives_window_resize(LIVES_WINDOW(widget), width, height);
1617   else gtk_widget_set_size_request(widget, width, height);
1618   return TRUE;
1619 #endif
1620   return FALSE;
1621 }
1622 
1623 
lives_widget_set_minimum_size(LiVESWidget * widget,int width,int height)1624 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_minimum_size(LiVESWidget *widget, int width, int height) {
1625 #ifdef GUI_GTK
1626   GdkGeometry geom;
1627   GdkWindowHints mask;
1628   GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
1629   if (GTK_IS_WINDOW(toplevel)) {
1630     geom.min_width = width;
1631     geom.min_height = height;
1632     mask = GDK_HINT_MIN_SIZE;
1633     gtk_window_set_geometry_hints(GTK_WINDOW(toplevel), widget, &geom, mask);
1634     return TRUE;
1635   }
1636 #endif
1637   return FALSE;
1638 }
1639 
1640 
lives_widget_set_maximum_size(LiVESWidget * widget,int width,int height)1641 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_maximum_size(LiVESWidget *widget, int width, int height) {
1642 #ifdef GUI_GTK
1643   GdkGeometry geom;
1644   GdkWindowHints mask;
1645   GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
1646   if (GTK_IS_WINDOW(toplevel)) {
1647     geom.max_width = width;
1648     geom.max_height = height;
1649     mask = GDK_HINT_MAX_SIZE;
1650     gtk_window_set_geometry_hints(GTK_WINDOW(toplevel), widget, &geom, mask);
1651     return TRUE;
1652   }
1653 #endif
1654   return FALSE;
1655 }
1656 
1657 
lives_widget_process_updates(LiVESWidget * widget)1658 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_process_updates(LiVESWidget *widget) {
1659 #ifdef GUI_GTK
1660   LiVESWidgetContext *ctx = lives_widget_context_get_thread_default();
1661   LiVESWindow *win, *modalold = modalw;
1662   boolean was_modal = TRUE;
1663   if (!ctx || ctx == lives_widget_context_default()) return TRUE;
1664 
1665   if (LIVES_IS_WINDOW(widget)) win = (LiVESWindow *)widget;
1666   else if (LIVES_IS_WIDGET(widget))
1667     win = lives_widget_get_window(widget);
1668   else return FALSE;
1669   if (win && LIVES_IS_WINDOW(win)) {
1670     was_modal = lives_window_get_modal(win);
1671     if (!was_modal) lives_window_set_modal(win, TRUE);
1672   }
1673 
1674   if (gov_running) {
1675     mainw->clutch = FALSE;
1676     if (!mainw->is_exiting) {
1677       while (!mainw->clutch) {
1678         lives_nanosleep(NSLEEP_TIME);
1679       }
1680     }
1681   }
1682 
1683   if (!was_modal) {
1684     lives_window_set_modal(win, FALSE);
1685     if (modalold) lives_window_set_modal(modalold, TRUE);
1686   }
1687   return TRUE;
1688 #endif
1689   return FALSE;
1690 }
1691 
1692 
lives_xwindow_get_origin(LiVESXWindow * xwin,int * posx,int * posy)1693 WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_get_origin(LiVESXWindow *xwin, int *posx, int *posy) {
1694 #ifdef GUI_GTK
1695   gdk_window_get_origin(xwin, posx, posy);
1696   return TRUE;
1697 #endif
1698   return FALSE;
1699 }
1700 
1701 
lives_xwindow_get_frame_extents(LiVESXWindow * xwin,lives_rect_t * rect)1702 WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_get_frame_extents(LiVESXWindow *xwin, lives_rect_t *rect) {
1703 #ifdef GUI_GTK
1704   gdk_window_get_frame_extents(xwin, (GdkRectangle *)rect);
1705   return TRUE;
1706 #endif
1707   return FALSE;
1708 }
1709 
1710 
lives_xwindow_invalidate_rect(LiVESXWindow * window,lives_rect_t * rect,boolean inv_childs)1711 WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_invalidate_rect(LiVESXWindow *window, lives_rect_t *rect,
1712     boolean inv_childs) {
1713 #ifdef GUI_GTK
1714   gdk_window_invalidate_rect(window, (const GdkRectangle *)rect, inv_childs);
1715   return TRUE;
1716 #endif
1717   return FALSE;
1718 }
1719 
1720 
lives_widget_reparent(LiVESWidget * widget,LiVESWidget * new_parent)1721 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_reparent(LiVESWidget *widget, LiVESWidget *new_parent) {
1722 #ifdef GUI_GTK
1723 #if GTK_CHECK_VERSION(3, 14, 0)
1724   GtkWidget *parent = gtk_widget_get_parent(widget);
1725   g_object_ref(widget);
1726   if (parent) {
1727     gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(widget)), widget);
1728   }
1729   gtk_container_add(GTK_CONTAINER(new_parent), widget);
1730   g_object_unref(widget);
1731 #else
1732   gtk_widget_reparent(widget, new_parent);
1733 #endif
1734   return TRUE;
1735 #endif
1736   return FALSE;
1737 }
1738 
1739 
lives_widget_is_ancestor(LiVESWidget * widget,LiVESWidget * ancestor)1740 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_ancestor(LiVESWidget *widget, LiVESWidget *ancestor) {
1741 #ifdef GUI_GTK
1742   return gtk_widget_is_ancestor(widget, ancestor);
1743 #endif
1744   return FALSE;
1745 }
1746 
1747 
lives_widget_set_app_paintable(LiVESWidget * widget,boolean paintable)1748 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_app_paintable(LiVESWidget *widget, boolean paintable) {
1749 #ifdef GUI_GTK
1750   gtk_widget_set_app_paintable(widget, paintable);
1751   return TRUE;
1752 #endif
1753   return FALSE;
1754 }
1755 
1756 
lives_widget_set_opacity(LiVESWidget * widget,double opacity)1757 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_opacity(LiVESWidget *widget, double opacity) {
1758 #ifdef GUI_GTK
1759 #if GTK_CHECK_VERSION(3, 8, 0)
1760   if (capable->wm_caps.is_composited) {
1761     gtk_widget_set_opacity(widget, opacity);
1762   }
1763   return TRUE;
1764 #endif
1765   if (opacity == 0.) lives_widget_hide(widget);
1766   if (opacity == 1.) lives_widget_show(widget);
1767 #endif
1768   return FALSE;
1769 }
1770 
1771 
_lives_dialog_run(LiVESDialog * dialog)1772 static LiVESResponseType _lives_dialog_run(LiVESDialog *dialog) {
1773 #ifdef GUI_GTK
1774   LiVESResponseType resp;
1775   lives_widget_show_all(LIVES_WIDGET(dialog));
1776   resp = gtk_dialog_run(dialog);
1777   return resp;
1778 #endif
1779   return LIVES_RESPONSE_INVALID;
1780 }
1781 
1782 
lives_dialog_run(LiVESDialog * dialog)1783 WIDGET_HELPER_GLOBAL_INLINE LiVESResponseType lives_dialog_run(LiVESDialog *dialog) {
1784   LiVESResponseType resp;
1785   main_thread_execute((lives_funcptr_t)_lives_dialog_run, WEED_SEED_INT, &resp, "v", dialog);
1786   return resp;
1787 }
1788 
1789 
lives_fg_run(lives_proc_thread_t lpt,void * retval)1790 void *lives_fg_run(lives_proc_thread_t lpt, void *retval) {
1791   void *ret = NULL;
1792   boolean waitgov = FALSE;
1793 #ifdef GUI_GTK
1794   LiVESWidgetContext *ctx = lives_widget_context_get_thread_default();
1795   if (!ctx || ctx == lives_widget_context_default()) {
1796     // run direct
1797     ret = fg_run_func(lpt, retval);
1798   } else {
1799     lpttorun = lpt;
1800     lpt_retval = (volatile void *)retval;
1801     if (!gov_running) {
1802       lives_idle_add_simple(governor_loop, NULL);
1803       while (!gov_running) {
1804         lives_nanosleep(NSLEEP_TIME);
1805       }
1806     } else {
1807       waitgov = TRUE;
1808       mainw->clutch = FALSE;
1809     }
1810     while (lpttorun || (waitgov && !mainw->clutch)) {
1811       lives_nanosleep(NSLEEP_TIME);
1812     }
1813     ret = (void *)lpt_result;
1814   }
1815 #endif
1816   return ret;
1817 }
1818 
1819 
lives_dialog_response(LiVESDialog * dialog,int response)1820 WIDGET_HELPER_GLOBAL_INLINE boolean lives_dialog_response(LiVESDialog *dialog, int response) {
1821 #ifdef GUI_GTK
1822   gtk_dialog_response(dialog, response);
1823   return TRUE;
1824 #endif
1825   return FALSE;
1826 }
1827 
1828 
lives_dialog_get_response_for_widget(LiVESDialog * dialog,LiVESWidget * widget)1829 WIDGET_HELPER_GLOBAL_INLINE int lives_dialog_get_response_for_widget(LiVESDialog *dialog, LiVESWidget *widget) {
1830 #ifdef GUI_GTK
1831   return gtk_dialog_get_response_for_widget(dialog, widget);
1832 #endif
1833   return LIVES_RESPONSE_NONE;
1834 }
1835 
1836 
1837 #if GTK_CHECK_VERSION(3, 16, 0)
1838 
1839 #define RND_STRLEN 12
1840 #define RND_STR_PREFIX "XXX"
1841 
make_random_string(const char * prefix)1842 static char *make_random_string(const char *prefix) {
1843   // give each widget a random name so we can style it individually
1844   char *str;
1845   size_t psize = strlen(prefix);
1846   size_t rsize = RND_STRLEN << 1;
1847   register int i;
1848 
1849   if (psize > RND_STRLEN) return NULL;
1850 
1851   str = (char *)lives_malloc(rsize);
1852   lives_snprintf(str, psize + 1, "%s", prefix);
1853 
1854   rsize--;
1855 
1856   for (i = psize; i < rsize; i++) str[i] = ((lives_random() & 15) + 65);
1857   str[rsize] = 0;
1858   return str;
1859 }
1860 #endif
1861 
1862 
1863 #ifdef GUI_GTK
1864 #if GTK_CHECK_VERSION(3, 16, 0)
1865 //#define ORD_NAMES
1866 
set_css_value_for_state_flag(LiVESWidget * widget,LiVESWidgetState state,const char * xselector,const char * detail,const char * value)1867 static boolean set_css_value_for_state_flag(LiVESWidget *widget, LiVESWidgetState state, const char *xselector,
1868     const char *detail, const char *value) {
1869   GtkCssProvider *provider;
1870   GtkStyleContext *ctx;
1871   char *widget_name, *wname, *selector;
1872   char *css_string;
1873   char *state_str, *selstr;
1874 #ifdef ORD_NAMES
1875   static int widnum = 1;
1876   int brk_widnum = 3128;
1877 #endif
1878   if (!widget) {
1879     int numtok = get_token_count(xselector, ' ') ;
1880     if (numtok > 1) {
1881       char **array = lives_strsplit(xselector, " ", 2);
1882       widget_name = lives_strdup(array[0]);
1883       selector = lives_strdup(array[1]);
1884       lives_strfreev(array);
1885     } else {
1886       widget_name = lives_strdup(xselector);
1887       selector = lives_strdup("");
1888     }
1889     provider = gtk_css_provider_new();
1890 
1891     // setting context provider for screen is VERY slow, so this should be used sparingly
1892     gtk_style_context_add_provider_for_screen(mainw->mgeom[widget_opts.monitor].screen, GTK_STYLE_PROVIDER
1893         (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 10000);
1894   } else {
1895     if (!LIVES_IS_WIDGET(widget)) return FALSE;
1896     selector = (char *)xselector;
1897 
1898     ctx = gtk_widget_get_style_context(widget);
1899     provider = gtk_css_provider_new();
1900     gtk_style_context_add_provider(ctx, GTK_STYLE_PROVIDER
1901                                    (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 10000);
1902 
1903     widget_name = lives_strdup(gtk_widget_get_name(widget));
1904 
1905     if (!widget_name || (strncmp(widget_name, RND_STR_PREFIX, strlen(RND_STR_PREFIX)))) {
1906       lives_freep((void **)&widget_name);
1907 #ifdef ORD_NAMES
1908       widget_name = lives_strdup_printf("%s-%d", RND_STR_PREFIX, ++widnum);
1909 #else
1910       widget_name = make_random_string(RND_STR_PREFIX);
1911 #endif
1912       gtk_widget_set_name(widget, widget_name);
1913 #ifdef ORD_NAMES
1914       if (widnum == brk_widnum) break_me("widnum");
1915 #endif
1916     }
1917   }
1918 
1919 #ifdef GTK_TEXT_VIEW_CSS_BUG
1920   if (widget && GTK_IS_TEXT_VIEW(widget)) {
1921     lives_freep((void **)&widget_name);
1922     widget_name = lives_strdup("GtkTextView");
1923   } else {
1924 #endif
1925     switch (state) {
1926     // TODO: gtk+ 3.x can set multiple states
1927     case GTK_STATE_FLAG_ACTIVE:
1928       state_str = ":active";
1929       break;
1930     case GTK_STATE_FLAG_FOCUSED:
1931 #if GTK_CHECK_VERSION(3, 18, 0)
1932       state_str = ":focus";
1933 #endif
1934       break;
1935     case GTK_STATE_FLAG_PRELIGHT:
1936 #if GTK_CHECK_VERSION(3, 18, 0)
1937       state_str = ":hover";
1938 #else
1939       state_str = ":prelight";
1940 #endif
1941       break;
1942     case GTK_STATE_FLAG_SELECTED:
1943       state_str = ":selected";
1944       break;
1945     case GTK_STATE_FLAG_CHECKED:
1946       state_str = ":checked";
1947       break;
1948     case GTK_STATE_FLAG_INCONSISTENT:
1949 #if GTK_CHECK_VERSION(3, 18, 0)
1950       state_str = ":indeterminate";
1951 #endif
1952       break;
1953     case GTK_STATE_FLAG_BACKDROP:
1954 #if GTK_CHECK_VERSION(3, 18, 0)
1955       state_str = ":backdrop";
1956 #endif
1957       break;
1958     case GTK_STATE_FLAG_INSENSITIVE:
1959 #if GTK_CHECK_VERSION(3, 24, 0)
1960       state_str = ":disabled";
1961 #else
1962       state_str = ":insensitive";
1963 #endif
1964       break;
1965     default:
1966       state_str = "";
1967     }
1968     if (widget) {
1969       // special tweaks
1970       if (!selector) {
1971         if (GTK_IS_FRAME(widget)) {
1972           if (selector != xselector) lives_free(selector);
1973           selector = lives_strdup("label");
1974         } else if (GTK_IS_TEXT_VIEW(widget)) {
1975           if (selector != xselector) lives_free(selector);
1976           selector = lives_strdup("text");
1977         }
1978         if (GTK_IS_SPIN_BUTTON(widget)) {
1979           if (selector != xselector) lives_free(selector);
1980           selector = lives_strdup("*");
1981         }
1982       }
1983     }
1984 
1985     if (!selector || !(*selector)) selstr = lives_strdup("");
1986     else selstr = lives_strdup_printf(" %s", selector);
1987     if (widget) {
1988 #if GTK_CHECK_VERSION(3, 24, 0)
1989       wname = lives_strdup_printf("#%s%s%s", widget_name, state_str, selstr);
1990 #else
1991       wname = lives_strdup_printf("#%s%s%s", widget_name, selstr, state_str);
1992 #endif
1993     } else {
1994       wname = lives_strdup_printf("%s%s%s", widget_name, selstr, state_str);
1995     }
1996     lives_free(selstr);
1997     if (selector && selector != xselector) lives_free(selector);
1998 
1999 #ifdef GTK_TEXT_VIEW_CSS_BUG
2000   }
2001 #endif
2002 
2003   lives_free(widget_name);
2004   css_string = g_strdup_printf(" %s {\n %s: %s;}\n", wname, detail, value);
2005 
2006   if (show_css) g_print("running CSS %s\n", css_string);
2007 
2008 #if GTK_CHECK_VERSION(4, 0, 0)
2009   gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
2010                                   css_string, -1);
2011 #else
2012   gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
2013                                   css_string, -1, NULL);
2014 #endif
2015   lives_free(wname);
2016   lives_free(css_string);
2017   lives_widget_object_unref(provider);
2018   return TRUE;
2019 }
2020 
2021 
set_css_value(LiVESWidget * widget,LiVESWidgetState state,const char * detail,const char * value)2022 boolean set_css_value(LiVESWidget *widget, LiVESWidgetState state, const char *detail, const char *value) {
2023   if (state == GTK_STATE_FLAG_NORMAL) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_NORMAL, NULL, detail, value);
2024   if (state & GTK_STATE_FLAG_ACTIVE) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_ACTIVE, NULL, detail, value);
2025   if (state & GTK_STATE_FLAG_PRELIGHT) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_PRELIGHT, NULL, detail, value);
2026   if (state & GTK_STATE_FLAG_SELECTED) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_SELECTED, NULL, detail, value);
2027   if (state & GTK_STATE_FLAG_INSENSITIVE) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_INSENSITIVE, NULL, detail, value);
2028   if (state & GTK_STATE_FLAG_INCONSISTENT) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_INCONSISTENT, NULL, detail, value);
2029   if (state & GTK_STATE_FLAG_FOCUSED) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_FOCUSED, NULL, detail, value);
2030   if (state & GTK_STATE_FLAG_BACKDROP) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_BACKDROP, NULL, detail, value);
2031   if (state & GTK_STATE_FLAG_CHECKED) set_css_value_for_state_flag(widget, GTK_STATE_FLAG_CHECKED, NULL, detail, value);
2032   return TRUE;
2033 }
2034 #endif
2035 #endif
2036 
2037 
2038 #ifdef GUI_GTK
set_css_value_direct(LiVESWidget * widget,LiVESWidgetState state,const char * selector,const char * detail,const char * value)2039 boolean set_css_value_direct(LiVESWidget *widget, LiVESWidgetState state, const char *selector, const char *detail,
2040                              const char *value) {
2041 #if GTK_CHECK_VERSION(3, 16, 0)
2042 
2043 #if !GTK_CHECK_VERSION(3, 24, 0)
2044   if (!lives_strcmp(detail, "min-width")
2045       || !lives_strcmp(detail, "min-height")
2046       || !lives_strcmp(detail, "caret-color"))
2047     return FALSE;
2048 #endif
2049   return set_css_value_for_state_flag(widget, state, selector, detail, value);
2050 #endif
2051   return FALSE;
2052 }
2053 #endif
2054 
2055 
lives_widget_set_bg_color(LiVESWidget * widget,LiVESWidgetState state,const LiVESWidgetColor * color)2056 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_bg_color(LiVESWidget *widget, LiVESWidgetState state,
2057     const LiVESWidgetColor *color) {
2058 #ifdef GUI_GTK
2059 #if GTK_CHECK_VERSION(3, 0, 0)
2060 #if GTK_CHECK_VERSION(3, 16, 0)
2061   char *colref = gdk_rgba_to_string(color);
2062   boolean retb = set_css_value(widget, state, "background-color", colref);
2063   if (retb) retb = lives_widget_set_base_color(widget, state, color);
2064   lives_free(colref);
2065   return retb;
2066 #else
2067   gtk_widget_override_background_color(widget, state, color);
2068 #endif
2069 #else
2070   gtk_widget_modify_bg(widget, state, color);
2071   gtk_widget_modify_base(widget, state, color);
2072 #endif
2073   return TRUE;
2074 #endif
2075   return FALSE;
2076 }
2077 
2078 
lives_widget_set_fg_color(LiVESWidget * widget,LiVESWidgetState state,const LiVESWidgetColor * color)2079 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_fg_color(LiVESWidget *widget, LiVESWidgetState state,
2080     const LiVESWidgetColor *color) {
2081 #ifdef GUI_GTK
2082 #if GTK_CHECK_VERSION(3, 0, 0)
2083 #if GTK_CHECK_VERSION(3, 16, 0)
2084   char *colref = gdk_rgba_to_string(color);
2085   boolean retb = set_css_value(widget, state, "color", colref);
2086   lives_free(colref);
2087   return retb;
2088 #else
2089   gtk_widget_override_color(widget, state, color);
2090 #endif
2091 #else
2092   gtk_widget_modify_text(widget, state, color);
2093   gtk_widget_modify_fg(widget, state, color);
2094 #endif
2095   return TRUE;
2096 #endif
2097   return FALSE;
2098 }
2099 
2100 
lives_widget_set_text_color(LiVESWidget * widget,LiVESWidgetState state,const LiVESWidgetColor * color)2101 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_text_color(LiVESWidget *widget, LiVESWidgetState state,
2102     const LiVESWidgetColor *color) {
2103 #ifdef GUI_GTK
2104 #if GTK_CHECK_VERSION(3, 0, 0)
2105 #if GTK_CHECK_VERSION(3, 16, 0)
2106   char *colref = gdk_rgba_to_string(color);
2107   boolean retb = set_css_value(widget, state, "color", colref);
2108   lives_free(colref);
2109   return retb;
2110 #else
2111   gtk_widget_override_color(widget, state, color);
2112 #endif
2113 #else
2114   gtk_widget_modify_text(widget, state, color);
2115 #endif
2116   return TRUE;
2117 #endif
2118 #ifdef GUI_QT
2119   widget->set_text_color(state, color);
2120   return TRUE;
2121 #endif
2122   return FALSE;
2123 }
2124 
2125 
lives_widget_set_base_color(LiVESWidget * widget,LiVESWidgetState state,const LiVESWidgetColor * color)2126 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_base_color(LiVESWidget *widget, LiVESWidgetState state,
2127     const LiVESWidgetColor *color) {
2128 #ifdef GUI_GTK
2129 #if GTK_CHECK_VERSION(3, 0, 0)
2130 #if GTK_CHECK_VERSION(3, 16, 0)
2131   char *colref = gdk_rgba_to_string(color);
2132   boolean retb = set_css_value(widget, state, "background", colref);
2133   lives_free(colref);
2134   return retb;
2135 #else
2136   gtk_widget_override_color(widget, state, color);
2137 #endif
2138 #else
2139   gtk_widget_modify_base(widget, state, color);
2140 #endif
2141   return TRUE;
2142 #endif
2143 #ifdef GUI_QT
2144   widget->set_base_color(state, color);
2145   return TRUE;
2146 #endif
2147   return FALSE;
2148 }
2149 
2150 
lives_widget_set_outline_color(LiVESWidget * widget,LiVESWidgetState state,const LiVESWidgetColor * color)2151 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_outline_color(LiVESWidget *widget, LiVESWidgetState state,
2152     const LiVESWidgetColor *color) {
2153 #ifdef GUI_GTK
2154 #if GTK_CHECK_VERSION(3, 16, 0)
2155   char *colref = gdk_rgba_to_string(color);
2156   boolean retb = set_css_value(widget, state, "outline-color", colref);
2157   lives_free(colref);
2158   return retb;
2159 #endif
2160 #endif
2161   return FALSE;
2162 }
2163 
2164 
lives_widget_set_border_color(LiVESWidget * widget,LiVESWidgetState state,const LiVESWidgetColor * color)2165 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_border_color(LiVESWidget *widget, LiVESWidgetState state,
2166     const LiVESWidgetColor *color) {
2167 #ifdef GUI_GTK
2168 #if GTK_CHECK_VERSION(3, 16, 0)
2169   char *colref = gdk_rgba_to_string(color);
2170   boolean retb = set_css_value(widget, state, "border-color", colref);
2171   lives_free(colref);
2172   return retb;
2173 #endif
2174 #endif
2175   return FALSE;
2176 }
2177 
2178 
lives_widget_set_text_size(LiVESWidget * widget,LiVESWidgetState state,const char * size)2179 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_text_size(LiVESWidget *widget, LiVESWidgetState state,
2180     const char *size) {
2181 #ifdef GUI_GTK
2182 #if GTK_CHECK_VERSION(3, 16, 0)
2183   boolean retb = set_css_value(widget, state, "font-size", size);
2184   return retb;
2185 #endif
2186 #endif
2187   return FALSE;
2188 }
2189 
2190 
lives_widget_get_fg_state_color(LiVESWidget * widget,LiVESWidgetState state,LiVESWidgetColor * color)2191 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_fg_state_color(LiVESWidget *widget, LiVESWidgetState state,
2192     LiVESWidgetColor *color) {
2193 #ifdef GUI_GTK
2194 #if GTK_CHECK_VERSION(3, 0, 0)
2195 #if GTK_CHECK_VERSION(4, 0, 0)
2196   gtk_style_context_get_color(gtk_widget_get_style_context(widget), color);
2197 #else
2198   gtk_style_context_get_color(gtk_widget_get_style_context(widget), lives_widget_get_state(widget), color);
2199 #endif
2200 #else
2201   lives_widget_color_copy(color, &gtk_widget_get_style(widget)->fg[LIVES_WIDGET_STATE_NORMAL]);
2202 #endif
2203   return TRUE;
2204 #endif
2205 #ifdef GUI_QT
2206   lives_widget_color_copy(color, widget->get_fg_color(state));
2207   return TRUE;
2208 #endif
2209   return FALSE;
2210 }
2211 
2212 
lives_widget_get_bg_state_color(LiVESWidget * widget,LiVESWidgetState state,LiVESWidgetColor * color)2213 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_bg_state_color(LiVESWidget *widget, LiVESWidgetState state,
2214     LiVESWidgetColor *color) {
2215 #ifdef GUI_GTK
2216 #if GTK_CHECK_VERSION(3, 0, 0)
2217   G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2218   gtk_style_context_get_background_color(gtk_widget_get_style_context(widget), lives_widget_get_state(widget), color);
2219   G_GNUC_END_IGNORE_DEPRECATIONS
2220 #else
2221   lives_widget_color_copy(color, &gtk_widget_get_style(widget)->bg[LIVES_WIDGET_STATE_NORMAL]);
2222 #endif
2223   return TRUE;
2224 #endif
2225 #ifdef GUI_QT
2226   lives_widget_color_copy(color, widget->get_bg_color(state));
2227   return TRUE;
2228 #endif
2229   return FALSE;
2230 }
2231 
2232 
lives_widget_color_equal(LiVESWidgetColor * c1,const LiVESWidgetColor * c2)2233 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_color_equal(LiVESWidgetColor *c1, const LiVESWidgetColor *c2) {
2234 #ifdef GUI_GTK
2235 #if LIVES_WIDGET_COLOR_HAS_ALPHA
2236   if (c1->alpha != c2->alpha) return FALSE;
2237 #endif
2238   if (c1->red != c2->red || c1->green != c2->green || c1->blue != c2->blue) return FALSE;
2239   return TRUE;
2240 #endif
2241   return FALSE;
2242 }
2243 
2244 
lives_widget_color_mix(LiVESWidgetColor * c1,const LiVESWidgetColor * c2,float mixval)2245 boolean lives_widget_color_mix(LiVESWidgetColor *c1, const LiVESWidgetColor *c2, float mixval) {
2246   // c1 = mixval * c1 + (1. - mixval) * c2
2247   if (mixval < 0. || mixval > 1. || !c1 || !c2) return FALSE;
2248 #ifdef GUI_GTK
2249   c1->red = (float)c1->red * mixval + (float)c2->red * (1. - mixval);
2250   c1->green = (float)c1->green * mixval + (float)c2->green * (1. - mixval);
2251   c1->blue = (float)c1->blue * mixval + (float)c2->blue * (1. - mixval);
2252   return TRUE;
2253 #endif
2254   return FALSE;
2255 }
2256 
2257 
lives_widget_color_copy(LiVESWidgetColor * c1,const LiVESWidgetColor * c2)2258 WIDGET_HELPER_GLOBAL_INLINE LiVESWidgetColor *lives_widget_color_copy(LiVESWidgetColor *c1, const LiVESWidgetColor *c2) {
2259   // if c1 is NULL, create a new copy of c2, otherwise copy c2 -> c1
2260   LiVESWidgetColor *c0 = NULL;
2261 #ifdef GUI_GTK
2262   if (c1) {
2263     c1->red = c2->red;
2264     c1->green = c2->green;
2265     c1->blue = c2->blue;
2266 #if GTK_CHECK_VERSION(3, 0, 0)
2267     c1->alpha = c2->alpha;
2268 #else
2269     c1->pixel = c2->pixel;
2270 #endif
2271   } else {
2272 #if GTK_CHECK_VERSION(3, 0, 0)
2273     c0 = gdk_rgba_copy(c2);
2274 #else
2275     c0 = gdk_color_copy(c2);
2276 #endif
2277   }
2278 #endif
2279 
2280   return c0;
2281 }
2282 
2283 
lives_event_box_new(void)2284 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_event_box_new(void) {
2285   LiVESWidget *eventbox = NULL;
2286 #ifdef GUI_GTK
2287   eventbox = gtk_event_box_new();
2288 #endif
2289 #ifdef GUI_QT
2290   eventbox = new LiVESEventBox;
2291 #endif
2292   return eventbox;
2293 }
2294 
2295 
lives_event_box_set_above_child(LiVESEventBox * ebox,boolean set)2296 WIDGET_HELPER_GLOBAL_INLINE boolean lives_event_box_set_above_child(LiVESEventBox *ebox, boolean set) {
2297 #ifdef GUI_GTK
2298   gtk_event_box_set_above_child(ebox, set);
2299   return TRUE;
2300 #endif
2301 #ifdef GUI_QT
2302   return TRUE;
2303 #endif
2304   return FALSE;
2305 }
2306 
2307 
lives_image_new(void)2308 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_image_new(void) {
2309   LiVESWidget *image = NULL;
2310 #ifdef GUI_GTK
2311   image = gtk_image_new();
2312 #endif
2313 #ifdef GUI_QT
2314   image = new LiVESImage;
2315 #endif
2316   return image;
2317 }
2318 
2319 
get_real_size_from_icon_size(LiVESIconSize size)2320 WIDGET_HELPER_LOCAL_INLINE int get_real_size_from_icon_size(LiVESIconSize size) {
2321   switch (size) {
2322   case LIVES_ICON_SIZE_SMALL_TOOLBAR:
2323   case LIVES_ICON_SIZE_BUTTON:
2324   case LIVES_ICON_SIZE_MENU:
2325     return 16;
2326   case LIVES_ICON_SIZE_LARGE_TOOLBAR:
2327     return 24;
2328   case LIVES_ICON_SIZE_DND:
2329     return 32;
2330   case LIVES_ICON_SIZE_DIALOG:
2331     return 48;
2332   default:
2333     break;
2334   }
2335   return -1;
2336 }
2337 
2338 
lives_pixbuf_new_from_stock_at_size(const char * stock_id,LiVESIconSize size,int x,int y)2339 LiVESPixbuf *lives_pixbuf_new_from_stock_at_size(const char *stock_id, LiVESIconSize size, int x, int y) {
2340   LiVESPixbuf *pixbuf = NULL;
2341   LiVESWidget *image = NULL;
2342   if (size == LIVES_ICON_SIZE_CUSTOM) {
2343     if (x == y) {
2344       if (x == get_real_size_from_icon_size(LIVES_ICON_SIZE_MENU)) size = LIVES_ICON_SIZE_MENU;
2345       if (x == get_real_size_from_icon_size(LIVES_ICON_SIZE_SMALL_TOOLBAR))
2346         size = LIVES_ICON_SIZE_SMALL_TOOLBAR;
2347       if (x == get_real_size_from_icon_size(LIVES_ICON_SIZE_LARGE_TOOLBAR))
2348         size = LIVES_ICON_SIZE_LARGE_TOOLBAR;
2349       if (x == get_real_size_from_icon_size(LIVES_ICON_SIZE_BUTTON)) size = LIVES_ICON_SIZE_BUTTON;
2350       if (x == get_real_size_from_icon_size(LIVES_ICON_SIZE_DND)) size = LIVES_ICON_SIZE_DND;
2351       if (x == get_real_size_from_icon_size(LIVES_ICON_SIZE_DIALOG)) size = LIVES_ICON_SIZE_DIALOG;
2352     }
2353   }
2354 
2355   if (size != LIVES_ICON_SIZE_CUSTOM) {
2356     if (lives_has_icon(widget_opts.icon_theme, stock_id, size)) {
2357 #if GTK_CHECK_VERSION(3, 10, 0)
2358       pixbuf = gtk_icon_theme_load_icon((LiVESIconTheme *)widget_opts.icon_theme, stock_id,
2359                                         get_real_size_from_icon_size(size),
2360                                         GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
2361       return pixbuf;
2362 #else
2363       image = gtk_image_new_from_stock(stock_id, size);
2364 #endif
2365     }
2366     if (image) return lives_image_get_pixbuf(LIVES_IMAGE(image));
2367   }
2368 
2369   // custom size, or failed at specified size
2370   // try all sizes to see if we get one
2371   if (!image) {
2372     if (lives_has_icon(widget_opts.icon_theme, stock_id, LIVES_ICON_SIZE_DIALOG)) {
2373       size = LIVES_ICON_SIZE_DIALOG;
2374     } else if (lives_has_icon(widget_opts.icon_theme, stock_id, LIVES_ICON_SIZE_DND)) {
2375       size = LIVES_ICON_SIZE_DND;
2376     } else if (lives_has_icon(widget_opts.icon_theme, stock_id, LIVES_ICON_SIZE_LARGE_TOOLBAR)) {
2377       size = LIVES_ICON_SIZE_LARGE_TOOLBAR;
2378     } else if (lives_has_icon(widget_opts.icon_theme, stock_id, LIVES_ICON_SIZE_SMALL_TOOLBAR)) {
2379       size = LIVES_ICON_SIZE_SMALL_TOOLBAR;
2380     } else if (lives_has_icon(widget_opts.icon_theme, stock_id, LIVES_ICON_SIZE_BUTTON)) {
2381       size = LIVES_ICON_SIZE_BUTTON;
2382     } else if (lives_has_icon(widget_opts.icon_theme, stock_id, LIVES_ICON_SIZE_MENU)) {
2383       size = LIVES_ICON_SIZE_MENU;
2384     } else return NULL;
2385 
2386 #if GTK_CHECK_VERSION(3, 10, 0)
2387     pixbuf = gtk_icon_theme_load_icon((LiVESIconTheme *)widget_opts.icon_theme, stock_id,
2388                                       get_real_size_from_icon_size(size),
2389                                       GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
2390     return pixbuf;
2391 #else
2392     image = gtk_image_new_from_stock(stock_id, size);
2393 #endif
2394     if (!image) return NULL;
2395     pixbuf = lives_image_get_pixbuf(LIVES_IMAGE(image));
2396   }
2397   return pixbuf;
2398 }
2399 
2400 
lives_image_new_from_stock_at_size(const char * stock_id,LiVESIconSize size,int x,int y)2401 LiVESWidget *lives_image_new_from_stock_at_size(const char *stock_id, LiVESIconSize size, int x, int y) {
2402   LiVESWidget *image = NULL;
2403   LiVESPixbuf *pixbuf = lives_pixbuf_new_from_stock_at_size(stock_id, size, x, y);
2404   if (pixbuf) {
2405     image = lives_image_new_from_pixbuf(pixbuf);
2406     lives_widget_object_unref(pixbuf);
2407   }
2408   return image;
2409 }
2410 
2411 
lives_image_new_from_stock(const char * stock_id,LiVESIconSize size)2412 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_image_new_from_stock(const char *stock_id,
2413     LiVESIconSize size) {
2414   return lives_image_new_from_stock_at_size(stock_id, size, get_real_size_from_icon_size(size),
2415          get_real_size_from_icon_size(size));
2416 }
2417 
2418 
lives_image_new_from_file(const char * filename)2419 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_image_new_from_file(const char *filename) {
2420   LiVESWidget *image = NULL;
2421 #ifdef GUI_GTK
2422   image = gtk_image_new_from_file(filename);
2423 #endif
2424   return image;
2425 }
2426 
2427 
lives_image_new_from_pixbuf(LiVESPixbuf * pixbuf)2428 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_image_new_from_pixbuf(LiVESPixbuf *pixbuf) {
2429   LiVESWidget *image = NULL;
2430 #ifdef GUI_GTK
2431   image = gtk_image_new_from_pixbuf(pixbuf);
2432 #endif
2433 #ifdef GUI_QT
2434   image = new LiVESImage(static_cast<QImage *>(pixbuf));
2435 #endif
2436   return image;
2437 }
2438 
2439 
lives_image_set_from_pixbuf(LiVESImage * image,LiVESPixbuf * pixbuf)2440 WIDGET_HELPER_GLOBAL_INLINE boolean lives_image_set_from_pixbuf(LiVESImage *image, LiVESPixbuf *pixbuf) {
2441 #ifdef GUI_GTK
2442   gtk_image_set_from_pixbuf(image, pixbuf);
2443   return TRUE;
2444 #endif
2445 #ifdef GUI_QT
2446   *(static_cast<QImage *>(image)) = pixbuf->copy(0, 0, (static_cast<QImage *>(pixbuf))->width(),
2447                                     (static_cast<QImage *>(pixbuf))->height());
2448   return TRUE;
2449 #endif
2450   return FALSE;
2451 }
2452 
2453 
lives_image_get_pixbuf(LiVESImage * image)2454 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_image_get_pixbuf(LiVESImage *image) {
2455   LiVESPixbuf *pixbuf = NULL;
2456 #ifdef GUI_GTK
2457   pixbuf = gtk_image_get_pixbuf(image);
2458 #endif
2459 #ifdef GUI_QT
2460   pixbuf = new LiVESPixbuf(image);
2461 #endif
2462   return pixbuf;
2463 }
2464 
2465 
lives_color_parse(const char * spec,LiVESWidgetColor * color)2466 WIDGET_HELPER_GLOBAL_INLINE boolean lives_color_parse(const char *spec, LiVESWidgetColor *color) {
2467   boolean retval = FALSE;
2468 #ifdef GUI_GTK
2469 #if GTK_CHECK_VERSION(3, 0, 0)
2470   retval = gdk_rgba_parse(color, spec);
2471 #else
2472   retval = gdk_color_parse(spec, color);
2473 #endif
2474 #endif
2475   return retval;
2476 }
2477 
2478 
lives_dialog_get_content_area(LiVESDialog * dialog)2479 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_dialog_get_content_area(LiVESDialog *dialog) {
2480 #ifdef GUI_GTK
2481 
2482 #if GTK_CHECK_VERSION(2, 14, 0)
2483   return gtk_dialog_get_content_area(LIVES_DIALOG(dialog));
2484 #else
2485   return LIVES_DIALOG(dialog)->vbox;
2486 #endif
2487 #endif
2488 #ifdef GUI_QT
2489   return dialog->get_content_area();
2490 #endif
2491   return NULL;
2492 }
2493 
2494 
lives_dialog_get_action_area(LiVESDialog * dialog)2495 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_dialog_get_action_area(LiVESDialog *dialog) {
2496 #ifdef GUI_GTK
2497 #if GTK_CHECK_VERSION(2, 14, 0)
2498 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2499   G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2500 #endif
2501   return gtk_dialog_get_action_area(LIVES_DIALOG(dialog));
2502 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
2503   G_GNUC_END_IGNORE_DEPRECATIONS
2504 #endif
2505 #else
2506   return LIVES_DIALOG(dialog)->vbox;
2507 #endif
2508 #endif
2509 #ifdef GUI_QT
2510   return dialog->get_action_area();
2511 #endif
2512   return NULL;
2513 }
2514 
2515 
lives_widget_set_margin_left(LiVESWidget * widget,int margin)2516 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_margin_left(LiVESWidget *widget, int margin) {
2517 #ifdef GUI_GTK
2518 #if GTK_CHECK_VERSION(3, 0, 0)
2519 #if GTK_CHECK_VERSION(3, 12, 0)
2520   gtk_widget_set_margin_start(widget, margin);
2521 #else
2522   gtk_widget_set_margin_left(widget, margin);
2523 #endif
2524   return TRUE;
2525 #endif
2526 #endif
2527   return FALSE;
2528 }
2529 
2530 
lives_widget_set_margin_right(LiVESWidget * widget,int margin)2531 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_margin_right(LiVESWidget *widget, int margin) {
2532 #ifdef GUI_GTK
2533 #if GTK_CHECK_VERSION(3, 0, 0)
2534 #if GTK_CHECK_VERSION(3, 12, 0)
2535   gtk_widget_set_margin_end(widget, margin);
2536 #else
2537   gtk_widget_set_margin_right(widget, margin);
2538 #endif
2539   return TRUE;
2540 #endif
2541 #endif
2542   return FALSE;
2543 }
2544 
2545 
lives_widget_set_margin_top(LiVESWidget * widget,int margin)2546 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_margin_top(LiVESWidget *widget, int margin) {
2547 #ifdef GUI_GTK
2548 #if GTK_CHECK_VERSION(3, 0, 0)
2549   gtk_widget_set_margin_top(widget, margin);
2550   return TRUE;
2551 #endif
2552 #endif
2553   return FALSE;
2554 }
2555 
2556 
lives_widget_set_margin_bottom(LiVESWidget * widget,int margin)2557 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_margin_bottom(LiVESWidget *widget, int margin) {
2558 #ifdef GUI_GTK
2559 #if GTK_CHECK_VERSION(3, 0, 0)
2560   gtk_widget_set_margin_bottom(widget, margin);
2561   return TRUE;
2562 #endif
2563 #endif
2564   return FALSE;
2565 }
2566 
2567 
lives_widget_set_margin(LiVESWidget * widget,int margin)2568 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_margin(LiVESWidget *widget, int margin) {
2569 #ifdef GUI_GTK
2570 #if GTK_CHECK_VERSION(3, 0, 0)
2571   lives_widget_set_margin_bottom(widget, margin);
2572   lives_widget_set_margin_top(widget, margin);
2573   lives_widget_set_margin_left(widget, margin);
2574   lives_widget_set_margin_right(widget, margin);
2575   return TRUE;
2576 #endif
2577 #endif
2578   return FALSE;
2579 }
2580 
2581 
lives_widget_set_padding(LiVESWidget * widget,int padding)2582 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_padding(LiVESWidget *widget, int padding) {
2583 #ifdef GUI_GTK
2584 #if GTK_CHECK_VERSION(3, 16, 0)
2585   char *wpx = lives_strdup_printf("%dpx", padding);
2586   set_css_value_direct(widget, LIVES_WIDGET_STATE_NORMAL, "", "padding", wpx);
2587   lives_free(wpx);
2588   return TRUE;
2589 #endif
2590 #endif
2591   return FALSE;
2592 }
2593 
2594 
2595 
lives_dialog_add_action_widget(LiVESDialog * dialog,LiVESWidget * widget,int response)2596 WIDGET_HELPER_GLOBAL_INLINE boolean lives_dialog_add_action_widget(LiVESDialog *dialog, LiVESWidget *widget, int response) {
2597   // TODO: use lives_dialog_add_button, lives_dialog_add_button_from_stock
2598 #ifdef GUI_GTK
2599 #if GTK_CHECK_VERSION(3, 0, 0)
2600   lives_widget_set_margin_left(widget, widget_opts.packing_width / 2);
2601   lives_widget_set_margin_right(widget, widget_opts.packing_width / 2);
2602 #endif
2603   gtk_dialog_add_action_widget(dialog, widget, response);
2604   gtk_box_set_spacing(LIVES_BOX(lives_widget_get_parent(widget)), widget_opts.packing_width * 4);
2605   return TRUE;
2606 #endif
2607   return FALSE;
2608 }
2609 
2610 
lives_window_new(LiVESWindowType wintype)2611 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_window_new(LiVESWindowType wintype) {
2612   LiVESWidget *window = NULL;
2613 #ifdef GUI_GTK
2614   window = gtk_window_new(wintype);
2615 #endif
2616   return window;
2617 }
2618 
2619 
lives_window_set_title(LiVESWindow * window,const char * title)2620 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_title(LiVESWindow *window, const char *title) {
2621 #ifdef GUI_GTK
2622   char *ntitle;
2623   if (*widget_opts.title_prefix) {
2624     ntitle = lives_strdup_printf("%s%s", widget_opts.title_prefix, title);
2625   } else ntitle = lives_strdup(title);
2626   gtk_window_set_title(window, ntitle);
2627   lives_free(ntitle);
2628   return TRUE;
2629 #endif
2630   return FALSE;
2631 }
2632 
2633 
lives_window_set_transient_for(LiVESWindow * window,LiVESWindow * parent)2634 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_transient_for(LiVESWindow *window, LiVESWindow *parent) {
2635 #ifdef GUI_GTK
2636   gtk_window_set_transient_for(window, parent);
2637   return TRUE;
2638 #endif
2639   return FALSE;
2640 }
2641 
2642 
modunmap(LiVESWindow * win,livespointer data)2643 static void modunmap(LiVESWindow *win, livespointer data) {if (win == modalw) modalw = NULL;}
moddest(LiVESWindow * win,livespointer data)2644 static void moddest(LiVESWindow *win, livespointer data) {if (win == modalw) modalw = NULL;}
moddelete(LiVESWindow * win,LiVESXEvent * event,livespointer data)2645 static boolean moddelete(LiVESWindow *win, LiVESXEvent *event, livespointer data) {
2646   if (win == modalw) modalw = NULL;
2647   return TRUE;
2648 }
2649 
lives_window_set_modal(LiVESWindow * window,boolean modal)2650 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_modal(LiVESWindow *window, boolean modal) {
2651   if (window == modalw) {
2652     lives_signal_handlers_sync_disconnect_by_func(LIVES_GUI_OBJECT(modalw), LIVES_GUI_CALLBACK(moddest), NULL);
2653     lives_signal_handlers_sync_disconnect_by_func(LIVES_GUI_OBJECT(modalw), LIVES_GUI_CALLBACK(moddelete), NULL);
2654     lives_signal_handlers_sync_disconnect_by_func(LIVES_GUI_OBJECT(modalw), LIVES_GUI_CALLBACK(modunmap), NULL);
2655     modalw = NULL;
2656   }
2657   if (modal) {
2658     lives_signal_sync_connect(window, LIVES_WIDGET_DELETE_EVENT,
2659                               LIVES_GUI_CALLBACK(moddelete), NULL);
2660     lives_signal_sync_connect(window, LIVES_WIDGET_DESTROY_SIGNAL,
2661                               LIVES_GUI_CALLBACK(moddest), NULL);
2662     lives_signal_sync_connect(window, LIVES_WIDGET_UNMAP_SIGNAL,
2663                               LIVES_GUI_CALLBACK(modunmap), NULL);
2664     modalw = window;
2665   }
2666 #ifdef GUI_GTK
2667   gtk_window_set_modal(window, modal);
2668   return TRUE;
2669 #endif
2670   return FALSE;
2671 }
2672 
2673 
lives_window_get_modal(LiVESWindow * window)2674 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_get_modal(LiVESWindow *window) {
2675 #ifdef GUI_GTK
2676   return gtk_window_get_modal(window);
2677 #endif
2678   return FALSE;
2679 }
2680 
2681 
lives_window_set_deletable(LiVESWindow * window,boolean deletable)2682 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_deletable(LiVESWindow *window, boolean deletable) {
2683 #ifdef GUI_GTK
2684   gtk_window_set_deletable(window, deletable);
2685   return TRUE;
2686 #endif
2687   return FALSE;
2688 }
2689 
2690 
lives_window_set_resizable(LiVESWindow * window,boolean resizable)2691 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_resizable(LiVESWindow *window, boolean resizable) {
2692 #ifdef GUI_GTK
2693   gtk_window_set_resizable(window, resizable);
2694   return TRUE;
2695 #endif
2696   return FALSE;
2697 }
2698 
2699 
lives_window_set_keep_below(LiVESWindow * window,boolean set)2700 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_keep_below(LiVESWindow *window, boolean set) {
2701 #ifdef GUI_GTK
2702   gtk_window_set_keep_below(window, set);
2703   return TRUE;
2704 #endif
2705   return FALSE;
2706 }
2707 
2708 
lives_window_set_keep_above(LiVESWindow * window,boolean set)2709 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_keep_above(LiVESWindow *window, boolean set) {
2710 #ifdef GUI_GTK
2711   gtk_window_set_keep_above(window, set);
2712   return TRUE;
2713 #endif
2714   return FALSE;
2715 }
2716 
2717 
lives_window_set_decorated(LiVESWindow * window,boolean set)2718 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_decorated(LiVESWindow *window, boolean set) {
2719 #ifdef GUI_GTK
2720   gtk_window_set_decorated(window, set);
2721   return TRUE;
2722 #endif
2723   return FALSE;
2724 }
2725 
2726 
lives_window_set_auto_startup_notification(boolean set)2727 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_auto_startup_notification(boolean set) {
2728 #ifdef GUI_GTK
2729   gtk_window_set_auto_startup_notification(set);
2730   return TRUE;
2731 #endif
2732 #ifdef GUI_QT
2733   // TODO
2734 #endif
2735 
2736   return FALSE;
2737 }
2738 
2739 
2740 /* WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_screen(LiVESWindow *window, LiVESXScreen *screen) { */
2741 /*   if (LIVES_IS_WINDOW(window)) { */
2742 /* #ifdef GUI_GTK */
2743 /*     gtk_window_set_screen(window, screen); */
2744 /*     return TRUE; */
2745 /* #endif */
2746 /*   } */
2747 /*   return FALSE; */
2748 /* } */
2749 
2750 
lives_window_set_monitor(LiVESWindow * window,int monnum)2751 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_monitor(LiVESWindow *window, int monnum) {
2752 #ifdef GUI_GTK
2753   if (LIVES_IS_WINDOW(window)) {
2754 #if !GTK_CHECK_VERSION(3, 20, 0)
2755     gtk_window_set_screen(window, mainw->mgeom[monnum].screen);
2756 #else
2757     gtk_window_fullscreen_on_monitor(window, mainw->mgeom[monnum].screen, monnum);
2758     gtk_window_unfullscreen(window);
2759 #endif
2760     return TRUE;
2761   }
2762 #endif
2763   return FALSE;
2764 }
2765 
2766 
lives_window_set_default_size(LiVESWindow * window,int width,int height)2767 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_default_size(LiVESWindow *window, int width, int height) {
2768 #ifdef GUI_GTK
2769   gtk_window_set_default_size(window, width, height);
2770   return TRUE;
2771 #endif
2772 #ifdef GUI_QT
2773   if (LIVES_IS_WINDOW(window)) {
2774     window->resize(width, height);
2775   }
2776   return TRUE;
2777 #endif
2778   return FALSE;
2779 }
2780 
2781 
lives_window_get_title(LiVESWindow * window)2782 WIDGET_HELPER_GLOBAL_INLINE const char *lives_window_get_title(LiVESWindow *window) {
2783 #ifdef GUI_GTK
2784   return gtk_window_get_title(window);
2785 #endif
2786 #ifdef GUI_QT
2787   return (const char *)window->windowTitle().toUtf8().constData();
2788 #endif
2789   return NULL;
2790 }
2791 
2792 
lives_window_move(LiVESWindow * window,int x,int y)2793 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_move(LiVESWindow *window, int x, int y) {
2794 #ifdef GUI_GTK
2795   gtk_window_move(window, x, y);
2796   return TRUE;
2797 #endif
2798   return FALSE;
2799 }
2800 
2801 
lives_widget_get_position(LiVESWidget * widget,int * x,int * y)2802 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_position(LiVESWidget *widget, int *x, int *y) {
2803 #ifdef GUI_GTK
2804   GdkWindow *window = lives_widget_get_xwindow(widget);
2805   if (x) *x = 0;
2806   if (y) *y = 0;
2807   if (GDK_IS_WINDOW(window))
2808     gdk_window_get_position(window, x, y);
2809   return TRUE;
2810 #endif
2811   return FALSE;
2812 }
2813 
2814 
lives_window_get_position(LiVESWindow * window,int * x,int * y)2815 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_get_position(LiVESWindow *window, int *x, int *y) {
2816 #ifdef GUI_GTK
2817   gtk_window_get_position(window, x, y);
2818   return TRUE;
2819 #endif
2820   return FALSE;
2821 }
2822 
2823 
lives_window_set_position(LiVESWindow * window,LiVESWindowPosition pos)2824 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_position(LiVESWindow *window, LiVESWindowPosition pos) {
2825 #ifdef GUI_GTK
2826   gtk_window_set_position(window, pos);
2827   return TRUE;
2828 #endif
2829   return FALSE;
2830 }
2831 
2832 
lives_window_set_hide_titlebar_when_maximized(LiVESWindow * window,boolean setting)2833 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_hide_titlebar_when_maximized(LiVESWindow *window, boolean setting) {
2834 #ifdef GUI_GTK
2835 #if GTK_CHECK_VERSION(3, 4, 0)
2836   gtk_window_set_hide_titlebar_when_maximized(window, setting);
2837 #endif
2838   return TRUE;
2839 #endif
2840 #ifdef GUI_QT
2841   // TODO
2842 #endif
2843   return FALSE;
2844 }
2845 
2846 
lives_window_resize(LiVESWindow * window,int width,int height)2847 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_resize(LiVESWindow *window, int width, int height) {
2848 #ifdef GUI_GTK
2849   gtk_window_resize(window, width, height);
2850   gtk_widget_set_size_request(GTK_WIDGET(window), width, height);
2851   return TRUE;
2852 #endif
2853   // TODO
2854   return FALSE;
2855 }
2856 
2857 
lives_window_present(LiVESWindow * window)2858 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_present(LiVESWindow *window) {
2859 #ifdef GUI_GTK
2860   gtk_window_present(window);
2861   return TRUE;
2862 #endif
2863 #ifdef GUI_QT
2864   window->raise();
2865   return TRUE;
2866 #endif
2867   return FALSE;
2868 }
2869 
2870 
lives_window_fullscreen(LiVESWindow * window)2871 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_fullscreen(LiVESWindow *window) {
2872 #ifdef GUI_GTK
2873   gtk_window_fullscreen(window);
2874   return TRUE;
2875 #endif
2876   return FALSE;
2877 }
2878 
2879 
lives_window_unfullscreen(LiVESWindow * window)2880 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_unfullscreen(LiVESWindow *window) {
2881 #ifdef GUI_GTK
2882   gtk_window_unfullscreen(window);
2883   return TRUE;
2884 #endif
2885   return FALSE;
2886 }
2887 
2888 
lives_window_maximize(LiVESWindow * window)2889 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_maximize(LiVESWindow *window) {
2890 #ifdef GUI_GTK
2891   gtk_window_maximize(window);
2892   return TRUE;
2893 #endif
2894   return FALSE;
2895 }
2896 
2897 
lives_window_unmaximize(LiVESWindow * window)2898 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_unmaximize(LiVESWindow *window) {
2899 #ifdef GUI_GTK
2900   gtk_window_unmaximize(window);
2901   return TRUE;
2902 #endif
2903   return FALSE;
2904 }
2905 
2906 
lives_window_get_focus(LiVESWindow * window)2907 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_window_get_focus(LiVESWindow *window) {
2908 #ifdef GUI_GTK
2909   return gtk_window_get_focus(window);
2910 #endif
2911   return NULL;
2912 }
2913 
2914 
lives_accel_group_new(void)2915 WIDGET_HELPER_GLOBAL_INLINE LiVESAccelGroup *lives_accel_group_new(void) {
2916   LiVESAccelGroup *group = NULL;
2917 #ifdef GUI_GTK
2918   group = gtk_accel_group_new();
2919 #endif
2920 #ifdef GUI_QT
2921   group = new LiVESAccelGroup;
2922 #endif
2923   return group;
2924 }
2925 
2926 
lives_accel_group_connect(LiVESAccelGroup * group,uint32_t key,LiVESXModifierType mod,LiVESAccelFlags flags,LiVESWidgetClosure * closure)2927 WIDGET_HELPER_GLOBAL_INLINE boolean lives_accel_group_connect(LiVESAccelGroup *group, uint32_t key, LiVESXModifierType mod,
2928     LiVESAccelFlags flags, LiVESWidgetClosure *closure) {
2929 #ifdef GUI_GTK
2930   gtk_accel_group_connect(group, key, mod, flags, closure);
2931   return TRUE;
2932 #endif
2933 #ifdef GUI_QT
2934   group->connect(key, mod, flags, closure);
2935   return FALSE;
2936 #endif
2937 }
2938 
2939 
lives_accel_group_disconnect(LiVESAccelGroup * group,LiVESWidgetClosure * closure)2940 WIDGET_HELPER_GLOBAL_INLINE boolean lives_accel_group_disconnect(LiVESAccelGroup *group, LiVESWidgetClosure *closure) {
2941 #ifdef GUI_GTK
2942   gtk_accel_group_disconnect(group, closure);
2943   return TRUE;
2944 #endif
2945 #ifdef GUI_QT
2946   group->disconnect(closure);
2947   return TRUE;
2948 #endif
2949   return FALSE;
2950 }
2951 
2952 
lives_widget_add_accelerator(LiVESWidget * widget,const char * accel_signal,LiVESAccelGroup * accel_group,uint32_t accel_key,LiVESXModifierType accel_mods,LiVESAccelFlags accel_flags)2953 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_add_accelerator(LiVESWidget *widget, const char *accel_signal,
2954     LiVESAccelGroup *accel_group,
2955     uint32_t accel_key, LiVESXModifierType accel_mods, LiVESAccelFlags accel_flags) {
2956 #ifdef GUI_GTK
2957   gtk_widget_add_accelerator(widget, accel_signal, accel_group, accel_key, accel_mods, accel_flags);
2958   return TRUE;
2959 #endif
2960 #ifdef GUI_QT
2961   widget->add_accel(accel_signal, accel_group, accel_key, accel_mods, accel_flags);
2962   return TRUE;
2963 #endif
2964   return FALSE;
2965 }
2966 
2967 
lives_window_add_accel_group(LiVESWindow * window,LiVESAccelGroup * group)2968 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_add_accel_group(LiVESWindow *window, LiVESAccelGroup *group) {
2969 #ifdef GUI_GTK
2970   gtk_window_add_accel_group(window, group);
2971   return TRUE;
2972 #endif
2973 #ifdef GUI_QT
2974   window->add_accel_group(group);
2975   return TRUE;
2976 #endif
2977   return FALSE;
2978 }
2979 
2980 
lives_widget_has_focus(LiVESWidget * widget)2981 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_has_focus(LiVESWidget *widget) {
2982   /// physical
2983 #ifdef GUI_GTK
2984   return gtk_widget_has_focus(widget);
2985 #endif
2986   return FALSE;
2987 }
2988 
2989 
lives_widget_is_focus(LiVESWidget * widget)2990 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_focus(LiVESWidget *widget) {
2991   /// logical
2992 #ifdef GUI_GTK
2993   return gtk_widget_is_focus(widget);
2994 #endif
2995   return FALSE;
2996 }
2997 
2998 
lives_widget_has_default(LiVESWidget * widget)2999 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_has_default(LiVESWidget *widget) {
3000 #ifdef GUI_GTK
3001   return gtk_widget_has_default(widget);
3002 #endif
3003   return FALSE;
3004 }
3005 
3006 
lives_window_remove_accel_group(LiVESWindow * window,LiVESAccelGroup * group)3007 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_remove_accel_group(LiVESWindow *window, LiVESAccelGroup *group) {
3008 #ifdef GUI_GTK
3009   gtk_window_remove_accel_group(window, group);
3010   return TRUE;
3011 #endif
3012 #ifdef GUI_QT
3013   window->remove_accel_group(group);
3014   return TRUE;
3015 #endif
3016   return FALSE;
3017 }
3018 
3019 
lives_menu_set_accel_group(LiVESMenu * menu,LiVESAccelGroup * group)3020 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_set_accel_group(LiVESMenu *menu, LiVESAccelGroup *group) {
3021 #ifdef GUI_GTK
3022   gtk_menu_set_accel_group(menu, group);
3023   return TRUE;
3024 #endif
3025 #ifdef GUI_QT
3026   menu->add_accel_group(group);
3027   return TRUE;
3028 #endif
3029   return FALSE;
3030 }
3031 
3032 
lives_accel_groups_activate(LiVESWidgetObject * object,uint32_t key,LiVESXModifierType mod)3033 WIDGET_HELPER_GLOBAL_INLINE boolean lives_accel_groups_activate(LiVESWidgetObject *object, uint32_t key,
3034     LiVESXModifierType mod) {
3035 #ifdef GUI_GTK
3036   gtk_accel_groups_activate(object, key, mod);
3037   return TRUE;
3038 #endif
3039 #ifdef GUI_QT
3040   object->activate_accel(key, mod);
3041   return TRUE;
3042 #endif
3043   return FALSE;
3044 }
3045 
3046 
lives_pixbuf_new(boolean has_alpha,int width,int height)3047 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_pixbuf_new(boolean has_alpha, int width, int height) {
3048 #ifdef GUI_GTK
3049   // alpha fmt is RGBA post mult
3050   return gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
3051 #endif
3052   return NULL;
3053 }
3054 
3055 
lives_pixbuf_copy(LiVESPixbuf * orig)3056 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_pixbuf_copy(LiVESPixbuf *orig) {
3057 #ifdef GUI_GTK
3058   // alpha fmt is RGBA post mult
3059   return gdk_pixbuf_copy(orig);
3060 #endif
3061   return NULL;
3062 }
3063 
3064 
lives_pixbuf_new_from_data(const unsigned char * buf,boolean has_alpha,int width,int height,int rowstride,LiVESPixbufDestroyNotify lives_free_buffer_fn,livespointer destroy_fn_data)3065 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_pixbuf_new_from_data(const unsigned char *buf, boolean has_alpha, int width,
3066     int height,
3067     int rowstride, LiVESPixbufDestroyNotify lives_free_buffer_fn,
3068     livespointer destroy_fn_data) {
3069 #ifdef GUI_GTK
3070   return gdk_pixbuf_new_from_data((const guchar *)buf, GDK_COLORSPACE_RGB, has_alpha, 8, width, height, rowstride,
3071                                   lives_free_buffer_fn,
3072                                   destroy_fn_data);
3073 #endif
3074   return NULL;
3075 }
3076 
3077 
lives_pixbuf_new_from_file(const char * filename,LiVESError ** error)3078 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_pixbuf_new_from_file(const char *filename, LiVESError **error) {
3079 #ifdef GUI_GTK
3080   return gdk_pixbuf_new_from_file(filename, error);
3081 #endif
3082   return NULL;
3083 }
3084 
3085 
lives_pixbuf_new_from_file_at_scale(const char * filename,int width,int height,boolean preserve_aspect_ratio,LiVESError ** error)3086 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_pixbuf_new_from_file_at_scale(const char *filename, int width, int height,
3087     boolean preserve_aspect_ratio,
3088     LiVESError **error) {
3089 #ifdef GUI_GTK
3090   return gdk_pixbuf_new_from_file_at_scale(filename, width, height, preserve_aspect_ratio, error);
3091 #endif
3092   return NULL;
3093 }
3094 
3095 
lives_pixbuf_get_rowstride(const LiVESPixbuf * pixbuf)3096 WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_rowstride(const LiVESPixbuf *pixbuf) {
3097 #ifdef GUI_GTK
3098   return gdk_pixbuf_get_rowstride(pixbuf);
3099 #endif
3100 
3101 #ifdef GUI_QT
3102   return (dynamic_cast<const QImage *>(pixbuf))->bytesPerLine();
3103 #endif
3104 }
3105 
3106 
lives_pixbuf_get_width(const LiVESPixbuf * pixbuf)3107 WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_width(const LiVESPixbuf *pixbuf) {
3108 #ifdef GUI_GTK
3109   return gdk_pixbuf_get_width(pixbuf);
3110 #endif
3111 
3112 #ifdef GUI_QT
3113   return (dynamic_cast<const QImage *>(pixbuf))->width();
3114 #endif
3115 }
3116 
3117 
lives_pixbuf_get_height(const LiVESPixbuf * pixbuf)3118 WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_height(const LiVESPixbuf *pixbuf) {
3119 #ifdef GUI_GTK
3120   return gdk_pixbuf_get_height(pixbuf);
3121 #endif
3122 
3123 #ifdef GUI_QT
3124   return (dynamic_cast<const QImage *>(pixbuf))->height();
3125 #endif
3126 }
3127 
3128 
lives_pixbuf_get_n_channels(const LiVESPixbuf * pixbuf)3129 WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_n_channels(const LiVESPixbuf *pixbuf) {
3130 #ifdef GUI_GTK
3131   return gdk_pixbuf_get_n_channels(pixbuf);
3132 #endif
3133 
3134 #ifdef GUI_QT
3135   return (dynamic_cast<const QImage *>(pixbuf))->depth() >> 3;
3136 #endif
3137 }
3138 
3139 
lives_pixbuf_get_pixels(const LiVESPixbuf * pixbuf)3140 WIDGET_HELPER_GLOBAL_INLINE unsigned char *lives_pixbuf_get_pixels(const LiVESPixbuf *pixbuf) {
3141 #ifdef GUI_GTK
3142   return gdk_pixbuf_get_pixels(pixbuf);
3143 #endif
3144 
3145 #ifdef GUI_QT
3146   return (uchar *)(dynamic_cast<const QImage *>(pixbuf))->bits();
3147 #endif
3148 }
3149 
3150 
lives_pixbuf_get_pixels_readonly(const LiVESPixbuf * pixbuf)3151 WIDGET_HELPER_GLOBAL_INLINE const unsigned char *lives_pixbuf_get_pixels_readonly(const LiVESPixbuf *pixbuf) {
3152 #ifdef GUI_GTK
3153   return (const guchar *)gdk_pixbuf_get_pixels(pixbuf);
3154 #endif
3155 
3156 #ifdef GUI_QT
3157   return (const uchar *)(dynamic_cast<const QImage *>(pixbuf))->bits();
3158 #endif
3159 }
3160 
3161 
lives_pixbuf_get_has_alpha(const LiVESPixbuf * pixbuf)3162 WIDGET_HELPER_GLOBAL_INLINE boolean lives_pixbuf_get_has_alpha(const LiVESPixbuf *pixbuf) {
3163 #ifdef GUI_GTK
3164   return gdk_pixbuf_get_has_alpha(pixbuf);
3165 #endif
3166 
3167 #ifdef GUI_QT
3168   return (dynamic_cast<const QImage *>(pixbuf))->hasAlphaChannel();
3169 #endif
3170 }
3171 
3172 
lives_pixbuf_scale_simple(const LiVESPixbuf * src,int dest_width,int dest_height,LiVESInterpType interp_type)3173 WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf *lives_pixbuf_scale_simple(const LiVESPixbuf *src, int dest_width, int dest_height,
3174     LiVESInterpType interp_type) {
3175 #ifdef GUI_GTK
3176   return gdk_pixbuf_scale_simple(src, dest_width, dest_height, interp_type);
3177 #endif
3178   return NULL;
3179 }
3180 
3181 
lives_pixbuf_saturate_and_pixelate(const LiVESPixbuf * src,LiVESPixbuf * dest,float saturation,boolean pixilate)3182 WIDGET_HELPER_GLOBAL_INLINE boolean lives_pixbuf_saturate_and_pixelate(const LiVESPixbuf *src, LiVESPixbuf *dest,
3183     float saturation,
3184     boolean pixilate) {
3185 #ifdef GUI_GTK
3186   gdk_pixbuf_saturate_and_pixelate(src, dest, saturation, pixilate);
3187   return TRUE;
3188 #endif
3189 #ifdef GUI_QT
3190   // TODO
3191 #endif
3192   return FALSE;
3193 }
3194 
3195 
lives_adjustment_new(double value,double lower,double upper,double step_increment,double page_increment,double page_size)3196 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_adjustment_new(double value, double lower, double upper,
3197     double step_increment, double page_increment, double page_size) {
3198   LiVESAdjustment *adj = NULL;
3199 #ifdef GUI_GTK
3200 #if GTK_CHECK_VERSION(3, 0, 0)
3201   adj = gtk_adjustment_new(value, lower, upper, step_increment, page_increment, page_size);
3202 #else
3203   adj = GTK_ADJUSTMENT(gtk_adjustment_new(value, lower, upper, step_increment, page_increment, page_size));
3204 #endif
3205 #endif
3206 #ifdef GUI_QT
3207   adj = new LiVESAdjustment(value, lower, upper, step_increment, page_increment, page_size);
3208 #endif
3209   return adj;
3210 }
3211 
3212 
lives_box_set_homogeneous(LiVESBox * box,boolean homogenous)3213 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_set_homogeneous(LiVESBox *box, boolean homogenous) {
3214 #ifdef GUI_GTK
3215   gtk_box_set_homogeneous(box, homogenous);
3216   return TRUE;
3217 #endif
3218 #ifdef GUI_QT
3219   // TODO
3220 #endif
3221   return FALSE;
3222 }
3223 
3224 
lives_box_reorder_child(LiVESBox * box,LiVESWidget * child,int pos)3225 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_reorder_child(LiVESBox *box, LiVESWidget *child, int pos) {
3226 #ifdef GUI_GTK
3227   gtk_box_reorder_child(box, child, pos);
3228   return TRUE;
3229 #endif
3230   return FALSE;
3231 }
3232 
3233 
lives_box_set_child_packing(LiVESBox * box,LiVESWidget * child,boolean expand,boolean fill,uint32_t padding,LiVESPackType pack_type)3234 LIVES_GLOBAL_INLINE boolean lives_box_set_child_packing(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill,
3235     uint32_t padding, LiVESPackType pack_type) {
3236 #ifdef GUI_GTK
3237   gtk_box_set_child_packing(box, child, expand, fill, padding, pack_type);
3238   return TRUE;
3239 #endif
3240   return FALSE;
3241 }
3242 
3243 
lives_box_set_spacing(LiVESBox * box,int spacing)3244 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_set_spacing(LiVESBox *box, int spacing) {
3245 #ifdef GUI_GTK
3246   gtk_box_set_spacing(box, spacing);
3247   return TRUE;
3248 #endif
3249   return FALSE;
3250 }
3251 
3252 
lives_hbox_new(boolean homogeneous,int spacing)3253 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_hbox_new(boolean homogeneous, int spacing) {
3254   LiVESWidget *hbox = NULL;
3255 #ifdef GUI_GTK
3256 #if GTK_CHECK_VERSION(3, 0, 0)
3257   hbox = gtk_box_new(LIVES_ORIENTATION_HORIZONTAL, spacing);
3258   lives_box_set_homogeneous(LIVES_BOX(hbox), homogeneous);
3259 #else
3260   hbox = gtk_hbox_new(homogeneous, spacing);
3261 #endif
3262 #endif
3263   return hbox;
3264 }
3265 
3266 
lives_vbox_new(boolean homogeneous,int spacing)3267 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_vbox_new(boolean homogeneous, int spacing) {
3268   LiVESWidget *vbox = NULL;
3269 #ifdef GUI_GTK
3270 #if GTK_CHECK_VERSION(3, 0, 0)
3271   vbox = gtk_box_new(LIVES_ORIENTATION_VERTICAL, spacing);
3272   lives_box_set_homogeneous(LIVES_BOX(vbox), homogeneous);
3273 #else
3274   vbox = gtk_vbox_new(homogeneous, spacing);
3275 #endif
3276 #endif
3277   return vbox;
3278 }
3279 
3280 
lives_box_pack_start(LiVESBox * box,LiVESWidget * child,boolean expand,boolean fill,uint32_t padding)3281 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_start(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill,
3282     uint32_t padding) {
3283 #ifdef GUI_GTK
3284   gtk_box_pack_start(box, child, expand, fill, padding);
3285   return TRUE;
3286 #endif
3287   return FALSE;
3288 }
3289 
3290 
lives_box_pack_end(LiVESBox * box,LiVESWidget * child,boolean expand,boolean fill,uint32_t padding)3291 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_end(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill,
3292     uint32_t padding) {
3293 #ifdef GUI_GTK
3294   gtk_box_pack_end(box, child, expand, fill, padding);
3295   return TRUE;
3296 #endif
3297   return FALSE;
3298 }
3299 
3300 
lives_hseparator_new(void)3301 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_hseparator_new(void) {
3302   LiVESWidget *hsep = NULL;
3303 #ifdef GUI_GTK
3304 #if GTK_CHECK_VERSION(3, 0, 0)
3305   hsep = gtk_separator_new(LIVES_ORIENTATION_HORIZONTAL);
3306 #else
3307   hsep = gtk_hseparator_new();
3308 #endif
3309   lives_widget_set_size_request(hsep, -1, 1);
3310 #endif
3311   return hsep;
3312 }
3313 
3314 
lives_vseparator_new(void)3315 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_vseparator_new(void) {
3316   LiVESWidget *vsep = NULL;
3317 #ifdef GUI_GTK
3318 #if GTK_CHECK_VERSION(3, 0, 0)
3319   vsep = gtk_separator_new(LIVES_ORIENTATION_VERTICAL);
3320 #else
3321   vsep = gtk_vseparator_new();
3322 #endif
3323   lives_widget_set_size_request(vsep, 1, -1);
3324 #endif
3325   return vsep;
3326 }
3327 
3328 
lives_hbutton_box_new(void)3329 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_hbutton_box_new(void) {
3330   LiVESWidget *bbox = NULL;
3331 #ifdef GUI_GTK
3332 #if GTK_CHECK_VERSION(3, 0, 0)
3333   bbox = gtk_button_box_new(LIVES_ORIENTATION_HORIZONTAL);
3334 #else
3335   bbox = gtk_hbutton_box_new();
3336 #endif
3337 #endif
3338   return bbox;
3339 }
3340 
3341 
lives_vbutton_box_new(void)3342 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_vbutton_box_new(void) {
3343   LiVESWidget *bbox = NULL;
3344 #ifdef GUI_GTK
3345 #if GTK_CHECK_VERSION(3, 0, 0)
3346   bbox = gtk_button_box_new(LIVES_ORIENTATION_VERTICAL);
3347 #else
3348   bbox = gtk_vbutton_box_new();
3349 #endif
3350 #endif
3351   return bbox;
3352 }
3353 
3354 
lives_button_box_set_layout(LiVESButtonBox * bbox,LiVESButtonBoxStyle bstyle)3355 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_set_layout(LiVESButtonBox *bbox, LiVESButtonBoxStyle bstyle) {
3356 #ifdef GUI_GTK
3357 #if !GTK_CHECK_VERSION(3, 12, 0)
3358   if (bstyle == LIVES_BUTTONBOX_EXPAND) {
3359     gtk_box_set_homogeneous(GTK_BOX(bbox), TRUE);
3360     gtk_box_set_spacing(GTK_BOX(bbox), 0);
3361     return TRUE;
3362   }
3363 #endif
3364   gtk_button_box_set_layout(bbox, bstyle);
3365   return TRUE;
3366 #endif
3367   return FALSE;
3368 }
3369 
3370 
3371 WIDGET_HELPER_GLOBAL_INLINE
lives_button_box_set_child_non_homogeneous(LiVESButtonBox * bbox,LiVESWidget * child,boolean set)3372 boolean lives_button_box_set_child_non_homogeneous(LiVESButtonBox *bbox, LiVESWidget *child, boolean set) {
3373 #ifdef GUI_GTK
3374 #if GTK_CHECK_VERSION(3, 2, 0)
3375   gtk_button_box_set_child_non_homogeneous(bbox, child, set);
3376   return TRUE;
3377 #endif
3378 #endif
3379   return FALSE;
3380 }
3381 
3382 
lives_vscale_new(LiVESAdjustment * adj)3383 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_vscale_new(LiVESAdjustment *adj) {
3384   LiVESWidget *vscale = NULL;
3385 #ifdef GUI_GTK
3386 #if GTK_CHECK_VERSION(3, 0, 0)
3387   vscale = gtk_scale_new(LIVES_ORIENTATION_VERTICAL, adj);
3388 #else
3389   vscale = gtk_vscale_new(adj);
3390 #endif
3391 #endif
3392 #ifdef GUI_QT
3393   vscale = new LiVESScale(LIVES_ORIENTATION_VERTICAL, adj);
3394 #endif
3395   return vscale;
3396 }
3397 
3398 
lives_hpaned_new(void)3399 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_hpaned_new(void) {
3400   LiVESWidget *hpaned = NULL;
3401 #ifdef GUI_GTK
3402 #if GTK_CHECK_VERSION(3, 0, 0)
3403   hpaned = gtk_paned_new(LIVES_ORIENTATION_HORIZONTAL);
3404 #else
3405   hpaned = gtk_hpaned_new();
3406 #endif
3407 #endif
3408   return hpaned;
3409 }
3410 
3411 
lives_vpaned_new(void)3412 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_vpaned_new(void) {
3413   LiVESWidget *vpaned = NULL;
3414 #ifdef GUI_GTK
3415 #if GTK_CHECK_VERSION(3, 0, 0)
3416   vpaned = gtk_paned_new(LIVES_ORIENTATION_VERTICAL);
3417 #else
3418   vpaned = gtk_vpaned_new();
3419 #endif
3420 #endif
3421   return vpaned;
3422 }
3423 
3424 
lives_hscrollbar_new(LiVESAdjustment * adj)3425 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_hscrollbar_new(LiVESAdjustment *adj) {
3426   LiVESWidget *hscrollbar = NULL;
3427 #ifdef GUI_GTK
3428 #if GTK_CHECK_VERSION(3, 0, 0)
3429   hscrollbar = gtk_scrollbar_new(LIVES_ORIENTATION_HORIZONTAL, adj);
3430 #else
3431   hscrollbar = gtk_hscrollbar_new(adj);
3432 #endif
3433 #endif
3434 #ifdef GUI_QT
3435   hscrollbar = new LiVESScrollbar(LIVES_ORIENTATION_HORIZONTAL, adj);
3436 #endif
3437   return hscrollbar;
3438 }
3439 
3440 
lives_vscrollbar_new(LiVESAdjustment * adj)3441 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_vscrollbar_new(LiVESAdjustment *adj) {
3442   LiVESWidget *vscrollbar = NULL;
3443 #ifdef GUI_GTK
3444 #if GTK_CHECK_VERSION(3, 0, 0)
3445   vscrollbar = gtk_scrollbar_new(LIVES_ORIENTATION_VERTICAL, adj);
3446 #else
3447   vscrollbar = gtk_vscrollbar_new(adj);
3448 #endif
3449 #endif
3450 #ifdef GUI_QT
3451   vscrollbar = new LiVESScrollbar(LIVES_ORIENTATION_VERTICAL, adj);
3452 #endif
3453   return vscrollbar;
3454 }
3455 
3456 
lives_label_new(const char * text)3457 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_label_new(const char *text) {
3458   LiVESWidget *label = NULL;
3459 #ifdef GUI_GTK
3460   label = gtk_label_new(text);
3461   gtk_label_set_use_underline(LIVES_LABEL(label), widget_opts.mnemonic_label);
3462   gtk_label_set_justify(LIVES_LABEL(label), widget_opts.justify);
3463   gtk_label_set_line_wrap(LIVES_LABEL(label), widget_opts.line_wrap);
3464 #endif
3465   return label;
3466 }
3467 
3468 
lives_arrow_new(LiVESArrowType arrow_type,LiVESShadowType shadow_type)3469 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_arrow_new(LiVESArrowType arrow_type, LiVESShadowType shadow_type) {
3470   LiVESWidget *arrow = NULL;
3471 #ifdef GUI_GTK
3472 #if GTK_CHECK_VERSION(3, 12, 0)
3473   const char *format = "<b>%s</b>";
3474   char *markup;
3475   char *str;
3476 
3477   switch (arrow_type) {
3478   case LIVES_ARROW_DOWN:
3479     str = "v";
3480     break;
3481   case LIVES_ARROW_LEFT:
3482     str = "<";
3483     break;
3484   case LIVES_ARROW_RIGHT:
3485     str = ">";
3486     break;
3487   default:
3488     return arrow;
3489   }
3490 
3491   arrow = gtk_label_new("");
3492   markup = g_markup_printf_escaped(format, str);
3493   gtk_label_set_markup(GTK_LABEL(arrow), markup);
3494   lives_free(markup);
3495 
3496 #else
3497   arrow = gtk_arrow_new(arrow_type, shadow_type);
3498 #endif
3499 #endif
3500   return arrow;
3501 }
3502 
3503 
lives_widget_set_halign(LiVESWidget * widget,LiVESAlign align)3504 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_halign(LiVESWidget *widget, LiVESAlign align) {
3505 #ifdef GUI_GTK
3506 #if GTK_CHECK_VERSION(3, 0, 0)
3507   if (LIVES_IS_LABEL(widget)) {
3508     if (align == LIVES_ALIGN_START) gtk_label_set_xalign(LIVES_LABEL(widget), 0.);
3509     if (align == LIVES_ALIGN_CENTER) gtk_label_set_xalign(LIVES_LABEL(widget), 0.5);
3510     if (align == LIVES_ALIGN_END) gtk_label_set_xalign(LIVES_LABEL(widget), 1.);
3511   } else gtk_widget_set_halign(widget, align);
3512 #else
3513   if (LIVES_IS_LABEL(widget)) {
3514     float xalign, yalign;
3515     gtk_misc_get_alignment(GTK_MISC(widget), &xalign, &yalign);
3516     switch (align) {
3517     case LIVES_ALIGN_START:
3518       gtk_misc_set_alignment(GTK_MISC(widget), 0., yalign);
3519       break;
3520     case LIVES_ALIGN_END:
3521       gtk_misc_set_alignment(GTK_MISC(widget), 1., yalign);
3522       break;
3523     case LIVES_ALIGN_CENTER:
3524       gtk_misc_set_alignment(GTK_MISC(widget), 0.5, yalign);
3525       break;
3526     default:
3527       return FALSE;
3528     }
3529     return TRUE;
3530   }
3531 #endif
3532 #endif
3533   return FALSE;
3534 }
3535 
3536 
lives_widget_set_valign(LiVESWidget * widget,LiVESAlign align)3537 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_valign(LiVESWidget *widget, LiVESAlign align) {
3538 #ifdef GUI_GTK
3539 #if GTK_CHECK_VERSION(3, 0, 0)
3540   gtk_widget_set_valign(widget, align);
3541 #else
3542   if (!LIVES_IS_LABEL(widget)) return FALSE;
3543   else {
3544     float xalign, yalign;
3545     gtk_misc_get_alignment(GTK_MISC(widget), &xalign, &yalign);
3546     switch (align) {
3547     case LIVES_ALIGN_START:
3548       gtk_misc_set_alignment(GTK_MISC(widget), xalign, 0.);
3549       break;
3550     case LIVES_ALIGN_END:
3551       gtk_misc_set_alignment(GTK_MISC(widget), xalign, 1.);
3552       break;
3553     case LIVES_ALIGN_CENTER:
3554       gtk_misc_set_alignment(GTK_MISC(widget), xalign, 0.5);
3555       break;
3556     default:
3557       return FALSE;
3558     }
3559   }
3560 #endif
3561   return TRUE;
3562 #endif
3563   return FALSE;
3564 }
3565 
3566 
lives_alignment_new(float xalign,float yalign,float xscale,float yscale)3567 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_alignment_new(float xalign, float yalign, float xscale, float yscale) {
3568   LiVESWidget *alignment = NULL;
3569 #ifdef GUI_GTK
3570 #if GTK_CHECK_VERSION(3, 0, 0)
3571   alignment = gtk_aspect_frame_new(NULL, xalign, yalign, xscale / yscale, TRUE);
3572   lives_frame_set_shadow_type(LIVES_FRAME(alignment), LIVES_SHADOW_NONE);
3573 #else
3574   alignment = gtk_alignment_new(xalign, yalign, xscale, yscale);
3575 #endif
3576 #endif
3577 #ifdef GUI_QT
3578   alignment = new LiVESAlignment(xalign, yalign, xscale, yscale);
3579 #endif
3580   return alignment;
3581 }
3582 
3583 
lives_alignment_set(LiVESWidget * alignment,float xalign,float yalign,float xscale,float yscale)3584 WIDGET_HELPER_GLOBAL_INLINE boolean lives_alignment_set(LiVESWidget *alignment, float xalign, float yalign, float xscale,
3585     float yscale) {
3586 #ifdef GUI_GTK
3587 #if GTK_CHECK_VERSION(3, 0, 0)
3588   gtk_aspect_frame_set(GTK_ASPECT_FRAME(alignment), xalign, yalign, xscale / yscale, TRUE);
3589 #else
3590   gtk_alignment_set(LIVES_ALIGNMENT(alignment), xalign, yalign, xscale, yscale);
3591 #endif
3592   return TRUE;
3593 #endif
3594 #ifdef GUI_QT
3595   alignment->set_alignment(xalign, yalign, xscale, yscale);
3596   return TRUE;
3597 #endif
3598   return FALSE;
3599 }
3600 
3601 
lives_expander_new(const char * label)3602 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_expander_new(const char *label) {
3603   LiVESWidget *expander = NULL;
3604 #ifdef GUI_GTK
3605   if (!widget_opts.mnemonic_label) expander = gtk_expander_new(label);
3606   else expander = gtk_expander_new_with_mnemonic(label);
3607 #if GTK_CHECK_VERSION(3, 2, 0)
3608   gtk_expander_set_resize_toplevel(GTK_EXPANDER(expander), TRUE);
3609 #endif
3610 #endif
3611   return expander;
3612 }
3613 
3614 
lives_expander_get_label_widget(LiVESExpander * expander)3615 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_expander_get_label_widget(LiVESExpander *expander) {
3616   LiVESWidget *widget = NULL;
3617 #ifdef GUI_GTK
3618   widget = gtk_expander_get_label_widget(expander);
3619 #endif
3620   return widget;
3621 }
3622 
3623 
lives_expander_set_use_markup(LiVESExpander * expander,boolean val)3624 WIDGET_HELPER_GLOBAL_INLINE boolean lives_expander_set_use_markup(LiVESExpander *expander, boolean val) {
3625 #ifdef GUI_GTK
3626   gtk_expander_set_use_markup(expander, val);
3627   return TRUE;
3628 #endif
3629   return FALSE;
3630 }
3631 
3632 
lives_expander_set_expanded(LiVESExpander * expander,boolean val)3633 WIDGET_HELPER_GLOBAL_INLINE boolean lives_expander_set_expanded(LiVESExpander *expander, boolean val) {
3634 #ifdef GUI_GTK
3635   gtk_expander_set_expanded(expander, val);
3636   return TRUE;
3637 #endif
3638   return FALSE;
3639 }
3640 
3641 
lives_expander_set_label(LiVESExpander * expander,const char * text)3642 WIDGET_HELPER_GLOBAL_INLINE boolean lives_expander_set_label(LiVESExpander *expander, const char *text) {
3643 
3644 #ifdef GUI_GTK
3645   char *labeltext = lives_strdup_printf("<big>%s</big>", text);
3646   gtk_expander_set_label(expander, labeltext);
3647   lives_free(labeltext);
3648   return TRUE;
3649 #endif
3650   return FALSE;
3651 }
3652 
3653 
lives_expander_get_expanded(LiVESExpander * expander)3654 WIDGET_HELPER_GLOBAL_INLINE boolean lives_expander_get_expanded(LiVESExpander *expander) {
3655 #ifdef GUI_GTK
3656   return gtk_expander_get_expanded(expander);
3657 #endif
3658   return FALSE;
3659 }
3660 
3661 
lives_label_set_width_chars(LiVESLabel * label,int nchars)3662 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_width_chars(LiVESLabel *label, int nchars) {
3663 #ifdef GUI_GTK
3664   gtk_label_set_width_chars(label, nchars);
3665   gtk_label_set_max_width_chars(label, nchars);
3666   return TRUE;
3667 #endif
3668   return FALSE;
3669 }
3670 
3671 
lives_label_set_line_wrap(LiVESLabel * label,boolean set)3672 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_line_wrap(LiVESLabel *label, boolean set) {
3673 #ifdef GUI_GTK
3674   gtk_label_set_line_wrap(label, set);
3675   return TRUE;
3676 #endif
3677   return FALSE;
3678 }
3679 
lives_label_set_line_wrap_mode(LiVESLabel * label,LingoWrapMode mode)3680 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_line_wrap_mode(LiVESLabel *label, LingoWrapMode mode) {
3681 #ifdef GUI_GTK
3682   gtk_label_set_line_wrap_mode(label, mode);
3683   return TRUE;
3684 #endif
3685   return FALSE;
3686 }
3687 
lives_label_seT_lines(LiVESLabel * label,int nlines)3688 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_seT_lines(LiVESLabel *label, int nlines) {
3689 #ifdef GUI_GTK
3690   gtk_label_set_lines(label, nlines);
3691   return TRUE;
3692 #endif
3693   return FALSE;
3694 }
3695 
lives_label_set_ellipsize(LiVESLabel * label,LiVESEllipsizeMode mode)3696 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_ellipsize(LiVESLabel *label, LiVESEllipsizeMode mode) {
3697 #ifdef GUI_GTK
3698   gtk_label_set_ellipsize(label, mode);
3699   return TRUE;
3700 #endif
3701   return FALSE;
3702 }
3703 
lives_label_set_halignment(LiVESLabel * label,float xalign)3704 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_halignment(LiVESLabel *label, float xalign) {
3705 #ifdef GUI_GTK
3706 #if GTK_CHECK_VERSION(3, 16, 0)
3707   gtk_label_set_xalign(label, xalign);
3708 #else
3709   if (xalign == 0.)
3710     lives_widget_set_halign(LIVES_WIDGET(label), LIVES_ALIGN_START);
3711   else if (xalign == 1.)
3712     lives_widget_set_halign(LIVES_WIDGET(label), LIVES_ALIGN_END);
3713   else
3714     lives_widget_set_halign(LIVES_WIDGET(label), LIVES_ALIGN_CENTER);
3715 #endif
3716   return TRUE;
3717 #endif
3718 #ifdef GUI_QT
3719   QRect qr = (static_cast<QFrame *>(label))->contentsRect();
3720   int pixels = (float)qr.width() * xalign;
3721   label->setIndent(pixels);
3722 #endif
3723   return FALSE;
3724 }
3725 
3726 
lives_combo_new(void)3727 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_combo_new(void) {
3728   LiVESWidget *combo = NULL;
3729 #ifdef GUI_GTK
3730 #if GTK_CHECK_VERSION(2, 24, 0)
3731   combo = gtk_combo_box_new_with_entry();
3732 #else
3733   combo = gtk_combo_box_entry_new_text();
3734 #endif
3735 #endif
3736 #ifdef GUI_QT
3737   combo = new LiVESCombo;
3738 #endif
3739   return combo;
3740 }
3741 
3742 
lives_combo_new_with_model(LiVESTreeModel * model)3743 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_combo_new_with_model(LiVESTreeModel *model) {
3744   LiVESWidget *combo = NULL;
3745 #ifdef GUI_GTK
3746 #if GTK_CHECK_VERSION(2, 24, 0)
3747   combo = gtk_combo_box_new_with_model_and_entry(model);
3748 #else
3749   combo = gtk_combo_box_entry_new();
3750   gtk_combo_box_set_model(GTK_COMBO_BOX(combo), model);
3751 #endif
3752 #endif
3753 #ifdef GUI_QT
3754   combo = new LiVESCombo;
3755   QComboBox *qcombo = dynamic_cast<QComboBox *>(combo);
3756   qcombo->setModel(model->to_qsimodel());
3757   if (model->get_qtree_widget()) qcombo->setView(model->get_qtree_widget());
3758 #endif
3759   return combo;
3760 }
3761 
3762 
lives_combo_get_model(LiVESCombo * combo)3763 WIDGET_HELPER_GLOBAL_INLINE LiVESTreeModel *lives_combo_get_model(LiVESCombo *combo) {
3764   LiVESTreeModel *model = NULL;
3765 #ifdef GUI_GTK
3766   model = gtk_combo_box_get_model(combo);
3767 #endif
3768   return model;
3769 }
3770 
3771 
lives_combo_set_model(LiVESCombo * combo,LiVESTreeModel * model)3772 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_model(LiVESCombo *combo, LiVESTreeModel *model) {
3773 #ifdef GUI_GTK
3774   gtk_combo_box_set_model(combo, model);
3775   return TRUE;
3776 #endif
3777   return FALSE;
3778 }
3779 
3780 
lives_combo_popup(LiVESCombo * combo)3781 void lives_combo_popup(LiVESCombo *combo) {
3782   // used in callback, so no inline
3783 #ifdef GUI_GTK
3784   gtk_combo_box_popup(combo);
3785 #endif
3786 }
3787 
3788 
lives_combo_set_focus_on_click(LiVESCombo * combo,boolean state)3789 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_focus_on_click(LiVESCombo *combo, boolean state) {
3790 #ifdef GUI_GTK
3791 #if GTK_CHECK_VERSION(3, 20, 0)
3792   gtk_widget_set_focus_on_click(GTK_WIDGET(combo), state);
3793 #else
3794   gtk_combo_box_set_focus_on_click(combo, state);
3795 #endif
3796   return TRUE;
3797 #endif
3798   return FALSE;
3799 }
3800 
3801 
lives_combo_append_text(LiVESCombo * combo,const char * text)3802 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_append_text(LiVESCombo *combo, const char *text) {
3803 #ifdef GUI_GTK
3804   LiVESTreeModel *tmodel = lives_combo_get_model(combo);
3805   if (!GTK_IS_LIST_STORE(tmodel)) return FALSE;
3806   else {
3807     LiVESTreeIter iter;
3808     LiVESListStore *lstore = GTK_LIST_STORE(tmodel);
3809     gtk_list_store_append(lstore, &iter);   /* Acquire an iterator */
3810     lives_tree_store_set(GTK_TREE_STORE(lstore), &iter, 0, text, -1);
3811   }
3812 
3813   /* #if GTK_CHECK_VERSION(2, 24, 0) */
3814   /*   gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), text); */
3815   /* #else */
3816   /*   gtk_combo_box_append_text(GTK_COMBO_BOX(combo), text); */
3817   /* #endif */
3818   return TRUE;
3819 #endif
3820   return FALSE;
3821 }
3822 
3823 
lives_combo_prepend_text(LiVESCombo * combo,const char * text)3824 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_prepend_text(LiVESCombo *combo, const char *text) {
3825 #ifdef GUI_GTK
3826   LiVESTreeModel *tmodel = lives_combo_get_model(combo);
3827   if (!GTK_IS_LIST_STORE(tmodel)) return FALSE;
3828   else {
3829     LiVESTreeIter iter;
3830     LiVESListStore *lstore = GTK_LIST_STORE(tmodel);
3831     gtk_list_store_prepend(lstore, &iter);   /* Acquire an iterator */
3832     lives_tree_store_set(GTK_TREE_STORE(lstore), &iter, 0, text, -1);
3833   }
3834   return TRUE;
3835 #endif
3836   return FALSE;
3837 }
3838 
3839 
lives_combo_remove_all_text(LiVESCombo * combo)3840 boolean lives_combo_remove_all_text(LiVESCombo *combo) {
3841 #ifdef GUI_GTK
3842   LiVESTreeModel *tmodel = lives_combo_get_model(combo);
3843   if (GTK_IS_TREE_STORE(tmodel)) {
3844     LiVESTreeStore *tstore = GTK_TREE_STORE(tmodel);
3845     gtk_tree_store_clear(tstore);
3846   } else if (GTK_IS_LIST_STORE(tmodel)) {
3847     LiVESListStore *lstore = GTK_LIST_STORE(tmodel);
3848     /// block CHANGED signal else it gets called for EVERY SINGLE removed element !
3849     //uint32_t sigid = g_signal_lookup(LIVES_WIDGET_CHANGED_SIGNAL, GTK_TYPE_COMBO_BOX);
3850     // does NOT WORK ! bug in glib / gtk ?
3851     //g_signal_handlers_block_matched(combo, G_SIGNAL_MATCH_ID, sigid, 0, NULL, NULL, NULL);
3852     gtk_list_store_clear(lstore);
3853     //g_signal_handlers_unblock_matched(combo, G_SIGNAL_MATCH_ID, sigid, 0, NULL, NULL, NULL);
3854   }
3855   return TRUE;
3856 #endif
3857   return FALSE;
3858 }
3859 
3860 
lives_combo_set_entry_text_column(LiVESCombo * combo,int column)3861 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_entry_text_column(LiVESCombo *combo, int column) {
3862 #ifdef GUI_GTK
3863 #if GTK_CHECK_VERSION(2, 24, 0)
3864   gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combo), column);
3865 #else
3866   gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(combo), column);
3867 #endif
3868   return TRUE;
3869 #endif
3870   return FALSE;
3871 }
3872 
3873 
lives_combo_get_active_text(LiVESCombo * combo)3874 WIDGET_HELPER_GLOBAL_INLINE const char *lives_combo_get_active_text(LiVESCombo *combo) {
3875   // return value should be freed
3876 #ifdef GUI_GTK
3877   return lives_entry_get_text(LIVES_ENTRY(lives_bin_get_child(LIVES_BIN(combo))));
3878 #endif
3879   return NULL;
3880 }
3881 
3882 
lives_combo_set_active_index(LiVESCombo * combo,int index)3883 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_active_index(LiVESCombo *combo, int index) {
3884 #ifdef GUI_GTK
3885   gtk_combo_box_set_active(combo, index);
3886   return TRUE;
3887 #endif
3888   return FALSE;
3889 }
3890 
3891 
lives_combo_set_active_iter(LiVESCombo * combo,LiVESTreeIter * iter)3892 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_active_iter(LiVESCombo *combo, LiVESTreeIter *iter) {
3893 #ifdef GUI_GTK
3894   gtk_combo_box_set_active_iter(combo, iter);
3895   return TRUE;
3896 #endif
3897   return FALSE;
3898 }
3899 
3900 
lives_combo_get_active_iter(LiVESCombo * combo,LiVESTreeIter * iter)3901 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_get_active_iter(LiVESCombo *combo, LiVESTreeIter *iter) {
3902 #ifdef GUI_GTK
3903   return gtk_combo_box_get_active_iter(combo, iter);
3904 #endif
3905   return FALSE;
3906 }
3907 
3908 
lives_combo_get_active_index(LiVESCombo * combo)3909 WIDGET_HELPER_GLOBAL_INLINE int lives_combo_get_active_index(LiVESCombo *combo) {
3910 #ifdef GUI_GTK
3911   LiVESTreeModel *tmodel = lives_combo_get_model(combo);
3912   if (GTK_IS_TREE_STORE(tmodel)) {
3913     int count = 0;
3914     LiVESTreeIter iter, iter1, iter2;
3915     if (!lives_combo_get_active_iter(combo, &iter)) return -1;
3916     if (gtk_tree_model_iter_children(tmodel, &iter1, NULL)) {
3917       if (gtk_tree_model_iter_children(tmodel, &iter2, &iter1)) {
3918         while (1) {
3919           if (iter2.stamp == iter.stamp) return count;
3920           count++;
3921           if (!gtk_tree_model_iter_next(tmodel, &iter2)) break;
3922         }
3923       }
3924     }
3925   }
3926   return gtk_combo_box_get_active(combo);
3927 #endif
3928   return -1;
3929 }
3930 
3931 
lives_text_view_new(void)3932 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_text_view_new(void) {
3933   LiVESWidget *tview = NULL;
3934 #ifdef GUI_GTK
3935   tview = gtk_text_view_new();
3936 #endif
3937   return tview;
3938 }
3939 
3940 
lives_text_view_new_with_buffer(LiVESTextBuffer * tbuff)3941 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_text_view_new_with_buffer(LiVESTextBuffer *tbuff) {
3942   LiVESWidget *tview = NULL;
3943 #ifdef GUI_GTK
3944   tview = gtk_text_view_new_with_buffer(tbuff);
3945 #endif
3946   return tview;
3947 }
3948 
3949 
lives_text_view_get_buffer(LiVESTextView * tview)3950 WIDGET_HELPER_GLOBAL_INLINE LiVESTextBuffer *lives_text_view_get_buffer(LiVESTextView *tview) {
3951   LiVESTextBuffer *tbuff = NULL;
3952 #ifdef GUI_GTK
3953   tbuff = gtk_text_view_get_buffer(tview);
3954 #endif
3955   return tbuff;
3956 }
3957 
3958 
lives_text_view_set_editable(LiVESTextView * tview,boolean setting)3959 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_editable(LiVESTextView *tview, boolean setting) {
3960 #ifdef GUI_GTK
3961   gtk_text_view_set_editable(tview, setting);
3962   return TRUE;
3963 #endif
3964   return FALSE;
3965 }
3966 
3967 
lives_text_view_set_accepts_tab(LiVESTextView * tview,boolean setting)3968 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_accepts_tab(LiVESTextView *tview, boolean setting) {
3969 #ifdef GUI_GTK
3970   gtk_text_view_set_accepts_tab(tview, setting);
3971   return TRUE;
3972 #endif
3973   return FALSE;
3974 }
3975 
3976 
lives_text_view_set_cursor_visible(LiVESTextView * tview,boolean setting)3977 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_cursor_visible(LiVESTextView *tview, boolean setting) {
3978 #ifdef GUI_GTK
3979   gtk_text_view_set_cursor_visible(tview, setting);
3980   return TRUE;
3981 #endif
3982   return FALSE;
3983 }
3984 
3985 
lives_text_view_set_wrap_mode(LiVESTextView * tview,LiVESWrapMode wrapmode)3986 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_wrap_mode(LiVESTextView *tview, LiVESWrapMode wrapmode) {
3987 #ifdef GUI_GTK
3988   gtk_text_view_set_wrap_mode(tview, wrapmode);
3989   return TRUE;
3990 #endif
3991   return FALSE;
3992 }
3993 
3994 
lives_text_view_set_justification(LiVESTextView * tview,LiVESJustification justify)3995 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_justification(LiVESTextView *tview, LiVESJustification justify) {
3996 #ifdef GUI_GTK
3997   gtk_text_view_set_justification(tview, justify);
3998   return TRUE;
3999 #endif
4000   return FALSE;
4001 }
4002 
4003 
lives_text_view_set_top_margin(LiVESTextView * tview,int margin)4004 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_top_margin(LiVESTextView *tview, int margin) {
4005 #ifdef GUI_GTK
4006 #if GTK_CHECK_VERSION(3, 18, 0)
4007   gtk_text_view_set_top_margin(tview, margin);
4008   return TRUE;
4009 #endif
4010 #endif
4011   return FALSE;
4012 }
4013 
4014 
lives_text_view_set_bottom_margin(LiVESTextView * tview,int margin)4015 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_view_set_bottom_margin(LiVESTextView *tview, int margin) {
4016 #ifdef GUI_GTK
4017 #if GTK_CHECK_VERSION(3, 18, 0)
4018   gtk_text_view_set_bottom_margin(tview, margin);
4019   return TRUE;
4020 #endif
4021 #endif
4022   return FALSE;
4023 }
4024 
4025 
lives_text_buffer_new(void)4026 WIDGET_HELPER_GLOBAL_INLINE LiVESTextBuffer *lives_text_buffer_new(void) {
4027   LiVESTextBuffer *tbuff = NULL;
4028 #ifdef GUI_GTK
4029   tbuff = gtk_text_buffer_new(NULL);
4030 #endif
4031   return tbuff;
4032 }
4033 
4034 
lives_text_buffer_insert(LiVESTextBuffer * tbuff,LiVESTextIter * iter,const char * text,int len)4035 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_insert(LiVESTextBuffer *tbuff, LiVESTextIter *iter, const char *text,
4036     int len) {
4037 #ifdef GUI_GTK
4038   gtk_text_buffer_insert(tbuff, iter, text, len);
4039   return TRUE;
4040 #endif
4041   return FALSE;
4042 }
4043 
4044 
lives_text_buffer_insert_at_cursor(LiVESTextBuffer * tbuff,const char * text,int len)4045 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_insert_at_cursor(LiVESTextBuffer *tbuff, const char *text, int len) {
4046 #ifdef GUI_GTK
4047   gtk_text_buffer_insert_at_cursor(tbuff, text, len);
4048   return TRUE;
4049 #endif
4050   return FALSE;
4051 }
4052 
4053 
lives_text_buffer_set_text(LiVESTextBuffer * tbuff,const char * text,int len)4054 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_set_text(LiVESTextBuffer *tbuff, const char *text, int len) {
4055 #ifdef GUI_GTK
4056   gtk_text_buffer_set_text(tbuff, text, len);
4057   return TRUE;
4058 #endif
4059   return FALSE;
4060 }
4061 
4062 
lives_text_buffer_get_text(LiVESTextBuffer * tbuff,LiVESTextIter * start,LiVESTextIter * end,boolean inc_hidden_chars)4063 WIDGET_HELPER_GLOBAL_INLINE char *lives_text_buffer_get_text(LiVESTextBuffer *tbuff, LiVESTextIter *start, LiVESTextIter *end,
4064     boolean inc_hidden_chars) {
4065 #ifdef GUI_GTK
4066   return gtk_text_buffer_get_text(tbuff, start, end, inc_hidden_chars);
4067 #endif
4068   return NULL;
4069 }
4070 
4071 
lives_text_buffer_get_all_text(LiVESTextBuffer * tbuff)4072 WIDGET_HELPER_GLOBAL_INLINE char *lives_text_buffer_get_all_text(LiVESTextBuffer *tbuff) {
4073   LiVESTextIter s, e;
4074   lives_text_buffer_get_start_iter(tbuff, &s);
4075   lives_text_buffer_get_end_iter(tbuff, &e);
4076   return lives_text_buffer_get_text(tbuff, &s, &e, FALSE);
4077 }
4078 
4079 
lives_text_buffer_get_start_iter(LiVESTextBuffer * tbuff,LiVESTextIter * iter)4080 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_start_iter(LiVESTextBuffer *tbuff, LiVESTextIter *iter) {
4081 #ifdef GUI_GTK
4082   gtk_text_buffer_get_start_iter(tbuff, iter);
4083   return TRUE;
4084 #endif
4085   return FALSE;
4086 }
4087 
4088 
lives_text_buffer_get_end_iter(LiVESTextBuffer * tbuff,LiVESTextIter * iter)4089 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_end_iter(LiVESTextBuffer *tbuff, LiVESTextIter *iter) {
4090 #ifdef GUI_GTK
4091   gtk_text_buffer_get_end_iter(tbuff, iter);
4092   return TRUE;
4093 #endif
4094   return FALSE;
4095 }
4096 
4097 
lives_text_buffer_place_cursor(LiVESTextBuffer * tbuff,LiVESTextIter * iter)4098 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_place_cursor(LiVESTextBuffer *tbuff, LiVESTextIter *iter) {
4099 #ifdef GUI_GTK
4100   gtk_text_buffer_place_cursor(tbuff, iter);
4101   return TRUE;
4102 #endif
4103   return FALSE;
4104 }
4105 
4106 
lives_text_buffer_create_mark(LiVESTextBuffer * tbuff,const char * mark_name,const LiVESTextIter * where,boolean left_gravity)4107 WIDGET_HELPER_GLOBAL_INLINE LiVESTextMark *lives_text_buffer_create_mark(LiVESTextBuffer *tbuff, const char *mark_name,
4108     const LiVESTextIter *where, boolean left_gravity) {
4109   LiVESTextMark *tmark;
4110 #ifdef GUI_GTK
4111   tmark = gtk_text_buffer_create_mark(tbuff, mark_name, where, left_gravity);
4112 #endif
4113   return tmark;
4114 }
4115 
4116 
lives_text_buffer_delete_mark(LiVESTextBuffer * tbuff,LiVESTextMark * mark)4117 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_delete_mark(LiVESTextBuffer *tbuff, LiVESTextMark *mark) {
4118 #ifdef GUI_GTK
4119   gtk_text_buffer_delete_mark(tbuff, mark);
4120   return TRUE;
4121 #endif
4122   return FALSE;
4123 }
4124 
4125 
lives_text_buffer_delete(LiVESTextBuffer * tbuff,LiVESTextIter * start,LiVESTextIter * end)4126 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_delete(LiVESTextBuffer *tbuff, LiVESTextIter *start, LiVESTextIter *end) {
4127 #ifdef GUI_GTK
4128   gtk_text_buffer_delete(tbuff, start, end);
4129   return TRUE;
4130 #endif
4131 #ifdef GUI_QT
4132   QTextCursor qtc = QTextCursor(tbuff);
4133   qtc.setPosition(*start);
4134   qtc.setPosition(*end, QTextCursor::KeepAnchor);
4135   qtc.removeSelectedText();
4136   return TRUE;
4137 #endif
4138   return FALSE;
4139 }
4140 
4141 
lives_text_buffer_get_iter_at_mark(LiVESTextBuffer * tbuff,LiVESTextIter * iter,LiVESTextMark * mark)4142 WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_iter_at_mark(LiVESTextBuffer *tbuff, LiVESTextIter *iter,
4143     LiVESTextMark *mark) {
4144 #ifdef GUI_GTK
4145   gtk_text_buffer_get_iter_at_mark(tbuff, iter, mark);
4146   return TRUE;
4147 #endif
4148   return FALSE;
4149 }
4150 
4151 
lives_dialog_new(void)4152 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_dialog_new(void) {
4153   LiVESWidget *dialog = NULL;
4154 #ifdef GUI_GTK
4155   dialog = gtk_dialog_new();
4156 #endif
4157   return dialog;
4158 }
4159 
4160 
lives_button_new(void)4161 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_button_new(void) {
4162   LiVESWidget *button = NULL;
4163 #ifdef GUI_GTK
4164   button = gtk_button_new();
4165   gtk_button_set_use_underline(GTK_BUTTON(button), widget_opts.mnemonic_label);
4166 #endif
4167   return button;
4168 }
4169 
4170 
lives_button_new_with_label(const char * label)4171 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_button_new_with_label(const char *label) {
4172   LiVESWidget *button = NULL;
4173 #ifdef GUI_GTK
4174   button = lives_button_new();
4175   lives_button_set_label(LIVES_BUTTON(button), label);
4176 #endif
4177   return button;
4178 }
4179 
4180 
lives_button_set_image_from_stock(LiVESButton * button,const char * stock_id)4181 LIVES_GLOBAL_INLINE boolean lives_button_set_image_from_stock(LiVESButton *button,
4182     const char *stock_id) {
4183   /// tweaks for better icons
4184   if (!strcmp(stock_id, LIVES_STOCK_YES)) stock_id = LIVES_STOCK_APPLY;
4185   if (!strcmp(stock_id, LIVES_STOCK_NO)) stock_id = LIVES_STOCK_STOP;
4186 
4187   if (!strcmp(stock_id, LIVES_STOCK_OK)) stock_id = LIVES_STOCK_APPLY;
4188   if (!strcmp(stock_id, LIVES_STOCK_CANCEL)) stock_id = LIVES_STOCK_STOP;
4189 
4190   if (!is_standard_widget(LIVES_WIDGET(button))) {
4191     if (stock_id && (widget_opts.show_button_images
4192                      || !strcmp(stock_id, LIVES_STOCK_ADD)
4193                      || !strcmp(stock_id, LIVES_STOCK_REMOVE)
4194                     )) {
4195       LiVESWidget *image = gtk_image_new_from_icon_name(stock_id, LIVES_ICON_SIZE_BUTTON);
4196       if (LIVES_IS_IMAGE(image)) gtk_button_set_image(LIVES_BUTTON(button), image);
4197       else return FALSE;
4198     }
4199   }
4200 
4201 #ifdef USE_SPECIAL_BUTTONS
4202   else {
4203     if (stock_id) {
4204       LiVESPixbuf *pixbuf = lives_pixbuf_new_from_stock_at_size(stock_id, LIVES_ICON_SIZE_BUTTON, 0, 0);
4205       if (LIVES_IS_PIXBUF(pixbuf))
4206         lives_widget_object_set_data(LIVES_WIDGET_OBJECT(button), SBUTT_PIXBUF_KEY, (livespointer)pixbuf);
4207       else return FALSE;
4208     }
4209   }
4210 #endif
4211   return TRUE;
4212 }
4213 
4214 
lives_standard_button_new_from_stock(const char * stock_id,const char * label,int width,int height)4215 LiVESWidget *lives_standard_button_new_from_stock(const char *stock_id, const char *label, int width, int height) {
4216   LiVESWidget *button = NULL;
4217 
4218 #if GTK_CHECK_VERSION(3, 10, 0)
4219   do {
4220     if (!stock_id) {
4221       button = lives_standard_button_new(width, height);
4222       break;
4223     }
4224     if (!strcmp(stock_id, LIVES_STOCK_LABEL_CANCEL)) stock_id = LIVES_STOCK_CANCEL;
4225     if (!strcmp(stock_id, LIVES_STOCK_LABEL_OK)) stock_id = LIVES_STOCK_OK;
4226 
4227     // gtk 3.10 + -> we need to set the text ourselves
4228     if (!strcmp(stock_id, LIVES_STOCK_APPLY)) {
4229       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_APPLY, width, height);
4230       break;
4231     }
4232     if (!strcmp(stock_id, LIVES_STOCK_OK)) {
4233       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_OK, width, height);
4234       break;
4235     }
4236     if (!strcmp(stock_id, LIVES_STOCK_CANCEL)) {
4237       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_CANCEL, width, height);
4238       break;
4239     }
4240     if (!strcmp(stock_id, LIVES_STOCK_YES)) {
4241       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_YES, width, height);
4242       break;
4243     }
4244     if (!strcmp(stock_id, LIVES_STOCK_NO)) {
4245       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_NO, width, height);
4246       break;
4247     }
4248     if (!strcmp(stock_id, LIVES_STOCK_CLOSE)) {
4249       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_CLOSE, width, height);
4250       break;
4251     }
4252     if (!strcmp(stock_id, LIVES_STOCK_REVERT_TO_SAVED)) {
4253       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_REVERT, width, height);
4254       break;
4255     }
4256     if (!strcmp(stock_id, LIVES_STOCK_REFRESH)) {
4257       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_REFRESH, width, height);
4258       break;
4259     }
4260     if (!strcmp(stock_id, LIVES_STOCK_DELETE)) {
4261       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_DELETE, width, height);
4262       break;
4263     }
4264     if (!strcmp(stock_id, LIVES_STOCK_SAVE)) {
4265       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_SAVE, width, height);
4266       break;
4267     }
4268     if (!strcmp(stock_id, LIVES_STOCK_SAVE_AS)) {
4269       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_SAVE_AS, width, height);
4270       break;
4271     }
4272     if (!strcmp(stock_id, LIVES_STOCK_OPEN)) {
4273       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_OPEN, width, height);
4274       break;
4275     }
4276     if (!strcmp(stock_id, LIVES_STOCK_SELECT_ALL)) {
4277       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_SELECT_ALL, width, height);
4278       break;
4279     }
4280     if (!strcmp(stock_id, LIVES_STOCK_QUIT)) {
4281       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_QUIT, width, height);
4282       break;
4283     }
4284     if (!strcmp(stock_id, LIVES_STOCK_GO_FORWARD)) {
4285       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_GO_FORWARD, width, height);
4286       break;
4287     }
4288     if (!strcmp(stock_id, LIVES_STOCK_MEDIA_FORWARD)) {
4289       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_MEDIA_FORWARD, width, height);
4290       break;
4291     }
4292     if (!strcmp(stock_id, LIVES_STOCK_MEDIA_REWIND)) {
4293       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_MEDIA_REWIND, width, height);
4294       break;
4295     }
4296     if (!strcmp(stock_id, LIVES_STOCK_MEDIA_STOP)) {
4297       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_MEDIA_STOP, width, height);
4298       break;
4299     }
4300     if (!strcmp(stock_id, LIVES_STOCK_MEDIA_PLAY)) {
4301       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_MEDIA_PLAY, width, height);
4302       break;
4303     }
4304     if (!strcmp(stock_id, LIVES_STOCK_MEDIA_PAUSE)) {
4305       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_MEDIA_PAUSE, width, height);
4306       break;
4307     }
4308     if (!strcmp(stock_id, LIVES_STOCK_MEDIA_RECORD)) {
4309       button = lives_standard_button_new_with_label(LIVES_STOCK_LABEL_MEDIA_RECORD, width, height);
4310       break;
4311     }
4312     // text not known
4313     button = lives_standard_button_new(width, height);
4314   } while (FALSE);
4315 
4316   if (stock_id) lives_button_set_image_from_stock(LIVES_BUTTON(button), stock_id);
4317 
4318 #else
4319   // < 3.10
4320   button = gtk_button_new_from_stock(stock_id);
4321 #endif
4322 
4323   if (!LIVES_IS_BUTTON(button)) {
4324     char *msg = lives_strdup_printf("Unable to find button with stock_id: %s", stock_id);
4325     LIVES_WARN(msg);
4326     lives_free(msg);
4327     button = lives_standard_button_new(width, height);
4328   }
4329 
4330 #ifdef GUI_GTK
4331 #if GTK_CHECK_VERSION(3, 6, 0)
4332   //gtk_button_set_always_show_image(GTK_BUTTON(button), widget_opts.show_button_images);
4333 #endif
4334   if (label)
4335     lives_standard_button_set_label(LIVES_BUTTON(button), label);
4336 #endif
4337 
4338   lives_widget_set_can_focus_and_default(button);
4339   lives_widget_apply_theme(button, LIVES_WIDGET_STATE_NORMAL);
4340   return button;
4341 }
4342 
4343 
4344 
lives_button_set_label(LiVESButton * button,const char * label)4345 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_set_label(LiVESButton *button, const char *label) {
4346 #ifdef USE_SPECIAL_BUTTONS
4347   if (is_standard_widget(LIVES_WIDGET(button))) return lives_standard_button_set_label(button, label);
4348 #endif
4349 #ifdef GUI_GTK
4350   gtk_button_set_label(button, label);
4351   return TRUE;
4352 #endif
4353   return FALSE;
4354 }
4355 
4356 
lives_button_get_label(LiVESButton * button)4357 WIDGET_HELPER_GLOBAL_INLINE const char *lives_button_get_label(LiVESButton *button) {
4358 #ifdef USE_SPECIAL_BUTTONS
4359   if (is_standard_widget(LIVES_WIDGET(button))) return lives_standard_button_get_label(button);
4360 #endif
4361 #ifdef GUI_GTK
4362   return gtk_button_get_label(button);
4363 #endif
4364   return NULL;
4365 }
4366 
4367 
lives_button_clicked(LiVESButton * button)4368 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_clicked(LiVESButton *button) {
4369 #ifdef GUI_GTK
4370   gtk_button_clicked(button);
4371   return TRUE;
4372 #endif
4373   return FALSE;
4374 }
4375 
4376 
lives_button_set_relief(LiVESButton * button,LiVESReliefStyle rstyle)4377 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_set_relief(LiVESButton *button, LiVESReliefStyle rstyle) {
4378 #ifdef GUI_GTK
4379   gtk_button_set_relief(button, rstyle);
4380   return TRUE;
4381 #endif
4382   return FALSE;
4383 }
4384 
4385 
lives_button_set_image(LiVESButton * button,LiVESWidget * image)4386 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_set_image(LiVESButton *button, LiVESWidget *image) {
4387 #ifdef GUI_GTK
4388   gtk_button_set_image(button, image);
4389   return TRUE;
4390 #endif
4391   return FALSE;
4392 }
4393 
4394 
lives_widget_set_focus_on_click(LiVESWidget * widget,boolean focus)4395 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_focus_on_click(LiVESWidget *widget, boolean focus) {
4396 #ifdef GUI_GTK
4397 #if GTK_CHECK_VERSION(3, 20, 0)
4398   gtk_widget_set_focus_on_click(widget, focus);
4399 #else
4400   if (!LIVES_IS_BUTTON(widget)) return FALSE;
4401   gtk_button_set_focus_on_click(LIVES_BUTTON(widget), focus);
4402 #endif
4403   return TRUE;
4404 #endif
4405   return FALSE;
4406 }
4407 
4408 
lives_button_set_focus_on_click(LiVESButton * button,boolean focus)4409 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_set_focus_on_click(LiVESButton *button, boolean focus) {
4410   return lives_widget_set_focus_on_click(LIVES_WIDGET(button), focus);
4411 }
4412 
4413 
lives_paned_get_position(LiVESPaned * paned)4414 WIDGET_HELPER_GLOBAL_INLINE int lives_paned_get_position(LiVESPaned *paned) {
4415 #ifdef GUI_GTK
4416   return gtk_paned_get_position(paned);
4417 #endif
4418   return -1;
4419 }
4420 
4421 
lives_paned_set_position(LiVESPaned * paned,int pos)4422 WIDGET_HELPER_GLOBAL_INLINE boolean lives_paned_set_position(LiVESPaned *paned, int pos) {
4423   // call this only after adding widgets
4424 #ifdef GUI_GTK
4425   gtk_paned_set_position(paned, pos);
4426   return TRUE;
4427 #endif
4428   return FALSE;
4429 }
4430 
4431 
lives_paned_pack(int where,LiVESPaned * paned,LiVESWidget * child,boolean resize,boolean shrink)4432 WIDGET_HELPER_GLOBAL_INLINE boolean lives_paned_pack(int where, LiVESPaned *paned, LiVESWidget *child, boolean resize,
4433     boolean shrink) {
4434 #ifdef GUI_GTK
4435   if (where == 1) gtk_paned_pack1(paned, child, resize, shrink);
4436   else gtk_paned_pack2(paned, child, resize, shrink);
4437   return TRUE;
4438 #endif
4439 #ifdef GUI_QT
4440   paned->insertWidget(where - 1, child);
4441   return TRUE;
4442 #endif
4443   return FALSE;
4444 }
4445 
4446 
lives_drawing_area_new(void)4447 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_drawing_area_new(void) {
4448   LiVESWidget *darea = NULL;
4449 #ifdef GUI_GTK
4450   darea = gtk_drawing_area_new();
4451 #endif
4452 #ifdef GUI_QT
4453   darea = new LiVESDrawingArea;
4454 #endif
4455   return darea;
4456 }
4457 
4458 
lives_event_get_time(LiVESXEvent * event)4459 WIDGET_HELPER_GLOBAL_INLINE int lives_event_get_time(LiVESXEvent *event) {
4460 #ifdef GUI_GTK
4461   return gdk_event_get_time(event);
4462 #endif
4463 #ifdef GUI_QT
4464   // TODO
4465   LiVESXEventButton *xevent = (LiVESXEventButton *)event;
4466   return xevent->time;
4467 #endif
4468   return 0;
4469 }
4470 
4471 
lives_toggle_button_get_active(LiVESToggleButton * button)4472 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_get_active(LiVESToggleButton *button) {
4473 #ifdef GUI_GTK
4474 #if LIVES_HAS_SWITCH_WIDGET
4475   if (LIVES_IS_SWITCH(button)) return gtk_switch_get_active(LIVES_SWITCH(button));
4476 #endif
4477   return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
4478 #endif
4479   return FALSE;
4480 }
4481 
4482 
lives_toggle_button_set_active(LiVESToggleButton * button,boolean active)4483 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_set_active(LiVESToggleButton *button, boolean active) {
4484 #ifdef GUI_GTK
4485 #if LIVES_HAS_SWITCH_WIDGET
4486   if (LIVES_IS_SWITCH(button)) lives_switch_set_active(LIVES_SWITCH(button), active);
4487   else
4488 #endif
4489     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
4490   return TRUE;
4491 #endif
4492   return FALSE;
4493 }
4494 
4495 
lives_toggle_button_set_mode(LiVESToggleButton * button,boolean drawind)4496 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_set_mode(LiVESToggleButton *button, boolean drawind) {
4497 #ifdef GUI_GTK
4498 #if LIVES_HAS_SWITCH_WIDGET
4499   if (!LIVES_IS_SWITCH(button))
4500 #endif
4501     gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(button), drawind);
4502   return TRUE;
4503 #endif
4504   return FALSE;
4505 }
4506 
4507 
lives_toggle_tool_button_new(void)4508 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_toggle_tool_button_new(void) {
4509   LiVESWidget *button = NULL;
4510 #ifdef GUI_GTK
4511   button = LIVES_WIDGET(gtk_toggle_tool_button_new());
4512 #endif
4513   return button;
4514 }
4515 
4516 
lives_toggle_tool_button_get_active(LiVESToggleToolButton * button)4517 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_tool_button_get_active(LiVESToggleToolButton *button) {
4518 #ifdef GUI_GTK
4519   return gtk_toggle_tool_button_get_active(button);
4520 #endif
4521   return FALSE;
4522 }
4523 
4524 
lives_toggle_tool_button_set_active(LiVESToggleToolButton * button,boolean active)4525 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_tool_button_set_active(LiVESToggleToolButton *button, boolean active) {
4526 #ifdef GUI_GTK
4527   gtk_toggle_tool_button_set_active(button, active);
4528   return TRUE;
4529 #endif
4530   return FALSE;
4531 }
4532 
4533 
lives_radio_button_new(LiVESSList * group)4534 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_radio_button_new(LiVESSList *group) {
4535   LiVESWidget *button = NULL;
4536 #ifdef GUI_GTK
4537   button = gtk_radio_button_new(group);
4538 #endif
4539   return button;
4540 }
4541 
4542 
lives_switch_new(void)4543 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_switch_new(void) {
4544   LiVESWidget *swtch = NULL;
4545 #if LIVES_HAS_SWITCH_WIDGET
4546   swtch = gtk_switch_new();
4547 #endif
4548   return swtch;
4549 }
4550 
lives_switch_get_active(LiVESSwitch * swtch)4551 WIDGET_HELPER_GLOBAL_INLINE boolean lives_switch_get_active(LiVESSwitch *swtch) {
4552 #if LIVES_HAS_SWITCH_WIDGET
4553   return gtk_switch_get_active(swtch);
4554 #endif
4555   return FALSE;
4556 }
4557 
lives_switch_set_active(LiVESSwitch * swtch,boolean active)4558 WIDGET_HELPER_GLOBAL_INLINE boolean lives_switch_set_active(LiVESSwitch *swtch, boolean active) {
4559 #if LIVES_HAS_SWITCH_WIDGET
4560   gtk_switch_set_active(swtch, active);
4561   return TRUE;
4562 #endif
4563   return FALSE;
4564 }
4565 
4566 
lives_spinner_new(void)4567 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_spinner_new(void) {
4568   LiVESWidget *spinner = NULL;
4569 #if LIVES_HAS_SPINNER_WIDGET
4570   spinner = gtk_spinner_new();
4571 #endif
4572   return spinner;
4573 }
4574 
lives_spinner_start(LiVESSpinner * spinner)4575 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spinner_start(LiVESSpinner *spinner) {
4576   if (spinner) {
4577 #if LIVES_HAS_SPINNER_WIDGET
4578     gtk_spinner_start(GTK_SPINNER(spinner));
4579     return TRUE;
4580 #endif
4581   }
4582   return FALSE;
4583 }
4584 
4585 
lives_spinner_stop(LiVESSpinner * spinner)4586 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spinner_stop(LiVESSpinner *spinner) {
4587   if (spinner) {
4588 #if LIVES_HAS_SPINNER_WIDGET
4589     gtk_spinner_stop(GTK_SPINNER(spinner));
4590     return TRUE;
4591 #endif
4592   }
4593   return FALSE;
4594 }
4595 
4596 
lives_check_button_new(void)4597 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_check_button_new(void) {
4598   LiVESWidget *button = NULL;
4599 #ifdef GUI_GTK
4600   button = gtk_check_button_new();
4601 #endif
4602   return button;
4603 }
4604 
4605 
lives_check_button_new_with_label(const char * label)4606 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_check_button_new_with_label(const char *label) {
4607   LiVESWidget *button = NULL;
4608 #ifdef GUI_GTK
4609   button = gtk_check_button_new_with_label(label);
4610 #endif
4611   return button;
4612 }
4613 
4614 
make_ttips_image_for(LiVESWidget * widget,const char * text)4615 static LiVESWidget *make_ttips_image_for(LiVESWidget *widget, const char *text) {
4616   LiVESWidget *ttips_image = lives_image_new_from_stock("livestock-help-info",
4617                              widget_opts.icon_size);
4618   if (ttips_image) {
4619 #if GTK_CHECK_VERSION(3, 16, 0)
4620     if (widget_opts.apply_theme) {
4621       set_css_value_direct(ttips_image, LIVES_WIDGET_STATE_NORMAL, "", "opacity", "0.75");
4622       set_css_value_direct(ttips_image, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
4623     }
4624 #endif
4625     lives_widget_set_no_show_all(ttips_image, TRUE);
4626     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(ttips_image), TTIPS_IMAGE_KEY, ttips_image);
4627     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(ttips_image), TTIPS_HIDE_KEY, ttips_image);
4628     if (text) lives_widget_set_tooltip_text(ttips_image, text);
4629     else {
4630       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(ttips_image),
4631                                    SHOWALL_OVERRIDE_KEY, LIVES_INT_TO_POINTER(TRUE));
4632     }
4633     lives_widget_set_show_hide_with(widget, ttips_image);
4634     lives_widget_set_sensitive_with(widget, ttips_image);
4635     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), HAS_TTIPS_IMAGE_KEY, ttips_image);
4636   }
4637   return ttips_image;
4638 }
4639 
4640 
lives_widget_set_tooltip_text(LiVESWidget * widget,const char * tip_text)4641 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_widget_set_tooltip_text(LiVESWidget *widget, const char *tip_text) {
4642   LiVESWidget *img_tips = NULL;
4643   boolean ttips_override = FALSE;
4644   const char *ttext = tip_text;
4645 
4646   if (!widget) return NULL;
4647 
4648   if (tip_text && *tip_text == '#' && !lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
4649       TTIPS_IMAGE_KEY)) {
4650     if (!(img_tips = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), HAS_TTIPS_IMAGE_KEY))) {
4651       img_tips = make_ttips_image_for(widget, ++ttext);
4652       if (img_tips) widget = img_tips;
4653     } else lives_widget_set_tooltip_text(img_tips, ++ttext);
4654   }
4655   if (!img_tips) {
4656     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), TTIPS_OVERRIDE_KEY))
4657       ttips_override = TRUE;
4658     if (!prefs->show_tooltips && !ttips_override) {
4659       if (tip_text) {
4660         lives_widget_object_set_data_auto(LIVES_WIDGET_OBJECT(widget), TTIPS_KEY,
4661                                           (livespointer)(lives_strdup(ttext)));
4662       } else {
4663         lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), TTIPS_KEY, NULL);
4664       }
4665       if (!lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
4666                                         TTIPS_IMAGE_KEY)) {
4667         if (!lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
4668                                           HAS_TTIPS_IMAGE_KEY)) {
4669           img_tips = make_ttips_image_for(widget, NULL);
4670           return img_tips;
4671         }
4672       }
4673       return NULL;
4674     }
4675     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
4676                                      TTIPS_IMAGE_KEY)) {
4677       if (ttext) {
4678         if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
4679                                          SHOWALL_OVERRIDE_KEY)) {
4680           LiVESWidget *cntrl;
4681           lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget),
4682                                        SHOWALL_OVERRIDE_KEY, NULL);
4683           if ((cntrl = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
4684                        SHOWHIDE_CONTROLLER_KEY))) {
4685             if (lives_widget_is_visible(cntrl)) lives_widget_show_all(widget);
4686           }
4687         }
4688       } else {
4689         lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget),
4690                                      SHOWALL_OVERRIDE_KEY, widget);
4691         lives_widget_hide(widget);
4692       }
4693     } else {
4694       if (!lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), HAS_TTIPS_IMAGE_KEY)) {
4695         img_tips = make_ttips_image_for(widget, NULL);
4696       }
4697     }
4698   }
4699 #ifdef GUI_GTK
4700 #if GTK_CHECK_VERSION(2, 12, 0)
4701   gtk_widget_set_tooltip_text(widget, ttext);
4702 #else
4703   GtkTooltips *tips;
4704   tips = gtk_tooltips_new();
4705   gtk_tooltips_set_tip(tips, widget, ttext, NULL);
4706 #endif
4707 #endif
4708   return img_tips;
4709 }
4710 
4711 
lives_widget_grab_focus(LiVESWidget * widget)4712 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_grab_focus(LiVESWidget *widget) {
4713 #ifdef GUI_GTK
4714   gtk_widget_set_can_focus(widget, TRUE);
4715   gtk_widget_grab_focus(widget);
4716   return TRUE;
4717 #endif
4718   return FALSE;
4719 }
4720 
4721 
lives_widget_grab_default(LiVESWidget * widget)4722 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_grab_default(LiVESWidget *widget) {
4723 #ifdef GUI_GTK
4724   gtk_widget_grab_default(widget);
4725   return TRUE;
4726 #endif
4727   return FALSE;
4728 }
4729 
4730 
lives_radio_button_get_group(LiVESRadioButton * rbutton)4731 WIDGET_HELPER_GLOBAL_INLINE LiVESSList *lives_radio_button_get_group(LiVESRadioButton *rbutton) {
4732 #ifdef GUI_GTK
4733   return gtk_radio_button_get_group(rbutton);
4734 #endif
4735   return NULL;
4736 }
4737 
4738 
lives_widget_get_parent(LiVESWidget * widget)4739 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_widget_get_parent(LiVESWidget *widget) {
4740 #ifdef GUI_GTK
4741   return gtk_widget_get_parent(widget);
4742 #endif
4743 #ifdef GUI_QT
4744   return widget->get_parent();
4745 #endif
4746   return NULL;
4747 }
4748 
4749 
lives_widget_get_toplevel(LiVESWidget * widget)4750 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_widget_get_toplevel(LiVESWidget *widget) {
4751 #ifdef GUI_GTK
4752   if (!GTK_IS_WIDGET(widget)) return NULL;
4753   return gtk_widget_get_toplevel(widget);
4754 #endif
4755   return NULL;
4756 }
4757 
4758 
lives_widget_get_xwindow(LiVESWidget * widget)4759 WIDGET_HELPER_GLOBAL_INLINE LiVESXWindow *lives_widget_get_xwindow(LiVESWidget *widget) {
4760 #ifdef GUI_GTK
4761 #if GTK_CHECK_VERSION(2, 12, 0)
4762   return gtk_widget_get_window(widget);
4763 #else
4764   return GDK_WINDOW(widget->window);
4765 #endif
4766 #endif
4767   return NULL;
4768 }
4769 
4770 
lives_widget_get_window(LiVESWidget * widget)4771 WIDGET_HELPER_GLOBAL_INLINE LiVESWindow *lives_widget_get_window(LiVESWidget *widget) {
4772 #ifdef GUI_GTK
4773   LiVESWidget *window = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
4774   if (GTK_IS_WINDOW(window)) return (LiVESWindow *)window;
4775 #endif
4776   return NULL;
4777 }
4778 
4779 
lives_xwindow_set_keep_above(LiVESXWindow * xwin,boolean setting)4780 WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_set_keep_above(LiVESXWindow *xwin, boolean setting) {
4781 #ifdef GUI_GTK
4782   gdk_window_set_keep_above(xwin, setting);
4783   return TRUE;
4784 #endif
4785   return FALSE;
4786 }
4787 
4788 
lives_widget_set_can_focus(LiVESWidget * widget,boolean state)4789 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_can_focus(LiVESWidget *widget, boolean state) {
4790 #ifdef GUI_GTK
4791 #if GTK_CHECK_VERSION(2, 18, 0)
4792   gtk_widget_set_can_focus(widget, state);
4793 #else
4794   if (state)
4795     GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
4796   else
4797     GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_FOCUS);
4798 #endif
4799   return TRUE;
4800 #endif
4801   return FALSE;
4802 }
4803 
4804 
lives_widget_set_can_default(LiVESWidget * widget,boolean state)4805 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_can_default(LiVESWidget *widget, boolean state) {
4806 #ifdef GUI_GTK
4807 #if GTK_CHECK_VERSION(2, 18, 0)
4808   gtk_widget_set_can_default(widget, state);
4809 #else
4810   if (state)
4811     GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_DEFAULT);
4812   else
4813     GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_DEFAULT);
4814 #endif
4815   return TRUE;
4816 #endif
4817   return FALSE;
4818 }
4819 
4820 
lives_widget_add_events(LiVESWidget * widget,int events)4821 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_add_events(LiVESWidget *widget, int events) {
4822 #ifdef GUI_GTK
4823   gtk_widget_add_events(widget, events);
4824   return TRUE;
4825 #endif
4826   return FALSE;
4827 }
4828 
4829 
lives_widget_set_events(LiVESWidget * widget,int events)4830 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_events(LiVESWidget *widget, int events) {
4831 #ifdef GUI_GTK
4832   gtk_widget_set_events(widget, events);
4833   return TRUE;
4834 #endif
4835 #ifdef GUI_QT
4836   widget->set_events(events);
4837   return TRUE;
4838 #endif
4839   return FALSE;
4840 }
4841 
4842 
lives_widget_remove_accelerator(LiVESWidget * widget,LiVESAccelGroup * acgroup,uint32_t accel_key,LiVESXModifierType accel_mods)4843 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_remove_accelerator(LiVESWidget *widget, LiVESAccelGroup *acgroup,
4844     uint32_t accel_key, LiVESXModifierType accel_mods) {
4845 #ifdef GUI_GTK
4846   return gtk_widget_remove_accelerator(widget, acgroup, accel_key, accel_mods);
4847 #endif
4848 #ifdef GUI_QT
4849   return (static_cast<LiVESWidgetObject *>(widget))->remove_accels(acgroup, accel_key, accel_mods);
4850 #endif
4851   return FALSE;
4852 }
4853 
4854 
lives_widget_get_preferred_size(LiVESWidget * widget,LiVESRequisition * min_size,LiVESRequisition * nat_size)4855 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_preferred_size(LiVESWidget *widget, LiVESRequisition *min_size,
4856     LiVESRequisition *nat_size) {
4857   // for GTK 4.x we will use widget::measure()
4858 #ifdef GUI_GTK
4859 #if GTK_CHECK_VERSION(3, 0, 0)
4860   gtk_widget_get_preferred_size(widget, min_size, nat_size);
4861   return TRUE;
4862 #endif
4863 #endif
4864   return FALSE;
4865 }
4866 
4867 
lives_widget_set_no_show_all(LiVESWidget * widget,boolean set)4868 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_no_show_all(LiVESWidget *widget, boolean set) {
4869 #ifdef GUI_GTK
4870   gtk_widget_set_no_show_all(widget, set);
4871   return TRUE;
4872 #endif
4873   return FALSE;
4874 }
4875 
4876 
lives_widget_get_no_show_all(LiVESWidget * widget)4877 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_no_show_all(LiVESWidget *widget) {
4878 #ifdef GUI_GTK
4879   return gtk_widget_get_no_show_all(widget);
4880 #endif
4881   return FALSE;
4882 }
4883 
4884 
lives_widget_is_sensitive(LiVESWidget * widget)4885 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_sensitive(LiVESWidget *widget) {
4886   // return TRUE is widget + parent is sensitive
4887 #ifdef GUI_GTK
4888 #if GTK_CHECK_VERSION(2, 18, 0)
4889   return gtk_widget_is_sensitive(widget);
4890 #else
4891   return GTK_WIDGET_IS_SENSITIVE(widget);
4892 #endif
4893 #endif
4894 #ifdef GUI_QT
4895   return widget->isEnabled();
4896 #endif
4897   return FALSE;
4898 }
4899 
4900 
lives_widget_is_visible(LiVESWidget * widget)4901 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_visible(LiVESWidget *widget) {
4902 #ifdef GUI_GTK
4903 #if GTK_CHECK_VERSION(2, 18, 0)
4904   return gtk_widget_get_visible(widget);
4905 #else
4906   return GTK_WIDGET_VISIBLE(widget);
4907 #endif
4908 #endif
4909 #ifdef GUI_QT
4910   return widget->isVisible();
4911 #endif
4912   return FALSE;
4913 }
4914 
4915 
lives_widget_is_realized(LiVESWidget * widget)4916 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_realized(LiVESWidget *widget) {
4917   // used for giw widgets
4918 #ifdef GUI_GTK
4919 #if GTK_CHECK_VERSION(2, 18, 0)
4920   return gtk_widget_get_realized(widget);
4921 #else
4922   return GTK_WIDGET_REALIZED(widget);
4923 #endif
4924 #endif
4925   return FALSE;
4926 }
4927 
4928 
lives_container_add(LiVESContainer * container,LiVESWidget * widget)4929 WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_add(LiVESContainer *container, LiVESWidget *widget) {
4930 #ifdef GUI_GTK
4931   gtk_container_add(container, widget);
4932   return TRUE;
4933 #endif
4934   return FALSE;
4935 }
4936 
4937 
lives_container_remove(LiVESContainer * container,LiVESWidget * widget)4938 WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_remove(LiVESContainer *container, LiVESWidget *widget) {
4939 #ifdef GUI_GTK
4940   gtk_container_remove(container, widget);
4941   return TRUE;
4942 #endif
4943   return FALSE;
4944 }
4945 
4946 
lives_container_set_border_width(LiVESContainer * container,uint32_t width)4947 WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_set_border_width(LiVESContainer *container, uint32_t width) {
4948   // sets border OUTSIDE container
4949 #ifdef GUI_GTK
4950   gtk_container_set_border_width(container, width);
4951   return TRUE;
4952 #endif
4953   return FALSE;
4954 }
4955 
4956 
lives_container_foreach(LiVESContainer * cont,LiVESWidgetCallback callback,livespointer cb_data)4957 WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_foreach(LiVESContainer *cont, LiVESWidgetCallback callback,
4958     livespointer cb_data) {
4959   // excludes internal children
4960 #ifdef GUI_GTK
4961   gtk_container_foreach(cont, callback, cb_data);
4962   return TRUE;
4963 #endif
4964   return FALSE;
4965 }
4966 
4967 
lives_container_forall(LiVESContainer * cont,LiVESWidgetCallback callback,livespointer cb_data)4968 WIDGET_HELPER_LOCAL_INLINE boolean lives_container_forall(LiVESContainer *cont, LiVESWidgetCallback callback,
4969     livespointer cb_data) {
4970   // includes internal children
4971 #ifdef GUI_GTK
4972   gtk_container_forall(cont, callback, cb_data);
4973   return TRUE;
4974 #endif
4975   return FALSE;
4976 }
4977 
4978 
lives_container_get_children(LiVESContainer * cont)4979 WIDGET_HELPER_GLOBAL_INLINE LiVESList *lives_container_get_children(LiVESContainer *cont) {
4980   LiVESList *children = NULL;
4981 #ifdef GUI_GTK
4982   children = gtk_container_get_children(cont);
4983 #endif
4984   return children;
4985 }
4986 
4987 
lives_container_set_focus_child(LiVESContainer * cont,LiVESWidget * child)4988 WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_set_focus_child(LiVESContainer *cont, LiVESWidget *child) {
4989 #ifdef GUI_GTK
4990   gtk_container_set_focus_child(cont, child);
4991   return TRUE;
4992 #endif
4993   return FALSE;
4994 }
4995 
4996 
lives_container_get_focus_child(LiVESContainer * cont)4997 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_container_get_focus_child(LiVESContainer *cont) {
4998 #ifdef GUI_GTK
4999   return gtk_container_get_focus_child(cont);
5000 #endif
5001   return NULL;
5002 }
5003 
5004 
lives_progress_bar_new(void)5005 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_progress_bar_new(void) {
5006   LiVESWidget *pbar = NULL;
5007 #ifdef GUI_GTK
5008   pbar = gtk_progress_bar_new();
5009 #endif
5010   return pbar;
5011 }
5012 
5013 
lives_progress_bar_set_fraction(LiVESProgressBar * pbar,double fraction)5014 WIDGET_HELPER_GLOBAL_INLINE boolean lives_progress_bar_set_fraction(LiVESProgressBar *pbar, double fraction) {
5015 #ifdef GUI_GTK
5016 #ifdef PROGBAR_IS_ENTRY
5017   if (palette->style & STYLE_1) {
5018     lives_widget_set_sensitive(LIVES_WIDGET(pbar), FALSE);
5019   }
5020   gtk_entry_set_progress_fraction(pbar, fraction);
5021   if (is_standard_widget(LIVES_WIDGET(pbar)) && widget_opts.apply_theme) {
5022     set_css_value_direct(LIVES_WIDGET(pbar), LIVES_WIDGET_STATE_NORMAL, "progress",
5023                          "border-width", "0px");
5024   }
5025 #else
5026   gtk_progress_bar_set_fraction(pbar, fraction);
5027 #endif
5028   return TRUE;
5029 #endif
5030   return FALSE;
5031 }
5032 
5033 
lives_progress_bar_set_pulse_step(LiVESProgressBar * pbar,double fraction)5034 WIDGET_HELPER_GLOBAL_INLINE boolean lives_progress_bar_set_pulse_step(LiVESProgressBar *pbar, double fraction) {
5035 #ifdef GUI_GTK
5036 #ifdef PROGBAR_IS_ENTRY
5037   gtk_entry_set_progress_pulse_step(pbar, fraction);
5038 #else
5039   gtk_progress_bar_set_pulse_step(pbar, fraction);
5040 #endif
5041   return TRUE;
5042 #endif
5043   return FALSE;
5044 }
5045 
5046 
lives_progress_bar_pulse(LiVESProgressBar * pbar)5047 WIDGET_HELPER_GLOBAL_INLINE boolean lives_progress_bar_pulse(LiVESProgressBar *pbar) {
5048 #ifdef GUI_GTK
5049 #ifdef PROGBAR_IS_ENTRY
5050   if (palette->style & STYLE_1) {
5051     lives_widget_set_sensitive(LIVES_WIDGET(pbar), TRUE);
5052   }
5053   gtk_entry_progress_pulse(pbar);
5054   if (is_standard_widget(LIVES_WIDGET(pbar)) && widget_opts.apply_theme) {
5055     char *tmp = lives_strdup_printf("%dpx", widget_opts.css_min_height);
5056     set_css_value_direct(LIVES_WIDGET(pbar), LIVES_WIDGET_STATE_NORMAL, "progress",
5057                          "border-top-width", tmp);
5058     set_css_value_direct(LIVES_WIDGET(pbar), LIVES_WIDGET_STATE_NORMAL, "progress",
5059                          "border-bottom-width", tmp);
5060     lives_free(tmp);
5061   }
5062 #else
5063   gtk_progress_bar_pulse(pbar);
5064 #endif
5065   return TRUE;
5066 #endif
5067   return FALSE;
5068 }
5069 
5070 
lives_spin_button_new(LiVESAdjustment * adj,double climb_rate,uint32_t digits)5071 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_spin_button_new(LiVESAdjustment *adj, double climb_rate, uint32_t digits) {
5072   LiVESWidget *sbutton = NULL;
5073 #ifdef GUI_GTK
5074   sbutton = gtk_spin_button_new(adj, climb_rate, digits);
5075 #endif
5076 #ifdef GUI_QT
5077   sbutton = new LiVESSpinButton(adj, climb_rate, digits);
5078 #endif
5079   return sbutton;
5080 }
5081 
5082 
lives_spin_button_get_value(LiVESSpinButton * button)5083 WIDGET_HELPER_GLOBAL_INLINE double lives_spin_button_get_value(LiVESSpinButton *button) {
5084 #ifdef GUI_GTK
5085   return gtk_spin_button_get_value(button);
5086 #endif
5087   return 0.;
5088 }
5089 
5090 
lives_spin_button_get_value_as_int(LiVESSpinButton * button)5091 WIDGET_HELPER_GLOBAL_INLINE int lives_spin_button_get_value_as_int(LiVESSpinButton *button) {
5092 #ifdef GUI_GTK
5093   return gtk_spin_button_get_value_as_int(button);
5094 #endif
5095   return 0.;
5096 }
5097 
5098 
lives_spin_button_get_adjustment(LiVESSpinButton * button)5099 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_spin_button_get_adjustment(LiVESSpinButton *button) {
5100   LiVESAdjustment *adj = NULL;
5101 #ifdef GUI_GTK
5102   adj = gtk_spin_button_get_adjustment(button);
5103 #endif
5104 #ifdef GUI_QT
5105   adj = button->get_adj();
5106 #endif
5107   return adj;
5108 }
5109 
5110 
lives_spin_button_set_adjustment(LiVESSpinButton * button,LiVESAdjustment * adj)5111 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_spin_button_set_adjustment(LiVESSpinButton *button, LiVESAdjustment *adj) {
5112 #ifdef GUI_GTK
5113   gtk_spin_button_set_adjustment(button, adj);
5114 #endif
5115   return adj;
5116 }
5117 
5118 
lives_spin_button_set_value(LiVESSpinButton * button,double value)5119 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_value(LiVESSpinButton *button, double value) {
5120   if (is_standard_widget(LIVES_WIDGET(button))) value = lives_spin_button_get_snapval(button, value);
5121 #ifdef GUI_GTK
5122   gtk_spin_button_set_value(button, value);
5123   return TRUE;
5124 #endif
5125   return FALSE;
5126 }
5127 
5128 
lives_spin_button_set_range(LiVESSpinButton * button,double min,double max)5129 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_range(LiVESSpinButton *button, double min, double max) {
5130 #ifdef GUI_GTK
5131   gtk_spin_button_set_range(button, min, max);
5132   return TRUE;
5133 #endif
5134   return FALSE;
5135 }
5136 
5137 
lives_spin_button_set_wrap(LiVESSpinButton * button,boolean wrap)5138 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_wrap(LiVESSpinButton *button, boolean wrap) {
5139 #ifdef GUI_GTK
5140   gtk_spin_button_set_wrap(button, wrap);
5141   return TRUE;
5142 #endif
5143   return FALSE;
5144 }
5145 
5146 
lives_spin_button_set_snap_to_ticks(LiVESSpinButton * button,boolean snap)5147 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_snap_to_ticks(LiVESSpinButton *button, boolean snap) {
5148 #ifdef GUI_GTK
5149   gtk_spin_button_set_snap_to_ticks(button, snap);
5150   return TRUE;
5151 #endif
5152   return FALSE;
5153 }
5154 
5155 
lives_spin_button_set_digits(LiVESSpinButton * button,uint32_t digits)5156 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_digits(LiVESSpinButton *button, uint32_t digits) {
5157 #ifdef GUI_GTK
5158   gtk_spin_button_set_digits(button, digits);
5159   return TRUE;
5160 #endif
5161   return FALSE;
5162 }
5163 
5164 
lives_spin_button_update(LiVESSpinButton * button)5165 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_update(LiVESSpinButton *button) {
5166 #ifdef GUI_GTK
5167   gtk_spin_button_update(button);
5168   return TRUE;
5169 #endif
5170   return FALSE;
5171 }
5172 
5173 
lives_tool_button_new(LiVESWidget * icon_widget,const char * label)5174 WIDGET_HELPER_GLOBAL_INLINE LiVESToolItem *lives_tool_button_new(LiVESWidget *icon_widget, const char *label) {
5175   LiVESToolItem *button = NULL;
5176 #ifdef GUI_GTK
5177   button = gtk_tool_button_new(icon_widget, label);
5178 #endif
5179   return button;
5180 }
5181 
5182 
lives_tool_item_new(void)5183 WIDGET_HELPER_GLOBAL_INLINE LiVESToolItem *lives_tool_item_new(void) {
5184   LiVESToolItem *item = NULL;
5185 #ifdef GUI_GTK
5186   item = gtk_tool_item_new();
5187 #endif
5188   return item;
5189 }
5190 
5191 
lives_separator_tool_item_new(void)5192 WIDGET_HELPER_GLOBAL_INLINE LiVESToolItem *lives_separator_tool_item_new(void) {
5193   LiVESToolItem *item = NULL;
5194 #ifdef GUI_GTK
5195   item = gtk_separator_tool_item_new();
5196 #endif
5197   return item;
5198 }
5199 
5200 
lives_tool_button_set_icon_widget(LiVESToolButton * button,LiVESWidget * icon)5201 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tool_button_set_icon_widget(LiVESToolButton *button, LiVESWidget *icon) {
5202 #ifdef GUI_GTK
5203   gtk_tool_button_set_icon_widget(button, icon);
5204   return TRUE;
5205 #endif
5206   return FALSE;
5207 }
5208 
5209 
lives_tool_button_get_icon_widget(LiVESToolButton * button)5210 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_tool_button_get_icon_widget(LiVESToolButton *button) {
5211 #ifdef GUI_GTK
5212   return gtk_tool_button_get_icon_widget(button);
5213 #endif
5214   return NULL;
5215 }
5216 
5217 
lives_tool_button_set_label_widget(LiVESToolButton * button,LiVESWidget * label)5218 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tool_button_set_label_widget(LiVESToolButton *button, LiVESWidget *label) {
5219 #ifdef GUI_GTK
5220   gtk_tool_button_set_label_widget(button, label);
5221   return TRUE;
5222 #endif
5223   return FALSE;
5224 }
5225 
5226 
lives_tool_button_get_label_widget(LiVESToolButton * button)5227 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_tool_button_get_label_widget(LiVESToolButton *button) {
5228 #ifdef GUI_GTK
5229   return gtk_tool_button_get_label_widget(button);
5230 #endif
5231   return NULL;
5232 }
5233 
5234 
lives_tool_button_set_use_underline(LiVESToolButton * button,boolean use_underline)5235 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tool_button_set_use_underline(LiVESToolButton *button, boolean use_underline) {
5236 #ifdef GUI_GTK
5237   gtk_tool_button_set_use_underline(button, use_underline);
5238   return TRUE;
5239 #endif
5240   return FALSE;
5241 }
5242 
5243 
lives_ruler_set_range(LiVESRuler * ruler,double lower,double upper,double position,double max_size)5244 WIDGET_HELPER_GLOBAL_INLINE boolean lives_ruler_set_range(LiVESRuler *ruler, double lower, double upper, double position,
5245     double max_size) {
5246 #ifdef GUI_GTK
5247 #if GTK_CHECK_VERSION(3, 0, 0)
5248   gtk_range_set_range(GTK_RANGE(ruler), lower, upper);
5249   gtk_range_set_value(GTK_RANGE(ruler), position);
5250 #else
5251   gtk_ruler_set_range(ruler, lower, upper, position, max_size);
5252   return TRUE;
5253 #endif
5254   return FALSE;
5255 #endif
5256 }
5257 
5258 
lives_message_dialog_new(LiVESWindow * parent,LiVESDialogFlags flags,LiVESMessageType type,LiVESButtonsType buttons,const char * msg_fmt,...)5259 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_message_dialog_new(LiVESWindow *parent, LiVESDialogFlags flags,
5260     LiVESMessageType type,
5261     LiVESButtonsType buttons, const char *msg_fmt, ...) {
5262   LiVESWidget *mdial = NULL;
5263 #ifdef GUI_GTK
5264   mdial = gtk_message_dialog_new(parent, flags | GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, msg_fmt, NULL);
5265 #endif
5266   if (mdial && mainw && mainw->mgeom) lives_window_set_monitor(LIVES_WINDOW(mdial),
5267         widget_opts.monitor);
5268   return mdial;
5269 }
5270 
5271 
lives_ruler_get_value(LiVESRuler * ruler)5272 WIDGET_HELPER_GLOBAL_INLINE double lives_ruler_get_value(LiVESRuler *ruler) {
5273 #ifdef GUI_GTK
5274 #if GTK_CHECK_VERSION(3, 0, 0)
5275   return gtk_range_get_value(GTK_RANGE(ruler));
5276 #else
5277   return ruler->position;
5278 #endif
5279 #endif
5280   return 0.;
5281 }
5282 
5283 
lives_ruler_set_value(LiVESRuler * ruler,double value)5284 WIDGET_HELPER_GLOBAL_INLINE double lives_ruler_set_value(LiVESRuler *ruler, double value) {
5285 #ifdef GUI_GTK
5286 #if GTK_CHECK_VERSION(3, 0, 0)
5287   gtk_range_set_value(GTK_RANGE(ruler), value);
5288 #else
5289   ruler->position = value;
5290 #endif
5291 #endif
5292   return value;
5293 }
5294 
5295 
lives_ruler_set_upper(LiVESRuler * ruler,double value)5296 WIDGET_HELPER_GLOBAL_INLINE double lives_ruler_set_upper(LiVESRuler *ruler, double value) {
5297 #ifdef GUI_GTK
5298 #if GTK_CHECK_VERSION(3, 0, 0)
5299 #ifdef ENABLE_GIW_3
5300   if (GIW_IS_TIMELINE(ruler)) {
5301     LiVESAdjustment *adj = giw_timeline_get_adjustment(GIW_TIMELINE(ruler));
5302     double lower = lives_adjustment_get_lower(adj);
5303     giw_timeline_set_range(GIW_TIMELINE(ruler), lower, value, giw_timeline_get_max_size(GIW_TIMELINE(ruler)));
5304   } else
5305 #endif
5306     gtk_adjustment_set_upper(gtk_range_get_adjustment(GTK_RANGE(ruler)), value);
5307 #else
5308   ruler->upper = value;
5309 #endif
5310 #endif
5311   return value;
5312 }
5313 
5314 
lives_ruler_set_lower(LiVESRuler * ruler,double value)5315 WIDGET_HELPER_GLOBAL_INLINE double lives_ruler_set_lower(LiVESRuler *ruler, double value) {
5316 #ifdef GUI_GTK
5317 #if GTK_CHECK_VERSION(3, 0, 0)
5318 #ifdef ENABLE_GIW_3
5319   if (GIW_IS_TIMELINE(ruler)) {
5320     LiVESAdjustment *adj = giw_timeline_get_adjustment(GIW_TIMELINE(ruler));
5321     double upper = lives_adjustment_get_upper(adj);
5322     giw_timeline_set_range(GIW_TIMELINE(ruler), value, upper, giw_timeline_get_max_size(GIW_TIMELINE(ruler)));
5323   } else
5324 #endif
5325     gtk_adjustment_set_lower(gtk_range_get_adjustment(GTK_RANGE(ruler)), value);
5326 #else
5327   ruler->lower = value;
5328 #endif
5329 #endif
5330   return value;
5331 }
5332 
5333 
lives_cell_renderer_text_new(void)5334 WIDGET_HELPER_GLOBAL_INLINE LiVESCellRenderer *lives_cell_renderer_text_new(void) {
5335   LiVESCellRenderer *renderer = NULL;
5336 #ifdef GUI_GTK
5337   renderer = gtk_cell_renderer_text_new();
5338 #endif
5339   return renderer;
5340 }
5341 
5342 
lives_cell_renderer_spin_new(void)5343 WIDGET_HELPER_GLOBAL_INLINE LiVESCellRenderer *lives_cell_renderer_spin_new(void) {
5344   LiVESCellRenderer *renderer = NULL;
5345 #ifdef GUI_GTK
5346 #if GTK_CHECK_VERSION(2, 10, 0)
5347   renderer = gtk_cell_renderer_spin_new();
5348 #endif
5349 #endif
5350   return renderer;
5351 }
5352 
5353 
lives_cell_renderer_toggle_new(void)5354 WIDGET_HELPER_GLOBAL_INLINE LiVESCellRenderer *lives_cell_renderer_toggle_new(void) {
5355   LiVESCellRenderer *renderer = NULL;
5356 #ifdef GUI_GTK
5357   renderer = gtk_cell_renderer_toggle_new();
5358 #endif
5359   return renderer;
5360 }
5361 
5362 
lives_cell_renderer_pixbuf_new(void)5363 WIDGET_HELPER_GLOBAL_INLINE LiVESCellRenderer *lives_cell_renderer_pixbuf_new(void) {
5364   LiVESCellRenderer *renderer = NULL;
5365 #ifdef GUI_GTK
5366   renderer = gtk_cell_renderer_pixbuf_new();
5367 #endif
5368   return renderer;
5369 }
5370 
5371 
lives_toolbar_new(void)5372 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_toolbar_new(void) {
5373   LiVESWidget *toolbar = NULL;
5374 #ifdef GUI_GTK
5375   toolbar = gtk_toolbar_new();
5376 #endif
5377   return toolbar;
5378 }
5379 
5380 
lives_toolbar_insert(LiVESToolbar * toolbar,LiVESToolItem * item,int pos)5381 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toolbar_insert(LiVESToolbar *toolbar, LiVESToolItem *item, int pos) {
5382 #ifdef GUI_GTK
5383   gtk_toolbar_insert(toolbar, item, pos);
5384   return TRUE;
5385 #endif
5386   return FALSE;
5387 }
5388 
5389 
lives_toolbar_set_show_arrow(LiVESToolbar * toolbar,boolean show)5390 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toolbar_set_show_arrow(LiVESToolbar *toolbar, boolean show) {
5391 #ifdef GUI_GTK
5392   gtk_toolbar_set_show_arrow(toolbar, show);
5393   return TRUE;
5394 #endif
5395   return FALSE;
5396 }
5397 
5398 
lives_toolbar_get_icon_size(LiVESToolbar * toolbar)5399 WIDGET_HELPER_GLOBAL_INLINE LiVESIconSize lives_toolbar_get_icon_size(LiVESToolbar *toolbar) {
5400 #ifdef GUI_GTK
5401   return gtk_toolbar_get_icon_size(toolbar);
5402 #endif
5403   return LIVES_ICON_SIZE_INVALID;
5404 }
5405 
5406 
lives_toolbar_set_icon_size(LiVESToolbar * toolbar,LiVESIconSize icon_size)5407 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toolbar_set_icon_size(LiVESToolbar *toolbar, LiVESIconSize icon_size) {
5408 #ifdef GUI_GTK
5409   gtk_toolbar_set_icon_size(toolbar, icon_size);
5410   return TRUE;
5411 #endif
5412   return FALSE;
5413 }
5414 
5415 
lives_toolbar_set_style(LiVESToolbar * toolbar,LiVESToolbarStyle style)5416 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toolbar_set_style(LiVESToolbar *toolbar, LiVESToolbarStyle style) {
5417 #ifdef GUI_GTK
5418   gtk_toolbar_set_style(toolbar, style);
5419   return TRUE;
5420 #endif
5421   return FALSE;
5422 }
5423 
5424 
lives_widget_get_allocation_x(LiVESWidget * widget)5425 WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_x(LiVESWidget *widget) {
5426   int x = 0;
5427 #ifdef GUI_GTK
5428 #if GTK_CHECK_VERSION(2, 18, 0)
5429   GtkAllocation alloc;
5430   gtk_widget_get_allocation(widget, &alloc);
5431   x = alloc.x;
5432 #else
5433   x = widget->allocation.x;
5434 #endif
5435 #endif
5436   return x;
5437 }
5438 
5439 
lives_widget_get_allocation_y(LiVESWidget * widget)5440 WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_y(LiVESWidget *widget) {
5441   int y = 0;
5442 #ifdef GUI_GTK
5443 #if GTK_CHECK_VERSION(2, 18, 0)
5444   GtkAllocation alloc;
5445   gtk_widget_get_allocation(widget, &alloc);
5446   y = alloc.y;
5447 #else
5448   y = widget->allocation.y;
5449 #endif
5450 #endif
5451   return y;
5452 }
5453 
5454 
lives_widget_get_allocation_width(LiVESWidget * widget)5455 WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_width(LiVESWidget *widget) {
5456   int width = 0;
5457 #ifdef GUI_GTK
5458 #if GTK_CHECK_VERSION(2, 18, 0)
5459   GtkAllocation alloc;
5460   gtk_widget_get_allocation(widget, &alloc);
5461   width = alloc.width;
5462 #else
5463   width = widget->allocation.width;
5464 #endif
5465 #endif
5466   return width;
5467 }
5468 
5469 
lives_widget_get_allocation_height(LiVESWidget * widget)5470 WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_height(LiVESWidget *widget) {
5471   int height = 0;
5472 #ifdef GUI_GTK
5473 #if GTK_CHECK_VERSION(2, 18, 0)
5474   GtkAllocation alloc;
5475   gtk_widget_get_allocation(widget, &alloc);
5476   height = alloc.height;
5477 #else
5478   height = widget->allocation.height;
5479 #endif
5480 #endif
5481   return height;
5482 }
5483 
5484 
lives_widget_set_state(LiVESWidget * widget,LiVESWidgetState state)5485 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_state(LiVESWidget *widget, LiVESWidgetState state) {
5486 #ifdef GUI_GTK
5487 #if GTK_CHECK_VERSION(3, 0, 0)
5488   gtk_widget_set_state_flags(widget, state, TRUE);
5489 #else
5490   gtk_widget_set_state(widget, state);
5491 #endif
5492   return TRUE;
5493 #endif
5494   return FALSE;
5495 }
5496 
5497 
lives_widget_get_state(LiVESWidget * widget)5498 WIDGET_HELPER_GLOBAL_INLINE LiVESWidgetState lives_widget_get_state(LiVESWidget *widget) {
5499 #ifdef GUI_GTK
5500 #if GTK_CHECK_VERSION(3, 0, 0)
5501   return gtk_widget_get_state_flags(widget);
5502 #else
5503 #if GTK_CHECK_VERSION(2, 18, 0)
5504   return gtk_widget_get_state(widget);
5505 #else
5506   return GTK_WIDGET_STATE(widget);
5507 #endif
5508 #endif
5509 #endif
5510   return (LiVESWidgetState)0;
5511 }
5512 
5513 
lives_bin_get_child(LiVESBin * bin)5514 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_bin_get_child(LiVESBin *bin) {
5515   LiVESWidget *child = NULL;
5516 #ifdef GUI_GTK
5517   child = gtk_bin_get_child(bin);
5518 #endif
5519   return child;
5520 }
5521 
5522 
lives_adjustment_get_upper(LiVESAdjustment * adj)5523 WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_upper(LiVESAdjustment *adj) {
5524   double upper = 0.;
5525 #ifdef GUI_GTK
5526 #if GTK_CHECK_VERSION(2, 14, 0)
5527   upper = gtk_adjustment_get_upper(adj);
5528 #else
5529   upper = adj->upper;
5530 #endif
5531 #endif
5532   return upper;
5533 }
5534 
5535 
lives_adjustment_get_lower(LiVESAdjustment * adj)5536 WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_lower(LiVESAdjustment *adj) {
5537   double lower = 0.;
5538 #ifdef GUI_GTK
5539 #if GTK_CHECK_VERSION(2, 14, 0)
5540   lower = gtk_adjustment_get_lower(adj);
5541 #else
5542   lower = adj->lower;
5543 #endif
5544 #endif
5545   return lower;
5546 }
5547 
5548 
lives_adjustment_get_page_size(LiVESAdjustment * adj)5549 WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_page_size(LiVESAdjustment *adj) {
5550   double page_size = 0.;
5551 #ifdef GUI_GTK
5552 #if GTK_CHECK_VERSION(2, 14, 0)
5553   page_size = gtk_adjustment_get_page_size(adj);
5554 #else
5555   page_size = adj->page_size;
5556 #endif
5557 #endif
5558   return page_size;
5559 }
5560 
5561 
lives_adjustment_get_step_increment(LiVESAdjustment * adj)5562 WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_step_increment(LiVESAdjustment *adj) {
5563   double step_increment = 0.;
5564 #ifdef GUI_GTK
5565 #if GTK_CHECK_VERSION(2, 14, 0)
5566   step_increment = gtk_adjustment_get_step_increment(adj);
5567 #else
5568   step_increment = adj->step_increment;
5569 #endif
5570 #endif
5571   return step_increment;
5572 }
5573 
5574 
lives_adjustment_get_value(LiVESAdjustment * adj)5575 WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_value(LiVESAdjustment *adj) {
5576   double value = 0.;
5577 #ifdef GUI_GTK
5578   value = gtk_adjustment_get_value(adj);
5579 #endif
5580   return value;
5581 }
5582 
5583 
lives_adjustment_set_upper(LiVESAdjustment * adj,double upper)5584 WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_upper(LiVESAdjustment *adj, double upper) {
5585 #ifdef GUI_GTK
5586 #if GTK_CHECK_VERSION(2, 14, 0)
5587   gtk_adjustment_set_upper(adj, upper);
5588 #else
5589   adj->upper = upper;
5590 #endif
5591   return TRUE;
5592 #endif
5593   return FALSE;
5594 }
5595 
5596 
lives_adjustment_set_lower(LiVESAdjustment * adj,double lower)5597 WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_lower(LiVESAdjustment *adj, double lower) {
5598 #ifdef GUI_GTK
5599 #if GTK_CHECK_VERSION(2, 14, 0)
5600   gtk_adjustment_set_lower(adj, lower);
5601 #else
5602   adj->lower = lower;
5603 #endif
5604   return TRUE;
5605 #endif
5606   return FALSE;
5607 }
5608 
5609 
lives_adjustment_set_page_size(LiVESAdjustment * adj,double page_size)5610 WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_page_size(LiVESAdjustment *adj, double page_size) {
5611 #ifdef GUI_GTK
5612 #if GTK_CHECK_VERSION(2, 14, 0)
5613   gtk_adjustment_set_page_size(adj, page_size);
5614 #else
5615   adj->page_size = page_size;
5616 #endif
5617   return TRUE;
5618 #endif
5619   return FALSE;
5620 }
5621 
5622 
lives_adjustment_set_step_increment(LiVESAdjustment * adj,double step_increment)5623 WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_step_increment(LiVESAdjustment *adj, double step_increment) {
5624 #ifdef GUI_GTK
5625 #if GTK_CHECK_VERSION(2, 14, 0)
5626   gtk_adjustment_set_step_increment(adj, step_increment);
5627 #else
5628   adj->step_increment = step_increment;
5629 #endif
5630   return TRUE;
5631 #endif
5632   return FALSE;
5633 }
5634 
5635 
lives_adjustment_set_value(LiVESAdjustment * adj,double value)5636 WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_value(LiVESAdjustment *adj, double value) {
5637 #ifdef GUI_GTK
5638   gtk_adjustment_set_value(adj, value);
5639   return TRUE;
5640 #endif
5641   return FALSE;
5642 }
5643 
5644 
lives_adjustment_clamp_page(LiVESAdjustment * adj,double lower,double upper)5645 WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_clamp_page(LiVESAdjustment *adj, double lower, double upper) {
5646 #ifdef GUI_GTK
5647   gtk_adjustment_clamp_page(adj, lower, upper);
5648   return TRUE;
5649 #endif
5650   return FALSE;
5651 }
5652 
5653 
lives_range_get_adjustment(LiVESRange * range)5654 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_range_get_adjustment(LiVESRange *range) {
5655   LiVESAdjustment *adj = NULL;
5656 #ifdef GUI_GTK
5657   adj = gtk_range_get_adjustment(range);
5658 #endif
5659   return adj;
5660 }
5661 
5662 
lives_range_set_value(LiVESRange * range,double value)5663 WIDGET_HELPER_GLOBAL_INLINE boolean lives_range_set_value(LiVESRange *range, double value) {
5664 #ifdef GUI_GTK
5665   gtk_range_set_value(range, value);
5666   return TRUE;
5667 #endif
5668   return FALSE;
5669 }
5670 
5671 
lives_range_set_range(LiVESRange * range,double min,double max)5672 WIDGET_HELPER_GLOBAL_INLINE boolean lives_range_set_range(LiVESRange *range, double min, double max) {
5673 #ifdef GUI_GTK
5674   gtk_range_set_range(range, min, max);
5675   return TRUE;
5676 #endif
5677   return FALSE;
5678 }
5679 
5680 
lives_range_set_increments(LiVESRange * range,double step,double page)5681 WIDGET_HELPER_GLOBAL_INLINE boolean lives_range_set_increments(LiVESRange *range, double step, double page) {
5682 #ifdef GUI_GTK
5683   gtk_range_set_increments(range, step, page);
5684   return TRUE;
5685 #endif
5686   return FALSE;
5687 }
5688 
5689 
lives_range_set_inverted(LiVESRange * range,boolean invert)5690 WIDGET_HELPER_GLOBAL_INLINE boolean lives_range_set_inverted(LiVESRange *range, boolean invert) {
5691 #ifdef GUI_GTK
5692   gtk_range_set_inverted(range, invert);
5693   return TRUE;
5694 #endif
5695   return FALSE;
5696 }
5697 
5698 
lives_range_get_value(LiVESRange * range)5699 WIDGET_HELPER_GLOBAL_INLINE double lives_range_get_value(LiVESRange *range) {
5700   double value = 0.;
5701 #ifdef GUI_GTK
5702   value = gtk_range_get_value(range);
5703 #endif
5704   return value;
5705 }
5706 
5707 
lives_tree_model_get(LiVESTreeModel * tmod,LiVESTreeIter * titer,...)5708 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_model_get(LiVESTreeModel *tmod, LiVESTreeIter *titer, ...) {
5709   boolean res = FALSE;
5710   va_list argList;
5711   va_start(argList, titer);
5712 #ifdef GUI_GTK
5713   gtk_tree_model_get_valist(tmod, titer, argList);
5714   res = TRUE;
5715 #endif
5716   va_end(argList);
5717   return res;
5718 }
5719 
5720 
lives_tree_model_get_iter(LiVESTreeModel * tmod,LiVESTreeIter * titer,LiVESTreePath * tpath)5721 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_model_get_iter(LiVESTreeModel *tmod, LiVESTreeIter *titer,
5722     LiVESTreePath *tpath) {
5723 #ifdef GUI_GTK
5724   return gtk_tree_model_get_iter(tmod, titer, tpath);
5725 #endif
5726   return FALSE;
5727 }
5728 
5729 
lives_tree_model_get_iter_first(LiVESTreeModel * tmod,LiVESTreeIter * titer)5730 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_model_get_iter_first(LiVESTreeModel *tmod, LiVESTreeIter *titer) {
5731 #ifdef GUI_GTK
5732   return gtk_tree_model_get_iter_first(tmod, titer);
5733 #endif
5734   return FALSE;
5735 }
5736 
5737 
lives_tree_model_get_path(LiVESTreeModel * tmod,LiVESTreeIter * titer)5738 WIDGET_HELPER_GLOBAL_INLINE LiVESTreePath *lives_tree_model_get_path(LiVESTreeModel *tmod, LiVESTreeIter *titer) {
5739   LiVESTreePath *tpath = NULL;
5740 #ifdef GUI_GTK
5741   tpath = gtk_tree_model_get_path(tmod, titer);
5742 #endif
5743   return tpath;
5744 }
5745 
5746 
lives_tree_model_iter_children(LiVESTreeModel * tmod,LiVESTreeIter * titer,LiVESTreeIter * parent)5747 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_model_iter_children(LiVESTreeModel *tmod, LiVESTreeIter *titer,
5748     LiVESTreeIter *parent) {
5749 #ifdef GUI_GTK
5750   return gtk_tree_model_iter_children(tmod, titer, parent);
5751 #endif
5752   return FALSE;
5753 }
5754 
5755 
lives_tree_model_iter_n_children(LiVESTreeModel * tmod,LiVESTreeIter * titer)5756 WIDGET_HELPER_GLOBAL_INLINE int lives_tree_model_iter_n_children(LiVESTreeModel *tmod, LiVESTreeIter *titer) {
5757 #ifdef GUI_GTK
5758   return gtk_tree_model_iter_n_children(tmod, titer);
5759 #endif
5760   return 0;
5761 }
5762 
5763 
lives_tree_model_iter_next(LiVESTreeModel * tmod,LiVESTreeIter * titer)5764 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_model_iter_next(LiVESTreeModel *tmod, LiVESTreeIter *titer) {
5765 #ifdef GUI_GTK
5766   return gtk_tree_model_iter_next(tmod, titer);
5767 #endif
5768   return FALSE;
5769 }
5770 
5771 
lives_tree_path_free(LiVESTreePath * tpath)5772 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_path_free(LiVESTreePath *tpath) {
5773 #ifdef GUI_GTK
5774   gtk_tree_path_free(tpath);
5775   return TRUE;
5776 #endif
5777   return FALSE;
5778 }
5779 
5780 
lives_tree_path_new_from_string(const char * path)5781 WIDGET_HELPER_GLOBAL_INLINE LiVESTreePath *lives_tree_path_new_from_string(const char *path) {
5782   LiVESTreePath *tpath = NULL;
5783 #ifdef GUI_GTK
5784   tpath = gtk_tree_path_new_from_string(path);
5785 #endif
5786   return tpath;
5787 }
5788 
5789 
lives_tree_path_get_depth(LiVESTreePath * tpath)5790 WIDGET_HELPER_GLOBAL_INLINE int lives_tree_path_get_depth(LiVESTreePath *tpath) {
5791   int depth = -1;
5792 #ifdef GUI_GTK
5793   depth = gtk_tree_path_get_depth(tpath);
5794 #endif
5795   return depth;
5796 }
5797 
5798 
lives_tree_path_get_indices(LiVESTreePath * tpath)5799 WIDGET_HELPER_GLOBAL_INLINE int *lives_tree_path_get_indices(LiVESTreePath *tpath) {
5800   int *indices = NULL;
5801 #ifdef GUI_GTK
5802   indices = gtk_tree_path_get_indices(tpath);
5803 #endif
5804   return indices;
5805 }
5806 
5807 
lives_tree_store_new(int ncols,...)5808 WIDGET_HELPER_GLOBAL_INLINE LiVESTreeStore *lives_tree_store_new(int ncols, ...) {
5809   LiVESTreeStore *tstore = NULL;
5810   va_list argList;
5811   va_start(argList, ncols);
5812 #ifdef GUI_GTK
5813   if (ncols > 0) {
5814     GType types[ncols];
5815     register int i;
5816     for (i = 0; i < ncols; i++) {
5817       types[i] = va_arg(argList, long unsigned int);
5818     }
5819     tstore = gtk_tree_store_newv(ncols, types);
5820   }
5821   // supposedly speeds things up a bit...
5822   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(tstore),
5823                                        GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
5824                                        GTK_SORT_ASCENDING);
5825 #endif
5826   va_end(argList);
5827   return tstore;
5828 }
5829 
5830 
lives_tree_store_append(LiVESTreeStore * tstore,LiVESTreeIter * titer,LiVESTreeIter * parent)5831 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_append(LiVESTreeStore *tstore, LiVESTreeIter *titer,
5832     LiVESTreeIter *parent) {
5833 #ifdef GUI_GTK
5834   gtk_tree_store_append(tstore, titer, parent);
5835   return TRUE;
5836 #endif
5837   return FALSE;
5838 }
5839 
5840 
lives_tree_store_prepend(LiVESTreeStore * tstore,LiVESTreeIter * titer,LiVESTreeIter * parent)5841 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_prepend(LiVESTreeStore *tstore, LiVESTreeIter *titer,
5842     LiVESTreeIter *parent) {
5843 #ifdef GUI_GTK
5844   gtk_tree_store_prepend(tstore, titer, parent);
5845   return TRUE;
5846 #endif
5847   return FALSE;
5848 }
5849 
5850 
lives_tree_store_set(LiVESTreeStore * tstore,LiVESTreeIter * titer,...)5851 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_set(LiVESTreeStore *tstore, LiVESTreeIter *titer, ...) {
5852   boolean res = FALSE;
5853   va_list argList;
5854   va_start(argList, titer);
5855 #ifdef GUI_GTK
5856   gtk_tree_store_set_valist(tstore, titer, argList);
5857   res = TRUE;
5858 #endif
5859   va_end(argList);
5860   return res;
5861 }
5862 
5863 
lives_tree_view_new_with_model(LiVESTreeModel * tmod)5864 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_tree_view_new_with_model(LiVESTreeModel *tmod) {
5865   LiVESWidget *tview = NULL;
5866 #ifdef GUI_GTK
5867   tview = gtk_tree_view_new_with_model(tmod);
5868 #endif
5869   return tview;
5870 }
5871 
5872 
lives_tree_view_new(void)5873 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_tree_view_new(void) {
5874   LiVESWidget *tview = NULL;
5875 #ifdef GUI_GTK
5876   tview = gtk_tree_view_new();
5877 #endif
5878   return tview;
5879 }
5880 
5881 
lives_tree_view_set_model(LiVESTreeView * tview,LiVESTreeModel * tmod)5882 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_view_set_model(LiVESTreeView *tview, LiVESTreeModel *tmod) {
5883 #ifdef GUI_GTK
5884   gtk_tree_view_set_model(tview, tmod);
5885   return TRUE;
5886 #endif
5887   return FALSE;
5888 }
5889 
5890 
lives_tree_view_get_model(LiVESTreeView * tview)5891 WIDGET_HELPER_GLOBAL_INLINE LiVESTreeModel *lives_tree_view_get_model(LiVESTreeView *tview) {
5892   LiVESTreeModel *tmod = NULL;
5893 #ifdef GUI_GTK
5894   tmod = gtk_tree_view_get_model(tview);
5895 #endif
5896   return tmod;
5897 }
5898 
5899 
lives_tree_view_get_selection(LiVESTreeView * tview)5900 WIDGET_HELPER_GLOBAL_INLINE LiVESTreeSelection *lives_tree_view_get_selection(LiVESTreeView *tview) {
5901   LiVESTreeSelection *tsel = NULL;
5902 #ifdef GUI_GTK
5903   tsel = gtk_tree_view_get_selection(tview);
5904 #endif
5905   return tsel;
5906 }
5907 
5908 
lives_tree_view_append_column(LiVESTreeView * tview,LiVESTreeViewColumn * tvcol)5909 WIDGET_HELPER_GLOBAL_INLINE int lives_tree_view_append_column(LiVESTreeView *tview, LiVESTreeViewColumn *tvcol) {
5910 #ifdef GUI_GTK
5911   gtk_tree_view_append_column(tview, tvcol);
5912   return TRUE;
5913 #endif
5914   return FALSE;
5915 }
5916 
5917 
lives_tree_view_set_headers_visible(LiVESTreeView * tview,boolean vis)5918 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_view_set_headers_visible(LiVESTreeView *tview, boolean vis) {
5919 #ifdef GUI_GTK
5920   gtk_tree_view_set_headers_visible(tview, vis);
5921   return TRUE;
5922 #endif
5923   return FALSE;
5924 }
5925 
5926 
lives_tree_view_get_hadjustment(LiVESTreeView * tview)5927 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_tree_view_get_hadjustment(LiVESTreeView *tview) {
5928   LiVESAdjustment *adj = NULL;
5929 #ifdef GUI_GTK
5930 #if GTK_CHECK_VERSION(3, 0, 0)
5931   adj = gtk_scrollable_get_hadjustment(GTK_SCROLLABLE(tview));
5932 #else
5933   adj = gtk_tree_view_get_hadjustment(tview);
5934 #endif
5935 #endif
5936   return adj;
5937 }
5938 
5939 
lives_tree_view_column_new_with_attributes(const char * title,LiVESCellRenderer * crend,...)5940 WIDGET_HELPER_GLOBAL_INLINE LiVESTreeViewColumn *lives_tree_view_column_new_with_attributes(const char *title,
5941     LiVESCellRenderer *crend,
5942     ...) {
5943   LiVESTreeViewColumn *tvcol = NULL;
5944   va_list args;
5945   va_start(args, crend);
5946   int column;
5947   char *attribute;
5948   boolean expand = FALSE;
5949 #ifdef GUI_GTK
5950 
5951   tvcol = gtk_tree_view_column_new();
5952   gtk_tree_view_column_set_title(tvcol, title);
5953   gtk_tree_view_column_pack_start(tvcol, crend, expand);
5954 
5955   attribute = va_arg(args, char *);
5956 
5957   while (attribute) {
5958     column = va_arg(args, int);
5959     gtk_tree_view_column_add_attribute(tvcol, crend, attribute, column);
5960     attribute = va_arg(args, char *);
5961   }
5962 
5963 #endif
5964   va_end(args);
5965   return tvcol;
5966 }
5967 
5968 
lives_tree_view_column_set_sizing(LiVESTreeViewColumn * tvcol,LiVESTreeViewColumnSizing type)5969 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_view_column_set_sizing(LiVESTreeViewColumn *tvcol,
5970     LiVESTreeViewColumnSizing type) {
5971 #ifdef GUI_GTK
5972   gtk_tree_view_column_set_sizing(tvcol, type);
5973   return TRUE;
5974 #endif
5975   return FALSE;
5976 }
5977 
5978 
lives_tree_view_column_set_fixed_width(LiVESTreeViewColumn * tvcol,int fwidth)5979 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_view_column_set_fixed_width(LiVESTreeViewColumn *tvcol, int fwidth) {
5980 #ifdef GUI_GTK
5981   gtk_tree_view_column_set_fixed_width(tvcol, fwidth);
5982   return TRUE;
5983 #endif
5984   return FALSE;
5985 }
5986 
5987 
lives_tree_selection_get_selected(LiVESTreeSelection * tsel,LiVESTreeModel ** tmod,LiVESTreeIter * titer)5988 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_selection_get_selected(LiVESTreeSelection *tsel, LiVESTreeModel **tmod,
5989     LiVESTreeIter *titer) {
5990 #ifdef GUI_GTK
5991   return gtk_tree_selection_get_selected(tsel, tmod, titer);
5992 #endif
5993   return FALSE;
5994 }
5995 
5996 
lives_tree_selection_set_mode(LiVESTreeSelection * tsel,LiVESSelectionMode tselmod)5997 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_selection_set_mode(LiVESTreeSelection *tsel, LiVESSelectionMode tselmod) {
5998 #ifdef GUI_GTK
5999   gtk_tree_selection_set_mode(tsel, tselmod);
6000   return TRUE;
6001 #endif
6002   return FALSE;
6003 }
6004 
6005 
lives_tree_selection_select_iter(LiVESTreeSelection * tsel,LiVESTreeIter * titer)6006 WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_selection_select_iter(LiVESTreeSelection *tsel, LiVESTreeIter *titer) {
6007 #ifdef GUI_GTK
6008   gtk_tree_selection_select_iter(tsel, titer);
6009   return TRUE;
6010 #endif
6011   return FALSE;
6012 }
6013 
6014 
lives_list_store_new(int ncols,...)6015 WIDGET_HELPER_GLOBAL_INLINE LiVESListStore *lives_list_store_new(int ncols, ...) {
6016   LiVESListStore *lstore = NULL;
6017   va_list argList;
6018   va_start(argList, ncols);
6019 #ifdef GUI_GTK
6020   if (ncols > 0) {
6021     GType types[ncols];
6022     register int i;
6023     for (i = 0; i < ncols; i++) {
6024       types[i] = va_arg(argList, long unsigned int);
6025     }
6026     lstore = gtk_list_store_newv(ncols, types);
6027   }
6028 #endif
6029   va_end(argList);
6030   return lstore;
6031 }
6032 
6033 
lives_list_store_set(LiVESListStore * lstore,LiVESTreeIter * titer,...)6034 WIDGET_HELPER_GLOBAL_INLINE boolean lives_list_store_set(LiVESListStore *lstore, LiVESTreeIter *titer, ...) {
6035   boolean res = FALSE;
6036   va_list argList;
6037   va_start(argList, titer);
6038 #ifdef GUI_GTK
6039   gtk_list_store_set_valist(lstore, titer, argList);
6040   res = TRUE;
6041 #endif
6042   va_end(argList);
6043   return res;
6044 }
6045 
6046 
lives_list_store_insert(LiVESListStore * lstore,LiVESTreeIter * titer,int position)6047 WIDGET_HELPER_GLOBAL_INLINE boolean lives_list_store_insert(LiVESListStore *lstore, LiVESTreeIter *titer, int position) {
6048 #ifdef GUI_GTK
6049   gtk_list_store_insert(lstore, titer, position);
6050   return TRUE;
6051 #endif
6052   return FALSE;
6053 }
6054 
6055 
lives_label_get_text(LiVESLabel * label)6056 WIDGET_HELPER_GLOBAL_INLINE const char *lives_label_get_text(LiVESLabel *label) {
6057 #ifdef GUI_GTK
6058   return gtk_label_get_text(label);
6059 #endif
6060   return NULL;
6061 }
6062 
6063 
lives_label_set_text(LiVESLabel * label,const char * text)6064 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_text(LiVESLabel *label, const char *text) {
6065   if (!text) return lives_label_set_text(label, "");
6066   if (widget_opts.use_markup) return lives_label_set_markup(label, text);
6067 #ifdef GUI_GTK
6068   if (widget_opts.mnemonic_label) gtk_label_set_text_with_mnemonic(label, text);
6069   else gtk_label_set_text(label, text);
6070   return TRUE;
6071 #endif
6072   return FALSE;
6073 }
6074 
6075 
lives_label_set_markup(LiVESLabel * label,const char * markup)6076 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_markup(LiVESLabel *label, const char *markup) {
6077 #ifdef GUI_GTK
6078   if (!widget_opts.mnemonic_label) gtk_label_set_markup(label, markup);
6079   else gtk_label_set_markup_with_mnemonic(label, markup);
6080   return TRUE;
6081 #endif
6082   return FALSE;
6083 }
6084 
6085 
lives_label_set_mnemonic_widget(LiVESLabel * label,LiVESWidget * widget)6086 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_mnemonic_widget(LiVESLabel *label, LiVESWidget *widget) {
6087 #ifdef GUI_GTK
6088   gtk_label_set_mnemonic_widget(label, widget);
6089   return TRUE;
6090 #endif
6091   return FALSE;
6092 }
6093 
6094 
lives_label_get_mnemonic_widget(LiVESLabel * label)6095 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_label_get_mnemonic_widget(LiVESLabel *label) {
6096   LiVESWidget *widget = NULL;
6097 #ifdef GUI_GTK
6098   widget = gtk_label_get_mnemonic_widget(label);
6099 #endif
6100   return widget;
6101 }
6102 
6103 
lives_label_set_selectable(LiVESLabel * label,boolean setting)6104 WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_selectable(LiVESLabel *label, boolean setting) {
6105 #ifdef GUI_GTK
6106   gtk_label_set_selectable(label, setting);
6107   return TRUE;
6108 #endif
6109   return FALSE;
6110 }
6111 
6112 
lives_editable_get_editable(LiVESEditable * editable)6113 WIDGET_HELPER_GLOBAL_INLINE boolean lives_editable_get_editable(LiVESEditable *editable) {
6114 #ifdef GUI_GTK
6115   return gtk_editable_get_editable(editable);
6116 #endif
6117   return FALSE;
6118 }
6119 
6120 
lives_editable_set_editable(LiVESEditable * editable,boolean is_editable)6121 WIDGET_HELPER_GLOBAL_INLINE boolean lives_editable_set_editable(LiVESEditable *editable, boolean is_editable) {
6122   lives_widget_set_can_focus(LIVES_WIDGET(editable), is_editable);
6123 #ifdef GUI_GTK
6124   gtk_editable_set_editable(editable, is_editable);
6125   return TRUE;
6126 #endif
6127   return FALSE;
6128 }
6129 
6130 
lives_editable_select_region(LiVESEditable * editable,int start_pos,int end_pos)6131 WIDGET_HELPER_GLOBAL_INLINE boolean lives_editable_select_region(LiVESEditable *editable, int start_pos, int end_pos) {
6132 #ifdef GUI_GTK
6133   gtk_editable_select_region(editable, start_pos, end_pos);
6134   return TRUE;
6135 #endif
6136   return FALSE;
6137 }
6138 
6139 
lives_entry_new(void)6140 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_entry_new(void) {
6141   LiVESWidget *entry = NULL;
6142 #ifdef GUI_GTK
6143   entry = gtk_entry_new();
6144 #endif
6145   return entry;
6146 }
6147 
6148 
lives_entry_set_max_length(LiVESEntry * entry,int len)6149 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_max_length(LiVESEntry *entry, int len) {
6150   // entry length (not display length)
6151 #ifdef GUI_GTK
6152   gtk_entry_set_max_length(entry, len);
6153   return TRUE;
6154 #endif
6155   return FALSE;
6156 }
6157 
6158 
lives_entry_set_activates_default(LiVESEntry * entry,boolean act)6159 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_activates_default(LiVESEntry *entry, boolean act) {
6160 #ifdef GUI_GTK
6161   gtk_entry_set_activates_default(entry, act);
6162   return TRUE;
6163 #endif
6164   return FALSE;
6165 }
6166 
6167 
lives_entry_get_activates_default(LiVESEntry * entry)6168 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_get_activates_default(LiVESEntry *entry) {
6169 #ifdef GUI_GTK
6170   return gtk_entry_get_activates_default(entry);
6171 #endif
6172   return FALSE;
6173 }
6174 
6175 
lives_entry_set_visibility(LiVESEntry * entry,boolean vis)6176 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_visibility(LiVESEntry *entry, boolean vis) {
6177 #ifdef GUI_GTK
6178   gtk_entry_set_visibility(entry, vis);
6179   return TRUE;
6180 #endif
6181   return FALSE;
6182 }
6183 
6184 
lives_entry_set_has_frame(LiVESEntry * entry,boolean has)6185 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_has_frame(LiVESEntry *entry, boolean has) {
6186 #ifdef GUI_GTK
6187   gtk_entry_set_has_frame(entry, has);
6188   return TRUE;
6189 #endif
6190   return FALSE;
6191 }
6192 
6193 
lives_entry_set_alignment(LiVESEntry * entry,float align)6194 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_alignment(LiVESEntry *entry, float align) {
6195 #ifdef GUI_GTK
6196   gtk_entry_set_alignment(entry, align);
6197   return TRUE;
6198 #endif
6199   return FALSE;
6200 }
6201 
6202 
lives_entry_get_text(LiVESEntry * entry)6203 WIDGET_HELPER_GLOBAL_INLINE const char *lives_entry_get_text(LiVESEntry *entry) {
6204 #ifdef GUI_GTK
6205   return gtk_entry_get_text(entry);
6206 #endif
6207   return NULL;
6208 }
6209 
6210 
lives_entry_set_text(LiVESEntry * entry,const char * text)6211 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_text(LiVESEntry *entry, const char *text) {
6212 #ifdef GUI_GTK
6213   if (widget_opts.justify == LIVES_JUSTIFY_START) lives_entry_set_alignment(entry, 0.);
6214   else if (widget_opts.justify == LIVES_JUSTIFY_CENTER) lives_entry_set_alignment(entry, 0.5);
6215   if (widget_opts.justify == LIVES_JUSTIFY_END) lives_entry_set_alignment(entry, 1.);
6216   gtk_entry_set_text(entry, text);
6217   return TRUE;
6218 #endif
6219   return FALSE;
6220 }
6221 
6222 
lives_entry_set_width_chars(LiVESEntry * entry,int nchars)6223 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_width_chars(LiVESEntry *entry, int nchars) {
6224   // display length
6225 #ifdef GUI_GTK
6226 #if GTK_CHECK_VERSION(3, 12, 0)
6227   gtk_entry_set_max_width_chars(entry, nchars);
6228 #endif
6229   gtk_entry_set_width_chars(entry, nchars);
6230   return TRUE;
6231 #endif
6232   return FALSE;
6233 }
6234 
6235 
lives_scrolled_window_new(LiVESAdjustment * hadj,LiVESAdjustment * vadj)6236 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_scrolled_window_new(LiVESAdjustment *hadj, LiVESAdjustment *vadj) {
6237   LiVESWidget *swindow = NULL;
6238 #ifdef GUI_GTK
6239   swindow = gtk_scrolled_window_new(hadj, vadj);
6240 #endif
6241   return swindow;
6242 }
6243 
6244 
lives_scrolled_window_get_hadjustment(LiVESScrolledWindow * swindow)6245 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_scrolled_window_get_hadjustment(LiVESScrolledWindow *swindow) {
6246   LiVESAdjustment *adj = NULL;
6247 #ifdef GUI_GTK
6248   adj = gtk_scrolled_window_get_hadjustment(swindow);
6249 #endif
6250   return adj;
6251 }
6252 
6253 
lives_scrolled_window_get_vadjustment(LiVESScrolledWindow * swindow)6254 WIDGET_HELPER_GLOBAL_INLINE LiVESAdjustment *lives_scrolled_window_get_vadjustment(LiVESScrolledWindow *swindow) {
6255   LiVESAdjustment *adj = NULL;
6256 #ifdef GUI_GTK
6257   adj = gtk_scrolled_window_get_vadjustment(swindow);
6258 #endif
6259   return adj;
6260 }
6261 
6262 
lives_scrolled_window_set_policy(LiVESScrolledWindow * scrolledwindow,LiVESPolicyType hpolicy,LiVESPolicyType vpolicy)6263 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_policy(LiVESScrolledWindow *scrolledwindow,
6264     LiVESPolicyType hpolicy,
6265     LiVESPolicyType vpolicy) {
6266 #ifdef GUI_GTK
6267   gtk_scrolled_window_set_policy(scrolledwindow, hpolicy, vpolicy);
6268   return TRUE;
6269 #endif
6270   return FALSE;
6271 }
6272 
6273 
lives_scrolled_window_add_with_viewport(LiVESScrolledWindow * scrolledwindow,LiVESWidget * child)6274 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_add_with_viewport(LiVESScrolledWindow *scrolledwindow,
6275     LiVESWidget *child) {
6276 #ifdef GUI_GTK
6277 #if !GTK_CHECK_VERSION(3, 8, 0)
6278   gtk_scrolled_window_add_with_viewport(scrolledwindow, child);
6279 #else
6280   lives_container_add(LIVES_CONTAINER(scrolledwindow), child);
6281 #endif
6282   return TRUE;
6283 #endif
6284   return FALSE;
6285 }
6286 
6287 
lives_scrolled_window_set_min_content_height(LiVESScrolledWindow * scrolledwindow,int height)6288 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_min_content_height(LiVESScrolledWindow *scrolledwindow,
6289     int height) {
6290 #ifdef GUI_GTK
6291 #if GTK_CHECK_VERSION(3, 0, 0)
6292   gtk_scrolled_window_set_min_content_height(scrolledwindow, height);
6293   return TRUE;
6294 #endif
6295 #endif
6296   return FALSE;
6297 }
6298 
6299 
lives_scrolled_window_set_min_content_width(LiVESScrolledWindow * scrolledwindow,int width)6300 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_min_content_width(LiVESScrolledWindow *scrolledwindow,
6301     int width) {
6302 #ifdef GUI_GTK
6303 #if GTK_CHECK_VERSION(3, 0, 0)
6304   gtk_scrolled_window_set_min_content_width(scrolledwindow, width);
6305   return TRUE;
6306 #endif
6307 #endif
6308   return FALSE;
6309 }
6310 
6311 
lives_xwindow_raise(LiVESXWindow * xwin)6312 WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_raise(LiVESXWindow *xwin) {
6313 #ifdef GUI_GTK
6314   gdk_window_raise(xwin);
6315   return TRUE;
6316 #endif
6317   return FALSE;
6318 }
6319 
6320 
lives_xwindow_set_cursor(LiVESXWindow * xwin,LiVESXCursor * cursor)6321 WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_set_cursor(LiVESXWindow *xwin, LiVESXCursor *cursor) {
6322 #ifdef GUI_GTK
6323   if (GDK_IS_WINDOW(xwin)) {
6324     if (!cursor || gdk_window_get_display(xwin) == gdk_cursor_get_display(cursor)) {
6325       gdk_window_set_cursor(xwin, cursor);
6326       return TRUE;
6327     }
6328   }
6329 #endif
6330   return FALSE;
6331 }
6332 
6333 
lives_dialog_set_has_separator(LiVESDialog * dialog,boolean has)6334 WIDGET_HELPER_GLOBAL_INLINE boolean lives_dialog_set_has_separator(LiVESDialog *dialog, boolean has) {
6335   // return TRUE if implemented
6336 
6337 #ifdef GUI_GTK
6338 #if !GTK_CHECK_VERSION(3, 0, 0)
6339   gtk_dialog_set_has_separator(dialog, has);
6340   return TRUE;
6341 #endif
6342 #endif
6343   return FALSE;
6344 }
6345 
6346 
lives_widget_set_hexpand(LiVESWidget * widget,boolean state)6347 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_hexpand(LiVESWidget *widget, boolean state) {
6348   // return TRUE if implemented
6349 #ifdef GUI_GTK
6350 #if GTK_CHECK_VERSION(3, 0, 0)
6351   gtk_widget_set_hexpand(widget, state);
6352   return TRUE;
6353 #endif
6354 #endif
6355   return FALSE;
6356 }
6357 
6358 
lives_widget_set_vexpand(LiVESWidget * widget,boolean state)6359 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_vexpand(LiVESWidget *widget, boolean state) {
6360   // return TRUE if implemented
6361 #ifdef GUI_GTK
6362 #if GTK_CHECK_VERSION(3, 0, 0)
6363   gtk_widget_set_vexpand(widget, state);
6364   return TRUE;
6365 #endif
6366 #endif
6367   return FALSE;
6368 }
6369 
6370 
lives_menu_new(void)6371 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_menu_new(void) {
6372   LiVESWidget *menu = NULL;
6373 #ifdef GUI_GTK
6374   menu = gtk_menu_new();
6375 #endif
6376   return menu;
6377 }
6378 
6379 
lives_menu_bar_new(void)6380 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_menu_bar_new(void) {
6381   LiVESWidget *menubar = NULL;
6382 #ifdef GUI_GTK
6383   menubar = gtk_menu_bar_new();
6384 #endif
6385   return menubar;
6386 }
6387 
6388 
lives_menu_item_new(void)6389 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_menu_item_new(void) {
6390   LiVESWidget *menuitem = NULL;
6391 #ifdef GUI_GTK
6392   menuitem = gtk_menu_item_new();
6393 #endif
6394   return menuitem;
6395 }
6396 
6397 
lives_menu_item_new_with_label(const char * label)6398 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_menu_item_new_with_label(const char *label) {
6399   LiVESWidget *menuitem = NULL;
6400 #ifdef GUI_GTK
6401   if (!widget_opts.mnemonic_label) menuitem = gtk_menu_item_new_with_label(label);
6402   else menuitem = gtk_menu_item_new_with_mnemonic(label);
6403 #endif
6404   return menuitem;
6405 }
6406 
6407 
lives_menu_item_set_accel_path(LiVESMenuItem * menuitem,const char * path)6408 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_item_set_accel_path(LiVESMenuItem *menuitem, const char *path) {
6409 #ifdef GUI_GTK
6410   gtk_menu_item_set_accel_path(menuitem, path);
6411   return TRUE;
6412 #endif
6413   return FALSE;
6414 }
6415 
6416 
lives_menu_item_get_submenu(LiVESMenuItem * menuitem)6417 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_menu_item_get_submenu(LiVESMenuItem *menuitem) {
6418 #ifdef GUI_GTK
6419   return gtk_menu_item_get_submenu(menuitem);
6420 #endif
6421   return NULL;
6422 }
6423 
6424 
lives_image_menu_item_new_with_label(const char * label)6425 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_image_menu_item_new_with_label(const char *label) {
6426   LiVESWidget *menuitem = NULL;
6427 #ifdef GUI_GTK
6428 #if GTK_CHECK_VERSION(3, 10, 0)
6429   if (!widget_opts.mnemonic_label) menuitem = gtk_menu_item_new_with_label(label);
6430   else menuitem = gtk_menu_item_new_with_mnemonic(label);
6431 #else
6432   if (!widget_opts.mnemonic_label) menuitem = gtk_image_menu_item_new_with_label(label);
6433   else menuitem = gtk_image_menu_item_new_with_mnemonic(label);
6434 #endif
6435 #endif
6436   return menuitem;
6437 }
6438 
6439 
lives_radio_menu_item_new_with_label(LiVESSList * group,const char * label)6440 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_radio_menu_item_new_with_label(LiVESSList *group, const char *label) {
6441   LiVESWidget *menuitem = NULL;
6442 #ifdef GUI_GTK
6443   if (!widget_opts.mnemonic_label) menuitem = gtk_radio_menu_item_new_with_label(group, label);
6444   else menuitem = gtk_radio_menu_item_new_with_mnemonic(group, label);
6445 #endif
6446   return menuitem;
6447 }
6448 
6449 
lives_radio_menu_item_get_group(LiVESRadioMenuItem * rmenuitem)6450 WIDGET_HELPER_GLOBAL_INLINE LiVESSList *lives_radio_menu_item_get_group(LiVESRadioMenuItem *rmenuitem) {
6451 #ifdef GUI_GTK
6452   return gtk_radio_menu_item_get_group(rmenuitem);
6453 #endif
6454   return NULL;
6455 }
6456 
6457 
lives_check_menu_item_new_with_label(const char * label)6458 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_check_menu_item_new_with_label(const char *label) {
6459   LiVESWidget *menuitem = NULL;
6460 #ifdef GUI_GTK
6461   if (!widget_opts.mnemonic_label) menuitem = gtk_check_menu_item_new_with_label(label);
6462   else menuitem = gtk_check_menu_item_new_with_mnemonic(label);   // TODO - deprecated
6463 #endif
6464   return menuitem;
6465 }
6466 
6467 
lives_check_menu_item_set_draw_as_radio(LiVESCheckMenuItem * item,boolean setting)6468 WIDGET_HELPER_GLOBAL_INLINE boolean lives_check_menu_item_set_draw_as_radio(LiVESCheckMenuItem *item, boolean setting) {
6469 #ifdef GUI_GTK
6470   gtk_check_menu_item_set_draw_as_radio(item, setting);
6471   return TRUE;
6472 #endif
6473   return FALSE;
6474 }
6475 
6476 
lives_image_menu_item_new_from_stock(const char * stock_id,LiVESAccelGroup * accel_group)6477 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_image_menu_item_new_from_stock(const char *stock_id,
6478     LiVESAccelGroup *accel_group) {
6479   LiVESWidget *menuitem = NULL;
6480 #ifdef GUI_GTK
6481 #if GTK_CHECK_VERSION(3, 10, 0)
6482   char *xstock_id = lives_strdup(stock_id); // need to back this up as we will use translation functions
6483   menuitem = gtk_menu_item_new_with_mnemonic(xstock_id);
6484 
6485   if (!strcmp(xstock_id, LIVES_STOCK_LABEL_SAVE)) {
6486     lives_menu_item_set_accel_path(LIVES_MENU_ITEM(menuitem), LIVES_ACCEL_PATH_SAVE);
6487   }
6488 
6489   if (!strcmp(xstock_id, LIVES_STOCK_LABEL_QUIT)) {
6490     lives_menu_item_set_accel_path(LIVES_MENU_ITEM(menuitem), LIVES_ACCEL_PATH_QUIT);
6491   }
6492   lives_free(xstock_id);
6493 #else
6494   menuitem = gtk_image_menu_item_new_from_stock(stock_id, accel_group);
6495 #endif
6496 #endif
6497   return menuitem;
6498 }
6499 
6500 
lives_menu_tool_button_new(LiVESWidget * icon,const char * label)6501 WIDGET_HELPER_GLOBAL_INLINE LiVESToolItem *lives_menu_tool_button_new(LiVESWidget *icon, const char *label) {
6502   LiVESToolItem *toolitem = NULL;
6503 #ifdef GUI_GTK
6504   toolitem = gtk_menu_tool_button_new(icon, label);
6505 #endif
6506   return toolitem;
6507 }
6508 
6509 
lives_menu_tool_button_set_menu(LiVESMenuToolButton * toolbutton,LiVESWidget * menu)6510 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_tool_button_set_menu(LiVESMenuToolButton *toolbutton, LiVESWidget *menu) {
6511 #ifdef GUI_GTK
6512   gtk_menu_tool_button_set_menu(toolbutton, menu);
6513   return TRUE;
6514 #endif
6515   return FALSE;
6516 }
6517 
6518 
lives_menu_item_set_submenu(LiVESMenuItem * menuitem,LiVESWidget * menu)6519 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_item_set_submenu(LiVESMenuItem *menuitem, LiVESWidget *menu) {
6520 #ifdef GUI_GTK
6521   gtk_menu_item_set_submenu(menuitem, menu);
6522   return TRUE;
6523 #endif
6524   return FALSE;
6525 }
6526 
6527 
lives_menu_item_activate(LiVESMenuItem * menuitem)6528 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_item_activate(LiVESMenuItem *menuitem) {
6529 #ifdef GUI_GTK
6530   gtk_menu_item_activate(menuitem);
6531   return TRUE;
6532 #endif
6533   return FALSE;
6534 }
6535 
6536 
lives_check_menu_item_set_active(LiVESCheckMenuItem * item,boolean state)6537 WIDGET_HELPER_GLOBAL_INLINE boolean lives_check_menu_item_set_active(LiVESCheckMenuItem *item, boolean state) {
6538 #ifdef GUI_GTK
6539   gtk_check_menu_item_set_active(item, state);
6540   return TRUE;
6541 #endif
6542   return FALSE;
6543 }
6544 
6545 
lives_check_menu_item_get_active(LiVESCheckMenuItem * item)6546 WIDGET_HELPER_GLOBAL_INLINE boolean lives_check_menu_item_get_active(LiVESCheckMenuItem *item) {
6547 #ifdef GUI_GTK
6548   return gtk_check_menu_item_get_active(item);
6549 #endif
6550   return FALSE;
6551 }
6552 
6553 
6554 #if !GTK_CHECK_VERSION(3, 10, 0)
6555 
lives_image_menu_item_set_image(LiVESImageMenuItem * item,LiVESWidget * image)6556 WIDGET_HELPER_GLOBAL_INLINE boolean lives_image_menu_item_set_image(LiVESImageMenuItem *item, LiVESWidget *image) {
6557 #ifdef GUI_GTK
6558   gtk_image_menu_item_set_image(item, image);
6559   return TRUE;
6560 #endif
6561   return FALSE;
6562 }
6563 
6564 #endif
6565 
lives_menu_set_title(LiVESMenu * menu,const char * title)6566 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_set_title(LiVESMenu *menu, const char *title) {
6567 #ifdef GUI_GTK
6568 #if !GTK_CHECK_VERSION(3, 10, 0)
6569   char *ntitle = lives_strdup_printf("%s%s", widget_opts.title_prefix, title);
6570   gtk_menu_set_title(menu, ntitle);
6571   lives_free(ntitle);
6572   return TRUE;
6573 #endif
6574 #endif
6575   return FALSE;
6576 }
6577 
6578 
lives_menu_popup(LiVESMenu * menu,LiVESXEventButton * event)6579 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_popup(LiVESMenu *menu, LiVESXEventButton *event) {
6580 #ifdef GUI_GTK
6581 #if GTK_CHECK_VERSION(3, 22, 0)
6582   gtk_menu_popup_at_pointer(menu, NULL);
6583 #else
6584   gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time);
6585 #endif
6586   return TRUE;
6587 #endif
6588   return FALSE;
6589 }
6590 
6591 
lives_menu_reorder_child(LiVESMenu * menu,LiVESWidget * child,int pos)6592 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_reorder_child(LiVESMenu *menu, LiVESWidget *child, int pos) {
6593 #ifdef GUI_GTK
6594   gtk_menu_reorder_child(menu, child, pos);
6595   return TRUE;
6596 #endif
6597   return FALSE;
6598 }
6599 
6600 
lives_menu_detach(LiVESMenu * menu)6601 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_detach(LiVESMenu *menu) {
6602   // NB also calls detacher callback
6603 #ifdef GUI_GTK
6604   gtk_menu_detach(menu);
6605   return TRUE;
6606 #endif
6607   return FALSE;
6608 }
6609 
6610 
lives_menu_shell_append(LiVESMenuShell * menushell,LiVESWidget * child)6611 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_shell_append(LiVESMenuShell *menushell, LiVESWidget *child) {
6612 #ifdef GUI_GTK
6613   gtk_menu_shell_append(menushell, child);
6614   return TRUE;
6615 #endif
6616   return FALSE;
6617 }
6618 
6619 
lives_menu_shell_insert(LiVESMenuShell * menushell,LiVESWidget * child,int pos)6620 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_shell_insert(LiVESMenuShell *menushell, LiVESWidget *child, int pos) {
6621 #ifdef GUI_GTK
6622   gtk_menu_shell_insert(menushell, child, pos);
6623   return TRUE;
6624 #endif
6625   return FALSE;
6626 }
6627 
6628 
lives_menu_shell_prepend(LiVESMenuShell * menushell,LiVESWidget * child)6629 WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_shell_prepend(LiVESMenuShell *menushell, LiVESWidget *child) {
6630 #ifdef GUI_GTK
6631   gtk_menu_shell_prepend(menushell, child);
6632   return TRUE;
6633 #endif
6634   return FALSE;
6635 }
6636 
6637 
lives_image_menu_item_set_always_show_image(LiVESImageMenuItem * item,boolean show)6638 WIDGET_HELPER_GLOBAL_INLINE boolean lives_image_menu_item_set_always_show_image(LiVESImageMenuItem *item, boolean show) {
6639   // return TRUE if implemented
6640 #ifdef GUI_GTK
6641 #if GTK_CHECK_VERSION(2, 16, 0)
6642 #if !GTK_CHECK_VERSION(3, 10, 0)
6643   gtk_image_menu_item_set_always_show_image(item, show);
6644 #endif
6645   return TRUE;
6646 #endif
6647 #endif
6648   return FALSE;
6649 }
6650 
6651 
lives_scale_set_draw_value(LiVESScale * scale,boolean draw_value)6652 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scale_set_draw_value(LiVESScale *scale, boolean draw_value) {
6653 #ifdef GUI_GTK
6654   return TRUE;
6655 #endif
6656   return FALSE;
6657 }
6658 
6659 
lives_scale_set_value_pos(LiVESScale * scale,LiVESPositionType ptype)6660 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scale_set_value_pos(LiVESScale *scale, LiVESPositionType ptype) {
6661 #ifdef GUI_GTK
6662   gtk_scale_set_value_pos(scale, ptype);
6663   return TRUE;
6664 #endif
6665   return FALSE;
6666 }
6667 
6668 
lives_scale_set_digits(LiVESScale * scale,int digits)6669 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scale_set_digits(LiVESScale *scale, int digits) {
6670 #ifdef GUI_GTK
6671   gtk_scale_set_digits(scale, digits);
6672   return TRUE;
6673 #endif
6674   return FALSE;
6675 }
6676 
6677 
lives_scale_button_set_orientation(LiVESScaleButton * scale,LiVESOrientation orientation)6678 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scale_button_set_orientation(LiVESScaleButton *scale, LiVESOrientation orientation) {
6679   // return TRUE if implemented
6680 #ifdef GUI_GTK
6681 #if GTK_CHECK_VERSION(3, 0, 0)
6682   gtk_orientable_set_orientation(GTK_ORIENTABLE(scale), orientation);
6683   return TRUE;
6684 #else
6685 #if GTK_CHECK_VERSION(2, 14, 0)
6686   gtk_scale_button_set_orientation(scale, orientation);
6687   return TRUE;
6688 #endif
6689 #endif
6690 #endif
6691   return FALSE;
6692 }
6693 
6694 
lives_scale_button_get_value(LiVESScaleButton * scale)6695 WIDGET_HELPER_GLOBAL_INLINE double lives_scale_button_get_value(LiVESScaleButton *scale) {
6696   double value = 0.;
6697 #ifdef GUI_GTK
6698 #if GTK_CHECK_VERSION(2, 14, 0)
6699   value = gtk_scale_button_get_value(scale);
6700 #else
6701   value = gtk_adjustment_get_value(gtk_range_get_adjustment(scale));
6702 #endif
6703 #endif
6704   return value;
6705 }
6706 
6707 
lives_scale_button_set_value(LiVESScaleButton * scale,double value)6708 WIDGET_HELPER_GLOBAL_INLINE boolean lives_scale_button_set_value(LiVESScaleButton *scale, double value) {
6709 #ifdef GUI_GTK
6710 #if GTK_CHECK_VERSION(2, 14, 0)
6711   gtk_scale_button_set_value(scale, value);
6712 #else
6713   gtk_adjustment_set_value(gtk_range_get_adjustment(scale), value);
6714 #endif
6715   return TRUE;
6716 #endif
6717   return FALSE;
6718 }
6719 
6720 
lives_file_chooser_get_filename(LiVESFileChooser * chooser)6721 WIDGET_HELPER_GLOBAL_INLINE char *lives_file_chooser_get_filename(LiVESFileChooser *chooser) {
6722   char *fname = NULL;
6723 #ifdef GUI_GTK
6724   fname = gtk_file_chooser_get_filename(chooser);
6725 #endif
6726   return fname;
6727 }
6728 
6729 
lives_file_chooser_get_filenames(LiVESFileChooser * chooser)6730 WIDGET_HELPER_GLOBAL_INLINE LiVESSList *lives_file_chooser_get_filenames(LiVESFileChooser *chooser) {
6731   LiVESSList *fnlist = NULL;
6732 #ifdef GUI_GTK
6733   fnlist = gtk_file_chooser_get_filenames(chooser);
6734 #endif
6735   return fnlist;
6736 }
6737 
6738 
6739 #if GTK_CHECK_VERSION(3,2,0)
lives_font_chooser_get_font(LiVESFontChooser * fc)6740 WIDGET_HELPER_GLOBAL_INLINE char *lives_font_chooser_get_font(LiVESFontChooser *fc) {
6741   return gtk_font_chooser_get_font(fc);
6742 }
6743 
lives_font_chooser_set_font(LiVESFontChooser * fc,const char * fontname)6744 WIDGET_HELPER_GLOBAL_INLINE boolean lives_font_chooser_set_font(LiVESFontChooser *fc,
6745     const char *fontname) {
6746   gtk_font_chooser_set_font(fc, fontname);
6747   return TRUE;
6748 }
6749 
lives_font_chooser_get_font_desc(LiVESFontChooser * fc)6750 WIDGET_HELPER_GLOBAL_INLINE LingoFontDescription *lives_font_chooser_get_font_desc(LiVESFontChooser *fc) {
6751   return gtk_font_chooser_get_font_desc(fc);
6752 }
6753 
lives_font_chooser_set_font_desc(LiVESFontChooser * fc,LingoFontDescription * lfd)6754 WIDGET_HELPER_GLOBAL_INLINE boolean lives_font_chooser_set_font_desc(LiVESFontChooser *fc,
6755     LingoFontDescription *lfd) {
6756   gtk_font_chooser_set_font_desc(fc, lfd);
6757   return TRUE;
6758 }
6759 #endif
6760 
6761 
6762 #ifdef GUI_GTK
lives_grid_new(void)6763 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_grid_new(void) {
6764   LiVESWidget *grid = NULL;
6765 #ifdef GUI_GTK
6766 #if GTK_CHECK_VERSION(3,2,0)  // required for grid widget
6767   grid = gtk_grid_new();
6768 #endif
6769 #endif
6770   return grid;
6771 }
6772 
6773 
lives_grid_set_row_spacing(LiVESGrid * grid,uint32_t spacing)6774 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grid_set_row_spacing(LiVESGrid *grid, uint32_t spacing) {
6775 #ifdef GUI_GTK
6776 #if GTK_CHECK_VERSION(3,2,0)  // required for grid widget
6777   gtk_grid_set_row_spacing(grid, spacing);
6778   return TRUE;
6779 #endif
6780 #endif
6781   return FALSE;
6782 }
6783 
6784 
lives_grid_set_column_spacing(LiVESGrid * grid,uint32_t spacing)6785 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grid_set_column_spacing(LiVESGrid *grid, uint32_t spacing) {
6786 #ifdef GUI_GTK
6787 #if GTK_CHECK_VERSION(3,2,0)  // required for grid widget
6788   gtk_grid_set_column_spacing(grid, spacing);
6789   return TRUE;
6790 #endif
6791 #endif
6792   return FALSE;
6793 }
6794 
6795 
lives_grid_remove_row(LiVESGrid * grid,int posn)6796 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grid_remove_row(LiVESGrid *grid, int posn) {
6797 #ifdef GUI_GTK
6798 #if GTK_CHECK_VERSION(3, 10, 0)
6799   gtk_grid_remove_row(grid, posn);
6800   return TRUE;
6801 #endif
6802 #endif
6803   return FALSE;
6804 }
6805 
6806 
lives_grid_insert_row(LiVESGrid * grid,int posn)6807 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grid_insert_row(LiVESGrid *grid, int posn) {
6808 #ifdef GUI_GTK
6809 #if GTK_CHECK_VERSION(3, 10, 0)
6810   gtk_grid_insert_row(grid, posn);
6811   return TRUE;
6812 #endif
6813 
6814   return FALSE;
6815 }
6816 
6817 
lives_grid_attach_next_to(LiVESGrid * grid,LiVESWidget * child,LiVESWidget * sibling,LiVESPositionType side,int width,int height)6818 WIDGET_HELPER_GLOBAL_INLINE boolean lives_grid_attach_next_to(LiVESGrid *grid, LiVESWidget *child, LiVESWidget *sibling,
6819     LiVESPositionType side, int width, int height) {
6820 #ifdef GUI_GTK
6821 #if GTK_CHECK_VERSION(3,2,0)  // required for grid widget
6822   gtk_grid_attach_next_to(grid, child, sibling, side, width, height);
6823   return TRUE;
6824 #endif
6825 #endif
6826   return FALSE;
6827 }
6828 #endif
6829 #endif
6830 
lives_frame_new(const char * label)6831 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_frame_new(const char *label) {
6832   LiVESWidget *frame = NULL;
6833 #ifdef GUI_GTK
6834   frame = gtk_frame_new(label);
6835 #endif
6836   return frame;
6837 }
6838 
6839 
lives_frame_set_label(LiVESFrame * frame,const char * label)6840 WIDGET_HELPER_GLOBAL_INLINE boolean lives_frame_set_label(LiVESFrame *frame, const char *label) {
6841 #ifdef GUI_GTK
6842   gtk_frame_set_label(frame, label);
6843   return TRUE;
6844 #endif
6845   return FALSE;
6846 }
6847 
6848 
lives_frame_set_label_align(LiVESFrame * frame,float xalign,float yalign)6849 WIDGET_HELPER_GLOBAL_INLINE boolean lives_frame_set_label_align(LiVESFrame *frame, float xalign, float yalign) {
6850 #ifdef GUI_GTK
6851   gtk_frame_set_label_align(frame, xalign, yalign);
6852   return TRUE;
6853 #endif
6854   return FALSE;
6855 }
6856 
6857 
lives_frame_set_label_widget(LiVESFrame * frame,LiVESWidget * widget)6858 WIDGET_HELPER_GLOBAL_INLINE boolean lives_frame_set_label_widget(LiVESFrame *frame, LiVESWidget *widget) {
6859 #ifdef GUI_GTK
6860   gtk_frame_set_label_widget(frame, widget);
6861   return TRUE;
6862 #endif
6863   return FALSE;
6864 }
6865 
6866 
lives_frame_get_label_widget(LiVESFrame * frame)6867 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_frame_get_label_widget(LiVESFrame *frame) {
6868   LiVESWidget *widget = NULL;
6869 #ifdef GUI_GTK
6870   widget = gtk_frame_get_label_widget(frame);
6871 #endif
6872   return widget;
6873 }
6874 
6875 
lives_frame_set_shadow_type(LiVESFrame * frame,LiVESShadowType stype)6876 WIDGET_HELPER_GLOBAL_INLINE boolean lives_frame_set_shadow_type(LiVESFrame *frame, LiVESShadowType stype) {
6877 #ifdef GUI_GTK
6878   gtk_frame_set_shadow_type(frame, stype);
6879   return TRUE;
6880 #endif
6881   return FALSE;
6882 }
6883 
6884 
lives_notebook_new(void)6885 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_notebook_new(void) {
6886   LiVESWidget *nbook = NULL;
6887 #ifdef GUI_GTK
6888   nbook = gtk_notebook_new();
6889 #endif
6890   return nbook;
6891 }
6892 
6893 
lives_notebook_get_nth_page(LiVESNotebook * nbook,int pagenum)6894 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_notebook_get_nth_page(LiVESNotebook *nbook, int pagenum) {
6895   LiVESWidget *page = NULL;
6896 #ifdef GUI_GTK
6897   page = gtk_notebook_get_nth_page(nbook, pagenum);
6898 #endif
6899   return page;
6900 }
6901 
6902 
lives_notebook_get_current_page(LiVESNotebook * nbook)6903 WIDGET_HELPER_GLOBAL_INLINE int lives_notebook_get_current_page(LiVESNotebook *nbook) {
6904   int pagenum = -1;
6905 #ifdef GUI_GTK
6906   pagenum = gtk_notebook_get_current_page(nbook);
6907 #endif
6908   return pagenum;
6909 }
6910 
6911 
lives_notebook_set_current_page(LiVESNotebook * nbook,int pagenum)6912 WIDGET_HELPER_GLOBAL_INLINE boolean lives_notebook_set_current_page(LiVESNotebook *nbook, int pagenum) {
6913 #ifdef GUI_GTK
6914   gtk_notebook_set_current_page(nbook, pagenum);
6915   return TRUE;
6916 #endif
6917   return FALSE;
6918 }
6919 
6920 
lives_notebook_set_tab_label(LiVESNotebook * nbook,LiVESWidget * child,LiVESWidget * tablabel)6921 WIDGET_HELPER_GLOBAL_INLINE boolean lives_notebook_set_tab_label(LiVESNotebook *nbook, LiVESWidget *child,
6922     LiVESWidget *tablabel) {
6923 #ifdef GUI_GTK
6924   gtk_notebook_set_tab_label(nbook, child, tablabel);
6925   return TRUE;
6926 #endif
6927   return FALSE;
6928 }
6929 
6930 
lives_table_new(uint32_t rows,uint32_t cols,boolean homogeneous)6931 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_table_new(uint32_t rows, uint32_t cols, boolean homogeneous) {
6932   LiVESWidget *table = NULL;
6933 #ifdef GUI_GTK
6934 #if LIVES_TABLE_IS_GRID  // required for grid remove row
6935   register int i;
6936   GtkGrid *grid = (GtkGrid *)lives_grid_new();
6937   gtk_grid_set_row_homogeneous(grid, homogeneous);
6938   gtk_grid_set_column_homogeneous(grid, homogeneous);
6939 
6940   for (i = 0; i < rows; i++) {
6941     lives_grid_insert_row(grid, 0);
6942   }
6943 
6944   for (i = 0; i < cols; i++) {
6945     gtk_grid_insert_column(grid, 0);
6946   }
6947 
6948   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(grid), ROWS_KEY, LIVES_INT_TO_POINTER(rows));
6949   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(grid), COLS_KEY, LIVES_INT_TO_POINTER(cols));
6950   table = (LiVESWidget *)grid;
6951 #else
6952   table = gtk_table_new(rows, cols, homogeneous);
6953 #endif
6954 #endif
6955   return table;
6956 }
6957 
6958 
lives_table_set_row_spacings(LiVESTable * table,uint32_t spacing)6959 WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_set_row_spacings(LiVESTable *table, uint32_t spacing) {
6960 #ifdef GUI_GTK
6961 #if LIVES_TABLE_IS_GRID  // required for grid remove row
6962   lives_grid_set_row_spacing(table, spacing);
6963 #else
6964   gtk_table_set_row_spacings(table, spacing);
6965   return TRUE;
6966 #endif
6967 #endif
6968   return FALSE;
6969 }
6970 
6971 
lives_table_set_col_spacings(LiVESTable * table,uint32_t spacing)6972 WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_set_col_spacings(LiVESTable *table, uint32_t spacing) {
6973 #ifdef GUI_GTK
6974 #if LIVES_TABLE_IS_GRID  // required for grid remove row
6975   lives_grid_set_column_spacing(table, spacing);
6976 #else
6977   gtk_table_set_col_spacings(table, spacing);
6978   return TRUE;
6979 #endif
6980 #endif
6981   return FALSE;
6982 }
6983 
6984 
lives_table_set_row_homogeneous(LiVESTable * table,boolean homogeneous)6985 WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_set_row_homogeneous(LiVESTable *table, boolean homogeneous) {
6986 #ifdef GUI_GTK
6987 #if LIVES_TABLE_IS_GRID
6988   gtk_grid_set_row_homogeneous(table, homogeneous);
6989   return TRUE;
6990 #else
6991   gtk_table_set_homogeneous(table, homogeneous);
6992 #endif
6993 #endif
6994   return FALSE;
6995 }
6996 
6997 
lives_table_set_column_homogeneous(LiVESTable * table,boolean homogeneous)6998 WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_set_column_homogeneous(LiVESTable *table, boolean homogeneous) {
6999 #ifdef GUI_GTK
7000 #if LIVES_TABLE_IS_GRID
7001   gtk_grid_set_column_homogeneous(table, homogeneous);
7002   return TRUE;
7003 #else
7004   gtk_table_set_homogeneous(table, homogeneous);
7005 #endif
7006 #endif
7007   return FALSE;
7008 }
7009 
7010 
lives_table_resize(LiVESTable * table,uint32_t rows,uint32_t cols)7011 WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_resize(LiVESTable *table, uint32_t rows, uint32_t cols) {
7012 #ifdef GUI_GTK
7013 #if LIVES_TABLE_IS_GRID  // required for grid remove row
7014   register int i;
7015 
7016   for (i = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(table), ROWS_KEY)); i < rows; i++) {
7017     lives_grid_insert_row(table, i);
7018   }
7019 
7020   for (i = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(table), COLS_KEY)); i < cols; i++) {
7021     gtk_grid_insert_column(table, i);
7022   }
7023 
7024   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(table), ROWS_KEY, LIVES_INT_TO_POINTER(rows));
7025   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(table), COLS_KEY, LIVES_INT_TO_POINTER(cols));
7026 #else
7027   gtk_table_resize(table, rows, cols);
7028 #endif
7029   return TRUE;
7030 #endif
7031   return FALSE;
7032 }
7033 
7034 
lives_table_attach(LiVESTable * table,LiVESWidget * child,uint32_t left,uint32_t right,uint32_t top,uint32_t bottom,LiVESAttachOptions xoptions,LiVESAttachOptions yoptions,uint32_t xpad,uint32_t ypad)7035 WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_attach(LiVESTable *table, LiVESWidget *child, uint32_t left, uint32_t right,
7036     uint32_t top, uint32_t bottom, LiVESAttachOptions xoptions, LiVESAttachOptions yoptions,
7037     uint32_t xpad, uint32_t ypad) {
7038 #ifdef GUI_GTK
7039 #if LIVES_TABLE_IS_GRID  // required for grid remove row
7040   gtk_grid_attach(table, child, left, top, right - left, bottom - top);
7041   if (xoptions & LIVES_EXPAND)
7042     lives_widget_set_hexpand(child, TRUE);
7043   else
7044     lives_widget_set_hexpand(child, FALSE);
7045   if (yoptions & LIVES_EXPAND)
7046     lives_widget_set_vexpand(child, TRUE);
7047   else
7048     lives_widget_set_vexpand(child, FALSE);
7049 
7050   lives_widget_set_margin_left(child, xpad);
7051   lives_widget_set_margin_right(child, xpad);
7052 
7053   lives_widget_set_margin_top(child, ypad);
7054   lives_widget_set_margin_bottom(child, ypad);
7055 #else
7056   gtk_table_attach(table, child, left, right, top, bottom, xoptions, yoptions, xpad, ypad);
7057 #endif
7058   return TRUE;
7059 #endif
7060   return FALSE;
7061 }
7062 
7063 
lives_color_button_new_with_color(const LiVESWidgetColor * color)7064 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_color_button_new_with_color(const LiVESWidgetColor *color) {
7065   LiVESWidget *cbutton = NULL;
7066 #ifdef GUI_GTK
7067 #if GTK_CHECK_VERSION(3, 0, 0)
7068   cbutton = gtk_color_button_new_with_rgba(color);
7069 #else
7070   cbutton = gtk_color_button_new_with_color(color);
7071 #endif
7072 #endif
7073   return cbutton;
7074 }
7075 
7076 
lives_color_button_get_color(LiVESColorButton * button,LiVESWidgetColor * color)7077 WIDGET_HELPER_GLOBAL_INLINE LiVESWidgetColor *lives_color_button_get_color(LiVESColorButton *button, LiVESWidgetColor *color) {
7078 #ifdef GUI_GTK
7079 #if GTK_CHECK_VERSION(3, 4, 0)
7080   gtk_color_chooser_get_rgba((GtkColorChooser *)button, color);
7081 #else
7082 #if GTK_CHECK_VERSION(3, 0, 0)
7083   gtk_color_button_get_rgba((GtkColorChooser *)button, color);
7084 #else
7085   gtk_color_button_get_color(button, color);
7086 #endif
7087 #endif
7088   return color;
7089 #endif
7090   return NULL;
7091 }
7092 
7093 
lives_color_button_set_alpha(LiVESColorButton * button,int16_t alpha)7094 WIDGET_HELPER_GLOBAL_INLINE boolean lives_color_button_set_alpha(LiVESColorButton *button, int16_t alpha) {
7095 #ifdef GUI_GTK
7096 #if GTK_CHECK_VERSION(3, 4, 0)
7097   LiVESWidgetColor color;
7098   gtk_color_chooser_get_rgba((GtkColorChooser *)button, &color);
7099   color.alpha = LIVES_WIDGET_COLOR_SCALE(alpha);
7100   gtk_color_chooser_set_rgba((GtkColorChooser *)button, &color);
7101 #else
7102   gtk_color_button_set_alpha(button, alpha);
7103 #endif
7104   return TRUE;
7105 #endif
7106   return FALSE;
7107 }
7108 
7109 
lives_color_button_get_alpha(LiVESColorButton * button)7110 WIDGET_HELPER_GLOBAL_INLINE int16_t lives_color_button_get_alpha(LiVESColorButton *button) {
7111 #ifdef GUI_GTK
7112 #if GTK_CHECK_VERSION(3, 4, 0)
7113   LiVESWidgetColor color;
7114   gtk_color_chooser_get_rgba((GtkColorChooser *)button, &color);
7115   return LIVES_WIDGET_COLOR_STRETCH(color.alpha);
7116 #else
7117   return gtk_color_button_get_alpha(button);
7118 #endif
7119 #endif
7120   return -1;
7121 }
7122 
7123 
lives_color_button_set_color(LiVESColorButton * button,const LiVESWidgetColor * color)7124 WIDGET_HELPER_GLOBAL_INLINE boolean lives_color_button_set_color(LiVESColorButton *button, const LiVESWidgetColor *color) {
7125 #ifdef GUI_GTK
7126 #if GTK_CHECK_VERSION(3, 4, 0)
7127   gtk_color_chooser_set_rgba((GtkColorChooser *)button, color);
7128 #else
7129 #if GTK_CHECK_VERSION(3, 0, 0)
7130   gtk_color_button_set_rgba((GtkColorChooser *)button, color);
7131 #else
7132   gtk_color_button_set_color(button, color);
7133 #endif
7134 #endif
7135   return TRUE;
7136 #endif
7137   return FALSE;
7138 }
7139 
7140 
lives_color_button_set_title(LiVESColorButton * button,const char * title)7141 WIDGET_HELPER_GLOBAL_INLINE boolean lives_color_button_set_title(LiVESColorButton *button, const char *title) {
7142 #ifdef GUI_GTK
7143   char *ntitle = lives_strdup_printf("%s%s", widget_opts.title_prefix, title);
7144   gtk_color_button_set_title(button, title);
7145   lives_free(ntitle);
7146   return TRUE;
7147 #endif
7148   return FALSE;
7149 }
7150 
7151 
lives_color_button_set_use_alpha(LiVESColorButton * button,boolean use_alpha)7152 WIDGET_HELPER_GLOBAL_INLINE boolean lives_color_button_set_use_alpha(LiVESColorButton *button, boolean use_alpha) {
7153 #ifdef GUI_GTK
7154 #if GTK_CHECK_VERSION(3, 4, 0)
7155   gtk_color_chooser_set_use_alpha((GtkColorChooser *)button, use_alpha);
7156 #else
7157 #if GTK_CHECK_VERSION(3, 0, 0)
7158   gtk_color_button_set_use_alpha((GtkColorChooser *)button, use_alpha);
7159 #else
7160   gtk_color_button_set_use_alpha(button, use_alpha);
7161 #endif
7162 #endif
7163   return TRUE;
7164 #endif
7165   return FALSE;
7166 }
7167 
7168 
lives_widget_get_mods(LiVESXDevice * device,LiVESWidget * widget,int * x,int * y,LiVESXModifierType * modmask)7169 WIDGET_HELPER_LOCAL_INLINE boolean lives_widget_get_mods(LiVESXDevice *device, LiVESWidget *widget, int *x, int *y,
7170     LiVESXModifierType *modmask) {
7171 #ifdef GUI_GTK
7172   LiVESXWindow *xwin;
7173   if (!widget) xwin = gdk_get_default_root_window();
7174   else xwin = lives_widget_get_xwindow(widget);
7175   if (!xwin) {
7176     LIVES_ERROR("Tried to get pointer for windowless widget");
7177     return TRUE;
7178   }
7179 #if GTK_CHECK_VERSION(3, 0, 0)
7180   gdk_window_get_device_position(xwin, device, x, y, modmask);
7181 #else
7182   gdk_window_get_pointer(xwin, x, y, modmask);
7183 #endif
7184   return TRUE;
7185 #endif
7186   return FALSE;
7187 }
7188 
7189 
lives_widget_get_pointer(LiVESXDevice * device,LiVESWidget * widget,int * x,int * y)7190 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_pointer(LiVESXDevice *device, LiVESWidget *widget, int *x, int *y) {
7191   return lives_widget_get_mods(device, widget, x, y, NULL);
7192 }
7193 
7194 
lives_widget_get_modmask(LiVESXDevice * device,LiVESWidget * widget,LiVESXModifierType * modmask)7195 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_modmask(LiVESXDevice *device, LiVESWidget *widget,
7196     LiVESXModifierType *modmask) {
7197   return lives_widget_get_mods(device, widget, NULL, NULL, modmask);
7198 }
7199 
7200 
lives_widget_destroyed(LiVESWidget * widget,void ** ptr)7201 static boolean lives_widget_destroyed(LiVESWidget *widget, void **ptr) {
7202   if (ptr) *ptr = NULL;
7203   return FALSE;
7204 }
7205 
7206 
lives_widget_timetodie(LiVESWidget * widget,LiVESWidget * getoverhere)7207 static boolean lives_widget_timetodie(LiVESWidget *widget, LiVESWidget *getoverhere) {
7208   if (LIVES_IS_WIDGET(getoverhere)) lives_widget_destroy(getoverhere);
7209   return FALSE;
7210 }
7211 
7212 
lives_widget_nullify_with(LiVESWidget * widget,void ** ptr)7213 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_nullify_with(LiVESWidget *widget, void **ptr) {
7214   lives_signal_sync_connect(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_DESTROY_SIGNAL,
7215                             LIVES_GUI_CALLBACK(lives_widget_destroyed),
7216                             ptr);
7217   return TRUE;
7218 }
7219 
7220 
lives_widget_destroy_with(LiVESWidget * widget,LiVESWidget * dieplease)7221 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_destroy_with(LiVESWidget *widget, LiVESWidget *dieplease) {
7222   lives_signal_sync_connect(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_DESTROY_SIGNAL,
7223                             LIVES_GUI_CALLBACK(lives_widget_timetodie),
7224                             dieplease);
7225   return TRUE;
7226 }
7227 
7228 
lives_widget_get_display(LiVESWidget * widget)7229 WIDGET_HELPER_GLOBAL_INLINE LiVESXDisplay *lives_widget_get_display(LiVESWidget *widget) {
7230   LiVESXDisplay *disp = NULL;
7231 #ifdef GUI_GTK
7232   disp = gtk_widget_get_display(widget);
7233 #endif
7234   return disp;
7235 }
7236 
7237 
lives_display_get_window_at_pointer(LiVESXDevice * device,LiVESXDisplay * display,int * win_x,int * win_y)7238 WIDGET_HELPER_GLOBAL_INLINE LiVESXWindow *lives_display_get_window_at_pointer
7239 (LiVESXDevice *device, LiVESXDisplay *display, int *win_x, int *win_y) {
7240   LiVESXWindow *xwindow = NULL;
7241 #ifdef GUI_GTK
7242 #if GTK_CHECK_VERSION(3, 0, 0)
7243   if (!device) return NULL;
7244   xwindow = gdk_device_get_window_at_position(device, win_x, win_y);
7245 #else
7246   xwindow = gdk_display_get_window_at_pointer(display, win_x, win_y);
7247 #endif
7248 #endif
7249   return xwindow;
7250 }
7251 
7252 
lives_display_get_pointer(LiVESXDevice * device,LiVESXDisplay * display,LiVESXScreen ** screen,int * x,int * y,LiVESXModifierType * mask)7253 WIDGET_HELPER_GLOBAL_INLINE boolean lives_display_get_pointer
7254 (LiVESXDevice *device, LiVESXDisplay *display, LiVESXScreen **screen, int *x, int *y, LiVESXModifierType *mask) {
7255 #ifdef GUI_GTK
7256 #if GTK_CHECK_VERSION(3, 0, 0)
7257   if (!device) return TRUE;
7258   gdk_device_get_position(device, screen, x, y);
7259 #else
7260   gdk_display_get_pointer(display, screen, x, y, mask);
7261 #endif
7262   return TRUE;
7263 #endif
7264   return FALSE;
7265 }
7266 
7267 
lives_display_warp_pointer(LiVESXDevice * device,LiVESXDisplay * display,LiVESXScreen * screen,int x,int y)7268 WIDGET_HELPER_GLOBAL_INLINE boolean lives_display_warp_pointer
7269 (LiVESXDevice *device, LiVESXDisplay *display, LiVESXScreen *screen, int x, int y) {
7270 #ifdef GUI_GTK
7271 #if GTK_CHECK_VERSION(3, 0, 0)
7272   if (!device) return TRUE;
7273   gdk_device_warp(device, screen, x, y);
7274 #else
7275 #if GLIB_CHECK_VERSION(2, 8, 0)
7276   gdk_display_warp_pointer(display, screen, x, y);
7277 #endif
7278 #endif
7279   return TRUE;
7280 #endif
7281   return FALSE;
7282 }
7283 
7284 
lives_widget_get_display_type(LiVESWidget * widget)7285 WIDGET_HELPER_GLOBAL_INLINE lives_display_t lives_widget_get_display_type(LiVESWidget *widget) {
7286   lives_display_t dtype = LIVES_DISPLAY_TYPE_UNKNOWN;
7287 #ifdef GUI_GTK
7288   if (GDK_IS_X11_DISPLAY(gtk_widget_get_display(widget))) dtype = LIVES_DISPLAY_TYPE_X11;
7289 #ifdef GDK_WINDOWING_WAYLAND
7290   else if (GDK_IS_WAYLAND_DISPLAY(gtk_widget_get_display(widget))) dtype = LIVES_DISPLAY_TYPE_WAYLAND;
7291 #endif
7292   else if (GDK_IS_WIN32_DISPLAY(gtk_widget_get_display(widget))) dtype = LIVES_DISPLAY_TYPE_WIN32;
7293 #endif
7294   return dtype;
7295 }
7296 
7297 
lives_widget_get_xwinid(LiVESWidget * widget,const char * msg)7298 WIDGET_HELPER_GLOBAL_INLINE uint64_t lives_widget_get_xwinid(LiVESWidget *widget, const char *msg) {
7299   uint64_t xwin = -1;
7300 #ifdef GUI_GTK
7301 #ifdef GDK_WINDOWING_X11
7302   if (lives_widget_get_display_type(widget) == LIVES_DISPLAY_TYPE_X11)
7303     xwin = (uint64_t)GDK_WINDOW_XID(lives_widget_get_xwindow(widget));
7304   else
7305 #endif
7306 #ifdef GDK_WINDOWING_WIN32
7307     if (lives_widget_get_display_type(widget) == LIVES_DISPLAY_TYPE_WIN32)
7308       xwin = (uint64_t)gdk_win32_window_get_handle(lives_widget_get_xwindow(widget));
7309     else
7310 #endif
7311 #endif
7312       if (msg) LIVES_WARN(msg);
7313 
7314   return xwin;
7315 }
7316 
7317 
lives_timer_add(uint32_t interval,LiVESWidgetSourceFunc function,livespointer data)7318 WIDGET_HELPER_GLOBAL_INLINE uint32_t lives_timer_add(uint32_t interval, LiVESWidgetSourceFunc function, livespointer data) {
7319   // interval in milliseconds
7320   lives_sigdata_t *sigdata = (lives_sigdata_t *)lives_calloc(1, sizeof(lives_sigdata_t));
7321   sigdata->callback = (lives_funcptr_t)function;
7322   sigdata->user_data = data;
7323   sigdata->is_timer = TRUE;
7324 
7325 #ifdef GUI_GTK
7326 #if GTK_CHECK_VERSION(3, 0, 0)
7327   if (interval > 1000) {
7328     sigdata->funcid = g_timeout_add_seconds(interval / 1000., async_timer_handler, sigdata);
7329   } else {
7330     sigdata->funcid = g_timeout_add(interval, async_timer_handler, sigdata);
7331   }
7332 #else
7333   sigdata->funcid = gtk_timeout_add(interval, async_timer_handler, sigdata);
7334 #endif
7335 #endif
7336 
7337   return sigdata->funcid;
7338 }
7339 
7340 
lives_timer_remove(uint32_t timer)7341 WIDGET_HELPER_GLOBAL_INLINE boolean lives_timer_remove(uint32_t timer) {
7342 #ifdef GUI_GTK
7343   g_source_remove(timer);
7344   return TRUE;
7345 #endif
7346   return FALSE;
7347 }
7348 
7349 
lives_idle_add(LiVESWidgetSourceFunc function,livespointer data)7350 WIDGET_HELPER_GLOBAL_INLINE uint32_t lives_idle_add(LiVESWidgetSourceFunc function, livespointer data) {
7351   lives_sigdata_t *sigdata = (lives_sigdata_t *)lives_calloc(1, sizeof(lives_sigdata_t));
7352   sigdata->callback = (lives_funcptr_t)function;
7353   sigdata->user_data = data;
7354   sigdata->is_timer = TRUE;
7355 
7356   sigdata->funcid = g_idle_add(async_timer_handler, sigdata);
7357   return sigdata->funcid;
7358 }
7359 
7360 
lives_source_remove(uint32_t handle)7361 WIDGET_HELPER_GLOBAL_INLINE boolean lives_source_remove(uint32_t handle) {
7362   return lives_timer_remove(handle);
7363 }
7364 
7365 
lives_accelerator_get_default_mod_mask(void)7366 WIDGET_HELPER_GLOBAL_INLINE uint32_t lives_accelerator_get_default_mod_mask(void) {
7367 #ifdef GUI_GTK
7368   return gtk_accelerator_get_default_mod_mask();
7369 #endif
7370   return 0;
7371 }
7372 
7373 
lives_screen_get_width(LiVESXScreen * screen)7374 WIDGET_HELPER_GLOBAL_INLINE int lives_screen_get_width(LiVESXScreen *screen) {
7375 #ifdef GUI_GTK
7376 #if !GTK_CHECK_VERSION(3, 22, 0)
7377   return gdk_screen_get_width(screen);
7378 #endif
7379 #endif
7380   return 0;
7381 }
7382 
7383 
lives_screen_get_height(LiVESXScreen * screen)7384 WIDGET_HELPER_GLOBAL_INLINE int lives_screen_get_height(LiVESXScreen *screen) {
7385 #ifdef GUI_GTK
7386 #if !GTK_CHECK_VERSION(3, 22, 0)
7387   return gdk_screen_get_height(screen);
7388 #endif
7389 #endif
7390   return 0;
7391 }
7392 
7393 
global_recent_manager_add(const char * full_file_name)7394 WIDGET_HELPER_GLOBAL_INLINE boolean global_recent_manager_add(const char *full_file_name) {
7395 #ifdef GUI_GTK
7396   char *tmp = g_filename_to_uri(full_file_name, NULL, NULL);
7397   gtk_recent_manager_add_item(gtk_recent_manager_get_default(), tmp);
7398   g_free(tmp);
7399   return TRUE;
7400 #endif
7401   return FALSE;
7402 }
7403 
7404 
lives_cursor_new_from_pixbuf(LiVESXDisplay * disp,LiVESPixbuf * pixbuf,int x,int y)7405 WIDGET_HELPER_GLOBAL_INLINE LiVESXCursor *lives_cursor_new_from_pixbuf(LiVESXDisplay *disp, LiVESPixbuf *pixbuf, int x, int y) {
7406   LiVESXCursor *cursor = NULL;
7407 #ifdef GUI_GTK
7408   cursor = gdk_cursor_new_from_pixbuf(disp, pixbuf, x, y);
7409 #endif
7410   return cursor;
7411 }
7412 
7413 
lives_has_toplevel_focus(LiVESWidget * widget)7414 WIDGET_HELPER_GLOBAL_INLINE boolean lives_has_toplevel_focus(LiVESWidget *widget) {
7415 #ifdef GUI_GTK
7416   return gtk_window_has_toplevel_focus(LIVES_WINDOW(widget));
7417 #endif
7418   return TRUE;
7419 }
7420 
7421 
lives_entry_set_editable(LiVESEntry * entry,boolean editable)7422 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_editable(LiVESEntry *entry, boolean editable) {
7423   return lives_editable_set_editable(LIVES_EDITABLE(entry), editable);
7424 }
7425 
7426 
lives_entry_get_editable(LiVESEntry * entry)7427 WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_get_editable(LiVESEntry *entry) {
7428   return lives_editable_get_editable(LIVES_EDITABLE(entry));
7429 }
7430 
7431 
7432 // compound functions
7433 
lives_image_scale(LiVESImage * image,int width,int height,LiVESInterpType interp_type)7434 WIDGET_HELPER_GLOBAL_INLINE boolean lives_image_scale(LiVESImage *image, int width, int height, LiVESInterpType interp_type) {
7435   LiVESPixbuf *pixbuf;
7436   if (!LIVES_IS_IMAGE(image)) return FALSE;
7437   pixbuf = lives_image_get_pixbuf(image);
7438   if (pixbuf) {
7439     LiVESPixbuf *new_pixbuf = lives_pixbuf_scale_simple(pixbuf, width, height, interp_type);
7440     lives_image_set_from_pixbuf(image, new_pixbuf);
7441     //if (LIVES_IS_WIDGET_OBJECT(pixbuf)) lives_widget_object_unref(pixbuf);
7442     if (new_pixbuf && LIVES_IS_WIDGET_OBJECT(new_pixbuf)) lives_widget_object_unref(new_pixbuf);
7443   }
7444   return TRUE;
7445 }
7446 
7447 
lives_widget_set_pack_type(LiVESBox * box,LiVESWidget * child,LiVESPackType pack)7448 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_pack_type(LiVESBox *box, LiVESWidget *child, LiVESPackType pack) {
7449 #ifdef GUI_GTK
7450   boolean expand, fill;
7451   uint32_t padding;
7452   gtk_box_query_child_packing(box, child, &expand, &fill, &padding, NULL);
7453   lives_box_set_child_packing(box, child, expand, fill, padding, pack);
7454 #endif
7455   return FALSE;
7456 }
7457 
7458 
lives_label_set_hpadding(LiVESLabel * label,int pad)7459 WIDGET_HELPER_GLOBAL_INLINE void lives_label_set_hpadding(LiVESLabel *label, int pad) {
7460   const char *text = lives_label_get_text(label);
7461   lives_label_set_width_chars(label, strlen(text) + pad);
7462 }
7463 
7464 
7465 #define H_ALIGN_ADJ (22. * widget_opts.scale) // why 22 ? no idea
7466 
align_horizontal_with(LiVESWidget * thingtoadd,LiVESWidget * thingtoalignwith)7467 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *align_horizontal_with(LiVESWidget *thingtoadd, LiVESWidget *thingtoalignwith) {
7468 #ifdef GUI_GTK
7469   GtkWidget *fixed = gtk_fixed_new();
7470   int x = lives_widget_get_allocation_x(thingtoalignwith);
7471   // allow for 1 packing_width before adding the real widget
7472   gtk_fixed_put(GTK_FIXED(fixed), thingtoadd, x - H_ALIGN_ADJ - widget_opts.packing_width, 0);
7473   lives_widget_set_show_hide_parent(thingtoadd);
7474   return fixed;
7475 #endif
7476   return NULL;
7477 }
7478 
7479 
lives_box_pack_first(LiVESBox * box,LiVESWidget * child,boolean expand,boolean fill,uint32_t padding)7480 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_first(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill,
7481     uint32_t padding) {
7482   if (lives_box_pack_start(box, child, expand, fill, padding))
7483     return lives_box_reorder_child(box, child, 0);
7484   return FALSE;
7485 }
7486 
7487 
lives_tooltips_copy(LiVESWidget * dest,LiVESWidget * source)7488 void lives_tooltips_copy(LiVESWidget *dest, LiVESWidget *source) {
7489 #ifdef GUI_GTK
7490 #if GTK_CHECK_VERSION(2, 12, 0)
7491   boolean mustfree = TRUE;
7492   char *text = (char *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(source), TTIPS_KEY);
7493   if (!text) text = gtk_widget_get_tooltip_text(source);
7494   else mustfree = FALSE;
7495   lives_widget_set_tooltip_text(dest, text);
7496   if (mustfree && text) lives_free(text);
7497 #else
7498   GtkTooltipsData *td = gtk_tooltips_data_get(source);
7499   if (!td) return;
7500   gtk_tooltips_set_tip(td->tooltips, dest, td->tip_text, td->tip_private);
7501 #endif
7502 #endif
7503 #ifdef GUI_QT
7504   dest->setToolTip(source->toolTip());
7505 #endif
7506 }
7507 
7508 
lives_combo_populate(LiVESCombo * combo,LiVESList * list)7509 boolean lives_combo_populate(LiVESCombo *combo, LiVESList *list) {
7510   LiVESList *revlist;
7511 
7512   // remove any current list
7513   LiVESTreeModel *tmodel = lives_combo_get_model(combo);
7514   if (tmodel) {
7515     if (!lives_combo_set_active_index(combo, -1)) return FALSE;
7516     if (!lives_combo_remove_all_text(combo)) return FALSE;
7517   }
7518 
7519   if (lives_list_length(list) > COMBO_LIST_LIMIT) {
7520     // use a treestore
7521     LiVESTreeIter iter1, iter2;
7522     LiVESTreeStore *tstore = lives_tree_store_new(1, LIVES_COL_TYPE_STRING);
7523     char *cat;
7524     for (revlist = list; revlist; revlist = revlist->next) {
7525       cat = lives_strndup((const char *)revlist->data, 1);
7526       // returns the iter for cat if it already exists, else appends cat and returns it
7527       lives_tree_store_find_iter(tstore, 0, cat, NULL, &iter1);
7528       lives_tree_store_append(tstore, &iter2, &iter1);   /* Acquire an iterator */
7529       lives_tree_store_set(tstore, &iter2, 0, revlist->data, -1);
7530       lives_free(cat);
7531     }
7532     lives_combo_set_model(LIVES_COMBO(combo), LIVES_TREE_MODEL(tstore));
7533     lives_combo_set_entry_text_column(combo, 0);
7534   } else {
7535     // reverse the list and then prepend the items
7536     // this is faster (O(1) than traversing the list and appending O(2))
7537     LiVESTreeIter iter;
7538     LiVESListStore *lstore = lives_list_store_new(1, LIVES_COL_TYPE_STRING);
7539     for (revlist = lives_list_last(list); revlist; revlist = revlist->prev) {
7540       gtk_list_store_prepend(lstore, &iter);   /* Acquire an iterator */
7541       gtk_list_store_set(GTK_LIST_STORE(lstore), &iter, 0, revlist->data, -1);
7542     }
7543     lives_combo_set_model(LIVES_COMBO(combo), LIVES_TREE_MODEL(lstore));
7544     lives_combo_set_entry_text_column(combo, 0);
7545   }
7546   return TRUE;
7547 }
7548 
7549 
7550 ///// lives compounds
7551 
lives_volume_button_new(LiVESOrientation orientation,LiVESAdjustment * adj,double volume)7552 LiVESWidget *lives_volume_button_new(LiVESOrientation orientation, LiVESAdjustment *adj, double volume) {
7553   LiVESWidget *volume_scale = NULL;
7554 #ifdef GUI_GTK
7555 #if GTK_CHECK_VERSION(2, 14, 0)
7556   volume_scale = gtk_volume_button_new();
7557   gtk_scale_button_set_value(GTK_SCALE_BUTTON(volume_scale), volume);
7558   lives_scale_button_set_orientation(LIVES_SCALE_BUTTON(volume_scale), orientation);
7559 #else
7560   if (orientation == LIVES_ORIENTATION_HORIZONTAL)
7561     volume_scale = gtk_hscale_new(adj);
7562   else
7563     volume_scale = gtk_vscale_new(adj);
7564 
7565   gtk_scale_set_draw_value(GTK_SCALE(volume_scale), FALSE);
7566 #endif
7567 #endif
7568   return volume_scale;
7569 }
7570 
7571 
lives_button_ungrab_default_special(LiVESWidget * button)7572 boolean lives_button_ungrab_default_special(LiVESWidget *button) {
7573   LiVESWidget *toplevel = lives_widget_get_toplevel(button);
7574   LiVESWidget *deflt = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(toplevel), DEFBUTTON_KEY);
7575 
7576   lives_widget_set_can_default(button, FALSE);
7577   if (button == deflt)
7578     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(LIVES_WIDGET_OBJECT(toplevel)),
7579                                  DEFBUTTON_KEY, NULL);
7580 #ifdef USE_SPECIAL_BUTTONS
7581   sbutt_render(button, 0, NULL);
7582 #endif
7583   return TRUE;
7584 }
7585 
7586 
lives_button_grab_default_special(LiVESWidget * button)7587 boolean lives_button_grab_default_special(LiVESWidget *button) {
7588   // grab default and set as default default
7589   if (!lives_widget_set_can_focus_and_default(button)) return FALSE;
7590   if (!lives_widget_grab_default(button)) return FALSE;
7591   else {
7592     LiVESWidget *toplevel = lives_widget_get_toplevel(button);
7593     LiVESWidget *deflt = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(toplevel), DEFBUTTON_KEY);
7594     if (button == deflt) return TRUE;
7595     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(LIVES_WIDGET_OBJECT(toplevel)),
7596                                  DEFBUTTON_KEY, button);
7597 #ifdef USE_SPECIAL_BUTTONS
7598     sbutt_render(button, 0, NULL);
7599     if (deflt) sbutt_render(deflt, 0, NULL);
7600 #endif
7601   }
7602   return TRUE;
7603 }
7604 
_set_css_min_size(LiVESWidget * w,const char * sel,int mw,int mh)7605 static void _set_css_min_size(LiVESWidget *w, const char *sel, int mw, int mh) {
7606 #if GTK_CHECK_VERSION(3, 16, 0)
7607   char *tmp;
7608   if (mw > 0) {
7609     tmp = lives_strdup_printf("%dpx", mw);
7610     set_css_value_direct(w, LIVES_WIDGET_STATE_NORMAL, sel, "min-width", tmp);
7611     lives_free(tmp);
7612   }
7613   if (mh > 0) {
7614     tmp = lives_strdup_printf("%dpx", mh);
7615     set_css_value_direct(w, LIVES_WIDGET_STATE_NORMAL, sel, "min-height", tmp);
7616     lives_free(tmp);
7617   }
7618 #endif
7619 }
7620 
set_css_min_size(LiVESWidget * w,int mw,int mh)7621 static void set_css_min_size(LiVESWidget *w, int mw, int mh) {
7622   _set_css_min_size(w, "", mw, mh);
7623   _set_css_min_size(w, "*", mw, mh);
7624 }
7625 
set_css_min_size_selected(LiVESWidget * w,char * selector,int mw,int mh)7626 static void set_css_min_size_selected(LiVESWidget *w, char *selector, int mw, int mh) {
7627   _set_css_min_size(w, selector, mw, mh);
7628 }
7629 
7630 
7631 ///////////////// lives_layout ////////////////////////
7632 
lives_layout_attach(LiVESLayout * layout,LiVESWidget * widget,int start,int end,int row)7633 WIDGET_HELPER_LOCAL_INLINE void lives_layout_attach(LiVESLayout *layout, LiVESWidget *widget, int start, int end, int row) {
7634   lives_table_attach(layout, widget, start, end, row, row + 1,
7635                      (LiVESAttachOptions)(LIVES_FILL | (LIVES_SHOULD_EXPAND_EXTRA_WIDTH
7636                                           ? LIVES_EXPAND : 0)), (LiVESAttachOptions)(0), 0, 0);
7637 }
7638 
7639 
lives_layout_expansion_row_new(LiVESLayout * layout,LiVESWidget * widget)7640 LiVESWidget *lives_layout_expansion_row_new(LiVESLayout *layout, LiVESWidget *widget) {
7641   LiVESList *xwidgets = (LiVESList *)lives_widget_object_steal_data(LIVES_WIDGET_OBJECT(layout), EXP_LIST_KEY);
7642   LiVESWidget *box = NULL;
7643   int rows, columns;
7644   if (widget) box = lives_widget_get_parent(widget);
7645 
7646   if (!box) {
7647     box = lives_layout_row_new(layout);
7648     if (widget) lives_layout_pack(LIVES_HBOX(box), widget);
7649   }
7650 
7651   columns = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), COLS_KEY));
7652   rows = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY));
7653   if (columns > 1) {
7654     lives_widget_object_ref(LIVES_WIDGET_OBJECT(box));
7655     lives_widget_unparent(box);
7656     lives_layout_attach(layout, box, 0, columns, rows - 1);
7657     lives_widget_object_unref(LIVES_WIDGET_OBJECT(box));
7658   }
7659   lives_widget_set_halign(box, LIVES_ALIGN_FILL);
7660   //lives_widget_set_halign(widget, LIVES_ALIGN_CENTER);
7661   xwidgets = lives_list_prepend(xwidgets, box);
7662   lives_widget_object_set_data_list(LIVES_WIDGET_OBJECT(layout), EXP_LIST_KEY, xwidgets);
7663   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(box), LROW_KEY, LIVES_INT_TO_POINTER(rows) - 1);
7664   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(box), EXPANSION_KEY, LIVES_INT_TO_POINTER(widget_opts.expand));
7665   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(box), JUST_KEY, LIVES_INT_TO_POINTER(widget_opts.justify));
7666   widget_opts.last_container = box;
7667   if (widget) return widget;
7668   return box;
7669 }
7670 
7671 
lives_layout_resize(LiVESLayout * layout,int rows,int columns)7672 static boolean lives_layout_resize(LiVESLayout *layout, int rows, int columns) {
7673   LiVESList *xwidgets = (LiVESList *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), EXP_LIST_KEY);
7674   lives_table_resize(LIVES_TABLE(layout), rows, columns);
7675   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY, LIVES_INT_TO_POINTER(rows));
7676   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), COLS_KEY, LIVES_INT_TO_POINTER(columns));
7677   while (xwidgets) {
7678     LiVESWidget *widget = (LiVESWidget *)xwidgets->data;
7679     int row = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), LROW_KEY));
7680     int expansion = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), EXPANSION_KEY));
7681     LiVESJustification justification = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
7682                                        JUST_KEY));
7683     int woe = widget_opts.expand;
7684     LiVESJustification woj = widget_opts.justify;
7685     lives_widget_object_ref(widget);
7686     lives_widget_unparent(widget);
7687     widget_opts.expand = expansion;
7688     widget_opts.justify = justification;
7689     lives_layout_attach(layout, widget, 0, columns, row);
7690     widget_opts.expand = woe;
7691     widget_opts.justify = woj;
7692     lives_widget_object_unref(widget);
7693     xwidgets = xwidgets->next;
7694   }
7695   return TRUE;
7696 }
7697 
7698 
lives_layout_pack(LiVESHBox * box,LiVESWidget * widget)7699 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_pack(LiVESHBox *box, LiVESWidget *widget) {
7700   LiVESWidget *layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(box), WH_LAYOUT_KEY);
7701   if (layout) {
7702     LiVESList *xwidgets = (LiVESList *)lives_widget_object_steal_data(LIVES_WIDGET_OBJECT(layout), EXP_LIST_KEY);
7703     int row = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY)) - 1;
7704     // remove any expansion widgets on this row
7705     if (xwidgets) {
7706       LiVESList *list = xwidgets;
7707       for (; list; list = list->next) {
7708         if (LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(xwidgets->data),
7709                                  LROW_KEY)) == row) {
7710           if (list->prev) list->prev->next = list->next;
7711           else xwidgets = list->next;
7712           if (list->next) list->next->prev = list->prev;
7713           list->prev = list->next = NULL;
7714           lives_list_free(list);
7715           break;
7716 	  // *INDENT-OFF*
7717         }}
7718       lives_widget_object_set_data_list(LIVES_WIDGET_OBJECT(layout), EXP_LIST_KEY, xwidgets);
7719     }}
7720   // *INDENT-ON*
7721   lives_box_pack_start(LIVES_BOX(box), widget, LIVES_SHOULD_EXPAND_EXTRA_WIDTH
7722                        || (LIVES_IS_LABEL(widget) && LIVES_SHOULD_EXPAND_WIDTH),
7723                        TRUE, LIVES_SHOULD_EXPAND_WIDTH
7724                        ? widget_opts.packing_width >> 1 : 0);
7725   lives_widget_set_halign(widget, lives_justify_to_align(widget_opts.justify));
7726   lives_widget_set_show_hide_parent(widget);
7727   widget_opts.last_container = LIVES_WIDGET(box);
7728   return widget;
7729 }
7730 
7731 
lives_layout_new(LiVESBox * box)7732 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_new(LiVESBox * box) {
7733   LiVESWidget *layout = lives_table_new(0, 0, FALSE);
7734   if (box) {
7735     if (LIVES_IS_VBOX(box)) {
7736       lives_box_pack_start(box, layout, LIVES_SHOULD_EXPAND_EXTRA_HEIGHT, TRUE,
7737                            LIVES_SHOULD_EXPAND_HEIGHT ? widget_opts.packing_height : 0);
7738     } else {
7739       lives_box_pack_start(box, layout, LIVES_SHOULD_EXPAND_EXTRA_WIDTH, TRUE,
7740                            LIVES_SHOULD_EXPAND_WIDTH ? widget_opts.packing_width : 0);
7741     }
7742   }
7743   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY, LIVES_INT_TO_POINTER(1));
7744   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), COLS_KEY, LIVES_INT_TO_POINTER(0));
7745   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), WADDED_KEY, LIVES_INT_TO_POINTER(0));
7746   lives_widget_object_set_data_list(LIVES_WIDGET_OBJECT(layout), EXP_LIST_KEY, NULL);
7747   lives_table_set_col_spacings(LIVES_TABLE(layout), 0);
7748   if (LIVES_SHOULD_EXPAND_HEIGHT)
7749     lives_table_set_row_spacings(LIVES_TABLE(layout), widget_opts.packing_height);
7750   if (LIVES_SHOULD_EXPAND_EXTRA_WIDTH)
7751     lives_table_set_col_spacings(LIVES_TABLE(layout), widget_opts.packing_width);
7752   //lives_table_set_column_homogeneous(LIVES_TABLE(layout), FALSE);
7753   return layout;
7754 }
7755 
7756 
lives_layout_hbox_new(LiVESLayout * layout)7757 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_hbox_new(LiVESLayout * layout) {
7758   LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
7759 #if GTK_CHECK_VERSION(3, 0, 0)
7760   LiVESWidget *widget = hbox;
7761 #else
7762   LiVESWidget *alignment = lives_alignment_new(widget_opts.justify == LIVES_JUSTIFY_CENTER ? 0.5 : widget_opts.justify ==
7763                            LIVES_JUSTIFY_END
7764                            ? 1. : 0., .5, 0., 0.);
7765   LiVESWidget *widget = alignment;
7766   lives_container_add(LIVES_CONTAINER(alignment), hbox);
7767 #endif
7768 
7769   int nadded = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), WADDED_KEY));
7770   int rows = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY));
7771   int columns = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), COLS_KEY));
7772   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, layout);
7773   if (++nadded > columns) lives_layout_resize(layout, rows, nadded);
7774   lives_layout_attach(layout, widget, nadded - 1, nadded, rows - 1);
7775   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), WADDED_KEY, LIVES_INT_TO_POINTER(nadded));
7776   if (widget_opts.apply_theme == 2) {
7777     lives_widget_apply_theme2(widget, LIVES_WIDGET_STATE_NORMAL, TRUE);
7778   }
7779   return hbox;
7780 }
7781 
7782 
lives_layout_add_row(LiVESLayout * layout)7783 WIDGET_HELPER_GLOBAL_INLINE int lives_layout_add_row(LiVESLayout * layout) {
7784   int rows = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY));
7785   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), ROWS_KEY, LIVES_INT_TO_POINTER(++rows));
7786   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(layout), WADDED_KEY, LIVES_INT_TO_POINTER(0));
7787   return rows;
7788 }
7789 
7790 
lives_layout_row_new(LiVESLayout * layout)7791 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_row_new(LiVESLayout * layout) {
7792   lives_layout_add_row(layout);
7793   return lives_layout_hbox_new(layout);
7794 }
7795 
7796 
lives_layout_label_set_text(LiVESLabel * label,const char * text)7797 WIDGET_HELPER_GLOBAL_INLINE void lives_layout_label_set_text(LiVESLabel * label, const char *text) {
7798   if (text) {
7799     char *markup, *full_markup;
7800     if (!widget_opts.use_markup) markup = lives_markup_escape_text(text, -1);
7801     else markup = (char *)text;
7802     full_markup = lives_strdup_printf("<big><b>%s</b></big>", markup);
7803     lives_label_set_markup(label, full_markup);
7804     if (markup != text) lives_free(markup);
7805     lives_free(full_markup);
7806   }
7807 }
7808 
7809 
lives_layout_add_label(LiVESLayout * layout,const char * text,boolean horizontal)7810 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_add_label(LiVESLayout * layout, const char *text, boolean horizontal) {
7811   if (horizontal) {
7812     LiVESWidget *hbox = lives_layout_hbox_new(layout);
7813     LiVESWidget *label = lives_standard_label_new_with_tooltips(text, LIVES_BOX(hbox), NULL);
7814     LiVESWidget *conter = widget_opts.last_container;
7815     widget_opts.last_label = label;
7816     lives_widget_object_ref(conter);
7817     lives_widget_unparent(conter);
7818     lives_layout_pack(LIVES_HBOX(hbox), conter);
7819     lives_widget_object_unref(conter);
7820     widget_opts.last_container = hbox;
7821     if (widget_opts.apply_theme == 2) set_child_alt_colour(hbox, TRUE);
7822     return label;
7823   } else {
7824     LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
7825     LiVESWidget *label = lives_standard_label_new_with_tooltips(NULL, LIVES_BOX(hbox), NULL);
7826     LiVESWidget *conter = widget_opts.last_container;
7827     lives_layout_label_set_text(LIVES_LABEL(label), text);
7828     widget_opts.last_label = label;
7829     lives_widget_object_ref(conter);
7830     lives_widget_unparent(conter);
7831     lives_widget_destroy(hbox);
7832     lives_layout_expansion_row_new(layout, conter);
7833     lives_widget_object_ref(conter);
7834     widget_opts.last_container = hbox;
7835     if (widget_opts.apply_theme == 2) set_child_alt_colour(hbox, TRUE);
7836     return label;
7837   }
7838 }
7839 
7840 
lives_layout_add_fill(LiVESLayout * layout,boolean horizontal)7841 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_add_fill(LiVESLayout * layout, boolean horizontal) {
7842   LiVESWidget *widget;
7843   if (horizontal) {
7844     LiVESWidget *hbox = lives_layout_hbox_new(layout);
7845     widget = add_fill_to_box(LIVES_BOX(hbox));
7846     widget_opts.last_container = hbox;
7847   } else {
7848     widget = lives_layout_add_label(layout, NULL, FALSE);
7849     lives_layout_expansion_row_new(layout, widget);
7850   }
7851   return widget;
7852 }
7853 
7854 
lives_layout_add_separator(LiVESLayout * layout,boolean horizontal)7855 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_layout_add_separator(LiVESLayout * layout, boolean horizontal) {
7856   LiVESWidget *separator;
7857   LiVESJustification woj = widget_opts.justify;
7858   widget_opts.justify = LIVES_JUSTIFY_CENTER;
7859   if (horizontal) separator = lives_layout_pack(LIVES_HBOX(lives_layout_hbox_new(layout)), lives_vseparator_new());
7860   else separator = add_hsep_to_box(LIVES_BOX(lives_layout_expansion_row_new(layout, NULL)));
7861   widget_opts.justify = woj;
7862   return separator;
7863 }
7864 
7865 ////////////////////////////////////////////////////////////////////
7866 
add_warn_image(LiVESWidget * widget,LiVESWidget * hbox)7867 static LiVESWidget *add_warn_image(LiVESWidget * widget, LiVESWidget * hbox) {
7868   LiVESWidget *warn_image = lives_image_new_from_stock(LIVES_STOCK_DIALOG_WARNING,
7869                             widget_opts.icon_size);
7870   if (hbox) {
7871     if (!widget_opts.pack_end)
7872       lives_box_pack_start(LIVES_BOX(hbox), warn_image, FALSE, FALSE, 4);
7873     else
7874       lives_box_pack_end(LIVES_BOX(hbox), warn_image, FALSE, FALSE, 4);
7875   }
7876   lives_widget_set_no_show_all(warn_image, TRUE);
7877   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(warn_image), TTIPS_OVERRIDE_KEY, warn_image);
7878   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), WARN_IMAGE_KEY, warn_image);
7879   lives_widget_set_sensitive_with(widget, warn_image);
7880 #if GTK_CHECK_VERSION(3, 16, 0)
7881   if (widget_opts.apply_theme) {
7882     set_css_value_direct(warn_image, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
7883   }
7884 #endif
7885   return warn_image;
7886 }
7887 
7888 
show_warn_image(LiVESWidget * widget,const char * text)7889 WIDGET_HELPER_GLOBAL_INLINE boolean show_warn_image(LiVESWidget * widget, const char *text) {
7890   LiVESWidget *warn_image;
7891   if (!(warn_image = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), WARN_IMAGE_KEY))) return FALSE;
7892   lives_widget_set_tooltip_text(warn_image, text);
7893   lives_widget_set_no_show_all(warn_image, FALSE);
7894   lives_widget_show_all(warn_image);
7895   lives_widget_set_sensitive(warn_image, TRUE);
7896   return TRUE;
7897 }
7898 
hide_warn_image(LiVESWidget * widget)7899 WIDGET_HELPER_GLOBAL_INLINE boolean hide_warn_image(LiVESWidget * widget) {
7900   LiVESWidget *warn_image;
7901   if (!(warn_image = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), WARN_IMAGE_KEY))) return FALSE;
7902   lives_widget_set_no_show_all(warn_image, FALSE);
7903   lives_widget_hide(warn_image);
7904   return TRUE;
7905 }
7906 
7907 
make_inner_hbox(LiVESBox * box,boolean start)7908 static LiVESWidget *make_inner_hbox(LiVESBox * box, boolean start) {
7909   /// create an hbox, this gets packed into box
7910   /// "start" defines whether we pack at start or end
7911   /// if box is a vbox, "start" is ignored, and we pack a second hbox in the first
7912   /// so it is always hbox inside an hbox
7913   ///
7914   /// create a vbox, this is packed into hbox, this allows adding space on either side
7915   ///
7916   /// finally, create another hbox and pack into vbox, this will hold all sub widgets,
7917   /// e.g. labels, buttons, filler
7918   /// this allows for expanding the vertical size, whilst packing sub widgets horizontally
7919 
7920   LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
7921   LiVESWidget *vbox = lives_vbox_new(FALSE, 0);
7922 
7923   if (widget_opts.apply_theme == 2) lives_widget_apply_theme2(hbox, LIVES_WIDGET_STATE_NORMAL, TRUE);
7924   else lives_widget_apply_theme(hbox, LIVES_WIDGET_STATE_NORMAL);
7925   if (LIVES_IS_HBOX(box)) {
7926     widget_opts.last_container = hbox;
7927     if (!widget_opts.pack_end)
7928       lives_box_pack_start(LIVES_BOX(box), hbox, LIVES_SHOULD_EXPAND_EXTRA_WIDTH,
7929                            LIVES_SHOULD_EXPAND_WIDTH, LIVES_SHOULD_EXPAND_FOR(box)
7930                            ? widget_opts.packing_width : 0);
7931     else
7932       lives_box_pack_end(LIVES_BOX(box), hbox, LIVES_SHOULD_EXPAND_EXTRA_WIDTH,
7933                          LIVES_SHOULD_EXPAND_WIDTH, LIVES_SHOULD_EXPAND_FOR(box)
7934                          ? widget_opts.packing_width : 0);
7935   } else {
7936     lives_box_pack_start(LIVES_BOX(box), hbox, FALSE, FALSE, LIVES_SHOULD_EXPAND_FOR(box)
7937                          ? widget_opts.packing_height : 0);
7938     box = LIVES_BOX(hbox);
7939     hbox = lives_hbox_new(FALSE, 0);
7940     widget_opts.last_container = hbox;
7941     lives_box_pack_start(LIVES_BOX(box), hbox, FALSE, FALSE, LIVES_SHOULD_EXPAND_FOR(box)
7942                          ? widget_opts.packing_width : 0);
7943   }
7944 
7945   lives_widget_set_valign(hbox, LIVES_ALIGN_CENTER);
7946 
7947   if (start)
7948     lives_box_pack_start(LIVES_BOX(hbox), vbox, LIVES_SHOULD_EXPAND_EXTRA_WIDTH,
7949                          LIVES_SHOULD_EXPAND_EXTRA_WIDTH, 0);
7950   else
7951     lives_box_pack_end(LIVES_BOX(hbox), vbox, LIVES_SHOULD_EXPAND_EXTRA_WIDTH,
7952                        LIVES_SHOULD_EXPAND_EXTRA_WIDTH, 0);
7953   lives_widget_set_show_hide_parent(vbox);
7954 
7955   hbox = lives_hbox_new(FALSE, 0);
7956 
7957   if (!LIVES_SHOULD_EXPAND_EXTRA_FOR(vbox)) lives_widget_set_valign(hbox, LIVES_ALIGN_CENTER);
7958   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, LIVES_SHOULD_EXPAND_FOR(vbox) ? widget_opts.packing_height / 2 : 0);
7959   lives_widget_set_show_hide_parent(hbox);
7960   return hbox;
7961 }
7962 
7963 
lives_widget_set_frozen(LiVESWidget * widget,boolean state)7964 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_frozen(LiVESWidget * widget, boolean state) {
7965   // set insens. but w.out dimming
7966 #if GTK_CHECK_VERSION(3, 16, 0)
7967   if (state) {
7968     set_css_value_direct(widget, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.75");
7969   } else
7970     set_css_value_direct(widget, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
7971 #endif
7972   return lives_widget_set_sensitive(widget, !state);
7973 }
7974 
7975 
7976 #ifdef USE_SPECIAL_BUTTONS
7977 
7978 #define BT_PRE_WIDTH 4.0
7979 #define BT_UNPRE_WIDTH 2.0
7980 
lives_painter_psurface_destroy_cb(livespointer data)7981 static void lives_painter_psurface_destroy_cb(livespointer data) {
7982   lives_painter_surface_t **pbsurf = (lives_painter_surface_t **)data;
7983   if (pbsurf) {
7984     lives_painter_surface_t *bsurf = *pbsurf;
7985     if (bsurf) lives_painter_surface_destroy(bsurf);
7986     lives_free(pbsurf);
7987   }
7988 }
7989 
lives_widget_object_set_data_psurface(LiVESWidgetObject * obj,const char * key,livespointer data)7990 static void lives_widget_object_set_data_psurface(LiVESWidgetObject * obj, const char *key, livespointer data) {
7991   lives_widget_object_set_data_full(obj, key, data,
7992                                     (LiVESDestroyNotify)lives_painter_psurface_destroy_cb);
7993 }
7994 
sbutt_render(LiVESWidget * sbutt,LiVESWidgetState state,livespointer user_data)7995 void sbutt_render(LiVESWidget * sbutt, LiVESWidgetState state, livespointer user_data) {
7996   if (!is_standard_widget(LIVES_WIDGET(sbutt))) return;
7997   else {
7998     LiVESWidget *widget = lives_bin_get_child(LIVES_BIN(sbutt));
7999     lives_painter_surface_t **pbsurf =
8000       (lives_painter_surface_t **)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
8001           SBUTT_SURFACE_KEY);
8002     state = lives_widget_get_state(sbutt); /// get updated state
8003     if (!pbsurf || !(*pbsurf)) return;
8004     else {
8005       lives_painter_t *cr;
8006       lives_painter_surface_t *bsurf;
8007       LingoLayout *layout =
8008         (LingoLayout *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt),
8009             SBUTT_LAYOUT_KEY);
8010       lives_colRGBA64_t fg, bg, pab, pab2;
8011       LiVESWidget *toplevel = lives_widget_get_toplevel(widget);
8012       LiVESWidget *deflt = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(toplevel), DEFBUTTON_KEY);
8013       LiVESWidget *defover = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(toplevel), DEFOVERRIDE_KEY);
8014       LiVESPixbuf *pixbuf = NULL;
8015       double offs_x = 0., offs_y = 0;
8016       boolean fake_default = (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt), SBUTT_FAKEDEF_KEY)
8017                               ? TRUE : FALSE);
8018       boolean prelit = (state & LIVES_WIDGET_STATE_PRELIGHT) == 0 ? FALSE : TRUE;
8019       boolean insens = (state & LIVES_WIDGET_STATE_INSENSITIVE) == 0 ? FALSE : TRUE;
8020       boolean focused = lives_widget_is_focus(sbutt);
8021       uint32_t acc;
8022       int themetype;
8023       int width, height;
8024       int lw = 0, lh = 0, x_pos, y_pos, w_, h_;
8025       int pbw = 0, pbh = 0;
8026 
8027       if (insens) prelit = focused = FALSE;
8028 
8029       pab2.red = pab2.green = pab2.blue = 0;
8030       pab2.alpha = 1.;
8031 
8032       themetype = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt), THEME_KEY));
8033       if (themetype) {
8034         if (themetype == 1) {
8035           widget_color_to_lives_rgba(&bg, &palette->normal_back);
8036           widget_color_to_lives_rgba(&fg, &palette->normal_fore);
8037         } else {
8038           widget_color_to_lives_rgba(&bg, &palette->menu_and_bars);
8039           widget_color_to_lives_rgba(&fg, &palette->menu_and_bars_fore);
8040         }
8041         if (prefs->extra_colours && mainw->pretty_colours) {
8042           widget_color_to_lives_rgba(&pab, &palette->nice1);
8043           widget_color_to_lives_rgba(&pab2, &palette->nice2);
8044         } else {
8045           widget_color_to_lives_rgba(&pab, &palette->menu_and_bars);
8046           widget_color_to_lives_rgba(&pab2, &palette->menu_and_bars);
8047         }
8048       }
8049 
8050       bsurf = *pbsurf;
8051 
8052       width = lives_widget_get_allocation_width(widget);
8053       height = lives_widget_get_allocation_height(widget);
8054 
8055       cr = lives_painter_create_from_surface(bsurf);
8056 
8057       if (themetype) {
8058         lives_painter_set_line_width(cr, BT_PRE_WIDTH);
8059         if (prelit) lives_painter_set_source_rgb_from_lives_rgba(cr, &pab);
8060         else lives_painter_set_source_rgb_from_lives_rgba(cr, &bg);
8061         lives_painter_rectangle(cr, 0, 0, width, height);
8062         lives_painter_stroke(cr);
8063         offs_x += BT_PRE_WIDTH;
8064         offs_y += BT_PRE_WIDTH;
8065 
8066         lives_painter_set_line_width(cr, BT_UNPRE_WIDTH);
8067         lives_painter_set_source_rgb_from_lives_rgba(cr, &pab);
8068         lives_painter_rectangle(cr, offs_x, offs_y, width - offs_x * 2., height - offs_y * 2.);
8069         lives_painter_stroke(cr);
8070       } else {
8071         offs_x += BT_PRE_WIDTH;
8072         offs_y += BT_PRE_WIDTH;
8073       }
8074 
8075       offs_x += BT_UNPRE_WIDTH;
8076       offs_y += BT_UNPRE_WIDTH;
8077 
8078       /// account for rounding errors
8079       offs_x -= 2.;
8080       offs_y -= 2.;
8081 
8082       if (offs_x < 0.) offs_x = 0.;
8083       if (offs_y < 0.) offs_y = 0.;
8084 
8085       lives_painter_rectangle(cr, offs_x, offs_y, width - offs_x * 2., height - offs_y * 2.);
8086       lives_painter_clip(cr);
8087 
8088       if (widget_opts.show_button_images
8089           || (pixbuf = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt), SBUTT_FORCEIMG_KEY))) {
8090         if (!pixbuf) pixbuf = (LiVESPixbuf *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt),
8091                                 SBUTT_PIXBUF_KEY);
8092         if (pixbuf) {
8093           pbw = lives_pixbuf_get_width(pixbuf);
8094           pbh = lives_pixbuf_get_height(pixbuf);
8095         }
8096       }
8097 
8098       if (!layout) {
8099         const char *text = (const char *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt),
8100                            SBUTT_TXT_KEY);
8101         if (text) {
8102           LiVESWidget *topl;
8103           LingoContext *ctx = gtk_widget_get_pango_context(widget);
8104           char *markup, *full_markup;
8105           layout = pango_layout_new(ctx);
8106           lingo_layout_set_alignment(layout, LINGO_ALIGN_CENTER);
8107 
8108           markup = lives_markup_escape_text(text, -1);
8109           full_markup = lives_strdup_printf("<span size=\"%s\">%s</span>", widget_opts.text_size,
8110                                             markup);
8111 
8112           lingo_layout_set_markup_with_accel(layout, full_markup, -1, '_', &acc);
8113           lives_free(markup); lives_free(full_markup);
8114           if (acc) {
8115             if (LIVES_IS_FRAME(toplevel)) topl = lives_bin_get_child(LIVES_BIN(toplevel));
8116             else topl = toplevel;
8117 
8118             if (topl && LIVES_IS_WINDOW(topl)) {
8119               LiVESAccelGroup *accel_group =
8120                 (LiVESAccelGroup *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(topl), BACCL_GROUP_KEY);
8121               if (!accel_group) {
8122                 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(topl), BACCL_GROUP_KEY, accel_group);
8123                 accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
8124                 lives_window_add_accel_group(LIVES_WINDOW(topl), accel_group);
8125               } else {
8126                 uint32_t oaccl = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(topl), BACCL_ACCL_KEY));
8127                 if (oaccl) lives_widget_remove_accelerator(sbutt, accel_group, oaccl, (LiVESXModifierType)LIVES_ALT_MASK);
8128               }
8129               lives_widget_add_accelerator(sbutt, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
8130                                            acc, (LiVESXModifierType)LIVES_ALT_MASK, (LiVESAccelFlags)0);
8131               lives_widget_object_set_data(LIVES_WIDGET_OBJECT(topl), BACCL_ACCL_KEY, LIVES_INT_TO_POINTER(acc));
8132             }
8133           }
8134           lingo_layout_get_size(layout, &w_, &h_);
8135 
8136           // scale width, height to pixels
8137           lw = ((double)w_) / (double)LINGO_SCALE;
8138           lh = ((double)h_) / (double)LINGO_SCALE;
8139 
8140           lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), SBUTT_LW_KEY,
8141                                        LIVES_INT_TO_POINTER(lw));
8142           lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), SBUTT_LH_KEY,
8143                                        LIVES_INT_TO_POINTER(lh));
8144           lives_widget_object_set_data_widget_object(LIVES_WIDGET_OBJECT(widget), SBUTT_LAYOUT_KEY,
8145               (livespointer)layout);
8146         }
8147       } else {
8148         lw = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
8149                                   SBUTT_LW_KEY));
8150         lh = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget),
8151                                   SBUTT_LH_KEY));
8152       }
8153 
8154       if (focused || fake_default || (sbutt == deflt && !defover)) {
8155         if (!fake_default && deflt && sbutt != deflt) {
8156           // clear def bg
8157           lives_widget_object_set_data(LIVES_WIDGET_OBJECT(toplevel), DEFOVERRIDE_KEY, sbutt);
8158           sbutt_render(deflt, 0, NULL);
8159         }
8160         if (themetype) {
8161           lives_painter_set_source_rgb_from_lives_rgba(cr, &pab2);
8162           lives_painter_rectangle(cr, offs_x, offs_y, width - offs_x * 2., height - offs_y * 2.);
8163           lives_painter_fill(cr);
8164         }
8165       } else {
8166         if (sbutt == defover) {
8167           lives_widget_object_set_data(LIVES_WIDGET_OBJECT(toplevel), DEFOVERRIDE_KEY, NULL);
8168           if (deflt) sbutt_render(deflt, 0, NULL);
8169         }
8170         if (themetype) {
8171           lives_painter_set_source_rgb_from_lives_rgba(cr, &bg);
8172           lives_painter_rectangle(cr, offs_x, offs_y, width - offs_x * 2., height - offs_y * 2.);
8173           lives_painter_fill(cr);
8174         }
8175       }
8176 
8177       // top left of layout
8178       x_pos = (width - lw) >> 1;
8179       y_pos = (height - lh) >> 1;
8180 
8181       // if pixbuf, offset a little more
8182       if (pixbuf && lw && layout) {
8183         if (!widget_opts.swap_label)
8184           x_pos -= (pbw + widget_opts.packing_width) >> 1;
8185         else
8186           x_pos += (pbw + widget_opts.packing_width) >> 1;
8187       }
8188 
8189       if (lh && lw && layout) {
8190         layout_to_lives_painter(layout, cr, LIVES_TEXT_MODE_FOREGROUND_ONLY, &fg,
8191                                 &bg, lw, lh, x_pos, y_pos, x_pos, y_pos);
8192         if (LINGO_IS_LAYOUT(layout))
8193           lingo_painter_show_layout(cr, layout);
8194       }
8195 
8196       if (pixbuf) {
8197         if (lw && layout) {
8198           // shift to get pixbuf pos
8199           if (!widget_opts.swap_label) {
8200             x_pos += (lw + widget_opts.packing_width);
8201             if (x_pos + pbw + widget_opts.packing_width + widget_opts.border_width < width)
8202               x_pos += widget_opts.packing_width;
8203           } else {
8204             x_pos -= (pbw + widget_opts.packing_width);
8205             if (x_pos > widget_opts.packing_width + widget_opts.border_width)
8206               x_pos -= widget_opts.packing_width;
8207           }
8208         } else x_pos -= pbw >> 1;
8209         y_pos = (height - pbh) >> 1;
8210         lives_painter_set_source_pixbuf(cr, pixbuf, x_pos, y_pos);
8211         lives_painter_rectangle(cr, 0, 0, pbw, pbh);
8212         lives_painter_paint(cr);
8213       }
8214       lives_painter_destroy(cr);
8215       lives_widget_queue_draw(sbutt);
8216     }
8217   }
8218 }
8219 
8220 
lives_standard_button_set_image(LiVESButton * sbutt,LiVESWidget * img)8221 WIDGET_HELPER_GLOBAL_INLINE boolean lives_standard_button_set_image(LiVESButton * sbutt,
8222     LiVESWidget * img) {
8223   if (!is_standard_widget(LIVES_WIDGET(sbutt))) return lives_button_set_image(sbutt, img);
8224 
8225   if (img) {
8226     LiVESPixbuf *pixbuf = lives_image_get_pixbuf(LIVES_IMAGE(img));
8227     if (LIVES_IS_PIXBUF(pixbuf)) lives_widget_object_set_data_widget_object(LIVES_WIDGET_OBJECT(sbutt),
8228           SBUTT_PIXBUF_KEY, (livespointer)pixbuf);
8229     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(sbutt),
8230                                  SBUTT_FORCEIMG_KEY, pixbuf);
8231   } else {
8232     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(sbutt),
8233                                  SBUTT_PIXBUF_KEY, NULL);
8234     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(sbutt),
8235                                  SBUTT_FORCEIMG_KEY, NULL);
8236   }
8237   sbutt_render(LIVES_WIDGET(sbutt), 0, NULL);
8238   return TRUE;
8239 }
8240 
8241 
lives_standard_button_new(int width,int height)8242 LiVESWidget *lives_standard_button_new(int width, int height) {
8243   lives_painter_surface_t **pbsurf =
8244     (lives_painter_surface_t **)lives_calloc(1, sizeof(lives_painter_surface_t *));
8245   LiVESWidget *button, *da;
8246 
8247   button = lives_button_new();
8248 
8249   if (widget_opts.apply_theme) {
8250     set_standard_widget(button, TRUE);
8251 
8252     if (palette->style & STYLE_LIGHT)
8253       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(button), THEME_KEY,
8254                                    LIVES_INT_TO_POINTER(2));
8255     else
8256       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(button), THEME_KEY,
8257                                    LIVES_INT_TO_POINTER(widget_opts.apply_theme));
8258 
8259 #if GTK_CHECK_VERSION(3, 16, 0)
8260     set_css_min_size(button, width, height);
8261     set_css_value_direct(button, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8262 
8263     lives_widget_set_padding(button, 0);
8264     set_css_value_direct(button, LIVES_WIDGET_STATE_NORMAL, "", "background", "none");
8265     set_css_value_direct(button, LIVES_WIDGET_STATE_NORMAL, "", "border-width", "0px");
8266 #endif
8267   }
8268 
8269   da = lives_standard_drawing_area_new(LIVES_GUI_CALLBACK(all_expose), pbsurf);
8270   lives_widget_object_set_data_psurface(LIVES_WIDGET_OBJECT(da),
8271                                         SBUTT_SURFACE_KEY, (livespointer)pbsurf);
8272 
8273   lives_container_add(LIVES_CONTAINER(button), da);
8274   lives_widget_set_show_hide_with(button, da);
8275 
8276   lives_widget_set_can_focus_and_default(button);
8277 
8278   lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_STATE_CHANGED_SIGNAL,
8279                             LIVES_GUI_CALLBACK(sbutt_render), NULL);
8280 #ifdef USE_SPECIAL_BUTTONS
8281   lives_widget_apply_theme(button, LIVES_WIDGET_STATE_NORMAL);
8282 #endif
8283   lives_widget_set_app_paintable(button, TRUE);
8284   lives_widget_set_app_paintable(da, TRUE);
8285   lives_widget_set_size_request(button, width, height);
8286 
8287   return button;
8288 }
8289 
lives_standard_button_set_label(LiVESButton * sbutt,const char * txt)8290 WIDGET_HELPER_GLOBAL_INLINE boolean lives_standard_button_set_label(LiVESButton * sbutt,
8291     const char *txt) {
8292   if (!is_standard_widget(LIVES_WIDGET(sbutt))) return lives_button_set_label(sbutt, txt);
8293   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(sbutt), SBUTT_LAYOUT_KEY, NULL);
8294   lives_widget_object_set_data_auto(LIVES_WIDGET_OBJECT(sbutt), SBUTT_TXT_KEY,
8295                                     txt ? lives_strdup(txt) : NULL);
8296   lives_widget_queue_draw(LIVES_WIDGET(sbutt));
8297   return TRUE;
8298 }
8299 
lives_standard_button_new_with_label(const char * txt,int width,int height)8300 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_button_new_with_label(const char *txt,
8301     int width, int height) {
8302   LiVESWidget *sbutt = lives_standard_button_new(width, height);
8303   lives_standard_button_set_label(LIVES_BUTTON(sbutt), txt);
8304   return sbutt;
8305 }
8306 
lives_standard_button_get_label(LiVESButton * sbutt)8307 WIDGET_HELPER_GLOBAL_INLINE const char *lives_standard_button_get_label(LiVESButton * sbutt) {
8308   if (!is_standard_widget(LIVES_WIDGET(sbutt))) return lives_button_get_label(sbutt);
8309   return lives_widget_object_get_data(LIVES_WIDGET_OBJECT(sbutt), SBUTT_TXT_KEY);
8310 }
8311 #endif
8312 
8313 
8314 
_lives_standard_button_set_full(LiVESWidget * sbutt,LiVESBox * box,boolean fake_default,const char * ttips)8315 static LiVESWidget *_lives_standard_button_set_full(LiVESWidget * sbutt, LiVESBox * box,
8316     boolean fake_default, const char *ttips) {
8317   LiVESWidget *img_tips = NULL, *hbox;
8318 
8319   if (ttips) img_tips = lives_widget_set_tooltip_text(sbutt, ttips);
8320 
8321   lives_button_set_focus_on_click(LIVES_BUTTON(sbutt), FALSE);
8322 
8323   if (box) {
8324     LiVESWidget *layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(box), WH_LAYOUT_KEY);
8325     int packing_width = 0;
8326     boolean expand;
8327 
8328     if (layout) {
8329       box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
8330       hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
8331       lives_widget_set_show_hide_with(sbutt, hbox);
8332     } else hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
8333 
8334     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
8335     if (expand) add_fill_to_box(LIVES_BOX(hbox));
8336     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
8337 
8338     lives_widget_set_hexpand(sbutt, FALSE);
8339     lives_widget_set_valign(sbutt, LIVES_ALIGN_CENTER);
8340 
8341     lives_box_pack_start(LIVES_BOX(hbox), sbutt, LIVES_SHOULD_EXPAND_WIDTH,
8342                          expand, packing_width);
8343 
8344     if (expand) add_fill_to_box(LIVES_BOX(hbox));
8345     lives_widget_set_show_hide_parent(sbutt);
8346 
8347     add_warn_image(sbutt, hbox);
8348     if (img_tips) {
8349       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
8350     }
8351   }
8352 
8353 #ifdef USE_SPECIAL_BUTTONS
8354   if (is_standard_widget(LIVES_WIDGET(sbutt))) {
8355     if (fake_default) {
8356       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(LIVES_WIDGET_OBJECT(sbutt)),
8357                                    SBUTT_FAKEDEF_KEY, sbutt);
8358     }
8359     sbutt_render(sbutt, 0, NULL);
8360 #endif
8361   }
8362   return sbutt;
8363 }
8364 
8365 
lives_standard_button_new_full(const char * label,int width,int height,LiVESBox * box,boolean fake_default,const char * ttips)8366 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_button_new_full(const char *label, int width,
8367     int height, LiVESBox * box,
8368     boolean fake_default,
8369     const char *ttips) {
8370   LiVESWidget *sbutt = lives_standard_button_new_with_label(label, width, height);
8371   return _lives_standard_button_set_full(sbutt, box, fake_default, ttips);
8372 }
8373 
8374 
lives_standard_button_new_from_stock_full(const char * stock_id,const char * label,int width,int height,LiVESBox * box,boolean fake_default,const char * ttips)8375 LiVESWidget *lives_standard_button_new_from_stock_full(const char *stock_id, const char *label,
8376     int width, int height,  LiVESBox * box,
8377     boolean fake_default,
8378     const char *ttips) {
8379   LiVESWidget *sbutt = lives_standard_button_new_from_stock(stock_id, label, width, height);
8380   return _lives_standard_button_set_full(sbutt, box, fake_default, ttips);
8381 }
8382 
lives_standard_hpaned_new(void)8383 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_hpaned_new(void) {
8384   LiVESWidget *hpaned;
8385 #ifdef GUI_GTK
8386 #if !GTK_CHECK_VERSION(3, 0, 0)
8387   hpaned = lives_hpaned_new();
8388 #else
8389   hpaned = gtk_paned_new(LIVES_ORIENTATION_HORIZONTAL);
8390   gtk_paned_set_wide_handle(GTK_PANED(hpaned), TRUE);
8391   if (widget_opts.apply_theme) {
8392     set_standard_widget(hpaned, TRUE);
8393 #if GTK_CHECK_VERSION(3, 16, 0)
8394     if (prefs->extra_colours && mainw->pretty_colours) {
8395       char *colref = gdk_rgba_to_string(&palette->nice1);
8396       // clear background image
8397       char *tmp = lives_strdup_printf("image(%s)", colref);
8398       set_css_value_direct(hpaned, LIVES_WIDGET_STATE_NORMAL, "separator",
8399                            "background-image", tmp);
8400       lives_free(tmp);
8401       lives_free(colref);
8402     }
8403 #endif
8404   }
8405 #endif
8406 #endif
8407   return hpaned;
8408 }
8409 
lives_standard_vpaned_new(void)8410 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_vpaned_new(void) {
8411   LiVESWidget *vpaned;
8412 #ifdef GUI_GTK
8413 #if GTK_CHECK_VERSION(3, 0, 0)
8414   vpaned = lives_vpaned_new();
8415 #else
8416   vpaned = gtk_paned_new(LIVES_ORIENTATION_VERTICAL);
8417   gtk_paned_set_wide_handle(GTK_PANED(vpaned), TRUE);
8418   if (widget_opts.apply_theme) {
8419     set_standard_widget(vpaned, TRUE);
8420 #if GTK_CHECK_VERSION(3, 16, 0)
8421     if (prefs->extra_colours && mainw->pretty_colours) {
8422       char *colref = gdk_rgba_to_string(&palette->nice1);
8423       // clear background image
8424       char *tmp = lives_strdup_printf("image(%s)", colref);
8425       set_css_value_direct(vpaned, LIVES_WIDGET_STATE_NORMAL, "separator",
8426                            "background-image", tmp);
8427       lives_free(tmp);
8428       lives_free(colref);
8429     }
8430 #endif
8431   }
8432 #endif
8433 #endif
8434   return vpaned;
8435 }
8436 
8437 
lives_standard_menu_new(void)8438 LiVESWidget *lives_standard_menu_new(void) {
8439   LiVESWidget *menu = lives_menu_new();
8440   if (menu) {
8441     if (widget_opts.apply_theme) {
8442       set_standard_widget(menu, TRUE);
8443       lives_widget_apply_theme2(menu, LIVES_WIDGET_STATE_NORMAL, TRUE);
8444 #if !GTK_CHECK_VERSION(3, 16, 0)
8445       lives_widget_apply_theme_dimmed2(menu, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8446       set_child_dimmed_colour2(menu, BUTTON_DIM_VAL);
8447 #else
8448       set_css_value_direct(menu, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8449 #endif
8450     }
8451   }
8452   return menu;
8453 }
8454 
8455 
lives_standard_menu_item_new(void)8456 LiVESWidget *lives_standard_menu_item_new(void) {
8457   LiVESWidget *menuitem = lives_menu_item_new();
8458   if (menuitem) {
8459     if (widget_opts.apply_theme) {
8460       set_standard_widget(menuitem, TRUE);
8461       lives_widget_apply_theme2(menuitem, LIVES_WIDGET_STATE_NORMAL, TRUE);
8462 #if !GTK_CHECK_VERSION(3, 16, 0)
8463       lives_widget_apply_theme_dimmed2(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8464       set_child_dimmed_colour2(menuitem, BUTTON_DIM_VAL);
8465 #else
8466       set_css_value_direct(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8467 #endif
8468     }
8469   }
8470   return menuitem;
8471 }
8472 
8473 
lives_standard_menu_item_new_with_label(const char * label)8474 LiVESWidget *lives_standard_menu_item_new_with_label(const char *label) {
8475   LiVESWidget *menuitem = lives_menu_item_new_with_label(label);
8476   if (menuitem) {
8477     if (widget_opts.apply_theme) {
8478       set_standard_widget(menuitem, TRUE);
8479       lives_widget_apply_theme2(menuitem, LIVES_WIDGET_STATE_NORMAL, TRUE);
8480 #if !GTK_CHECK_VERSION(3, 16, 0)
8481       lives_widget_apply_theme_dimmed2(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8482       set_child_dimmed_colour2(menuitem, BUTTON_DIM_VAL);
8483 #else
8484       set_css_value_direct(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8485 #endif
8486     }
8487   }
8488   return menuitem;
8489 }
8490 
8491 
lives_standard_image_menu_item_new_with_label(const char * label)8492 LiVESWidget *lives_standard_image_menu_item_new_with_label(const char *label) {
8493   LiVESWidget *menuitem = lives_image_menu_item_new_with_label(label);
8494   if (menuitem) {
8495     if (widget_opts.apply_theme) {
8496       set_standard_widget(menuitem, TRUE);
8497       lives_widget_apply_theme2(menuitem, LIVES_WIDGET_STATE_NORMAL, TRUE);
8498 #if !GTK_CHECK_VERSION(3, 16, 0)
8499       lives_widget_apply_theme_dimmed2(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8500       set_child_dimmed_colour2(menuitem, BUTTON_DIM_VAL);
8501 #else
8502       set_css_value_direct(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8503 #endif
8504     }
8505   }
8506   return menuitem;
8507 }
8508 
8509 
8510 
lives_standard_image_menu_item_new_from_stock(const char * stock_id,LiVESAccelGroup * accel_group)8511 LiVESWidget *lives_standard_image_menu_item_new_from_stock(const char *stock_id, LiVESAccelGroup * accel_group) {
8512   LiVESWidget *menuitem = lives_image_menu_item_new_from_stock(stock_id, accel_group);
8513   if (menuitem) {
8514     if (widget_opts.apply_theme) {
8515       set_standard_widget(menuitem, TRUE);
8516       lives_widget_apply_theme2(menuitem, LIVES_WIDGET_STATE_NORMAL, TRUE);
8517 #if !GTK_CHECK_VERSION(3, 16, 0)
8518       lives_widget_apply_theme_dimmed2(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8519       set_child_dimmed_colour2(menuitem, BUTTON_DIM_VAL);
8520 #else
8521       set_css_value_direct(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8522 #endif
8523     }
8524   }
8525   return menuitem;
8526 }
8527 
8528 
lives_standard_radio_menu_item_new_with_label(LiVESSList * group,const char * label)8529 LiVESWidget *lives_standard_radio_menu_item_new_with_label(LiVESSList * group, const char *label) {
8530   LiVESWidget *menuitem = lives_radio_menu_item_new_with_label(group, label);
8531   if (menuitem) {
8532     if (widget_opts.apply_theme) {
8533       set_standard_widget(menuitem, TRUE);
8534       lives_widget_apply_theme2(menuitem, LIVES_WIDGET_STATE_NORMAL, TRUE);
8535 #if !GTK_CHECK_VERSION(3, 16, 0)
8536       lives_widget_apply_theme_dimmed2(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8537       set_child_dimmed_colour2(menuitem, BUTTON_DIM_VAL);
8538 #else
8539       set_css_value_direct(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8540 #endif
8541     }
8542   }
8543   return menuitem;
8544 }
8545 
8546 
lives_standard_check_menu_item_new_with_label(const char * label,boolean active)8547 LiVESWidget *lives_standard_check_menu_item_new_with_label(const char *label, boolean active) {
8548   LiVESWidget *menuitem = lives_check_menu_item_new_with_label(label);
8549   lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(menuitem), active);
8550   if (menuitem) {
8551     if (widget_opts.apply_theme) {
8552       set_standard_widget(menuitem, TRUE);
8553       lives_widget_apply_theme2(menuitem, LIVES_WIDGET_STATE_NORMAL, TRUE);
8554 #if !GTK_CHECK_VERSION(3, 16, 0)
8555       lives_widget_apply_theme_dimmed2(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
8556       set_child_dimmed_colour2(menuitem, BUTTON_DIM_VAL);
8557 #else
8558       set_css_value_direct(menuitem, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8559 #endif
8560     }
8561   }
8562   return menuitem;
8563 }
8564 
togglevar_cb(LiVESWidget * w,boolean * var)8565 static void togglevar_cb(LiVESWidget * w, boolean * var) {if (var) *var = !(*var);}
8566 
8567 LiVESWidget *
lives_standard_check_menu_item_new_for_var(const char * labeltext,boolean * var,boolean invert)8568 lives_standard_check_menu_item_new_for_var(const char *labeltext, boolean * var, boolean invert) {
8569   LiVESWidget *mi = lives_standard_check_menu_item_new_with_label(labeltext, TRUE);
8570   if (invert) lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mi), !(*var));
8571   else lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mi), *var);
8572   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(mi), LIVES_WIDGET_TOGGLED_SIGNAL,
8573                                   LIVES_GUI_CALLBACK(togglevar_cb),
8574                                   (livespointer)var);
8575   return mi;
8576 }
8577 
8578 
lives_standard_notebook_new(const LiVESWidgetColor * bg_color,const LiVESWidgetColor * act_color)8579 LiVESWidget *lives_standard_notebook_new(const LiVESWidgetColor * bg_color, const LiVESWidgetColor * act_color) {
8580   LiVESWidget *notebook = lives_notebook_new();
8581 
8582 #if GTK_CHECK_VERSION(3, 16, 0)
8583   if (widget_opts.apply_theme) {
8584     char *colref = gdk_rgba_to_string(bg_color);
8585     set_standard_widget(notebook, TRUE);
8586     // clear background image
8587     set_css_value_direct(notebook, LIVES_WIDGET_STATE_NORMAL, "*", "background", "none");
8588     set_css_value_direct(notebook, LIVES_WIDGET_STATE_NORMAL, "*", "background-color", colref);
8589     lives_free(colref);
8590     colref = gdk_rgba_to_string(act_color);
8591     set_css_value_direct(notebook, LIVES_WIDGET_STATE_ACTIVE, "*", "background", "none");
8592     set_css_value_direct(notebook, LIVES_WIDGET_STATE_ACTIVE, "*", "background-color", colref);
8593     lives_free(colref);
8594   }
8595 #endif
8596   lives_widget_set_hexpand(notebook, TRUE);
8597   return notebook;
8598 }
8599 
8600 
lives_standard_label_new(const char * text)8601 LiVESWidget *lives_standard_label_new(const char *text) {
8602   LiVESWidget *label = NULL;
8603   label = lives_label_new(NULL);
8604   // allows markup
8605 
8606   if (text) lives_label_set_text(LIVES_LABEL(label), text);
8607   lives_widget_set_text_size(label, LIVES_WIDGET_STATE_NORMAL, widget_opts.text_size);
8608   lives_widget_set_halign(label, lives_justify_to_align(widget_opts.justify));
8609   if (widget_opts.apply_theme) {
8610     set_standard_widget(label, TRUE);
8611 #if !GTK_CHECK_VERSION(3, 24, 0)
8612     // non functional in gtk 3.18
8613     set_child_dimmed_colour(label, BUTTON_DIM_VAL);
8614     set_child_colour(label, TRUE);
8615 #else
8616     set_css_value_direct(label, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
8617 #endif
8618 
8619     if (widget_opts.apply_theme == 2) lives_widget_apply_theme2(label, LIVES_WIDGET_STATE_NORMAL, TRUE);
8620     else lives_widget_apply_theme(label, LIVES_WIDGET_STATE_NORMAL);
8621 
8622 #if !GTK_CHECK_VERSION(3, 16, 0)
8623     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(label), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
8624                                     LIVES_GUI_CALLBACK(widget_state_cb),
8625                                     NULL);
8626     widget_state_cb(LIVES_WIDGET_OBJECT(label), NULL, NULL);
8627 #endif
8628   }
8629   return label;
8630 }
8631 
8632 
lives_standard_label_new_with_tooltips(const char * text,LiVESBox * box,const char * tips)8633 LiVESWidget *lives_standard_label_new_with_tooltips(const char *text, LiVESBox * box,
8634     const char *tips) {
8635   LiVESWidget *label = lives_standard_label_new(text);
8636   LiVESWidget *img_tips = make_ttips_image_for(label, tips);
8637   LiVESWidget *hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
8638   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
8639   if (img_tips) {
8640     add_warn_image(label, hbox);
8641     lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
8642   }
8643   lives_widget_set_show_hide_parent(label);
8644   return label;
8645 }
8646 
8647 
lives_big_and_bold(const char * fmt,...)8648 char *lives_big_and_bold(const char *fmt, ...) {
8649   va_list xargs;
8650   char *text, *text2, *text3;
8651   va_start(xargs, fmt);
8652   text = lives_strdup_vprintf(fmt, xargs);
8653   va_end(xargs);
8654   text2 = lives_markup_escape_text(text, -1);
8655   lives_free(text);
8656   text3 = lives_strdup_printf("<big><b>%s</b></big>", text2);
8657   lives_free(text2);
8658   return text3;
8659 }
8660 
8661 
lives_standard_formatted_label_new(const char * text)8662 LiVESWidget *lives_standard_formatted_label_new(const char *text) {
8663   LiVESWidget *label;
8664   char *form_text;
8665   form_text = lives_strdup_printf("\n%s\n", text);
8666 
8667   widget_opts.justify = LIVES_JUSTIFY_CENTER;
8668   widget_opts.mnemonic_label = FALSE;
8669   label = lives_standard_label_new(NULL);
8670   if (widget_opts.use_markup)
8671     lives_label_set_markup(LIVES_LABEL(label), form_text);
8672   else
8673     lives_label_set_text(LIVES_LABEL(label), form_text);
8674   widget_opts.mnemonic_label = TRUE;
8675   widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
8676   if (lives_strlen(text) < MIN_MSG_WIDTH_CHARS) {
8677     lives_label_set_width_chars(LIVES_LABEL(label), MIN_MSG_WIDTH_CHARS);
8678   }
8679 
8680   lives_free(form_text);
8681   return label;
8682 }
8683 
8684 
lives_label_chomp(LiVESLabel * label)8685 LIVES_GLOBAL_INLINE void lives_label_chomp(LiVESLabel * label) {
8686   char *txt = lives_strdup(lives_label_get_text(label));
8687   lives_chomp(txt);
8688   lives_label_set_text(label, txt);
8689   lives_free(txt);
8690 }
8691 
8692 
lives_standard_drawing_area_new(LiVESGuiCallback callback,lives_painter_surface_t ** ppsurf)8693 LiVESWidget *lives_standard_drawing_area_new(LiVESGuiCallback callback, lives_painter_surface_t **ppsurf) {
8694   LiVESWidget *darea = NULL;
8695 #ifdef GUI_GTK
8696   darea = gtk_drawing_area_new();
8697   lives_widget_set_app_paintable(darea, TRUE);
8698   if (ppsurf) {
8699     if (callback)
8700 #if GTK_CHECK_VERSION(4, 0, 0)
8701       gtk_drawing_area_set_draw_func(darea, callback, (livespointer)ppsurf, NULL);
8702 #else
8703       lives_signal_connect(LIVES_GUI_OBJECT(darea), LIVES_WIDGET_EXPOSE_EVENT,
8704                            LIVES_GUI_CALLBACK(callback),
8705                            (livespointer)ppsurf);
8706 #endif
8707     lives_signal_sync_connect(LIVES_GUI_OBJECT(darea), LIVES_WIDGET_CONFIGURE_EVENT,
8708                               LIVES_GUI_CALLBACK(all_config),
8709                               (livespointer)ppsurf);
8710   }
8711   if (widget_opts.apply_theme) {
8712     set_standard_widget(darea, TRUE);
8713     lives_widget_apply_theme(darea, LIVES_WIDGET_STATE_NORMAL);
8714   }
8715 #endif
8716   return darea;
8717 }
8718 
8719 
lives_standard_label_new_with_mnemonic_widget(const char * text,LiVESWidget * mnemonic_widget)8720 LiVESWidget *lives_standard_label_new_with_mnemonic_widget(const char *text, LiVESWidget * mnemonic_widget) {
8721   LiVESWidget *label = NULL;
8722 
8723   label = lives_standard_label_new("");
8724   lives_label_set_text(LIVES_LABEL(label), text);
8725 
8726   if (mnemonic_widget) lives_label_set_mnemonic_widget(LIVES_LABEL(label), mnemonic_widget);
8727 
8728   return label;
8729 }
8730 
8731 
lives_standard_frame_new(const char * labeltext,float xalign,boolean invis)8732 LiVESWidget *lives_standard_frame_new(const char *labeltext, float xalign, boolean invis) {
8733   LiVESWidget *frame = lives_frame_new(NULL);
8734   LiVESWidget *label = NULL;
8735 
8736   if (LIVES_SHOULD_EXPAND)
8737     lives_container_set_border_width(LIVES_CONTAINER(frame), widget_opts.border_width);
8738 
8739   if (labeltext) {
8740     label = lives_standard_label_new(labeltext);
8741     lives_frame_set_label_widget(LIVES_FRAME(frame), label);
8742   }
8743 
8744   widget_opts.last_label = label;
8745 
8746   if (invis) lives_frame_set_shadow_type(LIVES_FRAME(frame), LIVES_SHADOW_NONE);
8747 
8748   if (widget_opts.apply_theme) {
8749     set_standard_widget(frame, TRUE);
8750     lives_widget_apply_theme(frame, LIVES_WIDGET_STATE_NORMAL);
8751     lives_widget_set_text_color(frame, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
8752 
8753 #if !GTK_CHECK_VERSION(3, 24, 0)
8754     if (prefs->extra_colours && mainw->pretty_colours)
8755       lives_widget_set_bg_color(frame, LIVES_WIDGET_STATE_NORMAL, &palette->nice1);
8756     else
8757       lives_widget_set_bg_color(frame, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
8758 #else
8759     if (prefs->extra_colours && mainw->pretty_colours) {
8760       char *colref = gdk_rgba_to_string(&palette->nice1);
8761       set_css_value_direct(frame, LIVES_WIDGET_STATE_NORMAL, "border",
8762                            "border-color", colref);
8763       lives_free(colref);
8764     } else {
8765       char *colref = gdk_rgba_to_string(&palette->menu_and_bars);
8766       set_css_value_direct(frame, LIVES_WIDGET_STATE_NORMAL, "border",
8767                            "border-color", colref);
8768       lives_free(colref);
8769     }
8770 #endif
8771   }
8772   if (xalign >= 0.) lives_frame_set_label_align(LIVES_FRAME(frame), xalign, 0.5);
8773 
8774   return frame;
8775 }
8776 
8777 
lives_justify_to_align(LiVESJustification justify)8778 WIDGET_HELPER_GLOBAL_INLINE LiVESAlign lives_justify_to_align(LiVESJustification justify) {
8779   if (justify == LIVES_JUSTIFY_DEFAULT) return LIVES_ALIGN_START;
8780   if (justify == LIVES_JUSTIFY_CENTER) return LIVES_ALIGN_CENTER;
8781   else return LIVES_ALIGN_END;
8782 }
8783 
8784 
lives_get_scroll_direction(LiVESXEventScroll * event)8785 WIDGET_HELPER_GLOBAL_INLINE LiVESScrollDirection lives_get_scroll_direction(LiVESXEventScroll * event) {
8786 #ifdef GUI_GTK
8787 #if GTK_CHECK_VERSION(3, 4, 0)
8788   double dx, dy;
8789   if (gdk_event_get_scroll_deltas(LIVES_XEVENT(event), &dx, &dy)) {
8790     if (dy < 0.) return LIVES_SCROLL_UP;
8791     if (dy > 0.) return LIVES_SCROLL_DOWN;
8792   }
8793 #endif
8794 #if GTK_CHECK_VERSION(3, 2, 0)
8795   LiVESScrollDirection direction;
8796   gdk_event_get_scroll_direction(LIVES_XEVENT(event), &direction);
8797   return direction;
8798 #else
8799   return event->direction;
8800 #endif
8801 #endif
8802   return LIVES_SCROLL_UP;
8803 }
8804 
8805 
_make_label_eventbox(const char * labeltext,LiVESWidget * widget,boolean add_sens)8806 static LiVESWidget *_make_label_eventbox(const char *labeltext, LiVESWidget * widget, boolean add_sens) {
8807   LiVESWidget *label;
8808   LiVESWidget *eventbox = lives_event_box_new();
8809   if (widget) lives_tooltips_copy(eventbox, widget);
8810   if (widget && widget_opts.mnemonic_label && labeltext) {
8811     label = lives_standard_label_new_with_mnemonic_widget(labeltext, widget);
8812   } else label = lives_standard_label_new(labeltext);
8813 
8814   widget_opts.last_label = label;
8815   lives_container_add(LIVES_CONTAINER(eventbox), label);
8816   lives_widget_set_halign(label, lives_justify_to_align(widget_opts.justify));
8817 
8818   if (widget && (LIVES_IS_TOGGLE_BUTTON(widget) || LIVES_IS_TOGGLE_TOOL_BUTTON(widget))) {
8819     lives_signal_sync_connect(LIVES_GUI_OBJECT(eventbox), LIVES_WIDGET_BUTTON_PRESS_EVENT,
8820                               LIVES_GUI_CALLBACK(label_act_toggle),
8821                               widget);
8822   }
8823   if (add_sens) {
8824     lives_widget_set_sensitive_with(widget, eventbox);
8825     lives_widget_set_sensitive_with(eventbox, label);
8826   }
8827   lives_widget_set_show_hide_with(widget, eventbox);
8828   lives_widget_set_show_hide_with(eventbox, label);
8829   if (widget_opts.apply_theme) {
8830     // default themeing
8831     lives_widget_apply_theme(eventbox, LIVES_WIDGET_STATE_NORMAL);
8832     lives_widget_apply_theme(eventbox, LIVES_WIDGET_STATE_INSENSITIVE);
8833 
8834 #if !GTK_CHECK_VERSION(3, 16, 0)
8835     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(label), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
8836                                     LIVES_GUI_CALLBACK(widget_state_cb), NULL);
8837 #endif
8838   }
8839   return eventbox;
8840 }
8841 
make_label_eventbox(const char * labeltext,LiVESWidget * widget)8842 WIDGET_HELPER_LOCAL_INLINE LiVESWidget *make_label_eventbox(const char *labeltext, LiVESWidget * widget) {
8843   return _make_label_eventbox(labeltext, widget, TRUE);
8844 }
8845 
8846 
sens_insens_cb(LiVESWidgetObject * object,livespointer pspec,livespointer user_data)8847 static void sens_insens_cb(LiVESWidgetObject * object, livespointer pspec, livespointer user_data) {
8848   LiVESWidget *widget = (LiVESWidget *)object;
8849   LiVESWidget *other = (LiVESWidget *)user_data;
8850   boolean sensitive = lives_widget_get_sensitive(widget);
8851   if (lives_widget_get_sensitive(other) != sensitive) {
8852     lives_widget_set_sensitive(other, sensitive);
8853   }
8854 }
8855 
8856 
lives_widget_set_sensitive_with(LiVESWidget * w1,LiVESWidget * w2)8857 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive_with(LiVESWidget * w1, LiVESWidget * w2) {
8858   // set w2 sensitivity == w1
8859   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(w1), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
8860                                   LIVES_GUI_CALLBACK(sens_insens_cb),
8861                                   (livespointer)w2);
8862   return TRUE;
8863 }
8864 
8865 
lives_widget_show_all_cb(LiVESWidget * other,livespointer user_data)8866 static void lives_widget_show_all_cb(LiVESWidget * other, livespointer user_data) {
8867   LiVESWidget *controller;
8868 
8869   if (LIVES_IS_WIDGET_OBJECT(other)) {
8870     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(other), SHOWALL_OVERRIDE_KEY)) return;
8871     controller = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(other),
8872                  SHOWHIDE_CONTROLLER_KEY);
8873     if (controller) {
8874       if (lives_widget_get_no_show_all(controller)) {
8875         lives_widget_set_no_show_all(other, TRUE);
8876         lives_widget_hide(other);
8877         return;
8878       }
8879     }
8880     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(other), TTIPS_HIDE_KEY)) {
8881       if (prefs->show_tooltips) {
8882         lives_widget_set_no_show_all(other, FALSE);
8883         lives_widget_show(other);
8884       }
8885       return;
8886     }
8887 
8888     if (controller && !lives_widget_get_no_show_all(controller)) {
8889       if (lives_widget_get_no_show_all(other)) {
8890         lives_widget_set_no_show_all(other, FALSE);
8891       }
8892     }
8893     /* if (!lives_widget_is_visible(widget)) { */
8894     /*   lives_widget_show_all(widget); */
8895     /* } */
8896     if (!lives_widget_is_visible(other)) {
8897       lives_widget_show_all(other);
8898     }
8899   }
8900 }
8901 
lives_widget_set_show_hide_with(LiVESWidget * widget,LiVESWidget * other)8902 boolean lives_widget_set_show_hide_with(LiVESWidget * widget, LiVESWidget * other) {
8903   // show / hide the other widget when and only when the child is shown / hidden
8904   if (!widget || !other) return FALSE;
8905   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(other),
8906                                SHOWHIDE_CONTROLLER_KEY, widget);
8907   if (!widget_opts.no_gui) {
8908     lives_signal_sync_connect(LIVES_GUI_OBJECT(other), LIVES_WIDGET_SHOW_SIGNAL,
8909                               LIVES_GUI_CALLBACK(lives_widget_show_all_cb),
8910                               (livespointer)(widget));
8911 
8912     lives_signal_sync_connect_swapped(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_SHOW_SIGNAL,
8913                                       LIVES_GUI_CALLBACK(lives_widget_show_all_cb),
8914                                       (livespointer)(other));
8915 
8916     lives_signal_sync_connect_swapped(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_HIDE_SIGNAL,
8917                                       LIVES_GUI_CALLBACK(lives_widget_hide),
8918                                       (livespointer)(other));
8919   }
8920   return TRUE;
8921 }
8922 
8923 
lives_widget_unset_show_hide_with(LiVESWidget * widget,LiVESWidget * other)8924 boolean lives_widget_unset_show_hide_with(LiVESWidget * widget, LiVESWidget * other) {
8925   // show / hide the other widget when and only when the child is shown / hidden
8926   if (!widget || !other) return FALSE;
8927   lives_signal_handlers_sync_disconnect_by_func
8928   (widget, LIVES_GUI_CALLBACK(lives_widget_show_all_cb), (livespointer)other);
8929   lives_signal_handlers_sync_disconnect_by_func
8930   (other, LIVES_GUI_CALLBACK(lives_widget_show_all_cb), (livespointer)widget);
8931   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(other),
8932                                SHOWHIDE_CONTROLLER_KEY, NULL);
8933   return TRUE;
8934 }
8935 
8936 
lives_widget_set_show_hide_parent(LiVESWidget * widget)8937 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_show_hide_parent(LiVESWidget * widget) {
8938   LiVESWidget *parent = lives_widget_get_parent(widget);
8939   if (parent) return lives_widget_set_show_hide_with(widget, parent);
8940   return FALSE;
8941 }
8942 
8943 
lives_standard_switch_new(const char * labeltext,boolean active,LiVESBox * box,const char * tooltip)8944 LiVESWidget *lives_standard_switch_new(const char *labeltext, boolean active, LiVESBox * box,
8945                                        const char *tooltip) {
8946   LiVESWidget *swtch = NULL;
8947 #if !LIVES_HAS_SWITCH_WIDGET
8948   return lives_standard_check_button_new(labeltext, active, box, tooltip);
8949 #else
8950   LiVESWidget *eventbox = NULL;
8951   LiVESWidget *container = NULL;
8952   LiVESWidget *hbox;
8953   LiVESWidget *img_tips = NULL;
8954 
8955 #if GTK_CHECK_VERSION(3, 14, 0)
8956   char *colref;
8957 #endif
8958   //char *tmp;
8959 
8960   boolean expand;
8961 
8962   swtch = lives_switch_new();
8963 
8964   widget_opts.last_label = NULL;
8965 
8966   if (tooltip) img_tips = lives_widget_set_tooltip_text(swtch, tooltip);
8967 
8968   if (box) {
8969     int packing_width = 0;
8970 
8971     if (labeltext) {
8972       eventbox = make_label_eventbox(labeltext, swtch);
8973       lives_widget_set_show_hide_with(swtch, eventbox);
8974     }
8975 
8976     hbox = make_inner_hbox(LIVES_BOX(box), !widget_opts.swap_label);
8977     lives_widget_set_show_hide_parent(swtch);
8978     container = widget_opts.last_container;
8979 
8980     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
8981     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
8982 
8983     if (widget_opts.swap_label && eventbox)
8984       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
8985 
8986     if (expand) add_fill_to_box(LIVES_BOX(hbox));
8987 
8988     lives_box_pack_start(LIVES_BOX(hbox), swtch, expand, expand,
8989                          !eventbox ? packing_width : 0);
8990 
8991     if (expand) add_fill_to_box(LIVES_BOX(hbox));
8992 
8993     if (!widget_opts.swap_label && eventbox)
8994       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
8995 
8996     add_warn_image(swtch, hbox);
8997 
8998     if (img_tips) {
8999       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
9000     }
9001   }
9002 
9003   if (widget_opts.apply_theme) {
9004 #if GTK_CHECK_VERSION(3, 0, 0)
9005 #if GTK_CHECK_VERSION(3, 16, 0)
9006     char *tmp;
9007 #endif
9008     set_standard_widget(swtch, TRUE);
9009     lives_widget_apply_theme(swtch, LIVES_WIDGET_STATE_NORMAL);
9010     set_css_min_size(swtch, widget_opts.css_min_width, widget_opts.css_min_height);
9011 
9012 #if GTK_CHECK_VERSION(3, 16, 0)
9013     if (prefs->extra_colours && mainw->pretty_colours) {
9014       lives_widget_set_border_color(swtch, LIVES_WIDGET_STATE_NORMAL, &palette->nice1);
9015 
9016       colref = gdk_rgba_to_string(&palette->menu_and_bars);
9017       tmp = lives_strdup_printf("image(%s)", colref);
9018       set_css_value_direct(swtch, LIVES_WIDGET_STATE_NORMAL, "slider",
9019                            "background-image", tmp);
9020       lives_free(tmp);
9021       lives_free(colref);
9022 
9023       colref = gdk_rgba_to_string(&palette->nice2);
9024       tmp = lives_strdup_printf("image(%s)", colref);
9025       set_css_value_direct(swtch, LIVES_WIDGET_STATE_INSENSITIVE, "slider",
9026                            "background-image", tmp);
9027       lives_free(tmp);
9028       lives_free(colref);
9029 
9030       lives_widget_set_border_color(swtch, LIVES_WIDGET_STATE_INSENSITIVE, &palette->nice2);
9031     }
9032     colref = gdk_rgba_to_string(&palette->normal_fore);
9033     tmp = lives_strdup_printf("image(%s)", colref);
9034     set_css_value_direct(swtch, LIVES_WIDGET_STATE_CHECKED, "slider",
9035                          "background-image", tmp);
9036     lives_free(tmp);
9037     lives_free(colref);
9038 #endif
9039 #endif
9040   }
9041   lives_switch_set_active(LIVES_SWITCH(swtch), active);
9042   widget_opts.last_container = container;
9043 #endif
9044   return swtch;
9045 }
9046 
9047 
lives_standard_check_button_new(const char * labeltext,boolean active,LiVESBox * box,const char * tooltip)9048 LiVESWidget *lives_standard_check_button_new(const char *labeltext, boolean active, LiVESBox * box,
9049     const char *tooltip) {
9050   LiVESWidget *checkbutton = NULL;
9051   LiVESWidget *eventbox = NULL;
9052   LiVESWidget *hbox;
9053   LiVESWidget *container = NULL;
9054   LiVESWidget *img_tips = NULL;
9055 
9056 #if GTK_CHECK_VERSION(3, 14, 0)
9057   char *colref;
9058 #endif
9059   char *tmp;
9060 
9061   boolean expand;
9062 
9063 #if LIVES_HAS_SWITCH_WIDGET
9064   if (prefs->cb_is_switch) return lives_standard_switch_new(labeltext, active, box, tooltip);
9065   else
9066 #endif
9067     checkbutton = lives_check_button_new();
9068 
9069   widget_opts.last_label = NULL;
9070 
9071   if (tooltip) img_tips = lives_widget_set_tooltip_text(checkbutton, tooltip);
9072 
9073   if (box) {
9074     int packing_width = 0;
9075 
9076     if (labeltext) {
9077       eventbox = make_label_eventbox(labeltext, checkbutton);
9078       lives_widget_set_show_hide_with(checkbutton, eventbox);
9079     }
9080 
9081     hbox = make_inner_hbox(LIVES_BOX(box), !widget_opts.swap_label);
9082     lives_widget_set_show_hide_parent(checkbutton);
9083     container = widget_opts.last_container;
9084 
9085     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
9086     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
9087 
9088     if (widget_opts.swap_label && eventbox)
9089       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9090 
9091     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9092 
9093     lives_box_pack_start(LIVES_BOX(hbox), checkbutton, expand, expand,
9094                          !eventbox ? packing_width : 0);
9095 
9096     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9097 
9098     if (!widget_opts.swap_label && eventbox)
9099       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9100 
9101     add_warn_image(checkbutton, hbox);
9102 
9103     if (img_tips) {
9104       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
9105     }
9106   }
9107 
9108   if (widget_opts.apply_theme) {
9109     set_standard_widget(checkbutton, TRUE);
9110     lives_widget_apply_theme(checkbutton, LIVES_WIDGET_STATE_NORMAL);
9111 #if GTK_CHECK_VERSION(3, 0, 0)
9112     set_css_min_size(checkbutton, widget_opts.css_min_width, widget_opts.css_min_height);
9113 #if GTK_CHECK_VERSION(3, 16, 0)
9114     if (prefs->extra_colours && mainw->pretty_colours) {
9115       if (!(palette->style & STYLE_LIGHT))
9116         colref = gdk_rgba_to_string(&palette->nice2);
9117       else
9118         colref = gdk_rgba_to_string(&palette->menu_and_bars);
9119 
9120       tmp = lives_strdup_printf("image(%s)", colref);
9121       set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_NORMAL, "check",
9122                            "background-image", tmp);
9123       set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_CHECKED, "check",
9124                            "background-image", tmp);
9125       set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_CHECKED, "check",
9126                            "border-image", tmp);
9127       lives_free(colref); lives_free(tmp);
9128 
9129       colref = gdk_rgba_to_string(&palette->normal_fore);
9130       set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_CHECKED, "check",
9131                            "color", colref);
9132       lives_free(colref);
9133 
9134       /* colref = gdk_rgba_to_string(&palette->nice2); */
9135       /* tmp = lives_strdup_printf("image(%s)", colref); */
9136       /* set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_INSENSITIVE, "check", */
9137       /*                      "background-image", tmp); */
9138       /* set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_INSENSITIVE, "check", */
9139       /*                      "border-image", tmp); */
9140       //lives_free(tmp);
9141     } else {
9142       colref = gdk_rgba_to_string(&palette->normal_fore);
9143       set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_CHECKED, "check",
9144                            "color", colref);
9145       lives_free(colref);
9146 
9147       colref = gdk_rgba_to_string(&palette->normal_back);
9148       set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_CHECKED, "check",
9149                            "background-color", colref);
9150       lives_free(colref);
9151     }
9152     set_css_value_direct(checkbutton, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
9153 #endif
9154 #endif
9155   }
9156 
9157   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(checkbutton), active);
9158   widget_opts.last_container = container;
9159   return checkbutton;
9160 }
9161 
9162 
lives_glowing_check_button_new(const char * labeltext,LiVESBox * box,const char * tooltip,boolean * togglevalue)9163 LiVESWidget *lives_glowing_check_button_new(const char *labeltext, LiVESBox * box, const char *tooltip, boolean * togglevalue) {
9164   boolean active = FALSE;
9165   LiVESWidget *checkbutton;
9166 #if GTK_CHECK_VERSION(3, 16, 0)
9167   char *colref;
9168 #endif
9169   if (togglevalue) active = *togglevalue;
9170 
9171   checkbutton = lives_standard_check_button_new(labeltext, active, box, tooltip);
9172   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
9173                                   LIVES_GUI_CALLBACK(lives_cool_toggled),
9174                                   togglevalue);
9175   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget_opts.last_label),
9176                                THEME_KEY, LIVES_INT_TO_POINTER(2));
9177 
9178   if (prefs->lamp_buttons) {
9179     lives_toggle_button_set_mode(LIVES_TOGGLE_BUTTON(checkbutton), FALSE);
9180     lives_widget_set_bg_color(checkbutton, LIVES_WIDGET_STATE_ACTIVE, &palette->light_green);
9181     lives_widget_set_bg_color(checkbutton, LIVES_WIDGET_STATE_NORMAL, &palette->dark_red);
9182     lives_cool_toggled(checkbutton, togglevalue);
9183     lives_signal_sync_connect(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_EXPOSE_EVENT,
9184                               LIVES_GUI_CALLBACK(draw_cool_toggle), NULL);
9185     if (widget_opts.apply_theme) {
9186 
9187       set_css_value_direct(checkbutton,  LIVES_WIDGET_STATE_NORMAL, "",
9188                            "box-shadow", "4px 0 alpha(white, 0.5)");
9189 #if GTK_CHECK_VERSION(3, 16, 0)
9190       colref = gdk_rgba_to_string(&palette->dark_red);
9191       set_css_value_direct(checkbutton,  LIVES_WIDGET_STATE_NORMAL, "button",
9192                            "color", colref);
9193       set_css_value_direct(checkbutton,  LIVES_WIDGET_STATE_NORMAL, "button",
9194                            "background-color", colref);
9195       lives_free(colref);
9196 
9197       /* if (prefs->extra_colours && mainw->pretty_colours) { */
9198       /*   colref = gdk_rgba_to_string(&palette->nice3); */
9199       /*   set_css_value_direct(checkbutton,  LIVES_WIDGET_STATE_CHECKED, "button", */
9200       /*                        "color", colref); */
9201       /*   set_css_value_direct(checkbutton,  LIVES_WIDGET_STATE_CHECKED, "button", */
9202       /*                        "background-color", colref); */
9203       /*   lives_free(colref); */
9204       /* } */
9205 
9206       set_css_value_direct(checkbutton,  LIVES_WIDGET_STATE_NORMAL, "",
9207                            "transition-duration", "0.2s");
9208 #endif
9209     }
9210   }
9211   return checkbutton;
9212 }
9213 
9214 
lives_glowing_tool_button_new(const char * labeltext,LiVESToolbar * tbar,const char * tooltip,boolean * togglevalue)9215 LiVESWidget *lives_glowing_tool_button_new(const char *labeltext, LiVESToolbar * tbar, const char *tooltip,
9216     boolean * togglevalue) {
9217   LiVESToolItem *titem = lives_tool_item_new();
9218   LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
9219   widget_opts.expand = LIVES_EXPAND_DEFAULT_HEIGHT;
9220   LiVESWidget *button = lives_glowing_check_button_new(labeltext, LIVES_BOX(hbox), tooltip, togglevalue);
9221   widget_opts.expand = LIVES_EXPAND_DEFAULT;
9222   lives_container_add(LIVES_CONTAINER(titem), hbox);
9223   if (tbar) lives_toolbar_insert(tbar, titem, -1);
9224   return button;
9225 }
9226 
9227 
lives_standard_menu_tool_button_new(LiVESWidget * icon,const char * label)9228 LiVESToolItem *lives_standard_menu_tool_button_new(LiVESWidget * icon, const char *label) {
9229   LiVESToolItem *toolitem = NULL;
9230 #ifdef GUI_GTK
9231   toolitem = lives_menu_tool_button_new(icon, label);
9232   if (widget_opts.apply_theme) {
9233     LiVESList *children = lives_container_get_children(LIVES_CONTAINER(toolitem)), *list = children;
9234     set_standard_widget(LIVES_WIDGET(toolitem), TRUE);
9235     lives_widget_set_bg_color(LIVES_WIDGET(toolitem), LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
9236     while (list) {
9237       LiVESWidget *widget = (LiVESWidget *)list->data;
9238       if (LIVES_IS_VBOX(widget)) {
9239         LiVESList *children2 = lives_container_get_children(LIVES_CONTAINER(toolitem)), *list2 = children2;
9240         lives_container_set_border_width(LIVES_CONTAINER(widget), 0);
9241         while (list2) {
9242           LiVESWidget *child = (LiVESWidget *)list2->data;
9243           if (LIVES_IS_CONTAINER(child)) lives_container_set_border_width(LIVES_CONTAINER(child), 0);
9244           lives_widget_set_valign(child, LIVES_ALIGN_FILL);
9245           lives_widget_set_halign(child, LIVES_ALIGN_FILL);
9246           lives_widget_set_margin_left(child, 0.);
9247           lives_widget_set_margin_right(child, 0.);
9248           lives_widget_set_margin_top(child, 0.);
9249           lives_widget_set_margin_bottom(child, 0.);
9250           list2 = list2->next;
9251         }
9252         lives_widget_set_bg_color(widget, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
9253         list2 = list2->next;
9254         lives_list_free(children2);
9255       }
9256       list = list->next;
9257     }
9258     lives_list_free(children);
9259   }
9260 #endif
9261   return toolitem;
9262 }
9263 
9264 
lives_standard_radio_button_new(const char * labeltext,LiVESSList ** rbgroup,LiVESBox * box,const char * tooltip)9265 LiVESWidget *lives_standard_radio_button_new(const char *labeltext, LiVESSList **rbgroup, LiVESBox * box, const char *tooltip) {
9266   LiVESWidget *radiobutton = NULL;
9267 
9268   // pack a themed check button into box
9269 
9270   LiVESWidget *eventbox = NULL;
9271   LiVESWidget *img_tips = NULL;
9272   LiVESWidget *hbox;
9273 
9274 #if GTK_CHECK_VERSION(3, 16, 0)
9275   char *colref, *tmp; //*csstxt;
9276 #endif
9277 
9278   boolean expand;
9279 
9280   widget_opts.last_label = NULL;
9281 
9282   radiobutton = lives_radio_button_new(*rbgroup);
9283 
9284   *rbgroup = lives_radio_button_get_group(LIVES_RADIO_BUTTON(radiobutton));
9285 
9286   if (tooltip) img_tips = lives_widget_set_tooltip_text(radiobutton, tooltip);
9287 
9288   if (box) {
9289     int packing_width = 0;
9290 
9291     if (labeltext) {
9292       eventbox = make_label_eventbox(labeltext, radiobutton);
9293     }
9294 
9295     hbox = make_inner_hbox(LIVES_BOX(box), !widget_opts.swap_label);
9296     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
9297 
9298     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
9299 
9300     if (widget_opts.swap_label && eventbox)
9301       lives_box_pack_start(LIVES_BOX(hbox), eventbox, TRUE, FALSE, packing_width);
9302 
9303     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9304 
9305     lives_box_pack_start(LIVES_BOX(hbox), radiobutton, expand, FALSE,
9306                          !eventbox ? packing_width : 0);
9307 
9308     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9309 
9310     if (!widget_opts.swap_label && eventbox)
9311       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9312 
9313     lives_widget_set_show_hide_parent(radiobutton);
9314 
9315     add_warn_image(radiobutton, hbox);
9316 
9317     if (img_tips) {
9318       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
9319     }
9320   }
9321 
9322   if (widget_opts.apply_theme) {
9323     set_standard_widget(radiobutton, TRUE);
9324     lives_widget_apply_theme(radiobutton, LIVES_WIDGET_STATE_NORMAL);
9325 #if GTK_CHECK_VERSION(3, 16, 0)
9326     if (prefs->extra_colours && mainw->pretty_colours) {
9327 
9328       if (!(palette->style & STYLE_LIGHT))
9329         colref = gdk_rgba_to_string(&palette->nice2);
9330       else
9331         colref = gdk_rgba_to_string(&palette->menu_and_bars);
9332       set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_NORMAL, "radio", "color", colref);
9333       tmp = lives_strdup_printf("image(%s)", colref);
9334       set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_NORMAL, "radio",
9335                            "background-image", tmp);
9336       lives_free(colref);
9337 
9338       if (!(palette->style & STYLE_LIGHT))
9339         colref = gdk_rgba_to_string(&palette->normal_fore);
9340       else {
9341         set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.25");
9342         set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_CHECKED, "", "opacity", "0.5");
9343         colref = gdk_rgba_to_string(&palette->nice3);
9344       }
9345       set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_CHECKED, "radio", "color", colref);
9346 
9347       tmp = lives_strdup_printf("image(%s)", colref);
9348       set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_CHECKED, "radio",
9349                            "background-image", tmp);
9350       /* csstxt = lives_strdup_printf("-gtk-gradient (radial, center center, 0, center center, " */
9351       /*                              "0.125, to (%s), to (rgba(0,0,0,0)))", colref); */
9352       /* set_css_value_direct(radiobutton, LIVES_WIDGET_STATE_CHECKED, "radio", */
9353       /*                      "border-image-source", csstxt); */
9354       //lives_free(csstxt);
9355       lives_free(tmp);
9356       lives_free(colref);
9357     }
9358 #endif
9359   }
9360   return radiobutton;
9361 }
9362 
9363 
lives_spin_button_set_step_increment(LiVESSpinButton * button,double step_increment)9364 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_step_increment(LiVESSpinButton * button, double step_increment) {
9365 #ifdef GUI_GTK
9366   LiVESAdjustment *adj = lives_spin_button_get_adjustment(button);
9367   lives_adjustment_set_step_increment(adj, step_increment);
9368   return TRUE;
9369 #endif
9370   return FALSE;
9371 }
9372 
9373 
lives_spin_button_set_snap_to_multiples(LiVESSpinButton * button,double mult)9374 WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_snap_to_multiples(LiVESSpinButton * button, double mult) {
9375 #ifdef GUI_GTK
9376   lives_spin_button_set_step_increment(button, mult);
9377   lives_spin_button_set_snap_to_ticks(button, TRUE);
9378   return TRUE;
9379 #endif
9380   return FALSE;
9381 }
9382 
9383 
calc_spin_button_width(double min,double max,int dp)9384 size_t calc_spin_button_width(double min, double max, int dp) {
9385   char *txt = lives_strdup_printf("%d", (int)max);
9386   size_t maxlen = strlen(txt);
9387   lives_free(txt);
9388   txt = lives_strdup_printf("%d", (int)min);
9389   if (strlen(txt) > maxlen) maxlen = strlen(txt);
9390   lives_free(txt);
9391   if (dp > 0) maxlen += dp + 1;
9392   if (maxlen < MIN_SPINBUTTON_SIZE) return MIN_SPINBUTTON_SIZE;
9393   return maxlen;
9394 }
9395 
9396 
lives_standard_spin_button_new(const char * labeltext,double val,double min,double max,double step,double page,int dp,LiVESBox * box,const char * tooltip)9397 LiVESWidget *lives_standard_spin_button_new(const char *labeltext, double val, double min,
9398     double max, double step, double page, int dp, LiVESBox * box,
9399     const char *tooltip) {
9400   // pack a themed spin button into box
9401   LiVESWidget *spinbutton = NULL;
9402   LiVESWidget *img_tips = NULL;
9403   LiVESWidget *eventbox = NULL;
9404   LiVESWidget *container = NULL;
9405   LiVESWidget *hbox;
9406   LiVESAdjustment *adj;
9407 
9408 #if GTK_CHECK_VERSION(3, 14, 0)
9409   char *colref;
9410 #endif
9411 
9412   boolean expand;
9413 
9414   int maxlen;
9415   widget_opts.last_label = NULL;
9416 
9417   adj = lives_adjustment_new(val, min, max, step, page, 0.);
9418   spinbutton = lives_spin_button_new(adj, 1, dp);
9419 
9420   val = lives_spin_button_get_snapval(LIVES_SPIN_BUTTON(spinbutton), val);
9421   lives_spin_button_set_value(LIVES_SPIN_BUTTON(spinbutton), val);
9422   lives_spin_button_update(LIVES_SPIN_BUTTON(spinbutton));
9423   set_standard_widget(spinbutton, TRUE);
9424 
9425   if (tooltip) img_tips = lives_widget_set_tooltip_text(spinbutton, tooltip);
9426 
9427   maxlen = calc_spin_button_width(min, max, dp);
9428   lives_entry_set_width_chars(LIVES_ENTRY(spinbutton), maxlen);
9429 
9430   lives_entry_set_activates_default(LIVES_ENTRY(spinbutton), TRUE);
9431   lives_entry_set_has_frame(LIVES_ENTRY(spinbutton), TRUE);
9432   lives_entry_set_alignment(LIVES_ENTRY(spinbutton), 0.2);
9433 #ifdef GUI_GTK
9434   //gtk_spin_button_set_update_policy(LIVES_SPIN_BUTTON(spinbutton), GTK_UPDATE_ALWAYS);
9435   gtk_spin_button_set_numeric(LIVES_SPIN_BUTTON(spinbutton), TRUE);
9436   gtk_entry_set_overwrite_mode(LIVES_ENTRY(spinbutton), TRUE);
9437 #endif
9438 
9439   if (box) {
9440     LiVESWidget *layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(box),
9441                           WH_LAYOUT_KEY);
9442     int packing_width = 0;
9443 
9444     if (labeltext) {
9445       eventbox = make_label_eventbox(labeltext, spinbutton);
9446       lives_widget_set_show_hide_with(spinbutton, eventbox);
9447     }
9448 
9449     hbox = make_inner_hbox(LIVES_BOX(box), widget_opts.swap_label || !eventbox);
9450     lives_widget_set_show_hide_with(spinbutton, hbox);
9451     container = widget_opts.last_container;
9452 
9453     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
9454 
9455     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
9456 
9457     if (!widget_opts.swap_label && eventbox) {
9458       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9459 
9460       if (layout) {
9461         // pack end because box is a layout hbox
9462         lives_widget_set_pack_type(LIVES_BOX(box), container, LIVES_PACK_END);
9463         box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
9464         hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
9465       }
9466     }
9467 
9468     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9469 
9470     lives_box_pack_start(LIVES_BOX(hbox), spinbutton, expand, TRUE, packing_width);
9471 
9472     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9473 
9474     if (widget_opts.swap_label && eventbox) {
9475       if (layout) {
9476         box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
9477         hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
9478         lives_widget_set_show_hide_with(spinbutton, hbox);
9479       }
9480       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9481     }
9482     lives_widget_set_show_hide_parent(spinbutton);
9483 
9484     add_warn_image(spinbutton, hbox);
9485 
9486     if (img_tips) {
9487       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
9488     }
9489   }
9490 
9491   if (widget_opts.apply_theme) {
9492     set_css_min_size(spinbutton, widget_opts.css_min_width, ((widget_opts.css_min_height * 3 + 3) >> 2) << 1);
9493 
9494 #if !GTK_CHECK_VERSION(3, 16, 0)
9495     // breaks button insens !
9496     lives_widget_apply_theme2(LIVES_WIDGET(spinbutton), LIVES_WIDGET_STATE_NORMAL, TRUE);
9497     lives_widget_apply_theme_dimmed2(spinbutton, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
9498 #else
9499     lives_widget_apply_theme2(LIVES_WIDGET(spinbutton), LIVES_WIDGET_STATE_NORMAL, FALSE);
9500 
9501     colref = gdk_rgba_to_string(&palette->normal_fore);
9502     set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_NORMAL, "", "color", colref);
9503     lives_free(colref);
9504 
9505     set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
9506     set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_INSENSITIVE, "button", "opacity", "0.5");
9507 
9508     if (prefs->extra_colours && mainw->pretty_colours) {
9509       char *tmp;
9510       colref = gdk_rgba_to_string(&palette->nice1);
9511       set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_NORMAL, "", "border-color", colref);
9512       tmp = lives_strdup_printf("0 0 0 1px %s inset", colref);
9513       set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_FOCUSED, "", "box-shadow", tmp);
9514       lives_free(tmp);
9515       lives_free(colref);
9516       colref = gdk_rgba_to_string(&palette->nice2);
9517       set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_NORMAL, "", "caret-color", colref);
9518       set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_NORMAL, "entry selection", "background-color", colref);
9519       lives_free(colref);
9520       colref = gdk_rgba_to_string(&palette->normal_fore);
9521       set_css_value_direct(spinbutton, LIVES_WIDGET_STATE_NORMAL, "entry selection", "color", colref);
9522       lives_free(colref);
9523     }
9524 #endif
9525     set_child_dimmed_colour2(spinbutton, BUTTON_DIM_VAL);// insens, themecols 1, child only
9526   }
9527 
9528   widget_opts.last_container = container;
9529   return spinbutton;
9530 }
9531 
9532 
setminsz(LiVESWidget * widget,livespointer data)9533 static void setminsz(LiVESWidget * widget, livespointer data) {
9534   set_css_min_size(widget, widget_opts.css_min_width, ((widget_opts.css_min_height * 3 + 3) >> 2) << 1);
9535   if (LIVES_IS_BUTTON(widget)) {
9536     set_css_value_direct(widget, LIVES_WIDGET_STATE_NORMAL, "", "padding-top", "0");
9537     set_css_value_direct(widget, LIVES_WIDGET_STATE_NORMAL, "", "padding-bottom", "0");
9538   }
9539   if (LIVES_IS_CONTAINER(widget)) {
9540     lives_container_forall(LIVES_CONTAINER(widget), setminsz, NULL);
9541   }
9542 }
9543 
lives_standard_combo_new(const char * labeltext,LiVESList * list,LiVESBox * box,const char * tooltip)9544 LiVESWidget *lives_standard_combo_new(const char *labeltext, LiVESList * list, LiVESBox * box, const char *tooltip) {
9545   LiVESWidget *combo = NULL;
9546   // pack a themed combo box into box
9547 
9548   // seems like it is not possible to set the arrow colours
9549   // nor the entireity of the background for the popup list
9550 
9551   LiVESWidget *eventbox = NULL;
9552   LiVESWidget *container = NULL;
9553   LiVESWidget *hbox;
9554   LiVESWidget *img_tips = NULL;
9555   LiVESEntry *entry;
9556 
9557   boolean expand;
9558 
9559   widget_opts.last_label = NULL;
9560 
9561   combo = lives_combo_new();
9562 
9563   if (tooltip) img_tips = lives_widget_set_tooltip_text(combo, tooltip);
9564 
9565   entry = (LiVESEntry *)lives_combo_get_entry(LIVES_COMBO(combo));
9566   lives_widget_set_text_size(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_NORMAL, widget_opts.text_size);
9567 
9568   lives_entry_set_has_frame(entry, TRUE);
9569   lives_entry_set_editable(LIVES_ENTRY(entry), FALSE);
9570   lives_entry_set_activates_default(entry, TRUE);
9571   lives_entry_set_width_chars(LIVES_ENTRY(entry), SHORT_ENTRY_WIDTH);
9572 
9573   lives_widget_set_sensitive_with(LIVES_WIDGET(entry), combo);
9574   lives_widget_set_sensitive_with(combo, LIVES_WIDGET(entry));
9575 
9576   lives_widget_set_can_focus(LIVES_WIDGET(entry), FALSE);
9577 
9578   lives_combo_set_focus_on_click(LIVES_COMBO(combo), FALSE);
9579 
9580   lives_widget_add_events(LIVES_WIDGET(entry), LIVES_BUTTON_RELEASE_MASK);
9581   lives_signal_sync_connect_swapped(LIVES_GUI_OBJECT(entry), LIVES_WIDGET_BUTTON_RELEASE_EVENT,
9582                                     LIVES_GUI_CALLBACK(lives_combo_popup), combo);
9583 
9584   if (box) {
9585     LiVESWidget *layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(box), WH_LAYOUT_KEY);
9586     int packing_width = 0;
9587 
9588     if (labeltext) {
9589       eventbox = make_label_eventbox(labeltext, LIVES_WIDGET(entry));
9590     }
9591 
9592     hbox = make_inner_hbox(LIVES_BOX(box), widget_opts.swap_label || !eventbox);
9593     lives_widget_set_show_hide_with(combo, hbox);
9594     container = widget_opts.last_container;
9595 
9596     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
9597     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
9598 
9599     if (!widget_opts.swap_label && eventbox) {
9600       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9601       if (layout) {
9602         // pack end because box is a layout hbox
9603         lives_widget_set_pack_type(LIVES_BOX(box), container, LIVES_PACK_END);
9604         box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
9605         hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
9606       }
9607     }
9608 
9609     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9610 
9611     lives_widget_set_hexpand(combo, FALSE);
9612     lives_widget_set_valign(combo, LIVES_ALIGN_CENTER);
9613     lives_box_pack_start(LIVES_BOX(hbox), combo, LIVES_SHOULD_EXPAND_WIDTH,
9614                          expand, !eventbox ? packing_width : 0);
9615 
9616     if (expand) add_fill_to_box(LIVES_BOX(hbox));
9617 
9618     if (widget_opts.swap_label && eventbox) {
9619       if (layout) {
9620         box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
9621         hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
9622         lives_widget_set_show_hide_with(combo, hbox);
9623       }
9624       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, 0);
9625     }
9626     lives_widget_set_show_hide_parent(combo);
9627 
9628     add_warn_image(combo, hbox);
9629 
9630     if (img_tips) {
9631       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
9632     }
9633   }
9634 
9635   if (list) {
9636     lives_combo_populate(LIVES_COMBO(combo), list);
9637     lives_combo_set_active_index(LIVES_COMBO(combo), 0);
9638   }
9639 
9640   if (widget_opts.apply_theme) {
9641     set_standard_widget(combo, TRUE);
9642     set_child_alt_colour(combo, TRUE);
9643 
9644 #if GTK_CHECK_VERSION(3, 0, 0)
9645     set_css_min_size(combo, widget_opts.css_min_width, ((widget_opts.css_min_height * 3 + 3) >> 2) << 1);
9646     lives_container_forall(LIVES_CONTAINER(combo), setminsz, NULL);
9647 
9648     set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_NORMAL, "", "border-radius", "5px");
9649 
9650 #if !GTK_CHECK_VERSION(3, 16, 0)
9651     set_child_dimmed_colour(combo, BUTTON_DIM_VAL); // insens, themecols 1, child only
9652 #else
9653     set_css_value_direct(combo, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
9654     if (prefs->extra_colours && mainw->pretty_colours) {
9655       char *tmp;
9656       char *colref = gdk_rgba_to_string(&palette->nice1);
9657       set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_NORMAL, "", "border-color", colref);
9658       tmp = lives_strdup_printf("0 0 0 1px %s inset", colref);
9659       set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_FOCUSED, "", "box-shadow", tmp);
9660       lives_free(tmp);
9661       lives_free(colref);
9662     }
9663 #endif
9664 #endif
9665 #if !GTK_CHECK_VERSION(3, 16, 0)
9666     lives_widget_apply_theme_dimmed(combo, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
9667     lives_widget_apply_theme_dimmed(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
9668     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(entry), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
9669                                     LIVES_GUI_CALLBACK(widget_state_cb), NULL);
9670     widget_state_cb(LIVES_WIDGET_OBJECT(entry), NULL, NULL);
9671     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(combo), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
9672                                     LIVES_GUI_CALLBACK(widget_state_cb), NULL);
9673     widget_state_cb(LIVES_WIDGET_OBJECT(combo), NULL, NULL);
9674 #endif
9675   }
9676   widget_opts.last_container = container;
9677   return combo;
9678 }
9679 
9680 
lives_standard_combo_new_with_model(LiVESTreeModel * model,LiVESBox * box)9681 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_combo_new_with_model(LiVESTreeModel * model, LiVESBox * box) {
9682   LiVESWidget *combo = lives_standard_combo_new(NULL, NULL, box, NULL);
9683   lives_combo_set_model(LIVES_COMBO(combo), model);
9684   return combo;
9685 }
9686 
9687 
lives_standard_entry_new(const char * labeltext,const char * txt,int dispwidth,int maxchars,LiVESBox * box,const char * tooltip)9688 LiVESWidget *lives_standard_entry_new(const char *labeltext, const char *txt, int dispwidth, int maxchars,
9689                                       LiVESBox * box, const char *tooltip) {
9690   LiVESWidget *entry = NULL;
9691   LiVESWidget *img_tips = NULL;
9692   LiVESWidget *container = NULL;
9693   LiVESWidget *hbox = NULL;
9694   LiVESWidget *eventbox = NULL;
9695 
9696   boolean expand;
9697 
9698   widget_opts.last_label = NULL;
9699 
9700   entry = lives_entry_new();
9701   lives_widget_set_valign(entry, LIVES_ALIGN_CENTER);
9702 
9703   lives_widget_set_text_size(entry, LIVES_WIDGET_STATE_NORMAL, widget_opts.text_size);
9704 
9705   if (tooltip) img_tips = lives_widget_set_tooltip_text(entry, tooltip);
9706 
9707   if (txt) lives_entry_set_text(LIVES_ENTRY(entry), txt);
9708 
9709   if (dispwidth != -1) lives_entry_set_width_chars(LIVES_ENTRY(entry), dispwidth);
9710   else {
9711     if (LIVES_SHOULD_EXPAND_EXTRA_WIDTH) lives_entry_set_width_chars(LIVES_ENTRY(entry), MEDIUM_ENTRY_WIDTH);
9712     else if (LIVES_SHOULD_EXPAND_WIDTH) lives_entry_set_width_chars(LIVES_ENTRY(entry), MEDIUM_ENTRY_WIDTH);
9713   }
9714 
9715   if (maxchars != -1) lives_entry_set_max_length(LIVES_ENTRY(entry), maxchars);
9716 
9717   lives_entry_set_activates_default(LIVES_ENTRY(entry), TRUE);
9718   lives_entry_set_has_frame(LIVES_ENTRY(entry), TRUE);
9719 
9720   //lives_widget_set_halign(entry, LIVES_ALIGN_START);  // NO ! - causes entry to shrink
9721   if (widget_opts.justify == LIVES_JUSTIFY_START) {
9722     lives_entry_set_alignment(LIVES_ENTRY(entry), 0.);
9723   }
9724   if (widget_opts.justify == LIVES_JUSTIFY_CENTER) {
9725     lives_entry_set_alignment(LIVES_ENTRY(entry), 0.5);
9726   }
9727   if (widget_opts.justify == LIVES_JUSTIFY_END) {
9728     lives_entry_set_alignment(LIVES_ENTRY(entry), 1.);
9729   }
9730 
9731   if (box) {
9732     LiVESWidget *layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(box),
9733                           WH_LAYOUT_KEY);
9734     int packing_width = 0;
9735 
9736     if (labeltext) {
9737       eventbox = make_label_eventbox(labeltext, entry);
9738     }
9739 
9740     hbox = make_inner_hbox(LIVES_BOX(box), widget_opts.swap_label || !eventbox);
9741     lives_widget_set_show_hide_with(entry, hbox);
9742     container = widget_opts.last_container;
9743 
9744     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
9745 
9746     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
9747 
9748     if (!widget_opts.swap_label && eventbox) {
9749       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9750 
9751       if (layout) {
9752         // pack end because box is a layout hbox
9753         lives_widget_set_pack_type(LIVES_BOX(box), container, LIVES_PACK_END);
9754         box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
9755         hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
9756       }
9757     }
9758 
9759     if (expand && dispwidth != -1) add_fill_to_box(LIVES_BOX(hbox));
9760 
9761     lives_box_pack_start(LIVES_BOX(hbox), entry, LIVES_SHOULD_EXPAND_WIDTH, dispwidth == -1, packing_width);
9762 
9763     if (expand && dispwidth != -1) add_fill_to_box(LIVES_BOX(hbox));
9764 
9765     if (widget_opts.swap_label && eventbox) {
9766       if (layout) {
9767         box = LIVES_BOX(lives_layout_hbox_new(LIVES_TABLE(layout)));
9768         hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
9769         lives_widget_set_show_hide_with(entry, hbox);
9770       }
9771       lives_box_pack_start(LIVES_BOX(hbox), eventbox, FALSE, FALSE, packing_width);
9772     }
9773     lives_widget_set_show_hide_parent(entry);
9774 
9775     add_warn_image(entry, hbox);
9776 
9777     if (img_tips) {
9778       lives_box_pack_start(LIVES_BOX(hbox), img_tips, FALSE, FALSE, widget_opts.packing_width >> 1);
9779     }
9780   }
9781 
9782   if (widget_opts.apply_theme) {
9783     set_standard_widget(entry, TRUE);
9784     lives_widget_apply_theme2(entry, LIVES_WIDGET_STATE_NORMAL, TRUE);
9785 #if GTK_CHECK_VERSION(3, 0, 0)
9786     set_css_min_size(entry, widget_opts.css_min_width, ((widget_opts.css_min_height * 3 + 3) >> 2) << 1);
9787 #if GTK_CHECK_VERSION(3, 16, 0)
9788     if (prefs->extra_colours && mainw->pretty_colours) {
9789       char *tmp;
9790       char *colref = gdk_rgba_to_string(&palette->nice1);
9791       set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_NORMAL, "", "border-color", colref);
9792       set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_FOCUSED, "", "border-color", colref);
9793       tmp = lives_strdup_printf("0 0 0 2px %s inset", colref);
9794       set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_FOCUSED, "", "box-shadow", tmp);
9795       lives_free(tmp);
9796       lives_free(colref);
9797       colref = gdk_rgba_to_string(&palette->nice2);
9798       set_css_value_direct(LIVES_WIDGET(entry), LIVES_WIDGET_STATE_NORMAL, "selection", "background-color", colref);
9799       lives_free(colref);
9800     }
9801 
9802     set_css_value_direct(entry, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
9803 #endif
9804     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(entry), LIVES_WIDGET_NOTIFY_SIGNAL "editable",
9805                                     LIVES_GUI_CALLBACK(edit_state_cb), NULL);
9806 #if !GTK_CHECK_VERSION(3, 16, 0)
9807     lives_widget_apply_theme_dimmed(entry, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
9808 #endif
9809 #else
9810     lives_widget_apply_theme_dimmed(entry, LIVES_WIDGET_STATE_INSENSITIVE, BUTTON_DIM_VAL);
9811 #endif
9812 #if !GTK_CHECK_VERSION(3, 16, 0)
9813     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(entry), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
9814                                     LIVES_GUI_CALLBACK(widget_state_cb), NULL);
9815     widget_state_cb(LIVES_WIDGET_OBJECT(entry), NULL, NULL);
9816 #endif
9817   }
9818 
9819   //lives_widget_set_size_request(entry, -1, (widget_opts.css_min_height * 2 + 1) >> 1);
9820   widget_opts.last_container = container;
9821   return entry;
9822 }
9823 
lives_standard_progress_bar_new(void)9824 LiVESWidget *lives_standard_progress_bar_new(void) {
9825   LiVESWidget *pbar;
9826 #ifdef PROGBAR_IS_ENTRY
9827   pbar = lives_entry_new();
9828   set_standard_widget(pbar, TRUE);
9829   lives_widget_set_valign(pbar, LIVES_ALIGN_CENTER);
9830   lives_widget_set_text_size(pbar, LIVES_WIDGET_STATE_NORMAL, widget_opts.text_size);
9831   lives_entry_set_editable(LIVES_ENTRY(pbar), FALSE);
9832   lives_widget_set_can_focus(LIVES_WIDGET(pbar), FALSE);
9833   if (widget_opts.justify == LIVES_JUSTIFY_START) {
9834     lives_entry_set_alignment(LIVES_ENTRY(pbar), 0.);
9835   }
9836   if (widget_opts.justify == LIVES_JUSTIFY_CENTER) {
9837     lives_entry_set_alignment(LIVES_ENTRY(pbar), 0.5);
9838   }
9839   if (widget_opts.justify == LIVES_JUSTIFY_END) {
9840     lives_entry_set_alignment(LIVES_ENTRY(pbar), 1.);
9841   }
9842 #else
9843   pbar = lives_progress_bar_new();
9844 #endif
9845 
9846   if (widget_opts.apply_theme) {
9847     lives_widget_apply_theme(pbar, LIVES_WIDGET_STATE_NORMAL);
9848 #if GTK_CHECK_VERSION(3, 0, 0)
9849 #if GTK_CHECK_VERSION(3, 16, 0)
9850     char *tmp, *colref;
9851 #endif
9852 #ifdef PROGBAR_IS_ENTRY
9853     char *colref2;
9854 #endif
9855     set_standard_widget(pbar, TRUE);
9856     set_css_min_size(pbar, -1, widget_opts.css_min_height);
9857 #if GTK_CHECK_VERSION(3, 16, 0)
9858     if (prefs->extra_colours && mainw->pretty_colours) {
9859       colref = gdk_rgba_to_string(&palette->nice1);
9860       tmp = lives_strdup_printf("image(%s)", colref);
9861       set_css_value_direct(pbar, LIVES_WIDGET_STATE_NORMAL, "progress",
9862                            "background-image", tmp);
9863       set_css_value_direct(pbar, LIVES_WIDGET_STATE_NORMAL, "progress",
9864                            "background-color", colref);
9865       set_css_value_direct(pbar, LIVES_WIDGET_STATE_NORMAL, "progress",
9866                            "color", colref);
9867       set_css_value_direct(pbar, LIVES_WIDGET_STATE_NORMAL, "progress",
9868                            "border-color", colref);
9869       lives_free(tmp);
9870 #ifdef PROGBAR_IS_ENTRY
9871       colref2 = gdk_rgba_to_string(&palette->nice2);
9872       tmp = lives_strdup_printf("linear-gradient(to right, %s, %s)", colref2, colref);
9873       set_css_value_direct(pbar, LIVES_WIDGET_STATE_INSENSITIVE, "progress",
9874                            "background-image", tmp);
9875       lives_free(tmp);
9876       lives_free(colref2);
9877       set_css_min_size_selected(pbar, "progress", widget_opts.css_min_width * 4, widget_opts.css_min_height);
9878 #endif
9879       lives_free(colref);
9880     }
9881 #ifdef PROGBAR_IS_ENTRY
9882     set_css_min_size_selected(pbar, "progress", -1, -1);
9883 #endif
9884 #endif
9885 #endif
9886   }
9887 
9888   return pbar;
9889 }
9890 
9891 
lives_dialog_add_button_from_stock(LiVESDialog * dialog,const char * stock_id,const char * label,int response_id)9892 LiVESWidget *lives_dialog_add_button_from_stock(LiVESDialog * dialog, const char *stock_id, const char *label,
9893     int response_id) {
9894   int bwidth = LIVES_SHOULD_EXPAND_EXTRA_WIDTH ? DLG_BUTTON_WIDTH * 2 : DLG_BUTTON_WIDTH;
9895   LiVESWidget *button = lives_standard_button_new_from_stock(stock_id, label, bwidth,
9896                         DLG_BUTTON_HEIGHT);
9897   LiVESWidget *first_button;
9898 
9899   if (dialog) lives_dialog_add_action_widget(dialog, button, response_id);
9900   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(button), NWIDTH_KEY, LIVES_INT_TO_POINTER(bwidth));
9901   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(button), THEME_KEY,
9902                                LIVES_INT_TO_POINTER(widget_opts.apply_theme));
9903 
9904   if (dialog) {
9905     /// if we have only ome button, center it
9906     if (!(first_button =
9907             (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(dialog), FBUTT_KEY))) {
9908       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(dialog), FBUTT_KEY, (livespointer)button);
9909       if (LIVES_SHOULD_EXPAND_WIDTH) lives_button_center(button);
9910     } else {
9911       /// else attach at end
9912       lives_button_uncenter(first_button,
9913                             LIVES_POINTER_TO_INT(lives_widget_object_get_data
9914                                 (LIVES_WIDGET_OBJECT(first_button), NWIDTH_KEY)));
9915     }
9916   }
9917 
9918   lives_widget_apply_theme(button, LIVES_WIDGET_STATE_NORMAL);
9919   if (is_standard_widget(button)) sbutt_render(button, 0L, NULL);
9920   return button;
9921 }
9922 
9923 
dlg_focus_changed(LiVESContainer * c,LiVESWidget * widget,livespointer user_data)9924 WIDGET_HELPER_LOCAL_INLINE void dlg_focus_changed(LiVESContainer * c, LiVESWidget * widget, livespointer user_data) {
9925 #if GTK_CHECK_VERSION(2, 18, 0)
9926   LiVESWidget *entry = NULL;
9927   while (LIVES_IS_CONTAINER(widget)) {
9928     LiVESWidget *fchild = lives_container_get_focus_child(LIVES_CONTAINER(widget));
9929     if (!fchild || fchild == widget) break;
9930     widget = fchild;
9931   }
9932 
9933   if (LIVES_IS_COMBO(widget)) {
9934     entry = lives_combo_get_entry(LIVES_COMBO(widget));
9935   } else entry = widget;
9936 
9937   if (entry && LIVES_IS_ENTRY(entry)) {
9938     if (lives_entry_get_activates_default(LIVES_ENTRY(widget))) {
9939       LiVESWidget *toplevel = lives_widget_get_toplevel(widget);
9940       LiVESWidget *button;
9941       if (!LIVES_IS_WIDGET(toplevel)) return;
9942       button = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(toplevel), DEFBUTTON_KEY);
9943       if (button && lives_widget_is_sensitive(button)) {
9944         // default button gets the default
9945         lives_widget_object_set_data(LIVES_WIDGET_OBJECT(toplevel), CDEF_KEY, NULL);
9946         lives_widget_grab_default(button);
9947         lives_widget_queue_draw(button);
9948       }
9949     }
9950   }
9951 #endif
9952 }
9953 
9954 
lives_dialog_set_button_layout(LiVESDialog * dlg,LiVESButtonBoxStyle bstyle)9955 WIDGET_HELPER_GLOBAL_INLINE boolean lives_dialog_set_button_layout(LiVESDialog * dlg,
9956     LiVESButtonBoxStyle bstyle) {
9957   LiVESWidget *bbox = lives_dialog_get_action_area(dlg);
9958   return lives_button_box_set_layout(LIVES_BUTTON_BOX(bbox), bstyle);
9959 }
9960 
9961 
lives_dialog_add_escape(LiVESDialog * dlg,LiVESWidget * button)9962 WIDGET_HELPER_GLOBAL_INLINE LiVESAccelGroup *lives_dialog_add_escape(LiVESDialog * dlg, LiVESWidget * button) {
9963   LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
9964   lives_widget_add_accelerator(button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
9965                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
9966   lives_window_add_accel_group(LIVES_WINDOW(dlg), accel_group);
9967   return accel_group;
9968 }
9969 
9970 
lives_standard_dialog_new(const char * title,boolean add_std_buttons,int width,int height)9971 LiVESWidget *lives_standard_dialog_new(const char *title, boolean add_std_buttons, int width, int height) {
9972   // in case of problems, try setting widget_opts.no_gui=TRUE
9973 
9974   LiVESWidget *dialog = NULL;
9975 
9976   dialog = lives_dialog_new();
9977 
9978   /* set_css_value_direct(dialog, LIVES_WIDGET_STATE_NORMAL, "", "opacity", "1."); */
9979   /* set_css_value_direct(dialog, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0."); */
9980   /* set_css_value_direct(dialog,  LIVES_WIDGET_STATE_INSENSITIVE, "", */
9981   /* 		       "transition-duration", "4s"); */
9982   /* set_css_value_direct(dialog,  LIVES_WIDGET_STATE_NORMAL, "", */
9983   /* 		       "transition-duration", "4s"); */
9984   /* lives_widget_set_sensitive(dialog, FALSE); */
9985 
9986   if (width <= 0) width = 8;
9987   if (height <= 0) height = 8;
9988 
9989   if (!widget_opts.no_gui) {
9990     LiVESWindow *transient = widget_opts.transient;
9991     if (!transient) transient = get_transient_full();
9992     if (transient) lives_window_set_transient_for(LIVES_WINDOW(dialog), transient);
9993   }
9994 
9995   lives_window_set_monitor(LIVES_WINDOW(dialog), widget_opts.monitor);
9996 
9997 #if !GTK_CHECK_VERSION(3, 0, 0)
9998   if (height > 8 && width > 8) {
9999 #endif
10000     lives_widget_set_minimum_size(dialog, width, height);
10001 #if !GTK_CHECK_VERSION(3, 0, 0)
10002   }
10003 #endif
10004 
10005   lives_window_set_default_size(LIVES_WINDOW(dialog), width, height);
10006   lives_widget_set_size_request(dialog, width, height);
10007 
10008   if (title) lives_window_set_title(LIVES_WINDOW(dialog), title);
10009 
10010   lives_window_set_deletable(LIVES_WINDOW(dialog), FALSE);
10011 
10012   if (LIVES_SHOULD_EXPAND_WIDTH) lives_widget_set_hexpand(dialog, TRUE);
10013   if (LIVES_SHOULD_EXPAND_HEIGHT) lives_widget_set_vexpand(dialog, TRUE);
10014 
10015   /* #if !GTK_CHECK_VERSION(3, 0, 0) */
10016   /*   lives_dialog_set_has_separator(LIVES_DIALOG(dialog), FALSE); */
10017   /* #endif */
10018 
10019   if (widget_opts.apply_theme) {
10020     lives_widget_apply_theme(dialog, LIVES_WIDGET_STATE_NORMAL);
10021     funkify_dialog(dialog);
10022 #if GTK_CHECK_VERSION(2, 18, 0)
10023     lives_signal_sync_connect(LIVES_GUI_OBJECT(lives_dialog_get_content_area(LIVES_DIALOG(dialog))),
10024                               LIVES_WIDGET_SET_FOCUS_CHILD_SIGNAL,
10025                               LIVES_GUI_CALLBACK(dlg_focus_changed), NULL);
10026 #endif
10027   } else {
10028     lives_container_set_border_width(LIVES_CONTAINER(dialog), widget_opts.border_width * 2);
10029   }
10030 
10031   // do this before widget_show(), then call lives_window_center() afterwards
10032   lives_window_set_position(LIVES_WINDOW(dialog), LIVES_WIN_POS_CENTER_ALWAYS);
10033 
10034   if (add_std_buttons) {
10035     // cancel button will automatically destroy the dialog
10036     // ok button needs manual destruction
10037 
10038     LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
10039     LiVESWidget *cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog),
10040                                 LIVES_STOCK_CANCEL, NULL, LIVES_RESPONSE_CANCEL);
10041 
10042     LiVESWidget *okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog),
10043                             LIVES_STOCK_OK, NULL, LIVES_RESPONSE_OK);
10044 
10045     lives_button_grab_default_special(okbutton);
10046 
10047     lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
10048                               LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
10049 
10050     lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
10051                                  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
10052 
10053     if (widget_opts.apply_theme) {
10054 #if !GTK_CHECK_VERSION(3, 16, 0)
10055       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
10056                                       LIVES_GUI_CALLBACK(widget_state_cb), NULL);
10057       widget_state_cb(LIVES_WIDGET_OBJECT(cancelbutton), NULL, NULL);
10058 
10059       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
10060                                       LIVES_GUI_CALLBACK(widget_state_cb), NULL);
10061       widget_state_cb(LIVES_WIDGET_OBJECT(okbutton), NULL, NULL);
10062 #endif
10063     }
10064 
10065     lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
10066   }
10067 
10068   lives_signal_sync_connect(LIVES_GUI_OBJECT(dialog), LIVES_WIDGET_DELETE_EVENT,
10069                             LIVES_GUI_CALLBACK(return_true), NULL);
10070 
10071   if (!widget_opts.non_modal)
10072     lives_window_set_modal(LIVES_WINDOW(dialog), TRUE);
10073 
10074   if (!widget_opts.non_modal)
10075     lives_window_set_resizable(LIVES_WINDOW(dialog), FALSE);
10076 
10077   return dialog;
10078 }
10079 
10080 
lives_standard_font_chooser_new(void)10081 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_font_chooser_new(void) {
10082   LiVESWidget *font_choo = NULL;
10083   int width = DEF_BUTTON_WIDTH, height = DEF_BUTTON_HEIGHT;
10084 #ifdef GUI_GTK
10085 #if GTK_CHECK_VERSION(3, 2, 0)
10086   char *ttl;
10087   font_choo = gtk_font_button_new();
10088   gtk_font_button_set_show_size(GTK_FONT_BUTTON(font_choo), FALSE);
10089   gtk_font_chooser_set_show_preview_entry(GTK_FONT_CHOOSER(font_choo), TRUE);
10090   gtk_font_chooser_set_preview_text(GTK_FONT_CHOOSER(font_choo), "LiVES");
10091   ttl = lives_strdup_printf("%s%s", widget_opts.title_prefix, _("Choose a Font..."));
10092   gtk_font_button_set_title(GTK_FONT_BUTTON(font_choo), ttl);
10093   lives_free(ttl);
10094 
10095   if (widget_opts.apply_theme) {
10096     set_standard_widget(font_choo, TRUE);
10097     lives_widget_apply_theme2(font_choo, LIVES_WIDGET_STATE_NORMAL, TRUE);
10098 
10099 #if GTK_CHECK_VERSION(3, 16, 0)
10100     set_css_min_size(font_choo, width, height);
10101     set_css_value_direct(font_choo, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
10102 
10103     lives_widget_set_padding(font_choo, 0);
10104     set_css_value_direct(font_choo, LIVES_WIDGET_STATE_NORMAL, "", "background", "none");
10105     //set_css_value_direct(font_choo, LIVES_WIDGET_STATE_NORMAL, "", "border-width", "0px");
10106 
10107     if (prefs->extra_colours && mainw->pretty_colours) {
10108       char *tmp;
10109       char *colref = gdk_rgba_to_string(&palette->nice1);
10110       set_css_value_direct(LIVES_WIDGET(font_choo), LIVES_WIDGET_STATE_NORMAL, "", "border-color", colref);
10111       tmp = lives_strdup_printf("0 0 0 1px %s inset", colref);
10112       set_css_value_direct(LIVES_WIDGET(font_choo), LIVES_WIDGET_STATE_PRELIGHT, "", "box-shadow", tmp);
10113       lives_free(tmp);
10114       lives_free(colref);
10115       colref = gdk_rgba_to_string(&palette->nice2);
10116       set_css_value_direct(LIVES_WIDGET(font_choo), LIVES_WIDGET_STATE_NORMAL, "", "background-color", colref);
10117     }
10118 
10119 #endif
10120   }
10121 #endif
10122 #endif
10123   return font_choo;
10124 }
10125 
10126 
10127 extern void on_filesel_button_clicked(LiVESButton *, livespointer);
10128 
lives_standard_dfentry_new(const char * labeltext,const char * txt,const char * defdir,int dispwidth,int maxchars,LiVESBox * box,const char * tooltip,boolean isdir)10129 static LiVESWidget *lives_standard_dfentry_new(const char *labeltext, const char *txt, const char *defdir, int dispwidth,
10130     int maxchars,
10131     LiVESBox * box, const char *tooltip, boolean isdir) {
10132   LiVESWidget *direntry = NULL;
10133   LiVESWidget *buttond;
10134   LiVESWidget *img_tips;
10135   LiVESWidget *warn_img;
10136 
10137   if (!box) return NULL;
10138 
10139   direntry = lives_standard_entry_new(labeltext, txt, dispwidth, maxchars == -1 ? PATH_MAX : maxchars, box, tooltip);
10140   lives_entry_set_editable(LIVES_ENTRY(direntry), FALSE);
10141 
10142   // add dir, with filechooser button
10143   buttond = lives_standard_file_button_new(isdir, defdir);
10144   if (widget_opts.last_label) lives_label_set_mnemonic_widget(LIVES_LABEL(widget_opts.last_label), buttond);
10145   lives_box_pack_start(LIVES_BOX(lives_widget_get_parent(direntry)), buttond, FALSE, FALSE, widget_opts.packing_width);
10146 
10147 
10148   if ((warn_img = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(direntry), WARN_IMAGE_KEY))) {
10149     lives_box_reorder_child(LIVES_BOX(lives_widget_get_parent(direntry)), buttond,
10150                             get_box_child_index(LIVES_BOX(lives_widget_get_parent(direntry)), warn_img));
10151   } else if ((img_tips = lives_widget_object_get_data(LIVES_WIDGET_OBJECT(direntry), HAS_TTIPS_IMAGE_KEY))) {
10152     lives_box_reorder_child(LIVES_BOX(lives_widget_get_parent(direntry)), buttond,
10153                             get_box_child_index(LIVES_BOX(lives_widget_get_parent(direntry)), img_tips));
10154   }
10155 
10156   lives_signal_sync_connect(buttond, LIVES_WIDGET_CLICKED_SIGNAL, LIVES_GUI_CALLBACK(on_filesel_button_clicked),
10157                             (livespointer)direntry);
10158   lives_widget_set_sensitive_with(buttond, direntry);
10159   lives_widget_set_show_hide_with(buttond, direntry);
10160   return direntry;
10161 }
10162 
10163 
lives_standard_direntry_new(const char * labeltext,const char * txt,int dispwidth,int maxchars,LiVESBox * box,const char * tooltip)10164 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_direntry_new(const char *labeltext, const char *txt, int dispwidth,
10165     int maxchars,
10166     LiVESBox * box, const char *tooltip) {
10167   return lives_standard_dfentry_new(labeltext, txt, txt, dispwidth, maxchars, box, tooltip, TRUE);
10168 }
10169 
10170 
lives_standard_fileentry_new(const char * labeltext,const char * txt,const char * defdir,int dispwidth,int maxchars,LiVESBox * box,const char * tooltip)10171 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_fileentry_new(const char *labeltext, const char *txt,
10172     const char *defdir,
10173     int dispwidth, int maxchars, LiVESBox * box, const char *tooltip) {
10174   return lives_standard_dfentry_new(labeltext, txt, defdir, dispwidth, maxchars, box, tooltip, FALSE);
10175 }
10176 
10177 
lives_standard_toolbar_new(void)10178 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_toolbar_new(void) {
10179   LiVESWidget *toolbar = lives_toolbar_new();
10180   lives_toolbar_set_show_arrow(LIVES_TOOLBAR(toolbar), TRUE);
10181   lives_toolbar_set_style(LIVES_TOOLBAR(toolbar), LIVES_TOOLBAR_ICONS);
10182   lives_toolbar_set_icon_size(LIVES_TOOLBAR(toolbar), widget_opts.icon_size);
10183   if (widget_opts.apply_theme) {
10184 #if GTK_CHECK_VERSION(3, 0, 0)
10185     set_css_min_size(toolbar, widget_opts.css_min_width, widget_opts.css_min_height);
10186 #endif
10187   }
10188   return toolbar;
10189 }
10190 
10191 
lives_standard_hscale_new(LiVESAdjustment * adj)10192 LiVESWidget *lives_standard_hscale_new(LiVESAdjustment * adj) {
10193   LiVESWidget *hscale = NULL;
10194 #ifdef GUI_GTK
10195 #if GTK_CHECK_VERSION(3, 0, 0)
10196   hscale = gtk_scale_new(LIVES_ORIENTATION_HORIZONTAL, adj);
10197 
10198   if (widget_opts.apply_theme) {
10199 #if GTK_CHECK_VERSION(3, 16, 0)
10200     char *colref = gdk_rgba_to_string(&palette->white);
10201     char *tmp = lives_strdup_printf("image(%s)", colref);
10202     set_css_value_direct(hscale, LIVES_WIDGET_STATE_NORMAL, "*",
10203                          "background-image", tmp);
10204     lives_free(tmp);
10205     lives_free(colref);
10206 
10207     if (prefs->extra_colours && mainw->pretty_colours) {
10208       colref = gdk_rgba_to_string(&palette->nice1);
10209       tmp = lives_strdup_printf("image(%s)", colref);
10210       set_css_value_direct(hscale, LIVES_WIDGET_STATE_NORMAL, "trough",
10211                            "background-image", tmp);
10212       lives_free(tmp);
10213       lives_free(colref);
10214     }
10215 
10216     set_css_min_size_selected(hscale, "slider", widget_opts.css_min_width, widget_opts.css_min_height);
10217     set_css_min_size_selected(hscale, "scale", DEF_BUTTON_WIDTH, widget_opts.css_min_height);
10218     set_css_value_direct(hscale, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
10219 #endif
10220   }
10221 
10222 #else
10223   hscale = gtk_hscale_new(adj);
10224 #endif
10225   gtk_scale_set_draw_value(LIVES_SCALE(hscale), FALSE);
10226 #endif
10227   return hscale;
10228 }
10229 
10230 
lives_standard_hruler_new(void)10231 LiVESWidget *lives_standard_hruler_new(void) {
10232   LiVESWidget *hruler = NULL;
10233 
10234 #ifdef GUI_GTK
10235 #if GTK_CHECK_VERSION(3, 0, 0)
10236   hruler = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL);
10237   gtk_scale_set_draw_value(GTK_SCALE(hruler), FALSE);
10238 #if GTK_CHECK_VERSION(3, 4, 0)
10239   gtk_scale_set_has_origin(GTK_SCALE(hruler), FALSE);
10240 #endif
10241   gtk_scale_set_digits(GTK_SCALE(hruler), 8);
10242 #else
10243   hruler = gtk_hruler_new();
10244   lives_widget_apply_theme(hruler, LIVES_WIDGET_STATE_INSENSITIVE);
10245 #endif
10246 
10247 #endif
10248 
10249   return hruler;
10250 }
10251 
10252 
lives_scrolled_window_scroll_to(LiVESScrolledWindow * sw,LiVESPositionType pos)10253 double lives_scrolled_window_scroll_to(LiVESScrolledWindow * sw, LiVESPositionType pos) {
10254   double val;
10255   LiVESAdjustment *adj;
10256   if (!sw) return -1.;
10257   else {
10258     if (pos == LIVES_POS_TOP || pos == LIVES_POS_BOTTOM) {
10259       adj = lives_scrolled_window_get_vadjustment(sw);
10260     } else {
10261       adj = lives_scrolled_window_get_hadjustment(sw);
10262     }
10263 
10264     if (pos == LIVES_POS_TOP || pos == LIVES_POS_LEFT) val = lives_adjustment_get_lower(adj);
10265     else val = lives_adjustment_get_upper(adj) - lives_adjustment_get_page_size(adj);
10266     lives_adjustment_set_value(adj, val);
10267   }
10268   return val;
10269 }
10270 
10271 
lives_standard_scrolled_window_new(int width,int height,LiVESWidget * child)10272 LiVESWidget *lives_standard_scrolled_window_new(int width, int height, LiVESWidget * child) {
10273   LiVESWidget *scrolledwindow = NULL;
10274   LiVESWidget *swchild;
10275 
10276   scrolledwindow = lives_scrolled_window_new(NULL, NULL);
10277   lives_scrolled_window_set_policy(LIVES_SCROLLED_WINDOW(scrolledwindow),
10278                                    LIVES_POLICY_AUTOMATIC, LIVES_POLICY_AUTOMATIC);
10279 
10280   if (LIVES_SHOULD_EXPAND_WIDTH)
10281     lives_widget_set_hexpand(scrolledwindow, TRUE);
10282   if (LIVES_SHOULD_EXPAND_HEIGHT)
10283     lives_widget_set_vexpand(scrolledwindow, TRUE);
10284 
10285   lives_container_set_border_width(LIVES_CONTAINER(scrolledwindow), widget_opts.border_width);
10286 
10287   if (child) {
10288 #ifdef GUI_GTK
10289 #if GTK_CHECK_VERSION(3, 0, 0)
10290     if (!LIVES_IS_SCROLLABLE(child))
10291 #else
10292     if (!LIVES_IS_TEXT_VIEW(child))
10293 #endif
10294     {
10295       lives_scrolled_window_add_with_viewport(LIVES_SCROLLED_WINDOW(scrolledwindow), child);
10296     } else {
10297       if (!LIVES_SHOULD_EXPAND_EXTRA_WIDTH) {
10298         LiVESWidget *align;
10299         align = lives_alignment_new(.5, 0., 0., 0.);
10300         lives_container_add(LIVES_CONTAINER(align), child);
10301         lives_scrolled_window_add_with_viewport(LIVES_SCROLLED_WINDOW(scrolledwindow), align);
10302       } else {
10303         lives_container_add(LIVES_CONTAINER(scrolledwindow), child);
10304       }
10305     }
10306 #endif
10307 #ifdef GUI_QT
10308     lives_container_add(scrolledwindow, child);
10309 #endif
10310   }
10311 
10312   swchild = lives_bin_get_child(LIVES_BIN(scrolledwindow));
10313 
10314 #ifdef GUI_QT
10315   if (width > -1 || height > -1)
10316     lives_widget_set_minimum_size(scrolledwindow, width, height);
10317 #endif
10318 
10319   lives_widget_apply_theme(swchild, LIVES_WIDGET_STATE_NORMAL);
10320 
10321   if (LIVES_SHOULD_EXPAND_WIDTH) {
10322     lives_widget_set_halign(swchild, LIVES_ALIGN_FILL);
10323     lives_widget_set_hexpand(swchild, TRUE);
10324   }
10325   if (LIVES_SHOULD_EXPAND_HEIGHT)
10326     lives_widget_set_vexpand(swchild, TRUE);
10327 
10328   if (LIVES_IS_CONTAINER(child) && LIVES_SHOULD_EXPAND) lives_container_set_border_width(LIVES_CONTAINER(child),
10329         widget_opts.border_width >> 1);
10330 
10331 #ifdef GUI_GTK
10332   if (GTK_IS_VIEWPORT(swchild))
10333     gtk_viewport_set_shadow_type(GTK_VIEWPORT(swchild), LIVES_SHADOW_IN);
10334 
10335   if (width != 0 && height != 0) {
10336 #if !GTK_CHECK_VERSION(3, 0, 0)
10337     if (width > -1 || height > -1)
10338       lives_widget_set_size_request(scrolledwindow, width, height);
10339     lives_widget_set_minimum_size(scrolledwindow, width, height); // crash if we dont have toplevel win
10340 #else
10341     if (height != -1) lives_scrolled_window_set_min_content_height(LIVES_SCROLLED_WINDOW(scrolledwindow), height);
10342     if (width != -1) lives_scrolled_window_set_min_content_width(LIVES_SCROLLED_WINDOW(scrolledwindow), width);
10343 #endif
10344   }
10345 #endif
10346 
10347   return scrolledwindow;
10348 }
10349 
10350 
lives_standard_expander_new(const char * ltext,LiVESBox * box,LiVESWidget * child)10351 LiVESWidget *lives_standard_expander_new(const char *ltext, LiVESBox * box, LiVESWidget * child) {
10352   LiVESWidget *expander = NULL, *container = NULL, *label = NULL;
10353 
10354 #ifdef GUI_GTK
10355   LiVESWidget *hbox;
10356   char *labeltext;
10357 
10358   if (LIVES_SHOULD_EXPAND) {
10359     labeltext = lives_strdup_printf("<big>%s</big>", ltext);
10360   } else labeltext = lives_strdup(ltext);
10361 
10362   expander = lives_expander_new(labeltext);
10363   lives_free(labeltext);
10364 
10365   lives_expander_set_use_markup(LIVES_EXPANDER(expander), TRUE);
10366 
10367   if (box) {
10368     int packing_width = 0;
10369 
10370     hbox = make_inner_hbox(LIVES_BOX(box), TRUE);
10371     lives_widget_set_show_hide_parent(expander);
10372     container = widget_opts.last_container;
10373 
10374     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width;
10375 
10376     if (widget_opts.justify == LIVES_JUSTIFY_CENTER || widget_opts.justify == LIVES_JUSTIFY_START)
10377       add_fill_to_box(LIVES_BOX(hbox));
10378 
10379     if (widget_opts.justify == LIVES_JUSTIFY_START) lives_widget_set_halign(expander, LIVES_ALIGN_START);
10380     if (widget_opts.justify != LIVES_JUSTIFY_END) add_fill_to_box(LIVES_BOX(hbox));
10381 
10382     if (widget_opts.justify == LIVES_JUSTIFY_CENTER) lives_widget_set_halign(expander, LIVES_ALIGN_CENTER);
10383     lives_box_pack_start(LIVES_BOX(hbox), expander, TRUE, TRUE, packing_width);
10384     lives_widget_set_valign(expander, LIVES_ALIGN_CENTER);
10385 
10386     if (widget_opts.justify == LIVES_JUSTIFY_END) lives_widget_set_halign(expander, LIVES_ALIGN_END);
10387     if (widget_opts.justify != LIVES_JUSTIFY_START) add_fill_to_box(LIVES_BOX(hbox));
10388 
10389     if (child) lives_container_add(LIVES_CONTAINER(expander), child);
10390     lives_container_set_border_width(LIVES_CONTAINER(expander), widget_opts.border_width);
10391   }
10392 
10393   if (widget_opts.apply_theme) {
10394 #ifdef GUI_GTK
10395 #if !GTK_CHECK_VERSION(3, 16, 0)
10396     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(expander), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
10397                                     LIVES_GUI_CALLBACK(widget_state_cb), NULL);
10398     widget_state_cb(LIVES_WIDGET_OBJECT(expander), NULL, NULL);
10399 
10400     if (widget_opts.last_label) {
10401       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget_opts.last_label), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
10402                                       LIVES_GUI_CALLBACK(widget_state_cb), NULL);
10403       widget_state_cb(LIVES_WIDGET_OBJECT(widget_opts.last_label), NULL, NULL);
10404     }
10405 #else
10406     set_css_value_direct(expander, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
10407 #endif
10408     lives_widget_apply_theme(expander, LIVES_WIDGET_STATE_NORMAL);
10409     lives_container_forall(LIVES_CONTAINER(expander), set_child_colour_internal, LIVES_INT_TO_POINTER(TRUE));
10410 #endif
10411   }
10412   label = lives_expander_get_label_widget(LIVES_EXPANDER(expander));
10413 #endif
10414   widget_opts.last_container = container;
10415   widget_opts.last_label = label;
10416   return expander;
10417 }
10418 
10419 
lives_standard_table_new(uint32_t rows,uint32_t cols,boolean homogeneous)10420 LiVESWidget *lives_standard_table_new(uint32_t rows, uint32_t cols, boolean homogeneous) {
10421   LiVESWidget *table = lives_table_new(rows, cols, homogeneous);
10422   lives_widget_apply_theme(table, LIVES_WIDGET_STATE_NORMAL);
10423   if (LIVES_SHOULD_EXPAND_WIDTH) lives_table_set_row_spacings(LIVES_TABLE(table),
10424         LIVES_SHOULD_EXPAND_EXTRA_WIDTH ? (widget_opts.packing_width << 2) : widget_opts.packing_width);
10425   else lives_table_set_row_spacings(LIVES_TABLE(table), 0);
10426   if (LIVES_SHOULD_EXPAND_HEIGHT) lives_table_set_col_spacings(LIVES_TABLE(table),
10427         LIVES_SHOULD_EXPAND_EXTRA_HEIGHT ? (widget_opts.packing_height << 2) : widget_opts.packing_height);
10428   else lives_table_set_col_spacings(LIVES_TABLE(table), 0);
10429   return table;
10430 }
10431 
10432 
lives_standard_text_view_new(const char * text,LiVESTextBuffer * tbuff)10433 LiVESWidget *lives_standard_text_view_new(const char *text, LiVESTextBuffer * tbuff) {
10434   LiVESWidget *textview;
10435 
10436   if (!tbuff)
10437     textview = lives_text_view_new();
10438   else
10439     textview = lives_text_view_new_with_buffer(tbuff);
10440 
10441   lives_widget_set_text_size(textview, LIVES_WIDGET_STATE_NORMAL, widget_opts.text_size);
10442   lives_text_view_set_editable(LIVES_TEXT_VIEW(textview), FALSE);
10443   lives_text_view_set_wrap_mode(LIVES_TEXT_VIEW(textview), LIVES_WRAP_WORD);
10444   lives_text_view_set_cursor_visible(LIVES_TEXT_VIEW(textview), FALSE);
10445   lives_container_set_border_width(LIVES_CONTAINER(textview), 2);
10446 
10447   if (text) {
10448     lives_text_view_set_text(LIVES_TEXT_VIEW(textview), text, -1);
10449   }
10450 
10451   if (widget_opts.apply_theme) {
10452     lives_widget_apply_theme3(textview, LIVES_WIDGET_STATE_NORMAL);
10453     if (prefs->extra_colours && mainw->pretty_colours) {
10454       char *colref = gdk_rgba_to_string(&palette->menu_and_bars);
10455       set_css_value_direct(textview, LIVES_WIDGET_STATE_NORMAL, "", "background-color", colref);
10456       lives_free(colref);
10457     }
10458     set_css_value_direct(textview, LIVES_WIDGET_STATE_INSENSITIVE, "", "opacity", "0.5");
10459   }
10460 
10461   lives_text_view_set_justification(LIVES_TEXT_VIEW(textview), widget_opts.justify);
10462   if (widget_opts.justify == LIVES_JUSTIFY_CENTER) {
10463     lives_widget_set_halign(textview, LIVES_ALIGN_CENTER);
10464     lives_widget_set_valign(textview, LIVES_ALIGN_CENTER);
10465   }
10466   return textview;
10467 }
10468 
10469 
lives_standard_file_button_new(boolean is_dir,const char * def_dir)10470 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_file_button_new(boolean is_dir, const char *def_dir) {
10471   LiVESWidget *fbutton;
10472   LiVESWidget *image = lives_image_new_from_stock(LIVES_STOCK_OPEN, LIVES_ICON_SIZE_BUTTON);
10473 
10474   /// height X height is correct
10475   fbutton = lives_standard_button_new(DEF_BUTTON_HEIGHT, DEF_BUTTON_HEIGHT);
10476   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(fbutton), ISDIR_KEY, LIVES_INT_TO_POINTER(is_dir));
10477   if (def_dir) lives_widget_object_set_data(LIVES_WIDGET_OBJECT(fbutton), DEFDIR_KEY, (livespointer)def_dir);
10478   lives_standard_button_set_image(LIVES_BUTTON(fbutton), image);
10479   return fbutton;
10480 }
10481 
10482 
lives_lock_button_get_locked(LiVESButton * button)10483 WIDGET_HELPER_GLOBAL_INLINE boolean lives_lock_button_get_locked(LiVESButton * button) {
10484   return (boolean)LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button),
10485                                        ISLOCKED_KEY));
10486 }
10487 
10488 
_on_lock_button_clicked(LiVESButton * button,livespointer user_data)10489 static void _on_lock_button_clicked(LiVESButton * button, livespointer user_data) {
10490   LiVESWidget *image;
10491   int locked = !(LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button),
10492                                       ISLOCKED_KEY)));
10493   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(button), ISLOCKED_KEY, LIVES_INT_TO_POINTER(locked));
10494   if (locked) {
10495     image = lives_image_new_from_stock(LIVES_LIVES_STOCK_LOCKED, LIVES_ICON_SIZE_BUTTON);
10496     lives_widget_set_opacity(LIVES_WIDGET(button), 1.0);
10497   } else {
10498     image = lives_image_new_from_stock(LIVES_LIVES_STOCK_UNLOCKED, LIVES_ICON_SIZE_BUTTON);
10499     lives_widget_set_opacity(LIVES_WIDGET(button), .75);
10500   }
10501   lives_standard_button_set_image(LIVES_BUTTON(button), image);
10502 }
10503 
10504 
label_act_lockbutton(LiVESWidget * widget,LiVESXEventButton * event,LiVESButton * lockbutton)10505 boolean label_act_lockbutton(LiVESWidget * widget, LiVESXEventButton * event, LiVESButton * lockbutton) {
10506   if (!lives_widget_is_sensitive(LIVES_WIDGET(lockbutton))) return FALSE;
10507   _on_lock_button_clicked(lockbutton, NULL);
10508   return FALSE;
10509 }
10510 
10511 
lives_lock_button_toggle(LiVESButton * button)10512 boolean lives_lock_button_toggle(LiVESButton * button) {
10513   _on_lock_button_clicked(button, NULL);
10514   return lives_lock_button_get_locked(button);
10515 }
10516 
10517 
lives_standard_lock_button_new(boolean is_locked,int width,int height,const char * label,const char * tooltip)10518 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_lock_button_new(boolean is_locked, int width,
10519     int height,
10520     const char *label,
10521     const char *tooltip) {
10522   LiVESWidget *lockbutton;
10523   lockbutton = lives_standard_button_new_with_label(label, width, height);
10524   lives_button_set_focus_on_click(LIVES_BUTTON(lockbutton), FALSE);
10525   if (tooltip) lives_widget_set_tooltip_text(lockbutton, tooltip);
10526   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(lockbutton), ISLOCKED_KEY, LIVES_INT_TO_POINTER(!is_locked));
10527   lives_signal_sync_connect(lockbutton, LIVES_WIDGET_CLICKED_SIGNAL, LIVES_GUI_CALLBACK(_on_lock_button_clicked), NULL);
10528   _on_lock_button_clicked(LIVES_BUTTON(lockbutton), LIVES_INT_TO_POINTER(widget_opts.apply_theme));
10529   return lockbutton;
10530 }
10531 
10532 
on_pwcolselx(LiVESButton * button,lives_rfx_t * rfx)10533 static void on_pwcolselx(LiVESButton * button, lives_rfx_t *rfx) {
10534   LiVESWidgetColor selected;
10535   LiVESWidget *sp_red = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), SPRED_KEY);
10536   LiVESWidget *sp_green = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), SPGREEN_KEY);
10537   LiVESWidget *sp_blue = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), SPBLUE_KEY);
10538   LiVESWidget *sp_alpha = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), SPALPHA_KEY);
10539 
10540   int r, g, b, a;
10541 
10542   lives_color_button_get_color(LIVES_COLOR_BUTTON(button), &selected);
10543 
10544   // get 0. -> 255. values
10545   if (sp_red) {
10546     r = (int)((double)(selected.red + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
10547     lives_spin_button_set_value(LIVES_SPIN_BUTTON(sp_red), (double)r);
10548   }
10549 
10550   if (sp_green) {
10551     g = (int)((double)(selected.green + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
10552     lives_spin_button_set_value(LIVES_SPIN_BUTTON(sp_green), (double)g);
10553   }
10554 
10555   if (sp_blue) {
10556     b = (int)((double)(selected.blue + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
10557     lives_spin_button_set_value(LIVES_SPIN_BUTTON(sp_blue), (double)b);
10558   }
10559 
10560   if (sp_alpha) {
10561 #if !LIVES_WIDGET_COLOR_HAS_ALPHA
10562     a = lives_color_button_get_alpha(LIVES_COLOR_BUTTON(button)) / 255.;
10563 #else
10564     a = (int)((double)(selected.alpha + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
10565 #endif
10566     lives_spin_button_set_value(LIVES_SPIN_BUTTON(sp_alpha), (double)a);
10567   }
10568 
10569   lives_color_button_set_color(LIVES_COLOR_BUTTON(button), &selected);
10570 }
10571 
10572 
after_param_red_changedx(LiVESSpinButton * spinbutton,livespointer udata)10573 static void after_param_red_changedx(LiVESSpinButton * spinbutton, livespointer udata) {
10574   LiVESWidgetColor colr;
10575 
10576   LiVESWidget *cbutton = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), CBUTTON_KEY);
10577   LiVESWidget *sp_green = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPGREEN_KEY);
10578   LiVESWidget *sp_blue = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPBLUE_KEY);
10579 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10580   LiVESWidget *sp_alpha = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPALPHA_KEY);
10581 #endif
10582 
10583   int new_red = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
10584   int old_green = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_green));
10585   int old_blue = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_blue));
10586 
10587   colr.red = LIVES_WIDGET_COLOR_SCALE_255(new_red);
10588   colr.green = LIVES_WIDGET_COLOR_SCALE_255(old_green);
10589   colr.blue = LIVES_WIDGET_COLOR_SCALE_255(old_blue);
10590 
10591 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10592   if (sp_alpha) {
10593     int old_alpha = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_alpha));
10594     colr.alpha = LIVES_WIDGET_COLOR_SCALE_255(old_alpha);
10595   } else colr.alpha = 1.0;
10596 #endif
10597   lives_color_button_set_color(LIVES_COLOR_BUTTON(cbutton), &colr);
10598 }
10599 
10600 
after_param_green_changedx(LiVESSpinButton * spinbutton,livespointer udata)10601 static void after_param_green_changedx(LiVESSpinButton * spinbutton, livespointer udata) {
10602   LiVESWidgetColor colr;
10603 
10604   LiVESWidget *cbutton = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), CBUTTON_KEY);
10605   LiVESWidget *sp_red = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPRED_KEY);
10606   LiVESWidget *sp_blue = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPBLUE_KEY);
10607 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10608   LiVESWidget *sp_alpha = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPALPHA_KEY);
10609 #endif
10610 
10611   int new_green = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
10612   int old_red = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_red));
10613   int old_blue = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_blue));
10614 
10615   colr.red = LIVES_WIDGET_COLOR_SCALE_255(old_red);
10616   colr.green = LIVES_WIDGET_COLOR_SCALE_255(new_green);
10617   colr.blue = LIVES_WIDGET_COLOR_SCALE_255(old_blue);
10618 
10619 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10620   if (sp_alpha) {
10621     int old_alpha = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_alpha));
10622     colr.alpha = LIVES_WIDGET_COLOR_SCALE_255(old_alpha);
10623   } else colr.alpha = 1.0;
10624 #endif
10625   lives_color_button_set_color(LIVES_COLOR_BUTTON(cbutton), &colr);
10626 }
10627 
10628 
after_param_blue_changedx(LiVESSpinButton * spinbutton,livespointer udata)10629 static void after_param_blue_changedx(LiVESSpinButton * spinbutton, livespointer udata) {
10630   LiVESWidgetColor colr;
10631 
10632   LiVESWidget *cbutton = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), CBUTTON_KEY);
10633   LiVESWidget *sp_green = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPGREEN_KEY);
10634   LiVESWidget *sp_red = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPRED_KEY);
10635 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10636   LiVESWidget *sp_alpha = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPALPHA_KEY);
10637 #endif
10638 
10639   int new_blue = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
10640   int old_green = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_green));
10641   int old_red = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_red));
10642 
10643   colr.red = LIVES_WIDGET_COLOR_SCALE_255(old_red);
10644   colr.green = LIVES_WIDGET_COLOR_SCALE_255(old_green);
10645   colr.blue = LIVES_WIDGET_COLOR_SCALE_255(new_blue);
10646 
10647 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10648   if (sp_alpha) {
10649     int old_alpha = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_alpha));
10650     colr.alpha = LIVES_WIDGET_COLOR_SCALE_255(old_alpha);
10651   } else colr.alpha = 1.0;
10652 #endif
10653   lives_color_button_set_color(LIVES_COLOR_BUTTON(cbutton), &colr);
10654 }
10655 
10656 
after_param_alpha_changedx(LiVESSpinButton * spinbutton,livespointer udata)10657 static void after_param_alpha_changedx(LiVESSpinButton * spinbutton, livespointer udata) {
10658   LiVESWidgetColor colr;
10659 
10660   LiVESWidget *cbutton = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), CBUTTON_KEY);
10661   LiVESWidget *sp_green = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPGREEN_KEY);
10662   LiVESWidget *sp_blue = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPBLUE_KEY);
10663   LiVESWidget *sp_red = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(cbutton), SPRED_KEY);
10664 
10665   int new_alpha = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
10666   int old_red = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_red));
10667   int old_green = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_green));
10668   int old_blue = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_blue));
10669 
10670   colr.red = LIVES_WIDGET_COLOR_SCALE_255(old_red);
10671   colr.green = LIVES_WIDGET_COLOR_SCALE_255(old_green);
10672   colr.blue = LIVES_WIDGET_COLOR_SCALE_255(old_blue);
10673 
10674 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10675   colr.alpha = LIVES_WIDGET_COLOR_SCALE_255(new_alpha);
10676 #else
10677   lives_color_button_set_alpha(LIVES_COLOR_BUTTON(cbutton), LIVES_WIDGET_COLOR_SCALE_255(new_alpha));
10678 #endif
10679   lives_color_button_set_color(LIVES_COLOR_BUTTON(cbutton), &colr);
10680 }
10681 
10682 
lives_standard_color_button_new(LiVESBox * box,const char * name,boolean use_alpha,lives_colRGBA64_t * rgba,LiVESWidget ** sb_red,LiVESWidget ** sb_green,LiVESWidget ** sb_blue,LiVESWidget ** sb_alpha)10683 LiVESWidget *lives_standard_color_button_new(LiVESBox * box, const char *name, boolean use_alpha, lives_colRGBA64_t *rgba,
10684     LiVESWidget **sb_red, LiVESWidget **sb_green, LiVESWidget **sb_blue, LiVESWidget **sb_alpha) {
10685   LiVESWidgetColor colr;
10686   LiVESWidget *cbutton, *labelcname = NULL;
10687   LiVESWidget *hbox = NULL;
10688   LiVESWidget *layout;
10689   LiVESWidget *frame = lives_standard_frame_new(NULL, 0., FALSE);
10690   LiVESWidget *spinbutton_red = NULL, *spinbutton_green = NULL, *spinbutton_blue = NULL, *spinbutton_alpha = NULL;
10691   LiVESWidget *parent = NULL;
10692   char *tmp, *tmp2;
10693 
10694   int packing_width = 0;
10695 
10696   boolean parent_is_layout = FALSE;
10697   boolean expand = FALSE;
10698 
10699   widget_opts.last_label = NULL;
10700 
10701   lives_container_set_border_width(LIVES_CONTAINER(frame), 0);
10702 
10703   if (box) {
10704     parent = lives_widget_get_parent(LIVES_WIDGET(box));
10705     if (parent && LIVES_IS_TABLE(parent) &&
10706         lives_widget_object_get_data(LIVES_WIDGET_OBJECT(parent), WADDED_KEY)) {
10707       parent_is_layout = TRUE;
10708       lives_table_set_column_homogeneous(LIVES_TABLE(parent), FALSE);
10709       hbox = LIVES_WIDGET(box);
10710     } else {
10711       hbox = make_inner_hbox(LIVES_BOX(box), !box || widget_opts.swap_label || !labelcname);
10712     }
10713     expand = LIVES_SHOULD_EXPAND_EXTRA_FOR(hbox);
10714 
10715     if (LIVES_SHOULD_EXPAND_WIDTH) packing_width = widget_opts.packing_width >> 1;
10716   }
10717 
10718   colr.red = LIVES_WIDGET_COLOR_SCALE_65535(rgba->red);
10719   colr.green = LIVES_WIDGET_COLOR_SCALE_65535(rgba->green);
10720   colr.blue = LIVES_WIDGET_COLOR_SCALE_65535(rgba->blue);
10721 #if LIVES_WIDGET_COLOR_HAS_ALPHA
10722   if (use_alpha) colr.alpha = LIVES_WIDGET_COLOR_SCALE_65535(rgba->alpha);
10723   else colr.alpha = 1.;
10724 #endif
10725 
10726   cbutton = lives_color_button_new_with_color(&colr);
10727 
10728   lives_color_button_set_use_alpha(LIVES_COLOR_BUTTON(cbutton), use_alpha);
10729   lives_color_button_set_color(LIVES_COLOR_BUTTON(cbutton), &colr);
10730   lives_widget_apply_theme(cbutton, LIVES_WIDGET_STATE_NORMAL);
10731   lives_widget_apply_theme2(cbutton, LIVES_WIDGET_STATE_PRELIGHT, TRUE);
10732   lives_widget_set_border_color(frame, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
10733 
10734 #if !LIVES_WIDGET_COLOR_HAS_ALPHA
10735   if (use_alpha)
10736     lives_color_button_set_alpha(LIVES_COLOR_BUTTON(cbutton), rgba->alpha);
10737 #endif
10738 
10739   if (name && box) {
10740     // must do this before re-using translation string !
10741     if (widget_opts.mnemonic_label) {
10742       labelcname = lives_standard_label_new_with_mnemonic_widget(name, cbutton);
10743     } else labelcname = lives_standard_label_new(name);
10744     lives_widget_set_show_hide_with(cbutton, labelcname);
10745     lives_widget_set_sensitive_with(cbutton, labelcname);
10746   }
10747 
10748   lives_widget_set_tooltip_text(cbutton, (_("Click to set the colour")));
10749   lives_color_button_set_title(LIVES_COLOR_BUTTON(cbutton), _("Select Colour"));
10750 
10751   if (box) {
10752     if (!widget_opts.swap_label) {
10753       if (labelcname) {
10754         if (LIVES_SHOULD_EXPAND_WIDTH) lives_widget_set_margin_left(labelcname, widget_opts.packing_width >> 2);
10755         lives_box_pack_start(LIVES_BOX(hbox), labelcname, FALSE, FALSE, widget_opts.packing_width);
10756         if (parent_is_layout) {
10757           hbox = lives_layout_hbox_new(LIVES_TABLE(parent));
10758           widget_opts.justify = LIVES_JUSTIFY_END;
10759         }
10760       }
10761     }
10762 
10763     if (sb_red) {
10764       layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY);
10765       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, NULL);
10766       spinbutton_red = lives_standard_spin_button_new((tmp = (_("_Red"))), rgba->red / 255., 0., 255., 1., 1., 0,
10767                        (LiVESBox *)hbox, (tmp2 = (_("The red value (0 - 255)"))));
10768       lives_free(tmp);
10769       lives_free(tmp2);
10770       lives_entry_set_width_chars(LIVES_ENTRY(spinbutton_red), 3);
10771       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, layout);
10772       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_red), CBUTTON_KEY, cbutton);
10773       *sb_red = spinbutton_red;
10774       lives_signal_sync_connect(LIVES_GUI_OBJECT(spinbutton_red), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
10775                                 LIVES_GUI_CALLBACK(after_param_red_changedx), NULL);
10776       if (parent_is_layout) {
10777         hbox = lives_layout_hbox_new(LIVES_TABLE(parent));
10778       } else if (expand) add_fill_to_box(LIVES_BOX(hbox));
10779       lives_widget_set_sensitive_with(cbutton, spinbutton_red);
10780       lives_widget_set_show_hide_with(cbutton, spinbutton_red);
10781     }
10782 
10783     if (sb_green) {
10784       layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY);
10785       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, NULL);
10786       spinbutton_green = lives_standard_spin_button_new((tmp = (_("_Green"))), rgba->green / 255., 0., 255., 1., 1., 0,
10787                          (LiVESBox *)hbox, (tmp2 = (_("The green value (0 - 255)"))));
10788       lives_free(tmp);
10789       lives_free(tmp2);
10790       lives_entry_set_width_chars(LIVES_ENTRY(spinbutton_green), 3);
10791       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, layout);
10792       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_green), CBUTTON_KEY, cbutton);
10793       *sb_green = spinbutton_green;
10794       lives_signal_sync_connect(LIVES_GUI_OBJECT(spinbutton_green), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
10795                                 LIVES_GUI_CALLBACK(after_param_green_changedx), NULL);
10796       if (parent_is_layout) {
10797         hbox = lives_layout_hbox_new(LIVES_TABLE(parent));
10798       } else if (expand) add_fill_to_box(LIVES_BOX(hbox));
10799       lives_widget_set_sensitive_with(cbutton, spinbutton_green);
10800       lives_widget_set_show_hide_with(cbutton, spinbutton_green);
10801     }
10802 
10803     if (sb_blue) {
10804       layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY);
10805       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, NULL);
10806       spinbutton_blue = lives_standard_spin_button_new((tmp = (_("_Blue"))), rgba->blue / 255., 0., 255., 1., 1., 0,
10807                         (LiVESBox *)hbox, (tmp2 = (_("The blue value (0 - 255)"))));
10808       lives_free(tmp);
10809       lives_free(tmp2);
10810       lives_entry_set_width_chars(LIVES_ENTRY(spinbutton_blue), 3);
10811       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, layout);
10812       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_blue), CBUTTON_KEY, cbutton);
10813       *sb_blue = spinbutton_blue;
10814       lives_signal_sync_connect(LIVES_GUI_OBJECT(spinbutton_blue), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
10815                                 LIVES_GUI_CALLBACK(after_param_blue_changedx), NULL);
10816       if (parent_is_layout) {
10817         hbox = lives_layout_hbox_new(LIVES_TABLE(parent));
10818       } else if (expand) add_fill_to_box(LIVES_BOX(hbox));
10819       lives_widget_set_sensitive_with(cbutton, spinbutton_blue);
10820       lives_widget_set_show_hide_with(cbutton, spinbutton_blue);
10821     }
10822 
10823     if (use_alpha && sb_alpha) {
10824       layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY);
10825       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, NULL);
10826       spinbutton_alpha = lives_standard_spin_button_new((tmp = (_("_Alpha"))), rgba->alpha / 255., 0., 255., 1., 1., 0,
10827                          (LiVESBox *)hbox, (tmp2 = (_("The alpha value (0 - 255)"))));
10828       lives_free(tmp);
10829       lives_free(tmp2);
10830       lives_entry_set_width_chars(LIVES_ENTRY(spinbutton_alpha), 3);
10831       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), WH_LAYOUT_KEY, layout);
10832       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_alpha), CBUTTON_KEY, cbutton);
10833       *sb_alpha = spinbutton_alpha;
10834       lives_signal_sync_connect(LIVES_GUI_OBJECT(spinbutton_alpha), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
10835                                 LIVES_GUI_CALLBACK(after_param_alpha_changedx), NULL);
10836       if (parent_is_layout) {
10837         hbox = lives_layout_hbox_new(LIVES_TABLE(parent));
10838       } else if (expand) add_fill_to_box(LIVES_BOX(hbox));
10839       lives_widget_set_sensitive_with(cbutton, spinbutton_alpha);
10840       lives_widget_set_show_hide_with(cbutton, spinbutton_alpha);
10841     }
10842 
10843     if (parent_is_layout) {
10844       widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
10845       hbox = make_inner_hbox(LIVES_BOX(hbox), TRUE);
10846     }
10847 
10848     lives_container_add(LIVES_CONTAINER(frame), cbutton);
10849     lives_box_pack_start(LIVES_BOX(hbox), frame, TRUE, FALSE, packing_width * 2.);
10850 
10851     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(cbutton), SPRED_KEY, spinbutton_red);
10852     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(cbutton), SPGREEN_KEY, spinbutton_green);
10853     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(cbutton), SPBLUE_KEY, spinbutton_blue);
10854     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(cbutton), SPALPHA_KEY, spinbutton_alpha);
10855 
10856     lives_widget_set_show_hide_parent(cbutton);
10857 
10858     if (widget_opts.apply_theme) {
10859       lives_widget_set_padding(cbutton, 0);
10860     }
10861 
10862     if (widget_opts.swap_label) {
10863       if (labelcname) {
10864         if (parent_is_layout) {
10865           hbox = lives_layout_hbox_new(LIVES_TABLE(parent));
10866           widget_opts.justify = LIVES_JUSTIFY_START;
10867         }
10868         if (LIVES_SHOULD_EXPAND_WIDTH) lives_widget_set_margin_right(labelcname, widget_opts.packing_width >> 2);
10869         lives_box_pack_start(LIVES_BOX(hbox), labelcname, FALSE, FALSE, widget_opts.packing_width);
10870       }
10871     }
10872   }
10873 
10874   if (parent_is_layout) {
10875     widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
10876   }
10877 
10878   lives_signal_sync_connect(LIVES_GUI_OBJECT(cbutton), LIVES_WIDGET_COLOR_SET_SIGNAL,
10879                             LIVES_GUI_CALLBACK(on_pwcolselx), NULL);
10880 
10881   widget_opts.last_label = labelcname;
10882   return cbutton;
10883 }
10884 
10885 
10886 // utils
10887 
10888 #if GTK_CHECK_VERSION(3, 10, 0)
10889 
10890 static const char *LIVES_STOCK_ALTS[N_STOCK_ALTS];
10891 
lives_get_stock_icon_alt(int alt_stock_id)10892 const char *lives_get_stock_icon_alt(int alt_stock_id) {
10893   return LIVES_STOCK_ALTS[alt_stock_id];
10894 }
10895 
10896 static const char *lives_icon_get_stock_alt(LiVESIconTheme * icon_theme, const char *str,  ...) GNU_SENTINEL;
lives_icon_get_stock_alt(LiVESIconTheme * icon_theme,const char * str,...)10897 static const char *lives_icon_get_stock_alt(LiVESIconTheme * icon_theme, const char *str, ...) {
10898   va_list xargs;
10899   va_start(xargs, str);
10900   for (; str; str++) {
10901     if (lives_has_icon(icon_theme, str, LIVES_ICON_SIZE_BUTTON)) break;
10902   }
10903   va_end(xargs);
10904   return str;
10905 }
10906 #endif
10907 
10908 
widget_helper_set_stock_icon_alts(LiVESIconTheme * icon_theme)10909 void widget_helper_set_stock_icon_alts(LiVESIconTheme * icon_theme) {
10910 #if GTK_CHECK_VERSION(3, 10, 0)
10911   LIVES_STOCK_ALTS[STOCK_ALTS_MEDIA_PAUSE] =
10912     lives_icon_get_stock_alt(icon_theme, LIVES_STOCK_MEDIA_PAUSE_ALT_1, LIVES_STOCK_MEDIA_PAUSE_ALT_2, (char *)NULL);
10913   LIVES_STOCK_ALTS[STOCK_ALTS_KEEP] =
10914     lives_icon_get_stock_alt(icon_theme, LIVES_STOCK_KEEP_ALT_1, LIVES_STOCK_KEEP_ALT_2, (char *)NULL);
10915 #endif
10916 }
10917 
10918 
widget_helper_init(void)10919 boolean widget_helper_init(void) {
10920 #ifdef GUI_GTK
10921   GSList *flist, *slist;
10922   LiVESList *dlist, *xlist = NULL;
10923   register int i;
10924 #endif
10925 
10926 #if !defined(GUI_GTK) || GTK_CHECK_VERSION(3, 10, 0)
10927   lives_snprintf(LIVES_STOCK_LABEL_CANCEL, 32, "%s", (_("_Cancel")));
10928   lives_snprintf(LIVES_STOCK_LABEL_OK, 32, "%s", (_("_OK")));
10929   lives_snprintf(LIVES_STOCK_LABEL_YES, 32, "%s", (_("_Yes")));
10930   lives_snprintf(LIVES_STOCK_LABEL_NO, 32, "%s", (_("_No")));
10931   lives_snprintf(LIVES_STOCK_LABEL_SAVE, 32, "%s", (_("_Save")));
10932   lives_snprintf(LIVES_STOCK_LABEL_SAVE_AS, 32, "%s", (_("Save _As")));
10933   lives_snprintf(LIVES_STOCK_LABEL_OPEN, 32, "%s", (_("_Open")));
10934   lives_snprintf(LIVES_STOCK_LABEL_QUIT, 32, "%s", (_("_Quit")));
10935   lives_snprintf(LIVES_STOCK_LABEL_APPLY, 32, "%s", (_("_Apply")));
10936   lives_snprintf(LIVES_STOCK_LABEL_CLOSE, 32, "%s", (_("_Close")));
10937   lives_snprintf(LIVES_STOCK_LABEL_REVERT, 32, "%s", (_("_Revert")));
10938   lives_snprintf(LIVES_STOCK_LABEL_REFRESH, 32, "%s", (_("_Refresh")));
10939   lives_snprintf(LIVES_STOCK_LABEL_DELETE, 32, "%s", (_("_Delete")));
10940   lives_snprintf(LIVES_STOCK_LABEL_GO_FORWARD, 32, "%s", (_("_Forward")));
10941   lives_snprintf(LIVES_STOCK_LABEL_MEDIA_FORWARD, 32, "%s", (_("R_ewind")));
10942   lives_snprintf(LIVES_STOCK_LABEL_MEDIA_REWIND, 32, "%s", (_("_Forward")));
10943   lives_snprintf(LIVES_STOCK_LABEL_MEDIA_PLAY, 32, "%s", (_("_Play")));
10944   lives_snprintf(LIVES_STOCK_LABEL_MEDIA_PAUSE, 32, "%s", (_("P_ause")));
10945   lives_snprintf(LIVES_STOCK_LABEL_MEDIA_STOP, 32, "%s", (_("_Stop")));
10946   lives_snprintf(LIVES_STOCK_LABEL_MEDIA_RECORD, 32, "%s", (_("_Record")));
10947   lives_snprintf(LIVES_STOCK_LABEL_SELECT_ALL, 32, "%s", (_("_Select All")));
10948 
10949   // non-standard
10950   lives_snprintf(LIVES_STOCK_LABEL_CLOSE_WINDOW, 32, "%s", (_("_Close Window")));
10951   lives_snprintf(LIVES_STOCK_LABEL_SKIP, 32, "%s", (_("_Skip")));
10952   lives_snprintf(LIVES_STOCK_LABEL_SELECT, 32, "%s", (_("_Select")));
10953 #endif
10954 
10955   def_widget_opts = _def_widget_opts;
10956   lives_memcpy(&widget_opts, &def_widget_opts, sizeof(widget_opts_t));
10957 
10958   // TODO: - for rtl set swap_labels ?
10959 
10960 #ifdef GUI_GTK
10961   gtk_accel_map_add_entry("<LiVES>/save", LIVES_KEY_s, LIVES_CONTROL_MASK);
10962   gtk_accel_map_add_entry("<LiVES>/quit", LIVES_KEY_q, LIVES_CONTROL_MASK);
10963 
10964   slist = flist = gdk_pixbuf_get_formats();
10965   while (slist) {
10966     GdkPixbufFormat *form = (GdkPixbufFormat *)slist->data;
10967     char **ext = gdk_pixbuf_format_get_extensions(form);
10968     for (i = 0; ext[i]; i++) {
10969       xlist = lives_list_append_unique(xlist, lives_strdup(ext[i]));
10970     }
10971     lives_strfreev(ext);
10972     slist = slist->next;
10973   }
10974   g_slist_free(flist);
10975 #endif
10976 
10977   if (xlist) {
10978     dlist = xlist;
10979     widget_opts.image_filter = (char **)lives_malloc((lives_list_length(xlist) + 1) * sizeof(char *));
10980     for (i = 0; dlist; i++) {
10981       widget_opts.image_filter[i] = lives_strdup_printf("*.%s", (char *)dlist->data);
10982       dlist = dlist->next;
10983     }
10984     widget_opts.image_filter[i] = NULL;
10985     lives_list_free_all(&xlist);
10986   }
10987   return TRUE;
10988 }
10989 
10990 
widget_opts_rescale(double scale)10991 boolean widget_opts_rescale(double scale) {
10992   widget_opts.scale = scale;
10993   if (def_widget_opts.css_min_width != -1) {
10994     widget_opts.css_min_width = (int)((double)def_widget_opts.css_min_width * widget_opts.scale + .5);
10995     widget_opts.css_min_width = ((widget_opts.css_min_width + 1) >> 1) << 1;
10996   }
10997   if (def_widget_opts.css_min_height != -1) {
10998     widget_opts.css_min_height = (int)((double)def_widget_opts.css_min_height * widget_opts.scale + .5);
10999     widget_opts.css_min_height = ((widget_opts.css_min_height + 1) >> 1) << 1;
11000   }
11001   widget_opts.border_width = (int)((double)def_widget_opts.border_width * widget_opts.scale + .5);
11002   widget_opts.packing_width = (int)((double)def_widget_opts.packing_width * widget_opts.scale + .5);
11003   widget_opts.packing_height = (int)((double)def_widget_opts.packing_height * widget_opts.scale + .5);
11004   widget_opts.filler_len = (int)((double)def_widget_opts.filler_len * widget_opts.scale + .5);
11005   return TRUE;
11006 }
11007 
11008 
lives_widget_queue_draw_if_visible(LiVESWidget * widget)11009 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw_if_visible(LiVESWidget * widget) {
11010   if (GTK_IS_WIDGET(widget) && gtk_widget_is_drawable(widget)) {
11011     lives_widget_queue_draw(widget);
11012     return TRUE;
11013   }
11014   return FALSE;
11015 }
11016 
11017 
lives_widget_queue_draw_and_update(LiVESWidget * widget)11018 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw_and_update(LiVESWidget * widget) {
11019   lives_widget_queue_draw(widget);
11020   lives_widget_process_updates(widget);
11021   return FALSE;
11022 }
11023 
11024 
lives_utf8_strcmpfunc(livesconstpointer a,livesconstpointer b,livespointer fwd)11025 int lives_utf8_strcmpfunc(livesconstpointer a, livesconstpointer b, livespointer fwd) {
11026   // do not inline !
11027   int ret;
11028   char *tmp1, *tmp2;
11029   if (LIVES_POINTER_TO_INT(fwd))
11030     ret = lives_strcmp_ordered((tmp1 = lives_utf8_collate_key(a, -1)),
11031                                (tmp2 = lives_utf8_collate_key(b, -1)));
11032   else
11033     ret = lives_strcmp_ordered((tmp1 = lives_utf8_collate_key(b, -1)),
11034                                (tmp2 = lives_utf8_collate_key(a, -1)));
11035   lives_free(tmp1);
11036   lives_free(tmp2);
11037   return ret;
11038 }
11039 
11040 
lives_utf8_menu_strcmpfunc(livesconstpointer a,livesconstpointer b,livespointer fwd)11041 static int lives_utf8_menu_strcmpfunc(livesconstpointer a, livesconstpointer b, livespointer fwd) {
11042   return lives_utf8_strcmpfunc(lives_menu_item_get_text((LiVESWidget *)a), lives_menu_item_get_text((LiVESWidget *)b), fwd);
11043 }
11044 
11045 
lives_menu_list_sort_alpha(LiVESList * list,boolean fwd)11046 WIDGET_HELPER_LOCAL_INLINE LiVESList *lives_menu_list_sort_alpha(LiVESList * list, boolean fwd) {
11047   return lives_list_sort_with_data(list, lives_utf8_menu_strcmpfunc, LIVES_INT_TO_POINTER(fwd));
11048 }
11049 
11050 
add_sorted_list_to_menu(LiVESMenu * menu,LiVESList * menu_list)11051 LiVESList *add_sorted_list_to_menu(LiVESMenu * menu, LiVESList * menu_list) {
11052   LiVESList **seclist;
11053   LiVESList *xmenu_list = menu_list = lives_menu_list_sort_alpha(menu_list, TRUE);
11054   while (menu_list) {
11055     if (!(LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(menu_list->data), HIDDEN_KEY)))) {
11056       lives_container_add(LIVES_CONTAINER(menu), (LiVESWidget *)menu_list->data);
11057     }
11058     if ((seclist = (LiVESList **)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(menu_list->data), SECLIST_KEY)) != NULL)
11059       * seclist = lives_list_prepend(*seclist, lives_widget_object_get_data(LIVES_WIDGET_OBJECT(menu_list->data),
11060                                      SECLIST_VAL_KEY));
11061     menu_list = menu_list->next;
11062   }
11063   return xmenu_list;
11064 }
11065 
11066 
lives_has_icon(LiVESIconTheme * icon_theme,const char * stock_id,LiVESIconSize size)11067 boolean lives_has_icon(LiVESIconTheme * icon_theme, const char *stock_id, LiVESIconSize size)  {
11068   boolean has_icon = FALSE;
11069 #ifdef GUI_GTK
11070 #if GTK_CHECK_VERSION(3, 0, 0)
11071   GtkIconInfo *iset = gtk_icon_theme_lookup_icon(icon_theme, stock_id, size, 0);
11072 #else
11073   GtkIconSet *iset = gtk_icon_factory_lookup_default(stock_id);
11074 #endif
11075   has_icon = (iset != NULL);
11076 #endif
11077   return has_icon;
11078 }
11079 
11080 
lives_painter_set_source_rgb_from_lives_rgb(lives_painter_t * cr,lives_colRGB48_t * col)11081 WIDGET_HELPER_GLOBAL_INLINE lives_colRGB48_t *lives_painter_set_source_rgb_from_lives_rgb(lives_painter_t *cr,
11082     lives_colRGB48_t *col) {
11083   lives_painter_set_source_rgb(cr, (double)col->red / 65535.,
11084                                (double)col->green / 65535.,
11085                                (double)col->blue / 65535.);
11086   return col;
11087 }
11088 
11089 
lives_painter_set_source_rgb_from_lives_rgba(lives_painter_t * cr,lives_colRGBA64_t * col)11090 WIDGET_HELPER_GLOBAL_INLINE lives_colRGBA64_t *lives_painter_set_source_rgb_from_lives_rgba(lives_painter_t *cr,
11091     lives_colRGBA64_t *col) {
11092   lives_painter_set_source_rgb(cr, (double)col->red / 65535.,
11093                                (double)col->green / 65535.,
11094                                (double)col->blue / 65535.);
11095   return col;
11096 }
11097 
11098 
lives_painter_set_source_rgb_from_lives_widget_color(lives_painter_t * cr,LiVESWidgetColor * wcol)11099 WIDGET_HELPER_GLOBAL_INLINE LiVESWidgetColor *lives_painter_set_source_rgb_from_lives_widget_color(lives_painter_t *cr,
11100     LiVESWidgetColor * wcol) {
11101   lives_colRGBA64_t col;
11102   widget_color_to_lives_rgba(&col, wcol);
11103   lives_painter_set_source_rgb_from_lives_rgba(cr, &col);
11104   return wcol;
11105 }
11106 
11107 
clear_widget_bg(LiVESWidget * widget,lives_painter_surface_t * s)11108 WIDGET_HELPER_GLOBAL_INLINE boolean clear_widget_bg(LiVESWidget * widget, lives_painter_surface_t *s) {
11109   lives_painter_t *cr;
11110   if (!s) return FALSE;
11111   if (!(cr = lives_painter_create_from_surface(s))) return FALSE;
11112   else {
11113     int rwidth = lives_widget_get_allocation_width(LIVES_WIDGET(widget));
11114     int rheight = lives_widget_get_allocation_height(LIVES_WIDGET(widget));
11115     lives_painter_render_background(widget, cr, 0., 0., rwidth, rheight);
11116     lives_painter_destroy(cr);
11117   }
11118   return TRUE;
11119 }
11120 
11121 
clear_widget_bg_area(LiVESWidget * widget,lives_painter_surface_t * s,double x,double y,double width,double height)11122 WIDGET_HELPER_GLOBAL_INLINE boolean clear_widget_bg_area(LiVESWidget * widget, lives_painter_surface_t *s,
11123     double x, double y, double width, double height) {
11124   lives_painter_t *cr;
11125   if (!s) return FALSE;
11126   if (!(cr = lives_painter_create_from_surface(s))) return FALSE;
11127   else {
11128     int rwidth = lives_widget_get_allocation_width(LIVES_WIDGET(widget));
11129     int rheight = lives_widget_get_allocation_height(LIVES_WIDGET(widget));
11130     if (width <= 0.) width = rwidth;
11131     if (height <= 0.) height = rheight;
11132     lives_painter_render_background(widget, cr, x, y, width, height);
11133     lives_painter_destroy(cr);
11134   }
11135   return TRUE;
11136 }
11137 
11138 
lives_cursor_unref(LiVESXCursor * cursor)11139 WIDGET_HELPER_GLOBAL_INLINE boolean lives_cursor_unref(LiVESXCursor * cursor) {
11140 #ifdef GUI_GTK
11141 #if GTK_CHECK_VERSION(3, 0, 0)
11142   g_object_unref(LIVES_GUI_OBJECT(cursor));
11143 #else
11144   gdk_cursor_unref(cursor);
11145   return TRUE;
11146 #endif
11147 #endif
11148 #ifdef GUI_QT
11149   delete cursor;
11150   return TRUE;
11151 #endif
11152   return FALSE;
11153 }
11154 
11155 
lives_widget_apply_theme(LiVESWidget * widget,LiVESWidgetState state)11156 void lives_widget_apply_theme(LiVESWidget * widget, LiVESWidgetState state) {
11157   if (!palette || ((palette->style & STYLE_1) && !widget_opts.apply_theme)) return;
11158   lives_widget_set_fg_color(widget, state, &palette->normal_fore);
11159   lives_widget_set_bg_color(widget, state, &palette->normal_back);
11160 #if GTK_CHECK_VERSION(3, 0, 0)
11161   lives_widget_set_base_color(widget, state, &palette->normal_back);
11162   lives_widget_set_text_color(widget, state, &palette->normal_fore);
11163 #endif
11164   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), THEME_KEY,
11165                                LIVES_INT_TO_POINTER(widget_opts.apply_theme));
11166 }
11167 
11168 
lives_widget_apply_theme2(LiVESWidget * widget,LiVESWidgetState state,boolean set_fg)11169 void lives_widget_apply_theme2(LiVESWidget * widget, LiVESWidgetState state, boolean set_fg) {
11170   if (!widget_opts.apply_theme) {
11171     if (!(palette->style & STYLE_1)) {
11172       lives_widget_set_fg_color(widget, state, &palette->normal_fore);
11173       lives_widget_set_bg_color(widget, state, &palette->normal_back);
11174     }
11175     return;
11176   }
11177   if (set_fg)
11178     lives_widget_set_fg_color(widget, state, &palette->menu_and_bars_fore);
11179   lives_widget_set_bg_color(widget, state, &palette->menu_and_bars);
11180 }
11181 
11182 
lives_widget_apply_theme3(LiVESWidget * widget,LiVESWidgetState state)11183 void lives_widget_apply_theme3(LiVESWidget * widget, LiVESWidgetState state) {
11184   if (!widget_opts.apply_theme) {
11185     if (!(palette->style & STYLE_1)) {
11186       lives_widget_set_fg_color(widget, state, &palette->normal_fore);
11187       lives_widget_set_bg_color(widget, state, &palette->normal_back);
11188     }
11189     return;
11190   }
11191   if (palette->style & STYLE_1) {
11192     lives_widget_set_text_color(widget, state, &palette->info_text);
11193     lives_widget_set_base_color(widget, state, &palette->info_base);
11194     lives_widget_set_fg_color(widget, state, &palette->info_text);
11195     lives_widget_set_bg_color(widget, state, &palette->info_base);
11196   }
11197 }
11198 
11199 
lives_widget_apply_theme_dimmed(LiVESWidget * widget,LiVESWidgetState state,int dimval)11200 void lives_widget_apply_theme_dimmed(LiVESWidget * widget, LiVESWidgetState state, int dimval) {
11201   if (!widget_opts.apply_theme) return;
11202   if (palette->style & STYLE_1) {
11203     LiVESWidgetColor dimmed_fg;
11204     lives_widget_color_copy(&dimmed_fg, &palette->normal_fore);
11205     lives_widget_color_mix(&dimmed_fg, &palette->normal_back, (float)dimval / 65535.);
11206     lives_widget_set_fg_color(widget, state, &dimmed_fg);
11207     lives_widget_set_bg_color(widget, state, &palette->normal_back);
11208   }
11209 }
11210 
11211 
lives_widget_apply_theme_dimmed2(LiVESWidget * widget,LiVESWidgetState state,int dimval)11212 void lives_widget_apply_theme_dimmed2(LiVESWidget * widget, LiVESWidgetState state, int dimval) {
11213   if (!widget_opts.apply_theme) return;
11214   if (palette->style & STYLE_1) {
11215     LiVESWidgetColor dimmed_fg;
11216     lives_widget_color_copy(&dimmed_fg, &palette->menu_and_bars_fore);
11217     lives_widget_color_mix(&dimmed_fg, &palette->menu_and_bars, (float)dimval / 65535.);
11218     lives_widget_set_fg_color(widget, state, &dimmed_fg);
11219     lives_widget_set_bg_color(widget, state, &palette->menu_and_bars);
11220   }
11221 }
11222 
11223 
lives_entry_set_completion_from_list(LiVESEntry * entry,LiVESList * xlist)11224 boolean lives_entry_set_completion_from_list(LiVESEntry * entry, LiVESList * xlist) {
11225 #ifdef GUI_GTK
11226   GtkListStore *store;
11227   LiVESEntryCompletion *completion;
11228   store = gtk_list_store_new(1, LIVES_COL_TYPE_STRING);
11229 
11230   while (xlist) {
11231     LiVESTreeIter iter;
11232     gtk_list_store_append(store, &iter);
11233     gtk_list_store_set(store, &iter, 0, (char *)xlist->data, -1);
11234     xlist = xlist->next;
11235   }
11236 
11237   completion = gtk_entry_completion_new();
11238   gtk_entry_completion_set_model(completion, (GtkTreeModel *)store);
11239   gtk_entry_completion_set_text_column(completion, 0);
11240   gtk_entry_completion_set_inline_completion(completion, TRUE);
11241   gtk_entry_completion_set_popup_set_width(completion, TRUE);
11242   gtk_entry_completion_set_popup_completion(completion, TRUE);
11243   gtk_entry_completion_set_popup_single_match(completion, FALSE);
11244   gtk_entry_set_completion(entry, completion);
11245   return TRUE;
11246 #endif
11247   return FALSE;
11248 }
11249 
11250 
lives_window_center(LiVESWindow * window)11251 boolean lives_window_center(LiVESWindow * window) {
11252   if (!widget_opts.no_gui) {
11253     int xcen, ycen;
11254     int width, height;
11255     int bx, by;
11256 
11257     lives_window_set_monitor(LIVES_WINDOW(window), widget_opts.monitor);
11258 
11259     if (!mainw->mgeom) {
11260       lives_widget_show(LIVES_WIDGET(window));
11261       lives_window_set_position(LIVES_WINDOW(window), LIVES_WIN_POS_CENTER_ALWAYS);
11262       return TRUE;
11263     }
11264 
11265     lives_window_set_position(LIVES_WINDOW(window), LIVES_WIN_POS_CENTER_ALWAYS);
11266 
11267     width = lives_widget_get_allocation_width(LIVES_WIDGET(window));
11268     if (width == 0) width = ((int)(620. * widget_opts.scale)); // MIN_MSGBOX_WIDTH in interface.h
11269     height = lives_widget_get_allocation_height(LIVES_WIDGET(window));
11270 
11271     get_border_size(LIVES_WIDGET(window), &bx, &by);
11272     width += bx;
11273     height += by;
11274 
11275     xcen = mainw->mgeom[widget_opts.monitor].x + ((mainw->mgeom[widget_opts.monitor].width - width) >> 1);
11276 
11277     ycen = mainw->mgeom[widget_opts.monitor].y + ((mainw->mgeom[widget_opts.monitor].height - height) >> 1);
11278     lives_window_move(LIVES_WINDOW(window), xcen, ycen);
11279   }
11280   return TRUE;
11281 }
11282 
11283 
lives_window_uncenter(LiVESWindow * window)11284 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_uncenter(LiVESWindow * window) {
11285   lives_window_set_position(LIVES_WINDOW(window), LIVES_WIN_POS_NONE);
11286   return TRUE;
11287 }
11288 
11289 
lives_widget_get_fg_color(LiVESWidget * widget,LiVESWidgetColor * color)11290 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_get_fg_color(LiVESWidget * widget, LiVESWidgetColor * color) {
11291   return lives_widget_get_fg_state_color(widget, LIVES_WIDGET_STATE_NORMAL, color);
11292 }
11293 
11294 
lives_widget_unparent(LiVESWidget * widget)11295 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_unparent(LiVESWidget * widget) {
11296   return lives_container_remove(LIVES_CONTAINER(lives_widget_get_parent(widget)), widget);
11297 }
11298 
11299 
_toggle_if_condmet(LiVESWidget * tbut,livespointer widget,boolean cond,const char * type)11300 static void _toggle_if_condmet(LiVESWidget * tbut, livespointer widget, boolean cond, const char *type) {
11301   char *keyval;
11302   int *condx;
11303 
11304   if (!cond) {
11305     keyval = lives_strdup_printf("%p_in%s_cond", widget, type);
11306     condx = (int *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(tbut), keyval);
11307     if (condx && *condx != 0) cond = TRUE;
11308   } else {
11309     keyval = lives_strdup_printf("%p_%s_cond", widget, type);
11310     condx = (int *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(tbut), keyval);
11311     if (condx && *condx <= 0) cond = FALSE;
11312   }
11313   lives_free(keyval);
11314   if (!strcmp(type, "sens"))
11315     lives_widget_set_sensitive(LIVES_WIDGET(widget), cond);
11316   else if (!strcmp(type, "visi")) {
11317     if (cond) lives_widget_show(LIVES_WIDGET(widget));
11318     else lives_widget_hide(LIVES_WIDGET(widget));
11319   }
11320 }
11321 
toggle_set_sensitive(LiVESWidget * tbut,livespointer widget)11322 static void toggle_set_sensitive(LiVESWidget * tbut, livespointer widget) {
11323   if (LIVES_IS_TOGGLE_BUTTON(tbut))
11324     _toggle_if_condmet(tbut, widget, lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tbut)), "sens");
11325   else if (LIVES_IS_TOGGLE_TOOL_BUTTON(tbut))
11326     _toggle_if_condmet(tbut, widget, lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(tbut)),
11327                        "sens");
11328   else if (LIVES_IS_CHECK_MENU_ITEM(tbut))
11329     _toggle_if_condmet(tbut, widget, lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(tbut)),
11330                        "sens");
11331 }
11332 
toggle_set_insensitive(LiVESWidget * tbut,livespointer widget)11333 static void toggle_set_insensitive(LiVESWidget * tbut, livespointer widget) {
11334   if (LIVES_IS_TOGGLE_BUTTON(tbut))
11335     _toggle_if_condmet(tbut, widget, !lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tbut)),
11336                        "sens");
11337   if (LIVES_IS_TOGGLE_TOOL_BUTTON(tbut))
11338     _toggle_if_condmet(tbut, widget, !lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(tbut)),
11339                        "sens");
11340   else if (LIVES_IS_CHECK_MENU_ITEM(tbut))
11341     _toggle_if_condmet(tbut, widget, !lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(tbut)),
11342                        "sens");
11343 }
11344 
toggle_set_visible(LiVESWidget * tbut,livespointer widget)11345 static void toggle_set_visible(LiVESWidget * tbut, livespointer widget) {
11346   if (LIVES_IS_TOGGLE_BUTTON(tbut))
11347     _toggle_if_condmet(tbut, widget, lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tbut)), "visi");
11348   else if (LIVES_IS_TOGGLE_TOOL_BUTTON(tbut))
11349     _toggle_if_condmet(tbut, widget, lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(tbut)),
11350                        "visi");
11351   else if (LIVES_IS_CHECK_MENU_ITEM(tbut))
11352     _toggle_if_condmet(tbut, widget, lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(tbut)),
11353                        "visi");
11354 }
11355 
toggle_set_invisible(LiVESWidget * tbut,livespointer widget)11356 static void toggle_set_invisible(LiVESWidget * tbut, livespointer widget) {
11357   if (LIVES_IS_TOGGLE_BUTTON(tbut))
11358     _toggle_if_condmet(tbut, widget, !lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tbut)),
11359                        "visi");
11360   else if (LIVES_IS_TOGGLE_TOOL_BUTTON(tbut))
11361     _toggle_if_condmet(tbut, widget, !lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(tbut)),
11362                        "visi");
11363   else if (LIVES_IS_CHECK_MENU_ITEM(tbut))
11364     _toggle_if_condmet(tbut, widget, !lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(tbut)),
11365                        "visi");
11366 }
11367 
11368 // togglebutton functions
11369 
toggle_sets_sensitive_cond(LiVESWidget * tb,LiVESWidget * widget,livespointer condsens,livespointer condinsens,boolean invert)11370 boolean toggle_sets_sensitive_cond(LiVESWidget * tb, LiVESWidget * widget,
11371                                    livespointer condsens, livespointer condinsens, boolean invert) {
11372   if (condsens) {
11373     /// set sensitive only if *condsens > 0
11374     char *keyval = lives_strdup_printf("%p_sens_cond", widget);
11375     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(tb), keyval, condsens);
11376   }
11377 
11378   if (condinsens) {
11379     /// set insensitive only if *condinsens == 0
11380     char *keyval = lives_strdup_printf("%p_insens_cond", widget);
11381     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(tb), keyval, condinsens);
11382   }
11383 
11384   if (!invert) {
11385     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tb), LIVES_WIDGET_TOGGLED_SIGNAL,
11386                                     LIVES_GUI_CALLBACK(toggle_set_sensitive),
11387                                     (livespointer)widget);
11388     toggle_set_sensitive(LIVES_WIDGET(tb), (livespointer)widget);
11389   } else {
11390     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tb), LIVES_WIDGET_TOGGLED_SIGNAL,
11391                                     LIVES_GUI_CALLBACK(toggle_set_insensitive),
11392                                     (livespointer)widget);
11393     toggle_set_insensitive(tb, (livespointer)widget);
11394   }
11395   return TRUE;
11396 }
11397 
toggle_sets_visible_cond(LiVESWidget * tb,LiVESWidget * widget,livespointer condsens,livespointer condinsens,boolean invert)11398 boolean toggle_sets_visible_cond(LiVESWidget * tb, LiVESWidget * widget,
11399                                  livespointer condsens, livespointer condinsens, boolean invert) {
11400   if (condsens) {
11401     /// set sensitive only if *condsens > 0
11402     char *keyval = lives_strdup_printf("%p_visi_cond", widget);
11403     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(tb), keyval, condsens);
11404   }
11405 
11406   if (condinsens) {
11407     /// set insensitive only if *condinsens == 0
11408     char *keyval = lives_strdup_printf("%p_invisi_cond", widget);
11409     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(tb), keyval, condinsens);
11410   }
11411 
11412   if (!invert) {
11413     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tb), LIVES_WIDGET_TOGGLED_SIGNAL,
11414                                     LIVES_GUI_CALLBACK(toggle_set_visible),
11415                                     (livespointer)widget);
11416     toggle_set_sensitive(tb, (livespointer)widget);
11417   } else {
11418     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tb), LIVES_WIDGET_TOGGLED_SIGNAL,
11419                                     LIVES_GUI_CALLBACK(toggle_set_invisible),
11420                                     (livespointer)widget);
11421     toggle_set_insensitive(tb, (livespointer)widget);
11422   }
11423   return TRUE;
11424 }
11425 
11426 
toggle_sets_sensitive(LiVESToggleButton * tb,LiVESWidget * widget,boolean invert)11427 WIDGET_HELPER_GLOBAL_INLINE boolean toggle_sets_sensitive(LiVESToggleButton * tb, LiVESWidget * widget,
11428     boolean invert) {
11429   return toggle_sets_sensitive_cond(LIVES_WIDGET(tb), widget, NULL, NULL, invert);
11430 }
toggle_toolbutton_sets_sensitive(LiVESToggleToolButton * ttb,LiVESWidget * widget,boolean invert)11431 WIDGET_HELPER_GLOBAL_INLINE boolean toggle_toolbutton_sets_sensitive(LiVESToggleToolButton * ttb, LiVESWidget * widget,
11432     boolean invert) {
11433   return toggle_sets_sensitive_cond(LIVES_WIDGET(ttb), widget, NULL, NULL, invert);
11434 }
menu_sets_sensitive(LiVESCheckMenuItem * mi,LiVESWidget * widget,boolean invert)11435 WIDGET_HELPER_GLOBAL_INLINE boolean menu_sets_sensitive(LiVESCheckMenuItem * mi, LiVESWidget * widget,
11436     boolean invert) {
11437   return toggle_sets_sensitive_cond(LIVES_WIDGET(mi), widget, NULL, NULL, invert);
11438 }
11439 
toggle_sets_visible(LiVESToggleButton * tb,LiVESWidget * widget,boolean invert)11440 WIDGET_HELPER_GLOBAL_INLINE boolean toggle_sets_visible(LiVESToggleButton * tb, LiVESWidget * widget,
11441     boolean invert) {
11442   return toggle_sets_visible_cond(LIVES_WIDGET(tb), widget, NULL, NULL, invert);
11443 }
toggle_toolbutton_sets_visible(LiVESToggleToolButton * ttb,LiVESWidget * widget,boolean invert)11444 WIDGET_HELPER_GLOBAL_INLINE boolean toggle_toolbutton_sets_visible(LiVESToggleToolButton * ttb, LiVESWidget * widget,
11445     boolean invert) {
11446   return toggle_sets_visible_cond(LIVES_WIDGET(ttb), widget, NULL, NULL, invert);
11447 }
menu_sets_visible(LiVESCheckMenuItem * mi,LiVESWidget * widget,boolean invert)11448 WIDGET_HELPER_GLOBAL_INLINE boolean menu_sets_visible(LiVESCheckMenuItem * mi, LiVESWidget * widget,
11449     boolean invert) {
11450   return toggle_sets_visible_cond(LIVES_WIDGET(mi), widget, NULL, NULL, invert);
11451 }
11452 
11453 
11454 // widget callback sets togglebutton active
widget_act_toggle(LiVESWidget * widget,LiVESWidget * togglebutton)11455 boolean widget_act_toggle(LiVESWidget * widget, LiVESWidget * togglebutton) {
11456   if (!lives_widget_is_sensitive(LIVES_WIDGET(togglebutton))) return FALSE;
11457   if (LIVES_IS_TOGGLE_TOOL_BUTTON(togglebutton))
11458     lives_toggle_tool_button_set_active(LIVES_TOGGLE_TOOL_BUTTON(togglebutton), TRUE);
11459   else
11460     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(togglebutton), TRUE);
11461   return FALSE;
11462 }
11463 
11464 
11465 // widget callback sets togglebutton inactive
widget_inact_toggle(LiVESWidget * widget,LiVESWidget * togglebutton)11466 boolean widget_inact_toggle(LiVESWidget * widget, LiVESWidget * togglebutton) {
11467   if (!lives_widget_is_sensitive(LIVES_WIDGET(togglebutton))) return FALSE;
11468   if (LIVES_IS_TOGGLE_TOOL_BUTTON(togglebutton))
11469     lives_toggle_tool_button_set_active(LIVES_TOGGLE_TOOL_BUTTON(togglebutton), FALSE);
11470   else
11471     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(togglebutton), FALSE);
11472   return FALSE;
11473 }
11474 
11475 
label_act_toggle(LiVESWidget * widget,LiVESXEventButton * event,LiVESWidget * togglebutton)11476 boolean label_act_toggle(LiVESWidget * widget, LiVESXEventButton * event, LiVESWidget * togglebutton) {
11477   if (mainw && LIVES_IS_PLAYING) return FALSE;
11478   if (LIVES_IS_TOGGLE_TOOL_BUTTON(togglebutton))
11479     return lives_toggle_tool_button_toggle(LIVES_TOGGLE_TOOL_BUTTON(togglebutton));
11480   return lives_toggle_button_toggle(LIVES_TOGGLE_BUTTON(togglebutton));
11481 }
11482 
11483 
11484 // set callback so that togglebutton controls var
toggle_toggles_var(LiVESToggleButton * tbut,boolean * var,boolean invert)11485 WIDGET_HELPER_GLOBAL_INLINE boolean toggle_toggles_var(LiVESToggleButton * tbut, boolean * var, boolean invert) {
11486   if (invert) lives_toggle_button_set_active(tbut, !(*var));
11487   else lives_toggle_button_set_active(tbut, *var);
11488   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tbut), LIVES_WIDGET_TOGGLED_SIGNAL,
11489                                   LIVES_GUI_CALLBACK(togglevar_cb),
11490                                   (livespointer)var);
11491   return TRUE;
11492 }
11493 
lives_toggle_button_toggle(LiVESToggleButton * tbutton)11494 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_toggle(LiVESToggleButton * tbutton) {
11495   if (lives_toggle_button_get_active(tbutton)) return lives_toggle_button_set_active(tbutton, FALSE);
11496   else return lives_toggle_button_set_active(tbutton, TRUE);
11497 }
11498 
lives_toggle_tool_button_toggle(LiVESToggleToolButton * tbutton)11499 WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_tool_button_toggle(LiVESToggleToolButton * tbutton) {
11500   if (lives_toggle_tool_button_get_active(tbutton)) return lives_toggle_tool_button_set_active(tbutton, FALSE);
11501   else return lives_toggle_tool_button_set_active(tbutton, TRUE);
11502 }
11503 
11504 
_set_tooltips_state(LiVESWidget * widget,livespointer state)11505 static void _set_tooltips_state(LiVESWidget * widget, livespointer state) {
11506 #ifdef GUI_GTK
11507 #if GTK_CHECK_VERSION(2, 12, 0)
11508   char *ttip;
11509   if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), TTIPS_OVERRIDE_KEY)) return;
11510 
11511   if (LIVES_POINTER_TO_INT(state)) {
11512     // enable
11513     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), TTIPS_HIDE_KEY)) {
11514       if (!lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), SHOWALL_OVERRIDE_KEY)) {
11515         lives_widget_show(widget);
11516       }
11517       return;
11518     }
11519     ttip = (char *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), TTIPS_KEY);
11520     if (ttip) {
11521       lives_widget_set_tooltip_text(widget, ttip);
11522       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget), TTIPS_KEY, NULL);
11523     }
11524   } else {
11525     if (lives_widget_object_get_data(LIVES_WIDGET_OBJECT(widget), TTIPS_HIDE_KEY)) {
11526       lives_widget_hide(widget);
11527       return;
11528     }
11529     ttip = gtk_widget_get_tooltip_text(widget);
11530     lives_widget_object_set_data_auto(LIVES_WIDGET_OBJECT(widget), TTIPS_KEY, ttip);
11531     lives_widget_set_tooltip_text(widget, NULL);
11532   }
11533   if (LIVES_IS_CONTAINER(widget)) {
11534     lives_container_forall(LIVES_CONTAINER(widget), _set_tooltips_state, state);
11535   }
11536 #endif
11537 #endif
11538 
11539 }
11540 
11541 
set_tooltips_state(LiVESWidget * widget,boolean state)11542 WIDGET_HELPER_GLOBAL_INLINE boolean set_tooltips_state(LiVESWidget * widget, boolean state) {
11543 #ifdef GUI_GTK
11544 #if GTK_CHECK_VERSION(2, 12, 0)
11545   _set_tooltips_state(widget, LIVES_INT_TO_POINTER(state));
11546   return TRUE;
11547 #endif
11548 #endif
11549   return FALSE;
11550 }
11551 
11552 
lives_spin_button_get_snapval(LiVESSpinButton * button,double val)11553 WIDGET_HELPER_GLOBAL_INLINE double lives_spin_button_get_snapval(LiVESSpinButton * button, double val) {
11554   double stepval, min, max, nval, stepfix;
11555   int digs = gtk_spin_button_get_digits(button);
11556   boolean wrap = gtk_spin_button_get_wrap(button);
11557   double tenpow = (double)lives_10pow(digs);
11558   gtk_spin_button_get_increments(button, &stepval, NULL);
11559   gtk_spin_button_get_range(button, &min, &max);
11560   stepfix = tenpow / stepval;
11561   if (val >= 0.)
11562     nval = (double)((int64_t)(val * stepfix + .5)) / stepfix;
11563   else
11564     nval = (double)((int64_t)(val * stepfix  - .5)) / stepfix;
11565   if (nval < min) {
11566     if (wrap) while (nval < min) nval += (max - min);
11567     else nval = min;
11568   }
11569   if (nval > max) {
11570     if (wrap) while (nval > max) nval -= (max - min);
11571     else nval = max;
11572   }
11573   return nval;
11574 }
11575 
11576 
set_child_colour_internal(LiVESWidget * widget,livespointer set_allx)11577 static void set_child_colour_internal(LiVESWidget * widget, livespointer set_allx) {
11578   boolean set_all = LIVES_POINTER_TO_INT(set_allx);
11579 
11580   if (!set_all && LIVES_IS_BUTTON(widget)) return; // avoids a problem with filechooser
11581   if (set_all || LIVES_IS_LABEL(widget)) {
11582     lives_widget_apply_theme(widget, LIVES_WIDGET_STATE_NORMAL);
11583     if (!LIVES_IS_LABEL(widget))
11584       lives_widget_apply_theme(widget, LIVES_WIDGET_STATE_INSENSITIVE);
11585   }
11586   if (LIVES_IS_CONTAINER(widget)) {
11587     lives_container_forall(LIVES_CONTAINER(widget), set_child_colour_internal, set_allx);
11588   }
11589 }
11590 
11591 
set_child_colour(LiVESWidget * widget,boolean set_all)11592 WIDGET_HELPER_GLOBAL_INLINE void set_child_colour(LiVESWidget * widget, boolean set_all) {
11593   // set widget and all children widgets
11594   // if set_all is FALSE, we only set labels (and ignore labels in buttons)
11595   set_child_colour_internal(widget, LIVES_INT_TO_POINTER(set_all));
11596 }
11597 
11598 
set_child_dimmed_colour_internal(LiVESWidget * widget,livespointer dim)11599 static void set_child_dimmed_colour_internal(LiVESWidget * widget, livespointer dim) {
11600   int dimval = LIVES_POINTER_TO_INT(dim);
11601 
11602   lives_widget_apply_theme_dimmed(widget, LIVES_WIDGET_STATE_INSENSITIVE, dimval);
11603   lives_widget_apply_theme_dimmed(widget, LIVES_WIDGET_STATE_NORMAL, dimval);
11604 
11605   if (LIVES_IS_CONTAINER(widget)) {
11606     lives_container_forall(LIVES_CONTAINER(widget), set_child_dimmed_colour_internal, dim);
11607   }
11608 }
11609 
11610 
set_child_dimmed_colour(LiVESWidget * widget,int dim)11611 WIDGET_HELPER_GLOBAL_INLINE void set_child_dimmed_colour(LiVESWidget * widget, int dim) {
11612   // set widget and all children widgets
11613   // fg is affected dim value
11614   // dim takes a value from 0 (full fg) -> 65535 (full bg)
11615   set_child_dimmed_colour_internal(widget, LIVES_INT_TO_POINTER(dim));
11616 }
11617 
11618 
set_child_dimmed_colour2_internal(LiVESWidget * widget,livespointer dim)11619 static void set_child_dimmed_colour2_internal(LiVESWidget * widget, livespointer dim) {
11620   int dimval = LIVES_POINTER_TO_INT(dim);
11621 
11622   lives_widget_apply_theme_dimmed2(widget, LIVES_WIDGET_STATE_INSENSITIVE, dimval);
11623 
11624   if (LIVES_IS_CONTAINER(widget)) {
11625     lives_container_forall(LIVES_CONTAINER(widget), set_child_dimmed_colour2_internal, dim);
11626   }
11627 }
11628 
11629 
set_child_dimmed_colour2(LiVESWidget * widget,int dim)11630 WIDGET_HELPER_GLOBAL_INLINE void set_child_dimmed_colour2(LiVESWidget * widget, int dim) {
11631   // set widget and all children widgets
11632   // fg is affected dim value
11633   // dim takes a value from 0 (full fg) -> 65535 (full bg)
11634   set_child_dimmed_colour2_internal(widget, LIVES_INT_TO_POINTER(dim));
11635 }
11636 
11637 
set_child_alt_colour_internal(LiVESWidget * widget,livespointer set_allx)11638 static void set_child_alt_colour_internal(LiVESWidget * widget, livespointer set_allx) {
11639   boolean set_all = LIVES_POINTER_TO_INT(set_allx);
11640 
11641   if (!set_all && LIVES_IS_BUTTON(widget)) return;
11642 
11643   if (set_all || LIVES_IS_LABEL(widget)) {
11644     lives_widget_apply_theme2(widget, LIVES_WIDGET_STATE_INSENSITIVE, TRUE);
11645     lives_widget_apply_theme2(widget, LIVES_WIDGET_STATE_NORMAL, TRUE);
11646     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(widget),
11647                                  THEME_KEY, LIVES_INT_TO_POINTER(2));
11648   }
11649 
11650   if (LIVES_IS_CONTAINER(widget)) {
11651     lives_container_forall(LIVES_CONTAINER(widget), set_child_alt_colour_internal, set_allx);
11652   }
11653 }
11654 
11655 
set_child_alt_colour(LiVESWidget * widget,boolean set_all)11656 WIDGET_HELPER_GLOBAL_INLINE void set_child_alt_colour(LiVESWidget * widget, boolean set_all) {
11657   // set widget and all children widgets
11658   // if set_all is FALSE, we only set labels (and ignore labels in buttons)
11659 
11660   set_child_alt_colour_internal(widget, LIVES_INT_TO_POINTER(set_all));
11661 }
11662 
11663 
set_child_alt_colour_internal_prelight(LiVESWidget * widget,livespointer data)11664 static void set_child_alt_colour_internal_prelight(LiVESWidget * widget, livespointer data) {
11665   lives_widget_apply_theme2(widget, LIVES_WIDGET_STATE_PRELIGHT, TRUE);
11666   if (LIVES_IS_CONTAINER(widget)) {
11667     lives_container_forall(LIVES_CONTAINER(widget), set_child_alt_colour_internal_prelight, NULL);
11668   }
11669 }
11670 
11671 
set_child_alt_colour_prelight(LiVESWidget * widget)11672 WIDGET_HELPER_GLOBAL_INLINE void set_child_alt_colour_prelight(LiVESWidget * widget) {
11673   // set widget and all children widgets
11674   // if set_all is FALSE, we only set labels (and ignore labels in buttons)
11675   set_child_alt_colour_internal_prelight(widget, NULL);
11676 }
11677 
11678 
set_child_colour3_internal(LiVESWidget * widget,livespointer set_allx)11679 static void set_child_colour3_internal(LiVESWidget * widget, livespointer set_allx) {
11680   boolean set_all = LIVES_POINTER_TO_INT(set_allx);
11681 
11682   if (!set_all && (LIVES_IS_BUTTON(widget))) {// || LIVES_IS_SCROLLBAR(widget))) {
11683     lives_widget_set_base_color(widget, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
11684     lives_widget_set_text_color(widget, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars_fore);
11685     return;
11686   }
11687 
11688   if (set_all || LIVES_IS_LABEL(widget)) {
11689     lives_widget_apply_theme3(widget, LIVES_WIDGET_STATE_NORMAL);
11690   }
11691 
11692   if (LIVES_IS_CONTAINER(widget)) {
11693     lives_container_forall(LIVES_CONTAINER(widget), set_child_colour3_internal, set_allx);
11694   }
11695 }
11696 
11697 
set_child_colour3(LiVESWidget * widget,boolean set_all)11698 WIDGET_HELPER_GLOBAL_INLINE void set_child_colour3(LiVESWidget * widget, boolean set_all) {
11699   // set widget and all children widgets
11700   // if set_all is FALSE, we only set labels (and ignore labels in buttons)
11701 
11702   set_child_colour3_internal(widget, LIVES_INT_TO_POINTER(set_all));
11703 }
11704 
11705 
lives_text_view_get_text(LiVESTextView * textview)11706 char *lives_text_view_get_text(LiVESTextView * textview) {
11707   LiVESTextIter siter, eiter;
11708   LiVESTextBuffer *textbuf = lives_text_view_get_buffer(textview);
11709   lives_text_buffer_get_start_iter(textbuf, &siter);
11710   lives_text_buffer_get_end_iter(textbuf, &eiter);
11711   return lives_text_buffer_get_text(textbuf, &siter, &eiter, FALSE);
11712 }
11713 
11714 
lives_text_view_set_text(LiVESTextView * textview,const char * text,int len)11715 boolean lives_text_view_set_text(LiVESTextView * textview, const char *text, int len) {
11716   LiVESTextBuffer *textbuf = lives_text_view_get_buffer(textview);
11717   if (textbuf)
11718     return lives_text_buffer_set_text(textbuf, text, len);
11719   return FALSE;
11720 }
11721 
11722 
lives_text_buffer_insert_at_end(LiVESTextBuffer * tbuff,const char * text)11723 boolean lives_text_buffer_insert_at_end(LiVESTextBuffer * tbuff, const char *text) {
11724   LiVESTextIter xiter;
11725   if (lives_text_buffer_get_end_iter(tbuff, &xiter))
11726     return lives_text_buffer_insert(tbuff, &xiter, text, -1);
11727   return FALSE;
11728 }
11729 
11730 
get_box_child_index(LiVESBox * box,LiVESWidget * tchild)11731 int get_box_child_index(LiVESBox * box, LiVESWidget * tchild) {
11732   LiVESList *list = lives_container_get_children(LIVES_CONTAINER(box));
11733   int val = -1;
11734   if (list) {
11735     val = lives_list_index(list, tchild);
11736     lives_list_free(list);
11737   }
11738   return val;
11739 }
11740 
11741 
lives_box_pack_top(LiVESBox * box,LiVESWidget * child,boolean expand,boolean fill,uint32_t padding)11742 WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_top(LiVESBox * box, LiVESWidget * child, boolean expand, boolean fill,
11743     uint32_t padding) {
11744   lives_box_pack_start(box, child, expand, fill, padding);
11745   lives_box_reorder_child(box, child, 0);
11746   return TRUE;
11747 }
11748 
11749 
lives_container_child_set_shrinkable(LiVESContainer * c,LiVESWidget * child,boolean val)11750 WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_child_set_shrinkable(LiVESContainer * c, LiVESWidget * child, boolean val) {
11751 #ifdef GUI_GTK
11752   GValue xbool = G_VALUE_INIT;
11753   g_value_init(&xbool, G_TYPE_BOOLEAN);
11754   g_value_set_boolean(&xbool, val);
11755   gtk_container_child_set_property(c, child, "shrink", &xbool);
11756   return TRUE;
11757 #endif
11758   return FALSE;
11759 }
11760 
11761 
set_submenu_colours(LiVESMenu * menu,LiVESWidgetColor * colf,LiVESWidgetColor * colb)11762 boolean set_submenu_colours(LiVESMenu * menu, LiVESWidgetColor * colf, LiVESWidgetColor * colb) {
11763   LiVESList *children = lives_container_get_children(LIVES_CONTAINER(menu)), *list = children;
11764   lives_widget_set_bg_color(LIVES_WIDGET(menu), LIVES_WIDGET_STATE_NORMAL, colb);
11765   lives_widget_set_fg_color(LIVES_WIDGET(menu), LIVES_WIDGET_STATE_NORMAL, colf);
11766   while (list) {
11767     LiVESWidget *child = (LiVESWidget *)list->data;
11768     if (LIVES_IS_MENU_ITEM(child)) {
11769       if ((menu = (LiVESMenu *)lives_menu_item_get_submenu(LIVES_MENU_ITEM(child))))
11770         set_submenu_colours(menu, colf, colb);
11771       else {
11772         lives_widget_set_bg_color(LIVES_WIDGET(child), LIVES_WIDGET_STATE_NORMAL, colb);
11773         lives_widget_set_fg_color(LIVES_WIDGET(child), LIVES_WIDGET_STATE_NORMAL, colf);
11774       }
11775     }
11776     list = list->next;
11777   }
11778   if (children) lives_list_free(children);
11779   return TRUE;
11780 }
11781 
11782 
lives_spin_button_configure(LiVESSpinButton * spinbutton,double value,double lower,double upper,double step_increment,double page_increment)11783 boolean lives_spin_button_configure(LiVESSpinButton * spinbutton, double value, double lower,
11784                                     double upper, double step_increment, double page_increment) {
11785   LiVESAdjustment *adj = lives_spin_button_get_adjustment(spinbutton);
11786 
11787 #ifdef GUI_GTK
11788 #if GTK_CHECK_VERSION(2, 14, 0)
11789   gtk_adjustment_configure(adj, value, lower, upper, step_increment, page_increment, 0.);
11790 #else
11791   g_object_freeze_notify(LIVES_WIDGET_OBJECT(adj));
11792   adj->upper = upper;
11793   adj->lower = lower;
11794   adj->value = value;
11795   adj->step_increment = step_increment;
11796   adj->page_increment = page_increment;
11797   g_object_thaw_notify(LIVES_WIDGET_OBJECT(adj));
11798   return TRUE;
11799 #endif
11800 #endif
11801   return FALSE;
11802 }
11803 
11804 
lives_tree_store_find_iter(LiVESTreeStore * tstore,int col,const char * val,LiVESTreeIter * titer1,LiVESTreeIter * titer2)11805 boolean lives_tree_store_find_iter(LiVESTreeStore * tstore, int col, const char *val, LiVESTreeIter * titer1,
11806                                    LiVESTreeIter * titer2) {
11807 #ifdef GUI_GTK
11808   if (gtk_tree_model_iter_children(LIVES_TREE_MODEL(tstore), titer2, titer1)) {
11809     char *ret;
11810     while (1) {
11811       gtk_tree_model_get(LIVES_TREE_MODEL(tstore), titer2, col, &ret, -1);
11812       if (!lives_strcmp(ret, val)) {
11813         lives_free(ret);
11814         return TRUE;
11815       }
11816       lives_free(ret);
11817       if (!gtk_tree_model_iter_next(LIVES_TREE_MODEL(tstore), titer2)) break;
11818     }
11819   }
11820   lives_tree_store_append(tstore, titer2, titer1);
11821   lives_tree_store_set(tstore, titer2, col, val, -1);
11822   return TRUE;
11823 #endif
11824   return FALSE;
11825 }
11826 
11827 
11828 ///// lives specific functions
11829 
11830 #include "rte_window.h"
11831 #include "ce_thumbs.h"
11832 
11833 static boolean noswitch = FALSE;
11834 static boolean re_add_idlefunc = FALSE;
11835 
do_some_things(void)11836 static void do_some_things(void) {
11837   // som old junk that may or may not be relevant now
11838 
11839   /// clip switching is not permitted during these "artificial" context updates
11840   noswitch = mainw->noswitch;
11841 
11842   /// except under very specific conditions:
11843   mainw->noswitch = !mainw->cs_is_permitted;
11844 
11845   if (mainw->multitrack && mainw->multitrack->idlefunc > 0) {
11846     /// remove th multitrack timer; we don't want to trigger an autosave right now
11847     lives_timer_remove(mainw->multitrack->idlefunc);
11848     mainw->multitrack->idlefunc = 0;
11849     if (!mainw->mt_needs_idlefunc) {
11850       re_add_idlefunc = mainw->mt_needs_idlefunc = TRUE;
11851     }
11852   }
11853 
11854   if (!mainw->is_exiting) {
11855     /// update the state of some widgets caused by OOB changes
11856     if (rte_window) rtew_set_key_check_state();
11857     if (mainw->ce_thumbs) {
11858       ce_thumbs_set_key_check_state();
11859       ce_thumbs_apply_liberation();
11860       if (mainw->ce_upd_clip) {
11861         ce_thumbs_highlight_current_clip();
11862         mainw->ce_upd_clip = FALSE;
11863 	// *INDENT-OFF*
11864       }}}
11865   // *INDENT-ON*
11866 }
11867 
11868 
do_more_stuff(void)11869 static void do_more_stuff(void) {
11870   /// re-enable the multitrack autosave timer if removed it, otherwise caller can do it
11871   if (re_add_idlefunc) maybe_add_mt_idlefunc();
11872 
11873   /// restore the prior state, in case it was reset by cs_is_permitted
11874   mainw->noswitch = noswitch;
11875 }
11876 
11877 
lives_widget_context_update(void)11878 boolean lives_widget_context_update(void) {
11879   volatile boolean clutch;
11880   static pthread_mutex_t ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
11881   if (timer_running) return FALSE;
11882   if (mainw->no_context_update) return FALSE;
11883   if (pthread_mutex_trylock(&ctx_mutex)) return FALSE;
11884   else {
11885     LiVESWidgetContext *ctx = lives_widget_context_get_thread_default();
11886     do_some_things();
11887     if (ctx && ctx != lives_widget_context_default() && gov_running) {
11888       clutch = mainw->clutch = FALSE;
11889       while (!clutch && !mainw->is_exiting) {
11890         lives_nanosleep(NSLEEP_TIME);
11891         clutch = mainw->clutch;
11892       }
11893     } else {
11894       int count = 0;
11895       while (count++ < EV_LIM && !mainw->is_exiting && lives_widget_context_pending(NULL)) {
11896         //LiVESXEvent *ev = lives_widgets_get_current_event();
11897         //if (ev) g_print("ev was %d\n", ev->type);
11898         //else g_print("NULL event\n");
11899         lives_widget_context_iteration(NULL, FALSE);
11900         //lives_nanosleep(NSLEEP_TIME);
11901       }
11902     }
11903     do_more_stuff();
11904   }
11905   pthread_mutex_unlock(&ctx_mutex);
11906   return TRUE;
11907 }
11908 
11909 
lives_menu_add_separator(LiVESMenu * menu)11910 LiVESWidget *lives_menu_add_separator(LiVESMenu * menu) {
11911   LiVESWidget *separatormenuitem = lives_menu_item_new();
11912   if (separatormenuitem) {
11913     lives_container_add(LIVES_CONTAINER(menu), separatormenuitem);
11914     lives_widget_set_sensitive(separatormenuitem, FALSE);
11915   }
11916   return separatormenuitem;
11917 }
11918 
11919 
lives_menu_item_set_text(LiVESWidget * menuitem,const char * text,boolean use_mnemonic)11920 WIDGET_HELPER_GLOBAL_INLINE void lives_menu_item_set_text(LiVESWidget * menuitem, const char *text, boolean use_mnemonic) {
11921   LiVESWidget *label;
11922   if (LIVES_IS_MENU_ITEM(menuitem)) {
11923     label = lives_bin_get_child(LIVES_BIN(menuitem));
11924     widget_opts.mnemonic_label = use_mnemonic;
11925     lives_label_set_text(LIVES_LABEL(label), text);
11926     widget_opts.mnemonic_label = TRUE;
11927   }
11928 }
11929 
11930 
lives_menu_item_get_text(LiVESWidget * menuitem)11931 WIDGET_HELPER_GLOBAL_INLINE const char *lives_menu_item_get_text(LiVESWidget * menuitem) {
11932   // text MUST be at least 255 chars long
11933   LiVESWidget *label = lives_bin_get_child(LIVES_BIN(menuitem));
11934   return lives_label_get_text(LIVES_LABEL(label));
11935 }
11936 
11937 
lives_display_get_n_screens(LiVESXDisplay * disp)11938 WIDGET_HELPER_GLOBAL_INLINE int lives_display_get_n_screens(LiVESXDisplay * disp) {
11939 #ifdef GUI_GTK
11940 #if GTK_CHECK_VERSION(3, 10, 0)
11941   return 1;
11942 #else
11943   return gdk_display_get_n_screens(disp);
11944 #endif
11945 #endif
11946   return 1;
11947 }
11948 
11949 
lives_set_cursor_style(lives_cursor_t cstyle,LiVESWidget * widget)11950 void lives_set_cursor_style(lives_cursor_t cstyle, LiVESWidget * widget) {
11951 #ifdef GUI_GTK
11952   LiVESXWindow *window;
11953   GdkCursor *cursor = NULL;
11954   GdkDisplay *disp;
11955   GdkCursorType ctype = GDK_X_CURSOR;
11956 
11957   if (!widget) {
11958     if (mainw->recovering_files || ((!mainw->multitrack && mainw->is_ready)
11959                                     || (mainw->multitrack &&
11960                                         mainw->multitrack->is_ready))) {
11961       if (cstyle != LIVES_CURSOR_NORMAL && mainw->cursor_style == cstyle) return;
11962       window = lives_widget_get_xwindow(LIVES_MAIN_WINDOW_WIDGET);
11963     } else return;
11964   } else window = lives_widget_get_xwindow(widget);
11965 
11966   if (!window || !LIVES_IS_XWINDOW(window)) return;
11967 
11968   switch (cstyle) {
11969   case LIVES_CURSOR_NORMAL:
11970     break;
11971   case LIVES_CURSOR_BUSY:
11972     ctype = GDK_WATCH;
11973     break;
11974   case LIVES_CURSOR_CENTER_PTR:
11975     ctype = GDK_CENTER_PTR;
11976     break;
11977   case LIVES_CURSOR_HAND2:
11978     ctype = GDK_HAND2;
11979     break;
11980   case LIVES_CURSOR_SB_H_DOUBLE_ARROW:
11981     ctype = GDK_SB_H_DOUBLE_ARROW;
11982     break;
11983   case LIVES_CURSOR_CROSSHAIR:
11984     ctype = GDK_CROSSHAIR;
11985     break;
11986   case LIVES_CURSOR_TOP_LEFT_CORNER:
11987     ctype = GDK_TOP_LEFT_CORNER;
11988     break;
11989   case LIVES_CURSOR_BOTTOM_RIGHT_CORNER:
11990     ctype = GDK_BOTTOM_RIGHT_CORNER;
11991     break;
11992   default: return;
11993   }
11994   if (!widget) {
11995     if (mainw->multitrack) mainw->multitrack->cursor_style = cstyle;
11996     else mainw->cursor_style = cstyle;
11997   }
11998 #if GTK_CHECK_VERSION(2, 22, 0)
11999   cursor = gdk_window_get_cursor(window);
12000   if (cursor && gdk_cursor_get_cursor_type(cursor) == ctype) return;
12001   cursor = NULL;
12002 #endif
12003   disp = gdk_window_get_display(window);
12004   if (cstyle != LIVES_CURSOR_NORMAL) {
12005     cursor = gdk_cursor_new_for_display(disp, ctype);
12006     gdk_window_set_cursor(window, cursor);
12007   } else gdk_window_set_cursor(window, NULL);
12008   if (cursor) lives_cursor_unref(cursor);
12009 #endif
12010 
12011   // TODO: gdk_x11_cursor_update_theme (
12012   // XFixesChangeCursor (Display *dpy, Cursor source, Cursor destination);
12013   // and then wait for X11 event...
12014   // then no need for the majority of lives_window_process_updates().....
12015 }
12016 
12017 
hide_cursor(LiVESXWindow * window)12018 void hide_cursor(LiVESXWindow * window) {
12019   //make the cursor invisible in playback windows
12020 #ifdef GUI_GTK
12021 
12022 #if GTK_CHECK_VERSION(2, 16, 0)
12023   if (GDK_IS_WINDOW(window)) {
12024 #if GTK_CHECK_VERSION(3, 16, 0)
12025     GdkCursor *cursor = gdk_cursor_new_for_display(gdk_window_get_display(window), GDK_BLANK_CURSOR);
12026 #else
12027     GdkCursor *cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
12028 #endif
12029     if (cursor) {
12030       gdk_window_set_cursor(window, cursor);
12031       lives_cursor_unref(cursor);
12032     }
12033   }
12034 #else
12035   static GdkCursor *hidden_cursor = NULL;
12036 
12037   char cursor_bits[] = {0x00};
12038   char cursormask_bits[] = {0x00};
12039   GdkPixmap *source, *mask;
12040   GdkColor fg = { 0, 0, 0, 0 };
12041   GdkColor bg = { 0, 0, 0, 0 };
12042 
12043   if (!hidden_cursor) {
12044     source = gdk_bitmap_create_from_data(NULL, cursor_bits, 1, 1);
12045     mask = gdk_bitmap_create_from_data(NULL, cursormask_bits, 1, 1);
12046     hidden_cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 0, 0);
12047     g_object_unref(source);
12048     g_object_unref(mask);
12049   }
12050   if (GDK_IS_WINDOW(window)) gdk_window_set_cursor(window, hidden_cursor);
12051 #endif
12052 #endif
12053 }
12054 
12055 
unhide_cursor(LiVESXWindow * window)12056 WIDGET_HELPER_GLOBAL_INLINE boolean unhide_cursor(LiVESXWindow * window) {
12057   if (LIVES_IS_XWINDOW(window)) return lives_xwindow_set_cursor(window, NULL);
12058   return FALSE;
12059 }
12060 
12061 ///#define USE_REVEAL - not working here
funkify_dialog(LiVESWidget * dialog)12062 void funkify_dialog(LiVESWidget * dialog) {
12063   if (prefs->funky_widgets) {
12064     LiVESWidget *frame = lives_standard_frame_new(NULL, 0., FALSE);
12065     LiVESWidget *box = lives_vbox_new(FALSE, 0);
12066     LiVESWidget *content = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
12067     LiVESWidget *action = lives_dialog_get_action_area(LIVES_DIALOG(dialog));
12068 
12069     lives_container_set_border_width(LIVES_CONTAINER(dialog), 0);
12070     lives_container_set_border_width(LIVES_CONTAINER(frame), 0);
12071 
12072     lives_widget_object_ref(content);
12073     lives_widget_unparent(content);
12074 
12075     lives_container_add(LIVES_CONTAINER(dialog), frame);
12076     lives_container_add(LIVES_CONTAINER(frame), box);
12077 
12078     lives_box_pack_start(LIVES_BOX(box), content, TRUE, TRUE, 0);
12079 
12080     lives_widget_set_margin_top(action, widget_opts.packing_height); // only works for gtk+ 3.x
12081 
12082     lives_widget_show_all(frame);
12083 
12084     lives_container_set_border_width(LIVES_CONTAINER(box), widget_opts.border_width * 2);
12085 #ifdef USE_REVEAL
12086     gtk_revealer_set_reveal_child(GTK_REVEALER(frame), TRUE);
12087 #endif
12088   } else {
12089     lives_container_set_border_width(LIVES_CONTAINER(dialog), widget_opts.border_width);
12090   }
12091 }
12092 
12093 
lives_cool_toggled(LiVESWidget * tbutton,livespointer user_data)12094 void lives_cool_toggled(LiVESWidget * tbutton, livespointer user_data) {
12095 #if GTK_CHECK_VERSION(3, 0, 0)
12096   //#if !GTK_CHECK_VERSION(3, 16, 0)
12097   // connect toggled event to this
12098   boolean *ret = (boolean *)user_data, active;
12099   if (!LIVES_IS_INTERACTIVE) return;
12100   active = ((LIVES_IS_TOGGLE_BUTTON(tbutton)
12101              && lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tbutton))) ||
12102             (LIVES_IS_TOGGLE_TOOL_BUTTON(tbutton)
12103              && lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(tbutton))));
12104   if (prefs->lamp_buttons) {
12105     if (active) {
12106       lives_widget_set_bg_color(tbutton, LIVES_WIDGET_STATE_ACTIVE, &palette->light_green);
12107     } else lives_widget_set_bg_color(tbutton, LIVES_WIDGET_STATE_NORMAL, &palette->dark_red);
12108   }
12109   if (ret) *ret = active;
12110   lives_widget_queue_draw(tbutton);
12111   //#endif
12112 #endif
12113 }
12114 
12115 
draw_cool_toggle(LiVESWidget * widget,lives_painter_t * cr,livespointer data)12116 boolean draw_cool_toggle(LiVESWidget * widget, lives_painter_t *cr, livespointer data) {
12117   // connect expose event to this
12118   double rwidth = (double)lives_widget_get_allocation_width(LIVES_WIDGET(widget));
12119   double rheight = (double)lives_widget_get_allocation_height(LIVES_WIDGET(widget));
12120   double rad, scalex = 1., scaley = .8;
12121   boolean active =
12122     ((LIVES_IS_TOGGLE_BUTTON(widget) && lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(widget))) ||
12123      (LIVES_IS_TOGGLE_TOOL_BUTTON(widget)
12124       && lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(widget))));
12125 
12126   if (!mainw->multitrack) rheight /= 2.;
12127 
12128   lives_painter_translate(cr, rwidth * (1. - scalex) / 2., rheight * (1. - scaley) / 2.);
12129 
12130   rwidth *= scalex;
12131   rheight *= scaley;
12132 
12133   if (widget == mainw->ext_audio_mon) rwidth = rheight = 4.;
12134 
12135   // draw the inside
12136   if (active) {
12137     lives_painter_set_source_rgba(cr, palette->light_green.red, palette->light_green.green,
12138                                   palette->light_green.blue, 1.);
12139   } else {
12140     lives_painter_set_source_rgba(cr, palette->dark_red.red, palette->dark_red.green,
12141                                   palette->dark_red.blue, 1.);
12142   }
12143 
12144   // draw rounded rctangle
12145   lives_painter_rectangle(cr, 0, rwidth / 4,
12146                           rwidth,
12147                           rheight - rwidth / 2);
12148   lives_painter_fill(cr);
12149 
12150   lives_painter_rectangle(cr, rwidth / 4, 0,
12151                           rwidth / 2,
12152                           rwidth / 4);
12153   lives_painter_fill(cr);
12154 
12155   lives_painter_rectangle(cr, rwidth / 4, rheight - rwidth / 4,
12156                           rwidth / 2,
12157                           rwidth / 4);
12158   lives_painter_fill(cr);
12159   //#endif
12160 
12161   rad = rwidth / 4.;
12162 
12163   lives_painter_move_to(cr, rwidth / 4., rwidth / 4.);
12164   lives_painter_line_to(cr, 0., rwidth / 4.);
12165   lives_painter_arc(cr, rwidth / 4., rwidth / 4., rad, M_PI, 1.5 * M_PI);
12166   lives_painter_line_to(cr, rwidth / 4., rwidth / 4.);
12167   lives_painter_fill(cr);
12168 
12169   lives_painter_move_to(cr, rwidth / 4.*3., rwidth / 4.);
12170   lives_painter_line_to(cr, rwidth / 4.*3., 0.);
12171   lives_painter_arc(cr, rwidth / 4.*3., rwidth / 4., rad, -M_PI / 2., 0.);
12172   lives_painter_line_to(cr, rwidth / 4.*3., rwidth / 4.);
12173   lives_painter_fill(cr);
12174 
12175   lives_painter_move_to(cr, rwidth / 4., rheight - rwidth / 4.);
12176   lives_painter_line_to(cr, rwidth / 4., rheight);
12177   lives_painter_arc(cr, rwidth / 4., rheight - rwidth / 4., rad, M_PI / 2., M_PI);
12178   lives_painter_line_to(cr, rwidth / 4., rheight - rwidth / 4.);
12179   lives_painter_fill(cr);
12180 
12181   lives_painter_move_to(cr, rwidth / 4.*3., rheight - rwidth / 4.);
12182   lives_painter_line_to(cr, rwidth, rheight - rwidth / 4.);
12183   lives_painter_arc(cr, rwidth / 4.*3., rheight - rwidth / 4., rad, 0., M_PI / 2.);
12184   lives_painter_line_to(cr, rwidth / 4.*3., rheight - rwidth / 4.);
12185   lives_painter_fill(cr);
12186 
12187   // draw the surround
12188 
12189   lives_painter_new_path(cr);
12190 
12191   lives_painter_set_source_rgba(cr, 0., 0., 0., .8);
12192   lives_painter_set_line_width(cr, 1.);
12193 
12194   lives_painter_arc(cr, rwidth / 4., rwidth / 4., rad, M_PI, 1.5 * M_PI);
12195   lives_painter_stroke(cr);
12196   lives_painter_arc(cr, rwidth / 4.*3., rwidth / 4., rad, -M_PI / 2., 0.);
12197   lives_painter_stroke(cr);
12198   lives_painter_arc(cr, rwidth / 4., rheight - rwidth / 4., rad, M_PI / 2., M_PI);
12199   lives_painter_stroke(cr);
12200   lives_painter_arc(cr, rwidth / 4.*3., rheight - rwidth / 4., rad, 0., M_PI / 2.);
12201 
12202   lives_painter_stroke(cr);
12203 
12204   lives_painter_move_to(cr, rwidth / 4., 0);
12205   lives_painter_line_to(cr, rwidth / 4.*3., 0);
12206 
12207   lives_painter_stroke(cr);
12208 
12209   lives_painter_move_to(cr, rwidth / 4., rheight);
12210   lives_painter_line_to(cr, rwidth / 4.*3., rheight);
12211 
12212   lives_painter_stroke(cr);
12213 
12214   lives_painter_move_to(cr, 0., rwidth / 4.);
12215   lives_painter_line_to(cr, 0., rheight - rwidth / 4.);
12216 
12217   lives_painter_stroke(cr);
12218 
12219   lives_painter_move_to(cr, rwidth, rwidth / 4.);
12220   lives_painter_line_to(cr, rwidth, rheight - rwidth / 4.);
12221 
12222   lives_painter_stroke(cr);
12223 
12224   if (active) {
12225     lives_painter_set_source_rgba(cr, 1., 1., 1., .6);
12226 
12227     lives_painter_move_to(cr, rwidth / 4., rwidth / 4.);
12228     lives_painter_line_to(cr, rwidth / 4.*3., rheight - rwidth / 4.);
12229     lives_painter_stroke(cr);
12230 
12231     lives_painter_move_to(cr, rwidth / 4., rheight - rwidth / 4.);
12232     lives_painter_line_to(cr, rwidth / 4.*3., rwidth / 4.);
12233     lives_painter_stroke(cr);
12234   }
12235   return TRUE;
12236 }
12237 
12238 
12239 
lives_window_get_inner_size(LiVESWindow * win,int * x,int * y)12240 WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_get_inner_size(LiVESWindow * win, int *x, int *y) {
12241   // get size request for child to fill window "win" (assuming win is maximised and moved maximum top / left)
12242 #ifdef GUI_GTK
12243   GdkRectangle rect;
12244   gint wx, wy;
12245   gdk_window_get_frame_extents(lives_widget_get_xwindow(LIVES_WIDGET(win)), &rect);
12246   gdk_window_get_origin(lives_widget_get_xwindow(LIVES_WIDGET(win)), &wx, &wy);
12247   if (x) *x = mainw->mgeom[widget_opts.monitor].width - (wx - rect.x) * 2;
12248   if (y) *y = mainw->mgeom[widget_opts.monitor].height;
12249   return TRUE;
12250 #endif
12251   return FALSE;
12252 }
12253 
12254 
get_border_size(LiVESWidget * win,int * bx,int * by)12255 boolean get_border_size(LiVESWidget * win, int *bx, int *by) {
12256 #ifdef GUI_GTK
12257   if (win == LIVES_MAIN_WINDOW_WIDGET) {
12258     int eww, ewh;
12259     if (get_screen_usable_size(&eww, &ewh)) {
12260       if (bx) *bx = mainw->mgeom[widget_opts.monitor].phys_width - eww;
12261       if (by) *by = mainw->mgeom[widget_opts.monitor].phys_height - ewh;
12262       return TRUE;
12263     }
12264     if (bx) *bx =
12265         mainw->mgeom[widget_opts.monitor].phys_width - mainw->mgeom[widget_opts.monitor].width;
12266     if (by) *by =
12267         mainw->mgeom[widget_opts.monitor].phys_height - mainw->mgeom[widget_opts.monitor].height;
12268   } else {
12269     GdkRectangle rect;
12270     GdkWindow *xwin = lives_widget_get_xwindow(win);
12271     int gww, gwh;
12272     if (!xwin) return FALSE;
12273 
12274     gdk_window_get_frame_extents(lives_widget_get_xwindow(win), &rect);
12275     gdk_window_get_origin(xwin, &gww, &gwh);
12276 
12277     if (bx) {
12278       *bx = rect.width - lives_widget_get_allocation_width(win);
12279     }
12280     if (by) {
12281       *by = rect.height - lives_widget_get_allocation_height(win);
12282     }
12283   }
12284   return TRUE;
12285 #endif
12286   return FALSE;
12287 }
12288 
12289 //   Set active string to the combo box
lives_combo_set_active_string(LiVESCombo * combo,const char * active_str)12290 WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_active_string(LiVESCombo * combo, const char *active_str) {
12291   return lives_entry_set_text(LIVES_ENTRY(lives_bin_get_child(LIVES_BIN(combo))), active_str);
12292 }
12293 
12294 
lives_combo_get_entry(LiVESCombo * widget)12295 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_combo_get_entry(LiVESCombo * widget) {
12296   return lives_bin_get_child(LIVES_BIN(widget));
12297 }
12298 
12299 
lives_widget_set_can_focus_and_default(LiVESWidget * widget)12300 WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_can_focus_and_default(LiVESWidget * widget) {
12301   if (!lives_widget_set_can_focus(widget, TRUE)) return FALSE;
12302   return lives_widget_set_can_default(widget, TRUE);
12303 }
12304 
12305 
lives_general_button_clicked(LiVESButton * button,livespointer data_to_free)12306 void lives_general_button_clicked(LiVESButton * button, livespointer data_to_free) {
12307   // destroy the button top-level and free data
12308   if (LIVES_IS_WIDGET(lives_widget_get_toplevel(LIVES_WIDGET(button)))) {
12309     lives_widget_destroy(lives_widget_get_toplevel(LIVES_WIDGET(button)));
12310     lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
12311   }
12312   lives_freep((void **)&data_to_free);
12313 
12314   /// TODO: this is BAD. Need to check that mainw->mt_needs_idlefunc is set conistently
12315   maybe_add_mt_idlefunc(); ///< add idlefunc iff mainw->mt_needs_idlefunc is set
12316 }
12317 
12318 
lives_standard_hseparator_new(void)12319 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_hseparator_new(void) {
12320   LiVESWidget *hseparator = lives_hseparator_new();
12321   if (widget_opts.apply_theme) {
12322     if (prefs->extra_colours && mainw->pretty_colours) {
12323       lives_widget_set_bg_color(hseparator, LIVES_WIDGET_STATE_NORMAL, &palette->nice1);
12324     } else {
12325       lives_widget_set_bg_color(hseparator, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
12326     }
12327     lives_widget_set_fg_color(hseparator, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
12328   }
12329   if (LIVES_SHOULD_EXPAND_HEIGHT)
12330     lives_widget_set_margin_top(hseparator, widget_opts.packing_height);
12331   if (LIVES_SHOULD_EXPAND_EXTRA_HEIGHT)
12332     lives_widget_set_margin_bottom(hseparator, widget_opts.packing_height);
12333   return hseparator;
12334 }
12335 
12336 
lives_standard_vseparator_new(void)12337 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_standard_vseparator_new(void) {
12338   LiVESWidget *vseparator = lives_vseparator_new();
12339   if (widget_opts.apply_theme) {
12340     if (prefs->extra_colours && mainw->pretty_colours) {
12341       lives_widget_set_bg_color(vseparator, LIVES_WIDGET_STATE_NORMAL, &palette->nice1);
12342     } else {
12343       lives_widget_set_bg_color(vseparator, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
12344     }
12345     lives_widget_set_fg_color(vseparator, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
12346   }
12347   if (LIVES_SHOULD_EXPAND_WIDTH)
12348     lives_widget_set_margin_left(vseparator, widget_opts.packing_width);
12349   if (LIVES_SHOULD_EXPAND_EXTRA_WIDTH)
12350     lives_widget_set_margin_right(vseparator, widget_opts.packing_width);
12351   return vseparator;
12352 }
12353 
12354 
add_hsep_to_box(LiVESBox * box)12355 LiVESWidget *add_hsep_to_box(LiVESBox * box) {
12356   LiVESWidget *hseparator = lives_standard_hseparator_new();
12357   int packing_height = widget_opts.packing_height;
12358   if (LIVES_IS_HBOX(box)) packing_height = 0;
12359   lives_box_pack_start(box, hseparator, LIVES_IS_HBOX(box)
12360                        || LIVES_SHOULD_EXPAND_EXTRA_FOR(box), TRUE, packing_height);
12361   return hseparator;
12362 }
12363 
12364 
add_vsep_to_box(LiVESBox * box)12365 LiVESWidget *add_vsep_to_box(LiVESBox * box) {
12366   LiVESWidget *vseparator = lives_standard_vseparator_new();
12367   int packing_width = widget_opts.packing_width >> 1;
12368   if (LIVES_SHOULD_EXPAND_EXTRA_FOR(box)) packing_width *= 2;
12369   if (LIVES_IS_VBOX(box)) packing_width = 0;
12370   lives_box_pack_start(box, vseparator, LIVES_IS_VBOX(box)
12371                        || LIVES_SHOULD_EXPAND_EXTRA_FOR(box), TRUE, packing_width);
12372   return vseparator;
12373 }
12374 
12375 
12376 //#define SHOW_FILL
add_fill_to_box(LiVESBox * box)12377 LiVESWidget *add_fill_to_box(LiVESBox * box) {
12378 #ifdef SHOW_FILL
12379   LiVESWidget *widget = lives_label_new("fill");
12380 #else
12381   LiVESWidget *widget = lives_standard_label_new("");
12382 #endif
12383   if (LIVES_IS_HBOX(box)) {
12384     int flen = 0;
12385     if (LIVES_SHOULD_EXPAND_FOR(box)) {
12386       int w = 0;
12387       LingoContext *ctx = lives_widget_create_lingo_context(LIVES_WIDGET(box));
12388       flen = widget_opts.filler_len;
12389       if (ctx && LINGO_IS_CONTEXT(ctx)) {
12390         LingoLayout *layout = lingo_layout_new(ctx);
12391         if (layout && LINGO_IS_LAYOUT(layout)) {
12392           lingo_layout_set_text(layout, "X", -1);
12393           lingo_layout_get_size(layout, &w, NULL);
12394           w /= LINGO_SCALE;
12395           lives_widget_object_unref(layout);
12396         }
12397         lives_widget_object_unref(ctx);
12398       }
12399       if (w) {
12400         int nchars = (float)widget_opts.filler_len / (float)w;
12401         if (nchars > 0) {
12402           flen = 0;
12403           lives_label_set_width_chars(LIVES_LABEL(widget), nchars);
12404         }
12405       }
12406     }
12407     lives_box_pack_start(box, widget, LIVES_SHOULD_EXPAND_EXTRA_FOR(box), TRUE, flen);
12408     if (LIVES_SHOULD_EXPAND_EXTRA_FOR(box))
12409       lives_widget_set_hexpand(widget, TRUE);
12410   } else {
12411     if (LIVES_SHOULD_EXPAND_EXTRA_FOR(box)) {
12412       lives_box_pack_start(box, widget, TRUE, TRUE, widget_opts.filler_len);
12413       lives_widget_set_vexpand(widget, TRUE);
12414     } else lives_box_pack_start(box, widget, FALSE, TRUE, LIVES_SHOULD_EXPAND_FOR(box) ? widget_opts.packing_height : 0);
12415   }
12416   if (widget_opts.apply_theme == 2) set_child_alt_colour(widget, TRUE);
12417   return widget;
12418 }
12419 
12420 
add_spring_to_box(LiVESBox * box,int min)12421 LiVESWidget *add_spring_to_box(LiVESBox * box, int min) {
12422   LiVESWidget *widget;
12423   int filler_len = widget_opts.filler_len;
12424   int woe = widget_opts.expand;
12425   widget_opts.filler_len = min;
12426   widget_opts.expand = LIVES_EXPAND_EXTRA;
12427   widget = add_fill_to_box(box);
12428   widget_opts.expand = woe;
12429   widget_opts.filler_len = filler_len;
12430   return widget;
12431 }
12432 
12433 
lives_toolbar_insert_space(LiVESToolbar * bar)12434 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_toolbar_insert_space(LiVESToolbar * bar) {
12435   LiVESWidget *spacer = NULL;
12436 #ifdef GUI_GTK
12437   spacer = LIVES_WIDGET(lives_separator_tool_item_new());
12438   gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(spacer), FALSE);
12439   gtk_tool_item_set_homogeneous(LIVES_TOOL_ITEM(spacer), FALSE);
12440   gtk_tool_item_set_expand(LIVES_TOOL_ITEM(spacer), LIVES_SHOULD_EXPAND_WIDTH);
12441   lives_toolbar_insert(LIVES_TOOLBAR(bar), LIVES_TOOL_ITEM(spacer), -1);
12442 #endif
12443   return spacer;
12444 }
12445 
12446 
lives_toolbar_insert_label(LiVESToolbar * bar,const char * text,LiVESWidget * actwidg)12447 WIDGET_HELPER_GLOBAL_INLINE LiVESWidget *lives_toolbar_insert_label(LiVESToolbar * bar, const char *text,
12448     LiVESWidget * actwidg) {
12449   LiVESWidget *item = NULL;
12450   widget_opts.last_label = widget_opts.last_container = NULL;
12451 #ifdef GUI_GTK
12452   item = LIVES_WIDGET(lives_tool_item_new());
12453   if (!actwidg) {
12454     widget_opts.last_label = lives_label_new(text);
12455     lives_container_add(LIVES_CONTAINER(item), widget_opts.last_label);
12456   } else {
12457     widget_opts.last_container = _make_label_eventbox(text, actwidg, FALSE);
12458     lives_container_add(LIVES_CONTAINER(item), widget_opts.last_container);
12459   }
12460   lives_toolbar_insert(bar, LIVES_TOOL_ITEM(item), -1);
12461 #endif
12462   return item;
12463 }
12464 
12465 
lives_button_box_set_button_width(LiVESButtonBox * bbox,LiVESWidget * button,int min_width)12466 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_set_button_width(LiVESButtonBox * bbox, LiVESWidget * button,
12467     int min_width) {
12468   lives_button_box_set_layout(bbox, LIVES_BUTTONBOX_SPREAD);
12469 #ifdef GUI_GTK
12470 #if !GTK_CHECK_VERSION(3, 0, 0)
12471   gtk_button_box_set_child_size(bbox, min_width / 4, DLG_BUTTON_HEIGHT);
12472   return TRUE;
12473 #endif
12474 #endif
12475   lives_widget_set_size_request(button, min_width, DLG_BUTTON_HEIGHT);
12476   return TRUE;
12477   return FALSE;
12478 }
12479 
12480 
lives_button_box_make_first(LiVESButtonBox * bbox,LiVESWidget * widget)12481 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_make_first(LiVESButtonBox * bbox, LiVESWidget * widget) {
12482 #ifdef GUI_GTK
12483   gtk_button_box_set_child_secondary(bbox, widget, TRUE);
12484   gtk_button_box_set_child_non_homogeneous(bbox, widget, TRUE);
12485   if (LIVES_SHOULD_EXPAND_WIDTH) {
12486     if (LIVES_IS_CONTAINER(widget))
12487       lives_container_set_border_width(LIVES_CONTAINER(widget), widget_opts.border_width);
12488   }
12489   return TRUE;
12490 #endif
12491   return FALSE;
12492 }
12493 
12494 
lives_dialog_make_widget_first(LiVESDialog * dlg,LiVESWidget * widget)12495 WIDGET_HELPER_GLOBAL_INLINE boolean lives_dialog_make_widget_first(LiVESDialog * dlg, LiVESWidget * widget) {
12496   LiVESWidget *daa = lives_dialog_get_action_area(dlg);
12497   return lives_button_box_make_first(LIVES_BUTTON_BOX(daa), widget);
12498 }
12499 
12500 
12501 
lives_button_center(LiVESWidget * button)12502 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_center(LiVESWidget * button) {
12503   if (LIVES_SHOULD_EXPAND_WIDTH)
12504     lives_widget_set_size_request(button, DEF_BUTTON_WIDTH * 4, DLG_BUTTON_HEIGHT);
12505   lives_button_box_set_layout(LIVES_BUTTON_BOX(lives_widget_get_parent(button)),
12506                               LIVES_BUTTONBOX_CENTER);
12507   lives_widget_set_halign(lives_widget_get_parent(button), LIVES_ALIGN_CENTER);
12508   return TRUE;
12509 }
12510 
12511 
lives_button_uncenter(LiVESWidget * button,int normal_width)12512 WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_uncenter(LiVESWidget * button, int normal_width) {
12513   lives_widget_set_size_request(button, normal_width, DLG_BUTTON_HEIGHT);
12514   lives_button_box_set_layout(LIVES_BUTTON_BOX(lives_widget_get_parent(button)), LIVES_BUTTONBOX_END);
12515   lives_widget_set_halign(lives_widget_get_parent(button), LIVES_ALIGN_FILL);
12516   return TRUE;
12517 }
12518 
12519 
lives_tool_button_set_border_color(LiVESWidget * button,LiVESWidgetState state,LiVESWidgetColor * colour)12520 boolean lives_tool_button_set_border_color(LiVESWidget * button, LiVESWidgetState state, LiVESWidgetColor * colour) {
12521   if (LIVES_IS_TOOL_BUTTON(button)) {
12522     LiVESWidget *widget, *parent;
12523     widget = lives_tool_button_get_icon_widget(LIVES_TOOL_BUTTON(button));
12524     if (!widget) widget = lives_tool_button_get_label_widget(LIVES_TOOL_BUTTON(button));
12525     if (widget) {
12526       parent  = lives_widget_get_parent(widget);
12527       if (parent) lives_widget_set_bg_color(parent, state, colour);
12528       lives_widget_set_valign(widget, LIVES_ALIGN_FILL);
12529       lives_widget_set_halign(widget, LIVES_ALIGN_FILL);
12530     }
12531     return TRUE;
12532   }
12533   return FALSE;
12534 }
12535 
12536 
lives_standard_tool_button_new(LiVESToolbar * bar,GtkWidget * icon_widget,const char * label,const char * tooltips)12537 LiVESWidget *lives_standard_tool_button_new(LiVESToolbar * bar, GtkWidget * icon_widget, const char *label,
12538     const char *tooltips) {
12539   LiVESToolItem *tbutton;
12540   widget_opts.last_label = NULL;
12541   if (label) {
12542     if (LIVES_SHOULD_EXPAND_HEIGHT) {
12543       char *labeltext = lives_strdup_printf("\n%s\n", label);
12544       widget_opts.last_label = lives_standard_label_new(labeltext);
12545       lives_free(labeltext);
12546     } else widget_opts.last_label = lives_standard_label_new(label);
12547   }
12548   tbutton = lives_tool_button_new(icon_widget, NULL);
12549   if (widget_opts.last_label) lives_tool_button_set_label_widget(LIVES_TOOL_BUTTON(tbutton), widget_opts.last_label);
12550   if (widget_opts.apply_theme) {
12551 #if !GTK_CHECK_VERSION(3, 16, 0)
12552     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(tbutton), LIVES_WIDGET_NOTIFY_SIGNAL "sensitive",
12553                                     LIVES_GUI_CALLBACK(widget_state_cb), NULL);
12554     widget_state_cb(LIVES_WIDGET_OBJECT(tbutton), NULL, NULL);
12555 #endif
12556   }
12557   if (tooltips) lives_widget_set_tooltip_text(LIVES_WIDGET(tbutton), tooltips);
12558   if (bar) lives_toolbar_insert(bar, tbutton, -1);
12559   return LIVES_WIDGET(tbutton);
12560 }
12561 
12562 
lives_accel_path_disconnect(LiVESAccelGroup * group,const char * path)12563 WIDGET_HELPER_GLOBAL_INLINE boolean lives_accel_path_disconnect(LiVESAccelGroup * group, const char *path) {
12564 #ifdef GUI_GTK
12565   GtkAccelKey key;
12566   gtk_accel_map_lookup_entry(path, &key);
12567   gtk_accel_group_disconnect_key(group, key.accel_key, key.accel_mods);
12568   return TRUE;
12569 #endif
12570   return FALSE;
12571 }
12572 
12573 
lives_rgba_col_new(int red,int green,int blue,int alpha)12574 WIDGET_HELPER_GLOBAL_INLINE lives_colRGBA64_t lives_rgba_col_new(int red, int green, int blue, int alpha) {
12575   lives_colRGBA64_t lcol = {red, green, blue, alpha};
12576   return lcol;
12577 }
12578 
12579 
widget_color_to_lives_rgba(lives_colRGBA64_t * lcolor,LiVESWidgetColor * color)12580 WIDGET_HELPER_GLOBAL_INLINE lives_colRGBA64_t *widget_color_to_lives_rgba(lives_colRGBA64_t *lcolor, LiVESWidgetColor * color) {
12581   lcolor->red = LIVES_WIDGET_COLOR_STRETCH(color->red);
12582   lcolor->green = LIVES_WIDGET_COLOR_STRETCH(color->green);
12583   lcolor->blue = LIVES_WIDGET_COLOR_STRETCH(color->blue);
12584 #if LIVES_WIDGET_COLOR_HAS_ALPHA
12585   lcolor->alpha = LIVES_WIDGET_COLOR_STRETCH(color->alpha);
12586 #else
12587   lcolor->alpha = 65535;
12588 #endif
12589   return lcolor;
12590 }
12591 
12592 
lives_rgba_to_widget_color(LiVESWidgetColor * color,lives_colRGBA64_t * lcolor)12593 WIDGET_HELPER_GLOBAL_INLINE LiVESWidgetColor *lives_rgba_to_widget_color(LiVESWidgetColor * color, lives_colRGBA64_t *lcolor) {
12594   color->red = LIVES_WIDGET_COLOR_SCALE_65535(lcolor->red);
12595   color->green = LIVES_WIDGET_COLOR_SCALE_65535(lcolor->green);
12596   color->blue = LIVES_WIDGET_COLOR_SCALE_65535(lcolor->blue);
12597 #if LIVES_WIDGET_COLOR_HAS_ALPHA
12598   color->alpha = LIVES_WIDGET_COLOR_SCALE_65535(lcolor->alpha);
12599 #endif
12600   return color;
12601 }
12602 
12603 
lives_rgba_equal(lives_colRGBA64_t * col1,lives_colRGBA64_t * col2)12604 WIDGET_HELPER_GLOBAL_INLINE boolean lives_rgba_equal(lives_colRGBA64_t *col1, lives_colRGBA64_t *col2) {
12605   return !lives_memcmp(col1, col2, sizeof(lives_colRGBA64_t));
12606 }
12607 
12608 
lives_rgba_copy(lives_colRGBA64_t * col1,lives_colRGBA64_t * col2)12609 WIDGET_HELPER_GLOBAL_INLINE lives_colRGBA64_t *lives_rgba_copy(lives_colRGBA64_t *col1, lives_colRGBA64_t *col2) {
12610   col1->red = col2->red;
12611   col1->green = col2->green;
12612   col1->blue = col2->blue;
12613   col1->alpha = col2->alpha;
12614   return col1;
12615 }
12616 
12617 
get_textsizes_list(void)12618 LiVESList *get_textsizes_list(void) {
12619   LiVESList *textsize_list = NULL;
12620 #ifdef GUI_GTK
12621   textsize_list = lives_list_append(textsize_list, (_("Extra extra small")));
12622   textsize_list = lives_list_append(textsize_list, (_("Extra small")));
12623   textsize_list = lives_list_append(textsize_list, (_("Small")));
12624   textsize_list = lives_list_append(textsize_list, (_("Medium")));
12625   textsize_list = lives_list_append(textsize_list, (_("Large")));
12626   textsize_list = lives_list_append(textsize_list, (_("Extra large")));
12627   textsize_list = lives_list_append(textsize_list, (_("Extra extra large")));
12628 #endif
12629   return textsize_list;
12630 }
12631 
12632 
lives_textsize_to_string(int val)12633 const char *lives_textsize_to_string(int val) {
12634   switch (val) {
12635   case 0:
12636     return LIVES_TEXT_SIZE_XX_SMALL;
12637   case 1:
12638     return LIVES_TEXT_SIZE_X_SMALL;
12639   case 2:
12640     return LIVES_TEXT_SIZE_SMALL;
12641   case 3:
12642     return LIVES_TEXT_SIZE_MEDIUM;
12643   case 4:
12644     return LIVES_TEXT_SIZE_LARGE;
12645   case 5:
12646     return LIVES_TEXT_SIZE_X_LARGE;
12647   case 6:
12648     return LIVES_TEXT_SIZE_XX_LARGE;
12649   default:
12650     return LIVES_TEXT_SIZE_NORMAL;
12651   }
12652 }
12653