1 // ce_thumbs.c
2 // LiVES
3 // (c) G. Finch 2013 - 2019 <salsaman+lives@gmail.com>
4 // Released under the GNU GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 // clip thumbnails window for dual head mode
8 
9 // TODO - buttons for some keys ?
10 
11 // TODO - drag fx order :  check for data conx
12 
13 // TODO - user defined screen mapping areas
14 
15 #include "main.h"
16 #include "effects-weed.h"
17 #include "effects.h"
18 #include "paramwindow.h"
19 #include "ce_thumbs.h"
20 #include "callbacks.h"
21 
22 static LiVESWidget **fxcombos;
23 static LiVESWidget **pscrolls;
24 static LiVESWidget **combo_entries;
25 static LiVESWidget **key_checks;
26 static LiVESWidget **rb_fx_areas;
27 static LiVESWidget **rb_clip_areas;
28 static LiVESWidget **clip_boxes;
29 static LiVESWidget *param_hbox;
30 static LiVESWidget *top_hbox;
31 
32 static ulong *ch_fns;
33 static ulong *combo_fns;
34 static ulong *rb_clip_fns;
35 static ulong *rb_fx_fns;
36 
37 static int rte_keys_virtual;
38 static int n_screen_areas;
39 static int n_clip_boxes;
40 
41 static int next_screen_area;
42 
43 static void ce_thumbs_remove_param_boxes(boolean remove_pinned);
44 static void ce_thumbs_remove_param_box(int key);
45 
46 
ce_thumbs_set_interactive(boolean interactive)47 void ce_thumbs_set_interactive(boolean interactive) {
48   int i;
49 
50   if (!interactive) {
51     for (i = 0; i < rte_keys_virtual; i++) {
52       lives_widget_set_sensitive(fxcombos[i], FALSE);
53       lives_widget_set_sensitive(key_checks[i], FALSE);
54     }
55   } else {
56     for (i = 0; i < rte_keys_virtual; i++) {
57       lives_widget_set_sensitive(fxcombos[i], TRUE);
58       if (rte_key_getmaxmode(i + 1) > 0) {
59         lives_widget_set_sensitive(key_checks[i], TRUE);
60 	// *INDENT-OFF*
61       }}}
62   // *INDENT-ON*
63 }
64 
65 
66 #if LIVES_HAS_GRID_WIDGET
switch_clip_cb(LiVESWidget * eventbox,LiVESXEventButton * event,livespointer user_data)67 static boolean switch_clip_cb(LiVESWidget * eventbox, LiVESXEventButton * event, livespointer user_data) {
68   int i = LIVES_POINTER_TO_INT(user_data);
69   if (!LIVES_IS_PLAYING) return FALSE;
70   if (!LIVES_IS_INTERACTIVE) return FALSE;
71   switch_clip(0, i, FALSE);
72   return FALSE;
73 }
74 
75 
ce_thumbs_fx_changed(LiVESCombo * combo,livespointer user_data)76 static void ce_thumbs_fx_changed(LiVESCombo * combo, livespointer user_data) {
77   // callback after user switches fx via combo
78   int key = LIVES_POINTER_TO_INT(user_data);
79   int mode, cmode;
80 
81   if ((mode = lives_combo_get_active_index(combo)) == -1) return; // -1 is returned after we set our own text (without the type)
82   cmode = rte_key_getmode(key + 1);
83 
84   if (cmode == mode) return;
85 
86   lives_widget_grab_focus(combo_entries[key]);
87 
88   rte_key_setmode(key + 1, mode);
89 }
90 #endif
91 
92 
ce_thumbs_set_key_check_state(void)93 void ce_thumbs_set_key_check_state(void) {
94   // set (delayed) keycheck state
95   for (int i = 0; i < prefs->rte_keys_virtual; i++) {
96     lives_signal_handler_block(key_checks[i], ch_fns[i]);
97     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(key_checks[i]),
98                                    LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(key_checks[i]),
99                                        "active")));
100     if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(key_checks[i])) && pscrolls[i]) ce_thumbs_remove_param_box(i);
101     lives_signal_handler_unblock(key_checks[i], ch_fns[i]);
102   }
103 }
104 
105 
ce_thumbs_set_keych(int key,boolean on)106 void ce_thumbs_set_keych(int key, boolean on) {
107   // set key check from other source
108   if (key >= rte_keys_virtual) return;
109   lives_signal_handler_block(key_checks[key], ch_fns[key]);
110   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(key_checks[key]), on);
111   if (!on && pscrolls[key]) ce_thumbs_remove_param_box(key);
112   lives_signal_handler_unblock(key_checks[key], ch_fns[key]);
113   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(key_checks[key]), "active", LIVES_INT_TO_POINTER(on));
114 }
115 
116 
ce_thumbs_set_mode_combo(int key,int mode)117 void ce_thumbs_set_mode_combo(int key, int mode) {
118   // set combo from other source : need to add params after
119   if (key >= rte_keys_virtual || mode < 0) return;
120   lives_signal_handler_block(fxcombos[key], combo_fns[key]);
121   lives_combo_set_active_index(LIVES_COMBO(fxcombos[key]), mode);
122   ce_thumbs_remove_param_box(key);
123   lives_signal_handler_unblock(fxcombos[key], combo_fns[key]);
124 }
125 
126 
pin_toggled(LiVESToggleButton * t,livespointer pkey)127 static void pin_toggled(LiVESToggleButton * t, livespointer pkey) {
128   int key = LIVES_POINTER_TO_INT(pkey);
129   boolean state = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[key]), "pinned"));
130   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pscrolls[key]), "pinned", LIVES_INT_TO_POINTER(!state));
131 }
132 
133 #if LIVES_HAS_GRID_WIDGET
134 
clip_area_toggled(LiVESToggleButton * t,livespointer parea)135 static void clip_area_toggled(LiVESToggleButton * t, livespointer parea) {
136   int area = LIVES_POINTER_TO_INT(parea);
137   if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(rb_clip_areas[area]))) {
138     mainw->active_sa_clips = area;
139     ce_thumbs_highlight_current_clip();
140   }
141 }
142 
143 #endif
144 
145 #define SPARE_CLIP_BOXES 100
146 
start_ce_thumb_mode(void)147 void start_ce_thumb_mode(void) {
148 #if LIVES_HAS_GRID_WIDGET
149 
150   LiVESWidget *thumb_image = NULL;
151   LiVESWidget *vbox, *vbox2, *vbox3;
152   LiVESWidget *usibl = NULL, *sibl = NULL;
153   LiVESWidget *hbox, *hbox2;
154   LiVESWidget *tscroll, *cscroll;
155   LiVESWidget *label;
156   LiVESWidget *arrow;
157 
158   LiVESWidget *tgrid = lives_grid_new();
159 
160   LiVESWidget *align;
161 
162   LiVESPixbuf *thumbnail;
163 
164   LiVESList *cliplist = mainw->cliplist;
165   LiVESList *fxlist = NULL;
166 
167   GSList *rb_fx_areas_group = NULL;
168   GSList *rb_clip_areas_group = NULL;
169 
170   char filename[PATH_MAX];
171   char *tmp;
172 
173   int width = CLIP_THUMB_WIDTH, height = CLIP_THUMB_HEIGHT;
174   int modes = rte_getmodespk();
175   int cpw;
176 
177   int count = -1, rcount = 0;
178 
179   int i, j;
180 
181   rte_keys_virtual = prefs->rte_keys_virtual;
182   n_screen_areas = mainw->n_screen_areas;
183   n_clip_boxes = lives_list_length(mainw->cliplist) + SPARE_CLIP_BOXES;
184 
185   next_screen_area = SCREEN_AREA_NONE;
186 
187   lives_grid_set_row_spacing(LIVES_GRID(tgrid), 0);
188   lives_grid_set_column_spacing(LIVES_GRID(tgrid), 0);
189 
190   //lives_container_set_border_width (LIVES_CONTAINER (tgrid), width);
191 
192   // dual monitor mode, the gui monitor can show clip thumbnails
193 
194   top_hbox = lives_hbox_new(FALSE, 0);
195   lives_widget_object_ref(mainw->top_vbox);
196   lives_widget_unparent(mainw->top_vbox);
197 
198   lives_container_add(LIVES_CONTAINER(LIVES_MAIN_WINDOW_WIDGET), top_hbox);
199   lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
200   //lives_box_pack_start(LIVES_BOX(mainw->top_vbox), top_hbox, TRUE, TRUE, 0);
201 
202   if (palette->style & STYLE_1) lives_widget_set_bg_color(top_hbox, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
203 
204   // fx area
205   vbox = lives_vbox_new(FALSE, widget_opts.packing_height);
206 
207   tscroll = lives_standard_scrolled_window_new(width, height, vbox);
208   lives_box_pack_start(LIVES_BOX(top_hbox), tscroll, FALSE, TRUE, 0);
209   lives_scrolled_window_set_policy(LIVES_SCROLLED_WINDOW(tscroll), LIVES_POLICY_NEVER, LIVES_POLICY_AUTOMATIC);
210   lives_widget_set_hexpand(tscroll, FALSE);
211 
212   fxcombos = (LiVESWidget **)lives_malloc((rte_keys_virtual) * modes * sizeof(LiVESWidget *));
213   pscrolls = (LiVESWidget **)lives_malloc((rte_keys_virtual) * modes * sizeof(LiVESWidget *));
214   combo_entries = (LiVESWidget **)lives_malloc((rte_keys_virtual) * modes * sizeof(LiVESWidget *));
215   key_checks = (LiVESWidget **)lives_malloc((rte_keys_virtual) * modes * sizeof(LiVESWidget *));
216 
217   rb_fx_areas = (LiVESWidget **)lives_malloc((n_screen_areas) * modes * sizeof(LiVESWidget *));
218   rb_clip_areas = (LiVESWidget **)lives_malloc((n_screen_areas) * modes * sizeof(LiVESWidget *));
219 
220   clip_boxes = (LiVESWidget **)lives_malloc((n_clip_boxes) * modes * sizeof(LiVESWidget *));
221 
222   ch_fns = (ulong *)lives_malloc((rte_keys_virtual) * sizeof(ulong));
223   combo_fns = (ulong *)lives_malloc((rte_keys_virtual) * sizeof(ulong));
224   rb_clip_fns = (ulong *)lives_malloc((n_screen_areas) * sizeof(ulong));
225   rb_fx_fns = (ulong *)lives_malloc((n_screen_areas) * sizeof(ulong));
226 
227   for (i = 0; i < n_clip_boxes; i++) {
228     clip_boxes[i] = NULL;
229   }
230 
231   for (i = 0; i < rte_keys_virtual; i++) {
232     pscrolls[i] = NULL;
233 
234     fxlist = NULL;
235 
236     for (j = 0; j <= rte_key_getmaxmode(i + 1); j++) {
237       fxlist = lives_list_append(fxlist, rte_keymode_get_filter_name(i + 1, j, FALSE));
238     }
239 
240     hbox = lives_hbox_new(FALSE, 0);
241     lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
242 
243     tmp = lives_strdup_printf(_("Mapped to ctrl-%d"), i + 1);
244     key_checks[i] = lives_standard_check_button_new(NULL, (mainw->rte & (GU641 << i)), LIVES_BOX(hbox), tmp);
245     lives_free(tmp);
246 
247     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(key_checks[i]), mainw->rte & (GU641 << i));
248     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(key_checks[i]), "active",
249                                  LIVES_INT_TO_POINTER(lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(key_checks[i]))));
250 
251     ch_fns[i] = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(key_checks[i]), LIVES_WIDGET_TOGGLED_SIGNAL,
252                 LIVES_GUI_CALLBACK(rte_on_off_callback_hook), LIVES_INT_TO_POINTER(i + 1));
253 
254     fxcombos[i] = lives_standard_combo_new(NULL, fxlist, LIVES_BOX(hbox), NULL);
255 
256     if (fxlist) {
257       lives_list_free_all(&fxlist);
258       lives_combo_set_active_index(LIVES_COMBO(fxcombos[i]), rte_key_getmode(i + 1));
259     } else {
260       lives_widget_set_sensitive(key_checks[i], FALSE);
261     }
262 
263     combo_entries[i] = lives_combo_get_entry(LIVES_COMBO(fxcombos[i]));
264 
265     lives_entry_set_editable(LIVES_ENTRY(combo_entries[i]), FALSE);
266 
267     combo_fns[i] = lives_signal_sync_connect(LIVES_GUI_OBJECT(fxcombos[i]), LIVES_WIDGET_CHANGED_SIGNAL,
268                    LIVES_GUI_CALLBACK(ce_thumbs_fx_changed), LIVES_INT_TO_POINTER(i));
269   }
270 
271   add_vsep_to_box(LIVES_BOX(top_hbox));
272 
273   // rhs vbox
274   vbox2 = lives_vbox_new(FALSE, 0);
275   lives_box_pack_start(LIVES_BOX(top_hbox), vbox2, TRUE, TRUE, 0);
276 
277   // rhs top hbox
278   hbox2 = lives_hbox_new(FALSE, widget_opts.packing_width);
279   lives_box_pack_start(LIVES_BOX(vbox2), hbox2, TRUE, TRUE, 0);
280 
281   // vbox for arrows and areas
282   vbox3 = lives_vbox_new(FALSE, 0);
283   lives_box_pack_start(LIVES_BOX(hbox2), vbox3, FALSE, TRUE, 0);
284 
285   // add arrows
286   hbox = lives_hbox_new(FALSE, 0);
287   lives_widget_set_hexpand(hbox, FALSE);
288 
289   lives_box_pack_start(LIVES_BOX(vbox3), hbox, FALSE, TRUE, 0);
290   arrow = lives_arrow_new(LIVES_ARROW_LEFT, LIVES_SHADOW_NONE);
291   lives_box_pack_start(LIVES_BOX(hbox), arrow, FALSE, TRUE, 0);
292 
293   label = lives_standard_label_new(_("Effects"));
294   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, TRUE, 0);
295   add_fill_to_box(LIVES_BOX(hbox));
296   label = lives_standard_label_new(_("Clips"));
297   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, TRUE, 0);
298 
299   arrow = lives_arrow_new(LIVES_ARROW_RIGHT, LIVES_SHADOW_NONE);
300   lives_box_pack_start(LIVES_BOX(hbox), arrow, FALSE, TRUE, 0);
301 
302   // screen areas
303   vbox = lives_vbox_new(FALSE, widget_opts.packing_height);
304   tscroll = lives_standard_scrolled_window_new(width, height, vbox);
305 
306   lives_box_pack_start(LIVES_BOX(vbox3), tscroll, FALSE, TRUE, 0);
307   lives_scrolled_window_set_policy(LIVES_SCROLLED_WINDOW(tscroll), LIVES_POLICY_NEVER, LIVES_POLICY_AUTOMATIC);
308   lives_widget_set_hexpand(tscroll, FALSE);
309 
310   for (i = 0; i < n_screen_areas; i++) {
311     hbox = lives_hbox_new(FALSE, 0);
312     lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
313 
314     // radiobuttons for fx
315     rb_fx_areas[i] = lives_standard_radio_button_new("", &rb_fx_areas_group, LIVES_BOX(hbox),
316                      (tmp = lives_strdup_printf(_("Show / apply effects to %s\n"),
317                             mainw->screen_areas[i].name)));
318     lives_free(tmp);
319 
320     if (i != SCREEN_AREA_FOREGROUND) lives_widget_set_sensitive(rb_fx_areas[i], FALSE);
321 
322     label = lives_standard_label_new(mainw->screen_areas[i].name);
323     lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, TRUE, 0);
324 
325     // radiobuttons for fx
326     rb_clip_areas[i] = lives_standard_radio_button_new("",
327                        &rb_clip_areas_group, LIVES_BOX(hbox),
328                        (tmp = lives_strdup_printf(_("Select clip for %s\n"),
329                               mainw->screen_areas[i].name)));
330     lives_free(tmp);
331 
332     rb_clip_fns[i] = lives_signal_sync_connect(LIVES_GUI_OBJECT(rb_clip_areas[i]), LIVES_WIDGET_TOGGLED_SIGNAL,
333                      LIVES_GUI_CALLBACK(clip_area_toggled), LIVES_INT_TO_POINTER(i));
334   }
335 
336   add_vsep_to_box(LIVES_BOX(hbox2));
337 
338   cscroll = lives_standard_scrolled_window_new(width, height, tgrid);
339   lives_scrolled_window_set_policy(LIVES_SCROLLED_WINDOW(cscroll), LIVES_POLICY_NEVER, LIVES_POLICY_AUTOMATIC);
340   lives_box_pack_start(LIVES_BOX(hbox2), cscroll, TRUE, TRUE, 0);
341 
342   ////
343   add_hsep_to_box(LIVES_BOX(vbox2));
344 
345   // insert a scrolled window for param boxes
346   param_hbox = lives_hbox_new(FALSE, 0);
347 
348   tscroll = lives_standard_scrolled_window_new(width, height, param_hbox);
349   lives_scrolled_window_set_policy(LIVES_SCROLLED_WINDOW(tscroll), LIVES_POLICY_AUTOMATIC, LIVES_POLICY_AUTOMATIC);
350 
351   lives_box_pack_start(LIVES_BOX(vbox2), tscroll, TRUE, TRUE, 0);
352 
353   lives_widget_hide(mainw->eventbox);
354   if (prefs->show_msg_area) lives_widget_hide(mainw->message_box);
355   lives_widget_show_all(top_hbox);
356 
357   lives_widget_context_update(); // need size of cscroll to fit thumbs
358 
359   cpw = (lives_widget_get_allocation_width(tscroll) - widget_opts.border_width * 2) / (width * 1.5) - 2;
360 
361   // add thumbs to grid
362 
363   while (cliplist) {
364     count++;
365 
366     i = LIVES_POINTER_TO_INT(cliplist->data);
367     if (i == mainw->scrap_file || i == mainw->ascrap_file ||
368         (!IS_NORMAL_CLIP(i) &&
369          mainw->files[i]->clip_type != CLIP_TYPE_YUV4MPEG && mainw->files[i]->clip_type != CLIP_TYPE_VIDEODEV) ||
370         !CLIP_HAS_VIDEO(i)) {
371       cliplist = cliplist->next;
372       continue;
373     }
374 
375     // make a small thumbnail, add it to the clips box
376     thumbnail = make_thumb(NULL, i, width, height, mainw->files[i]->start, LIVES_INTERP_NORMAL, TRUE);
377 
378     clip_boxes[count] = lives_event_box_new();
379     lives_widget_object_set_data(LIVES_WIDGET_OBJECT(clip_boxes[count]), "clipno", LIVES_INT_TO_POINTER(i));
380     lives_widget_set_size_request(clip_boxes[count], width * 1.5, height * 1.5);
381 
382     if (palette->style & STYLE_1) {
383       lives_widget_set_bg_color(clip_boxes[count], LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
384       lives_widget_set_bg_color(clip_boxes[count], LIVES_WIDGET_STATE_PRELIGHT, &palette->menu_and_bars);
385     }
386 
387     lives_widget_add_events(clip_boxes[count], LIVES_BUTTON_PRESS_MASK);
388 
389     align = lives_alignment_new(.5, .5, 0., 0.);
390 
391     thumb_image = lives_image_new();
392     lives_image_set_from_pixbuf(LIVES_IMAGE(thumb_image), thumbnail);
393     if (thumbnail) lives_widget_object_unref(thumbnail);
394     lives_container_add(LIVES_CONTAINER(clip_boxes[count]), align);
395 
396     if (rcount > 0) {
397       if (rcount == cpw - 1) rcount = 0;
398       else {
399         lives_grid_attach_next_to(LIVES_GRID(tgrid), clip_boxes[count], sibl, LIVES_POS_RIGHT, 1, 1);
400         sibl = clip_boxes[count];
401       }
402     }
403 
404     if (rcount == 0) {
405       lives_grid_attach_next_to(LIVES_GRID(tgrid), clip_boxes[count], usibl, LIVES_POS_BOTTOM, 1, 1);
406       sibl = usibl = clip_boxes[count];
407     }
408 
409     lives_snprintf(filename, PATH_MAX, "%s", (tmp = lives_path_get_basename(mainw->files[i]->name)));
410     lives_free(tmp);
411     get_basename(filename);
412     lives_widget_set_tooltip_text(clip_boxes[count], filename);
413 
414     //if (palette->style&STYLE_3) lives_widget_set_fg_color (label, LIVES_WIDGET_STATE_PRELIGHT, &palette->info_text);
415     //if (palette->style&STYLE_4) lives_widget_set_fg_color (label, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
416 
417     lives_container_add(LIVES_CONTAINER(align), thumb_image);
418 
419     rcount++;
420 
421     lives_signal_sync_connect(LIVES_GUI_OBJECT(clip_boxes[count]), LIVES_WIDGET_BUTTON_PRESS_EVENT,
422                               LIVES_GUI_CALLBACK(switch_clip_cb), LIVES_INT_TO_POINTER(i));
423 
424     cliplist = cliplist->next;
425   }
426 
427   if (prefs->open_maximised) {
428     lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
429   }
430 
431   lives_widget_show_all(top_hbox);
432 
433   ce_thumbs_liberate_clip_area(mainw->num_tr_applied > 0 ? SCREEN_AREA_BACKGROUND : SCREEN_AREA_FOREGROUND);
434   ce_thumbs_set_clip_area();
435 
436   mainw->ce_thumbs = TRUE;
437 
438 #endif
439 }
440 
441 
end_ce_thumb_mode(void)442 void end_ce_thumb_mode(void) {
443   mainw->ce_thumbs = FALSE;
444   ce_thumbs_remove_param_boxes(TRUE);
445   lives_widget_destroy(top_hbox);
446   lives_container_add(LIVES_CONTAINER(LIVES_MAIN_WINDOW_WIDGET), mainw->top_vbox);
447   lives_widget_show(mainw->eventbox);
448   if (prefs->show_msg_area) lives_widget_show(mainw->message_box);
449   lives_free(fxcombos); lives_free(pscrolls); lives_free(combo_entries);
450   lives_free(key_checks); lives_free(rb_fx_areas); lives_free(rb_clip_areas);
451   lives_free(clip_boxes); lives_free(ch_fns); lives_free(rb_clip_fns);
452   lives_free(rb_fx_fns);
453 }
454 
455 
ce_thumbs_add_param_box(int key,boolean remove)456 void ce_thumbs_add_param_box(int key, boolean remove) {
457   // when an effect with params is applied, show the parms in a box
458   weed_plant_t *inst;
459   lives_rfx_t *rfx;
460 
461   LiVESWidget *vbox;
462   LiVESWidget *hbox;
463   LiVESWidget *label;
464   LiVESWidget *pin_check;
465 
466   char *fname, *tmp, *tmp2;
467 
468   int mode = rte_key_getmode(key + 1);
469 
470   if (key >= rte_keys_virtual) return;
471 
472   if (remove) {
473     // remove old boxes unless pinned
474     ce_thumbs_remove_param_boxes(FALSE);
475   }
476 
477   inst = rte_keymode_get_instance(key + 1, mode);
478 
479   rfx = weed_to_rfx(inst, FALSE); // rfx will inherit the refcount
480   rfx->min_frames = -1;
481 
482   // here we just check if we have any params to display
483   if (!make_param_box(NULL, rfx)) {
484     rfx_free(rfx);
485     lives_free(rfx);
486     return;
487   }
488 
489   vbox = lives_vbox_new(FALSE, 0);
490 
491   pscrolls[key] = lives_standard_scrolled_window_new(-1, -1, vbox);
492   lives_scrolled_window_set_policy(LIVES_SCROLLED_WINDOW(pscrolls[key]), LIVES_POLICY_NEVER, LIVES_POLICY_AUTOMATIC);
493   lives_widget_set_hexpand(pscrolls[key], FALSE);
494 
495   lives_box_pack_start(LIVES_BOX(param_hbox), pscrolls[key], TRUE, TRUE, 0);
496 
497   fname = weed_instance_get_filter_name(inst, TRUE);
498   label = lives_standard_label_new(fname);
499   lives_free(fname);
500 
501   hbox = lives_hbox_new(FALSE, 0);
502   lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
503 
504   add_fill_to_box(LIVES_BOX(hbox));
505   lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_height);
506   add_fill_to_box(LIVES_BOX(hbox));
507 
508   /* TRANSLATORS - "pin" as in "pinned to window" */
509   pin_check = lives_standard_check_button_new((tmp = (_("_Pin"))), FALSE, LIVES_BOX(hbox),
510               (tmp2 = (_("Pin the parameter box to the window"))));
511 
512   lives_free(tmp); lives_free(tmp2);
513 
514   lives_signal_sync_connect_after(LIVES_GUI_OBJECT(pin_check), LIVES_WIDGET_TOGGLED_SIGNAL,
515                                   LIVES_GUI_CALLBACK(pin_toggled), LIVES_INT_TO_POINTER(key));
516 
517   on_fx_pre_activate(rfx, TRUE, vbox);
518 
519   // record the key so we know whose parameters to record later
520   weed_set_int_value((weed_plant_t *)rfx->source, WEED_LEAF_HOST_KEY, key);
521 
522   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pscrolls[key]), "pinned", LIVES_INT_TO_POINTER(FALSE));
523   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pscrolls[key]), "update", LIVES_INT_TO_POINTER(FALSE));
524   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pscrolls[key]), RFX_KEY, rfx);
525   lives_widget_show_all(param_hbox);
526 }
527 
528 
ce_thumbs_remove_param_box(int key)529 static void ce_thumbs_remove_param_box(int key) {
530   // remove a single param box from the param_hbox
531   lives_rfx_t *rfx;
532   if (key >= rte_keys_virtual) return;
533   if (!pscrolls[key]) return;
534   rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[key]), RFX_KEY);
535   on_paramwindow_button_clicked(NULL, rfx); // free rfx and unref the inst (must be done before destroying the pscrolls[key]
536   lives_widget_destroy(pscrolls[key]);
537   pscrolls[key] = NULL;
538   lives_widget_queue_draw(param_hbox);
539 }
540 
541 
ce_thumbs_remove_param_boxes(boolean remove_pinned)542 static void ce_thumbs_remove_param_boxes(boolean remove_pinned) {
543   // remove all param boxes, (except any which are "pinned")
544   for (int i = 0; i < rte_keys_virtual; i++) {
545     if (pscrolls[i]) {
546       if (remove_pinned || !LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[i]), "pinned")))
547         ce_thumbs_remove_param_box(i);
548     }
549   }
550 }
551 
552 
ce_thumbs_register_rfx_change(int key,int mode)553 void ce_thumbs_register_rfx_change(int key, int mode) {
554   // register a param box to be updated visually, from an asynchronous source - either from a A->V data connection or from osc
555   if (key >= rte_keys_virtual || !pscrolls[key]) return;
556   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pscrolls[key]), "update", LIVES_INT_TO_POINTER(TRUE));
557 }
558 
559 
ce_thumbs_apply_rfx_changes(void)560 void ce_thumbs_apply_rfx_changes(void) {
561   // apply asynch updates
562   lives_rfx_t *rfx;
563 
564   for (int i = 0; i < rte_keys_virtual; i++) {
565     if (pscrolls[i]) {
566       if (LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[i]), "update"))) {
567         lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pscrolls[i]), "update", LIVES_INT_TO_POINTER(FALSE));
568         rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[i]), RFX_KEY);
569         update_visual_params(rfx, FALSE);
570 	// *INDENT-OFF*
571       }}}
572   // *INDENT-ON*
573 }
574 
575 
ce_thumbs_update_params(int key,int i,LiVESList * list)576 void ce_thumbs_update_params(int key, int i, LiVESList * list) {
577   // called only from weed_set_blend_factor() and from setting param in rte_window
578   lives_rfx_t *rfx;
579   if (key >= rte_keys_virtual) return;
580 
581   if (pscrolls[key]) {
582     rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[key]), RFX_KEY);
583     mainw->block_param_updates = TRUE;
584     set_param_from_list(list, &rfx->params[key], 0, TRUE, TRUE);
585     mainw->block_param_updates = FALSE;
586   }
587 }
588 
589 
ce_thumbs_update_visual_params(int key)590 void ce_thumbs_update_visual_params(int key) {
591   // param change in rte_window - set params box here
592   lives_rfx_t *rfx;
593   if (key >= rte_keys_virtual) return;
594 
595   if (pscrolls[key]) {
596     rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[key]), RFX_KEY);
597     update_visual_params(rfx, FALSE);
598   }
599 }
600 
601 
ce_thumbs_check_for_rte(lives_rfx_t * rfx,lives_rfx_t * rte_rfx,int key)602 void ce_thumbs_check_for_rte(lives_rfx_t *rfx, lives_rfx_t *rte_rfx, int key) {
603   // param change in ce_thumbs, update rte_window
604   for (int i = 0; i < rte_keys_virtual; i++) {
605     if (pscrolls[i] && i == key &&
606         rfx == (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(pscrolls[key]), RFX_KEY)) {
607       update_visual_params(rte_rfx, FALSE);
608       break;
609     }
610   }
611 }
612 
613 
ce_thumbs_reset_combo(int key)614 void ce_thumbs_reset_combo(int key) {
615   // called from rte_window when the mapping is changed
616 
617   LiVESList *fxlist = NULL;
618   int mode;
619 
620   if (key >= rte_keys_virtual) return;
621   for (int j = 0; j <= rte_key_getmaxmode(key + 1); j++) {
622     fxlist = lives_list_append(fxlist, rte_keymode_get_filter_name(key + 1, j, FALSE));
623   }
624   lives_combo_populate(LIVES_COMBO(fxcombos[key]), fxlist);
625   if (fxlist) {
626     weed_plant_t *inst;
627     lives_widget_set_sensitive(key_checks[key], TRUE);
628     lives_list_free_all(&fxlist);
629     mode = rte_key_getmode(key + 1);
630     ce_thumbs_set_mode_combo(key, mode);
631     if ((inst = rte_keymode_get_instance(key + 1, mode)) != NULL) {
632       ce_thumbs_add_param_box(key, TRUE);
633       weed_instance_unref(inst);
634     }
635   } else {
636     lives_widget_set_sensitive(key_checks[key], FALSE);
637     lives_combo_set_active_string(LIVES_COMBO(fxcombos[key]), "");
638   }
639 }
640 
641 
ce_thumbs_reset_combos(void)642 void ce_thumbs_reset_combos(void) {
643   // called from rte_window when the mapping is cleared
644   for (int i = 0; i < rte_keys_virtual; i++) {
645     ce_thumbs_reset_combo(i);
646   }
647 }
648 
649 
ce_thumbs_set_clip_area(void)650 void ce_thumbs_set_clip_area(void) {
651   int i;
652   for (i = 0; i < n_screen_areas; i++) lives_signal_handler_block(rb_clip_areas[i], rb_clip_fns[i]);
653   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rb_clip_areas[mainw->active_sa_clips]), TRUE);
654   for (i = 0; i < n_screen_areas; i++) lives_signal_handler_unblock(rb_clip_areas[i], rb_clip_fns[i]);
655   ce_thumbs_highlight_current_clip();
656 }
657 
658 
ce_thumbs_set_fx_area(int area)659 void ce_thumbs_set_fx_area(int area) {
660   //register int i;
661   //for (i=0;i<n_screen_areas;i++) lives_signal_handler_block(rb_fx_areas[i],rb_fx_fns[i]);
662   lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rb_fx_areas[area]), TRUE);
663   //for (i=0;i<n_screen_areas;i++) lives_signal_handler_unblock(rb_fx_areas[i],rb_fx_fns[i]);
664   mainw->active_sa_fx = area;
665 }
666 
667 
ce_thumbs_update_current_clip(void)668 void ce_thumbs_update_current_clip(void) {
669   mainw->ce_upd_clip = TRUE;
670 }
671 
672 
ce_thumbs_highlight_current_clip(void)673 void ce_thumbs_highlight_current_clip(void) {
674   // unprelight all clip boxes, prelight current clip (fg or bg)
675   boolean match = FALSE;
676   int clipno;
677 
678   for (int i = 0; i < n_clip_boxes; i++) {
679     if (!clip_boxes[i]) break;
680     if (!match) {
681       clipno = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(clip_boxes[i]), "clipno"));
682       switch (mainw->active_sa_clips) {
683       case SCREEN_AREA_FOREGROUND:
684         if (clipno == mainw->current_file) match = TRUE;
685         break;
686       case SCREEN_AREA_BACKGROUND:
687         if (clipno == mainw->blend_file) match = TRUE;
688         if (mainw->blend_file == -1 && clipno == mainw->current_file) match = TRUE;
689         break;
690       default: break;
691       }
692       if (match) {
693         lives_widget_set_state(clip_boxes[i], LIVES_WIDGET_STATE_PRELIGHT);
694         continue;
695       }
696     }
697     lives_widget_set_state(clip_boxes[i], LIVES_WIDGET_STATE_NORMAL);
698   }
699 }
700 
701 
ce_thumbs_liberate_clip_area(int area)702 void ce_thumbs_liberate_clip_area(int area) {
703   lives_widget_set_sensitive(rb_clip_areas[area], TRUE);
704   ce_thumbs_set_clip_area();
705 }
706 
707 
ce_thumbs_liberate_clip_area_register(int area)708 void ce_thumbs_liberate_clip_area_register(int area) {
709   next_screen_area = area;
710 }
711 
712 
ce_thumbs_apply_liberation(void)713 void ce_thumbs_apply_liberation(void) {
714   if (next_screen_area != SCREEN_AREA_NONE)
715     ce_thumbs_liberate_clip_area(next_screen_area);
716   next_screen_area = SCREEN_AREA_NONE;
717 }
718 
719