1 // paramspecial.c
2 // LiVES
3 // (c) G. Finch 2004 - 2019 <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 // dynamic window generation from parameter arrays :-)
8 // special widgets
9 
10 #include "main.h"
11 #include "resample.h"
12 #include "effects.h"
13 #include "paramwindow.h"
14 #include "framedraw.h"
15 #include "callbacks.h"
16 
17 static lives_special_aspect_t aspect;
18 static lives_special_fontchooser_t fchooser;
19 static lives_special_framedraw_rect_t framedraw;
20 static LiVESList *fileread;
21 static LiVESList *filewrite;
22 static LiVESList *passwd_widgets;
23 
24 static boolean special_inited = FALSE;
25 
26 
reset_framedraw_preview(void)27 void reset_framedraw_preview(void) {invalidate_preview(&framedraw);}
28 
29 
init_special(void)30 void init_special(void) {
31   if (special_inited) return;
32 
33   special_inited = TRUE;
34   fchooser.nwidgets = 0;
35   aspect.nwidgets = 0;
36 
37   framedraw.xstart_param = framedraw.ystart_param = framedraw.xend_param = framedraw.yend_param = NULL;
38   framedraw.stdwidgets = 0;
39   framedraw.extra_params = NULL;
40   framedraw.num_extra = 0;
41   framedraw.added = FALSE;
42   framedraw.type = LIVES_PARAM_SPECIAL_TYPE_NONE;
43   mergealign.start_param = mergealign.end_param = NULL;
44   passwd_widgets = NULL;
45   fileread = NULL;
46   filewrite = NULL;
47 }
48 
49 
paramspecial_get_aspect()50 const lives_special_aspect_t *paramspecial_get_aspect() {return &aspect;}
51 
52 
add_to_special(const char * sp_string,lives_rfx_t * rfx)53 void add_to_special(const char *sp_string, lives_rfx_t *rfx) {
54   int num_widgets = get_token_count(sp_string, '|') - 2;
55   char **array = lives_strsplit(sp_string, "|", num_widgets + 2);
56 
57   // TODO - assert only one of each of these
58 
59   if (!strcmp(array[0], "aspect")) {
60     aspect.width_param = &rfx->params[atoi(array[1])];
61     aspect.height_param = &rfx->params[atoi(array[2])];
62   } else if (!strcmp(array[0], "fontchooser")) {
63 #if GTK_CHECK_VERSION(3, 2, 0)
64     fchooser.font_param = &rfx->params[atoi(array[1])];
65     fchooser.size_param = &rfx->params[atoi(array[2])];
66     if (!*((char *)fchooser.font_param->value))
67       set_rfx_param_by_name_string(rfx, fchooser.font_param->name, widget_opts.font_name, TRUE);
68 #endif
69   } else if (!strcmp(array[0], "mergealign")) {
70     mergealign.start_param = &rfx->params[atoi(array[1])];
71     mergealign.end_param = &rfx->params[atoi(array[2])];
72     mergealign.rfx = rfx;
73   } else if (!strcmp(array[0], "framedraw")) {
74     if (fx_dialog[1]) {
75       lives_strfreev(array);
76       return;
77     }
78     framedraw.rfx = rfx;
79     if (!strcmp(array[1], "rectdemask")) {
80       framedraw.type = LIVES_PARAM_SPECIAL_TYPE_RECT_DEMASK;
81       framedraw.xstart_param = &rfx->params[atoi(array[2])];
82       framedraw.ystart_param = &rfx->params[atoi(array[3])];
83       framedraw.xend_param = &rfx->params[atoi(array[4])];
84       framedraw.yend_param = &rfx->params[atoi(array[5])];
85       framedraw.stdwidgets = 4;
86     } else if (!strcmp(array[1], "multirect") || !strcmp(array[1], "multrect")) { // allow for spelling errors in earlier RFX
87       framedraw.type = LIVES_PARAM_SPECIAL_TYPE_RECT_MULTIRECT;
88       framedraw.xstart_param = &rfx->params[atoi(array[2])];
89       framedraw.ystart_param = &rfx->params[atoi(array[3])];
90       framedraw.xend_param = &rfx->params[atoi(array[4])];
91       framedraw.yend_param = &rfx->params[atoi(array[5])];
92       framedraw.stdwidgets = 4;
93     } else if (!strcmp(array[1], "singlepoint")) {
94       framedraw.type = LIVES_PARAM_SPECIAL_TYPE_SINGLEPOINT;
95       framedraw.xstart_param = &rfx->params[atoi(array[2])];
96       framedraw.ystart_param = &rfx->params[atoi(array[3])];
97       framedraw.stdwidgets = 2;
98     } else if (!strcmp(array[1], "scaledpoint")) {
99       framedraw.type = LIVES_PARAM_SPECIAL_TYPE_SCALEDPOINT;
100       framedraw.xstart_param = &rfx->params[atoi(array[2])];
101       framedraw.ystart_param = &rfx->params[atoi(array[3])];
102       framedraw.scale_param = &rfx->params[atoi(array[4])];
103       framedraw.stdwidgets = 3;
104     }
105 
106     if (num_widgets > framedraw.stdwidgets) framedraw.extra_params =
107         (int *)lives_malloc(((framedraw.num_extra = (num_widgets - framedraw.stdwidgets))) * sizint);
108 
109     for (int i = 0; i < num_widgets; i++) {
110       int pnum = atoi(array[i + 2]);
111       if (rfx->status == RFX_STATUS_WEED) {
112         if (mainw->multitrack) {
113           if (rfx->params[pnum].multi == PVAL_MULTI_PER_CHANNEL) {
114             /// handling for "value per channel" parameters in multitrack
115             if ((rfx->params[pnum].hidden & HIDDEN_MULTI) == HIDDEN_MULTI) {
116               if (mainw->multitrack->track_index != -1) {
117                 rfx->params[pnum].hidden ^= HIDDEN_MULTI; // multivalues allowed
118               } else {
119                 rfx->params[pnum].hidden |= HIDDEN_MULTI; // multivalues hidden
120 		// *INDENT-OFF*
121               }}}}}
122       // *INDENT-ON*
123       if (i >= framedraw.stdwidgets) framedraw.extra_params[i - framedraw.stdwidgets] = pnum;
124     }
125 
126     if (mainw->multitrack) {
127       mainw->multitrack->framedraw = &framedraw;
128       lives_widget_set_bg_color(mainw->multitrack->fd_frame, LIVES_WIDGET_STATE_NORMAL, &palette->light_red);
129     }
130   }
131 
132   // can be multiple of each of these
133 
134   else if (!strcmp(array[0], "fileread")) {
135     int idx = atoi(array[1]);
136     fileread = lives_list_append(fileread, (livespointer)&rfx->params[idx]);
137 
138     // ensure we get an entry and not a text_view
139     if ((int)rfx->params[idx].max > RFX_TEXT_MAGIC) rfx->params[idx].max = (double)RFX_TEXT_MAGIC;
140   } else if (!strcmp(array[0], "filewrite")) {
141     int idx = atoi(array[1]);
142     filewrite = lives_list_append(filewrite, (livespointer)&rfx->params[idx]);
143     rfx->params[idx].edited = TRUE;
144 
145     // ensure we get an entry and not a text_view
146     if ((int)rfx->params[idx].max > RFX_TEXT_MAGIC) rfx->params[idx].max = (double)RFX_TEXT_MAGIC;
147   } else if (!strcmp(array[0], "password")) {
148     int idx = atoi(array[1]);
149     passwd_widgets = lives_list_append(passwd_widgets, (livespointer)&rfx->params[idx]);
150 
151     // ensure we get an entry and not a text_view
152     if ((int)rfx->params[idx].max > RFX_TEXT_MAGIC) rfx->params[idx].max = (double)RFX_TEXT_MAGIC;
153   }
154 
155   lives_strfreev(array);
156 }
157 
158 
fd_tweak(lives_rfx_t * rfx)159 void fd_tweak(lives_rfx_t *rfx) {
160   if (rfx->props & RFX_PROPS_MAY_RESIZE) {
161     if (framedraw.type != LIVES_PARAM_SPECIAL_TYPE_NONE) {
162       // for effects which can resize, and have a special framedraw, we will use original sized image
163       lives_widget_hide(mainw->framedraw_preview);
164       lives_widget_set_sensitive(mainw->framedraw_spinbutton, TRUE);
165       lives_widget_set_sensitive(mainw->framedraw_scale, TRUE);
166     }
167   }
168   if (framedraw.type != LIVES_PARAM_SPECIAL_TYPE_RECT_DEMASK) {
169     lives_widget_set_no_show_all(mainw->framedraw_maskbox, TRUE);
170   }
171 }
172 
173 
fd_connect_spinbutton(lives_rfx_t * rfx)174 void fd_connect_spinbutton(lives_rfx_t *rfx) {framedraw_connect_spinbutton(&framedraw, rfx);}
175 
176 
passwd_toggle_vis(LiVESToggleButton * b,livespointer entry)177 static void passwd_toggle_vis(LiVESToggleButton * b, livespointer entry) {
178   lives_entry_set_visibility(LIVES_ENTRY(entry), lives_toggle_button_get_active(b));
179 }
180 
reset_aspect(LiVESButton * button,livespointer user_data)181 static void reset_aspect(LiVESButton * button, livespointer user_data) {
182   if (lives_lock_button_get_locked(button)) {
183     lives_special_aspect_t *aspect = (lives_special_aspect_t *)user_data;
184     double width = lives_spin_button_get_value(LIVES_SPIN_BUTTON(aspect->width_param->widgets[0]));
185     double height = lives_spin_button_get_value(LIVES_SPIN_BUTTON(aspect->height_param->widgets[0]));
186     aspect->ratio = width / height;
187   }
188 }
189 
190 #if GTK_CHECK_VERSION(3, 2, 0)
font_set_cb(LiVESFontButton * button,livespointer data)191 static void font_set_cb(LiVESFontButton * button, livespointer data) {
192   lives_rfx_t *rfx = (lives_rfx_t *)data;
193   char *fname = lives_font_chooser_get_font(LIVES_FONT_CHOOSER(button));
194   LingoFontDescription *lfd = lives_font_chooser_get_font_desc(LIVES_FONT_CHOOSER(button));
195   int size = lingo_font_description_get_size(lfd);
196 
197   lives_signal_handler_block(fchooser.font_param->widgets[0], fchooser.entry_func);
198   lives_entry_set_text(LIVES_ENTRY(fchooser.font_param->widgets[0]), fname);
199   after_param_text_changed(fchooser.font_param->widgets[0], rfx);
200   lives_signal_handler_unblock(fchooser.font_param->widgets[0], fchooser.entry_func);
201 
202   lives_signal_handler_block(fchooser.size_param->widgets[0], fchooser.size_paramfunc);
203   lives_spin_button_set_value(LIVES_SPIN_BUTTON(fchooser.size_param->widgets[0]), size / LINGO_SCALE);
204   lives_signal_handler_unblock(fchooser.size_param->widgets[0], fchooser.size_paramfunc);
205 
206   lives_free(fname);
207   lingo_font_description_free(lfd);
208 }
209 
text_size_cb(LiVESSpinButton * button,livespointer data)210 static void text_size_cb(LiVESSpinButton * button, livespointer data) {
211   int sval = lives_spin_button_get_value_as_int(button);
212   LingoFontDescription *lfd =
213     lives_font_chooser_get_font_desc(LIVES_FONT_CHOOSER(fchooser.font_param->widgets[1]));
214   lingo_font_description_set_size(lfd, sval * LINGO_SCALE);
215   lives_font_chooser_set_font_desc(LIVES_FONT_CHOOSER(fchooser.font_param->widgets[1]), lfd);
216   lingo_font_description_free(lfd);
217 }
218 
font_entry_cb(LiVESEntry * entry,livespointer data)219 static void font_entry_cb(LiVESEntry * entry, livespointer data) {
220   LiVESFontButton *button = (LiVESFontButton *)fchooser.font_param->widgets[1];
221   //lives_font_chooser_set_font(LIVES_FONT_CHOOSER(button), lives_entry_get_text(entry));
222   text_size_cb(LIVES_SPIN_BUTTON(fchooser.size_param->widgets[0]), data);
223   font_set_cb(button, data);
224 }
225 #endif
226 
227 
check_for_special_type(lives_rfx_t * rfx,lives_param_t * param,LiVESBox * pbox)228 void check_for_special_type(lives_rfx_t *rfx, lives_param_t *param, LiVESBox * pbox) {
229   LiVESList *slist;
230   // check if this parameter is part of a special window
231   // as we are drawing the paramwindow
232 
233   if (param == framedraw.xstart_param) {
234     param->special_type = framedraw.type;
235     param->special_type_index = 0;
236   }
237   if (param == framedraw.ystart_param) {
238     param->special_type = framedraw.type;
239     param->special_type_index = 1;
240   }
241   if (mainw->current_file > -1) {
242     if (param == framedraw.xend_param) {
243       param->special_type = framedraw.type;
244       param->special_type_index = 2;
245     }
246     if (param == framedraw.yend_param) {
247       param->special_type = framedraw.type;
248       param->special_type_index = 3;
249     }
250 
251     if (param == aspect.width_param) {
252       param->special_type = LIVES_PARAM_SPECIAL_TYPE_ASPECT_RATIO;
253       param->special_type_index = 0;
254     }
255 
256     if (param == aspect.height_param) {
257       param->special_type = LIVES_PARAM_SPECIAL_TYPE_ASPECT_RATIO;
258       param->special_type_index = 1;
259     }
260 
261     if (param == fchooser.font_param) {
262       param->special_type = LIVES_PARAM_SPECIAL_TYPE_FONT_CHOOSER;
263       param->special_type_index = 0;
264     }
265     if (param == fchooser.size_param) {
266       param->special_type = LIVES_PARAM_SPECIAL_TYPE_FONT_CHOOSER;
267       param->special_type_index = 1;
268     }
269   }
270 
271   slist = fileread;
272   while (slist) {
273     if (param == (lives_param_t *)(slist->data)) {
274       param->special_type = LIVES_PARAM_SPECIAL_TYPE_FILEREAD;
275     }
276     slist = slist->next;
277   }
278 
279   slist = filewrite;
280   while (slist) {
281     if (param == (lives_param_t *)(slist->data)) {
282       param->special_type = LIVES_PARAM_SPECIAL_TYPE_FILEWRITE;
283     }
284     slist = slist->next;
285   }
286 
287   // password fields
288   slist = passwd_widgets;
289   while (slist) {
290     if (param == (lives_param_t *)(slist->data)) {
291       param->special_type = LIVES_PARAM_SPECIAL_TYPE_PASSWORD;
292     }
293     slist = slist->next;
294   }
295 }
296 
297 
check_for_special(lives_rfx_t * rfx,lives_param_t * param,LiVESBox * pbox)298 void check_for_special(lives_rfx_t *rfx, lives_param_t *param, LiVESBox * pbox) {
299   LiVESWidget *checkbutton;
300   LiVESWidget *widget = param->widgets[0];
301   LiVESWidget *hbox;
302   LiVESWidget *box;
303   LiVESWidget *buttond;
304   LiVESList *slist;
305 
306   // check if this parameter is part of a special window
307   // as we are drawing the paramwindow
308 
309   if (param == framedraw.xstart_param) {
310     param->special_type = framedraw.type;
311     param->special_type_index = 0;
312     if (framedraw.type == LIVES_PARAM_SPECIAL_TYPE_RECT_DEMASK)
313       lives_spin_button_set_value(LIVES_SPIN_BUTTON(widget), 0.);
314     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
315                                     LIVES_GUI_CALLBACK(after_framedraw_widget_changed), &framedraw);
316   }
317   if (param == framedraw.ystart_param) {
318     param->special_type = framedraw.type;
319     param->special_type_index = 1;
320     if (framedraw.type == LIVES_PARAM_SPECIAL_TYPE_RECT_DEMASK)
321       lives_spin_button_set_value(LIVES_SPIN_BUTTON(widget), 0.);
322     lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
323                                     LIVES_GUI_CALLBACK(after_framedraw_widget_changed), &framedraw);
324   }
325   if (mainw->current_file > -1) {
326     if (param == framedraw.xend_param) {
327       param->special_type = framedraw.type;
328       param->special_type_index = 2;
329       if (framedraw.type == LIVES_PARAM_SPECIAL_TYPE_RECT_DEMASK)
330         lives_spin_button_set_value(LIVES_SPIN_BUTTON(widget), (double)cfile->hsize);
331       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
332                                       LIVES_GUI_CALLBACK(after_framedraw_widget_changed), &framedraw);
333     }
334     if (param == framedraw.yend_param) {
335       param->special_type = framedraw.type;
336       param->special_type_index = 3;
337       if (framedraw.type == LIVES_PARAM_SPECIAL_TYPE_RECT_DEMASK)
338         lives_spin_button_set_value(LIVES_SPIN_BUTTON(widget), (double)cfile->vsize);
339       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
340                                       LIVES_GUI_CALLBACK(after_framedraw_widget_changed), &framedraw);
341     }
342 
343     if (framedraw.stdwidgets > 0 && !framedraw.added) {
344       if (framedraw.xstart_param && framedraw.xstart_param->widgets[0] &&
345           framedraw.ystart_param && framedraw.ystart_param->widgets[0]) {
346         if (framedraw.stdwidgets == 2 || (framedraw.stdwidgets == 3 && framedraw.scale_param &&
347                                           framedraw.scale_param->widgets[0]) || (framedraw.xend_param
348                                               && framedraw.xend_param->widgets[0] &&
349                                               framedraw.yend_param && framedraw.yend_param->widgets[0])) {
350           if (!mainw->multitrack) {
351             framedraw_connect(&framedraw, cfile->hsize, cfile->vsize, rfx); // turn passive preview->active
352             framedraw_add_reset(LIVES_VBOX(LIVES_WIDGET(pbox)), &framedraw);
353           } else {
354             mainw->framedraw = mainw->play_image;
355           }
356           framedraw.added = TRUE;
357         }
358       }
359     }
360 
361     if (param == aspect.width_param) {
362       if (CURRENT_CLIP_HAS_VIDEO) lives_spin_button_set_value(LIVES_SPIN_BUTTON(widget), cfile->hsize);
363       aspect.width_func = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
364                           LIVES_GUI_CALLBACK(after_aspect_width_changed), NULL);
365       aspect.nwidgets++;
366     }
367 
368     if (param == aspect.height_param) {
369       if (CURRENT_CLIP_HAS_VIDEO) lives_spin_button_set_value(LIVES_SPIN_BUTTON(widget), cfile->vsize);
370       aspect.height_func = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
371                            LIVES_GUI_CALLBACK(after_aspect_height_changed), NULL);
372       aspect.nwidgets++;
373     }
374 
375 #if GTK_CHECK_VERSION(3, 2, 0)
376     if (param == fchooser.font_param) {
377       LiVESWidget *tbox = widget;
378       int idx;
379       box = lives_widget_get_parent(widget);
380       while (box && !LIVES_IS_HBOX(box)) {
381         tbox = box;
382         box = lives_widget_get_parent(box);
383       }
384       if (!box) return;
385       idx = get_box_child_index(LIVES_BOX(box), tbox);
386       param->widgets[1] = buttond = lives_standard_font_chooser_new();
387       lives_font_chooser_set_font(LIVES_FONT_CHOOSER(param->widgets[1]), param->value);
388 
389       lives_box_pack_start(LIVES_BOX(box), buttond, TRUE, TRUE, 0);
390       lives_box_reorder_child(LIVES_BOX(box), buttond, idx);
391       if (lives_widget_is_visible(widget)) lives_widget_show_all(buttond);
392 
393       lives_widget_object_ref(tbox);
394       lives_widget_unparent(tbox);
395 
396       if (!lives_widget_is_sensitive(widget)) lives_widget_set_sensitive(buttond, FALSE);
397       lives_widget_set_show_hide_with(widget, buttond);
398       lives_widget_set_sensitive_with(widget, buttond);
399 
400       lives_widget_destroy_with(buttond, tbox);
401 
402       lives_signal_sync_connect(LIVES_GUI_OBJECT(param->widgets[1]), LIVES_WIDGET_FONT_SET_SIGNAL,
403                                 LIVES_GUI_CALLBACK(font_set_cb), (livespointer)rfx);
404 
405       fchooser.entry_func = lives_signal_sync_connect(LIVES_GUI_OBJECT(widget),
406                             LIVES_WIDGET_CHANGED_SIGNAL,
407                             LIVES_GUI_CALLBACK(font_entry_cb), (livespointer)rfx);
408 
409       if (fchooser.nwidgets == 1) {
410         double fsize = get_double_param(fchooser.size_param);
411         lives_entry_set_text(LIVES_ENTRY(param->widgets[0]), param->value);
412         font_entry_cb(LIVES_ENTRY(param->widgets[0]), (livespointer)rfx);
413         lives_spin_button_set_value(LIVES_SPIN_BUTTON(fchooser.size_param->widgets[0]), fsize);
414         text_size_cb(LIVES_SPIN_BUTTON(fchooser.size_param->widgets[0]), (livespointer)rfx);
415       }
416       fchooser.nwidgets++;
417     }
418 
419     if (param == fchooser.size_param) {
420       fchooser.size_paramfunc = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(widget),
421                                 LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
422                                 LIVES_GUI_CALLBACK(text_size_cb), (livespointer)rfx);
423       if (fchooser.nwidgets == 1) {
424         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), get_double_param(param->value));
425         text_size_cb(LIVES_SPIN_BUTTON(fchooser.size_param->widgets[0]), (livespointer)rfx);
426       }
427       fchooser.nwidgets++;
428     }
429 #endif
430 
431     if ((param == aspect.width_param || param == aspect.height_param) && aspect.nwidgets == 2) {
432       boolean expand = widget_opts.expand == LIVES_EXPAND_EXTRA;
433       char *labeltext = (_("Maintain _Aspect Ratio"));
434 
435       aspect.no_reset = TRUE;
436       aspect.lockbutton = lives_standard_lock_button_new(TRUE, ASPECT_BUTTON_WIDTH,
437                           ASPECT_BUTTON_HEIGHT, labeltext, NULL);
438       lives_free(labeltext);
439 
440       lives_signal_sync_connect(aspect.lockbutton, LIVES_WIDGET_CLICKED_SIGNAL,
441                                 LIVES_GUI_CALLBACK(reset_aspect), (livespointer)&aspect);
442 
443       reset_aspect(LIVES_BUTTON(aspect.lockbutton), &aspect);
444 
445       hbox = lives_hbox_new(FALSE, 0);
446       lives_widget_apply_theme(hbox, LIVES_WIDGET_STATE_NORMAL);
447 
448       if (!LIVES_IS_HBOX(pbox)) {
449         hbox = lives_hbox_new(FALSE, 0);
450         lives_widget_show(hbox);
451         lives_box_pack_start(LIVES_BOX(LIVES_WIDGET(pbox)), hbox, FALSE, FALSE, widget_opts.packing_height * 2);
452         lives_box_pack_end(LIVES_BOX(hbox), aspect.lockbutton, expand, FALSE, 0);
453       } else {
454         lives_box_pack_start(LIVES_BOX(LIVES_WIDGET(pbox)), hbox, FALSE, FALSE, widget_opts.packing_width * 1.5);
455         lives_box_pack_start(LIVES_BOX(hbox), aspect.lockbutton, expand, FALSE, 0);
456       }
457 
458       if (expand) add_fill_to_box(LIVES_BOX(hbox));
459     }
460   }
461 
462   slist = fileread;
463   while (slist) {
464     if (param == (lives_param_t *)(slist->data)) {
465       char *def_dir;
466       if (!widget) continue;
467 
468       box = lives_widget_get_parent(widget);
469 
470       while (box && !LIVES_IS_HBOX(box)) {
471         box = lives_widget_get_parent(box);
472       }
473 
474       if (!box) return;
475 
476       def_dir = lives_get_current_dir();
477 
478       if (LIVES_IS_ENTRY(widget)) {
479         if (*(lives_entry_get_text(LIVES_ENTRY(widget)))) {
480           char dirnamex[PATH_MAX];
481           lives_snprintf(dirnamex, PATH_MAX, "%s", lives_entry_get_text(LIVES_ENTRY(widget)));
482           get_dirname(dirnamex);
483           lives_free(def_dir);
484           def_dir = lives_strdup(dirnamex);
485         }
486       }
487 
488       param->widgets[2] = buttond = lives_standard_file_button_new(FALSE, def_dir);
489       lives_free(def_dir);
490       lives_box_pack_start(LIVES_BOX(box), buttond, FALSE, FALSE, widget_opts.packing_width);
491 
492       lives_signal_sync_connect(buttond, LIVES_WIDGET_CLICKED_SIGNAL, LIVES_GUI_CALLBACK(on_filesel_button_clicked),
493                                 (livespointer)widget);
494 
495       if (!lives_widget_is_sensitive(widget)) lives_widget_set_sensitive(buttond, FALSE);
496       lives_widget_set_show_hide_with(widget, buttond);
497       lives_widget_set_sensitive_with(widget, buttond);
498 
499       if (LIVES_IS_ENTRY(widget)) {
500         lives_entry_set_editable(LIVES_ENTRY(widget), FALSE);
501         if (param->widgets[1] &&
502             LIVES_IS_LABEL(param->widgets[1]) &&
503             lives_label_get_mnemonic_widget(LIVES_LABEL(param->widgets[1])) != NULL)
504           lives_label_set_mnemonic_widget(LIVES_LABEL(param->widgets[1]), buttond);
505         lives_entry_set_max_length(LIVES_ENTRY(widget), PATH_MAX);
506       }
507     }
508 
509     slist = slist->next;
510   }
511 
512   slist = filewrite;
513   while (slist) {
514     if (param == (lives_param_t *)(slist->data)) {
515 
516       if (!widget) continue;
517 
518       box = lives_widget_get_parent(widget);
519 
520       while (box && !LIVES_IS_HBOX(box)) {
521         box = lives_widget_get_parent(box);
522       }
523 
524       if (!box) return;
525 
526       param->widgets[2] = buttond = lives_standard_file_button_new(FALSE, NULL);
527 
528       lives_widget_object_set_data(LIVES_WIDGET_OBJECT(buttond), FILESEL_TYPE_KEY, (livespointer)LIVES_FILE_SELECTION_SAVE);
529       lives_box_pack_start(LIVES_BOX(box), buttond, FALSE, FALSE, widget_opts.packing_width);
530       lives_signal_sync_connect(buttond, LIVES_WIDGET_CLICKED_SIGNAL, LIVES_GUI_CALLBACK(on_filesel_button_clicked),
531                                 (livespointer)widget);
532 
533       if (!lives_widget_is_sensitive(widget)) lives_widget_set_sensitive(buttond, FALSE);
534       lives_widget_set_show_hide_with(widget, buttond);
535       lives_widget_set_sensitive_with(widget, buttond);
536 
537       if (LIVES_IS_ENTRY(widget)) {
538         lives_entry_set_editable(LIVES_ENTRY(widget), TRUE);
539         if (param->widgets[1] &&
540             LIVES_IS_LABEL(param->widgets[1]) &&
541             lives_label_get_mnemonic_widget(LIVES_LABEL(param->widgets[1])) != NULL)
542           lives_label_set_mnemonic_widget(LIVES_LABEL(param->widgets[1]), buttond);
543         lives_entry_set_max_length(LIVES_ENTRY(widget), PATH_MAX);
544       }
545     }
546 
547     slist = slist->next;
548   }
549 
550   // password fields
551 
552   for (slist = passwd_widgets; slist; slist = slist->next) {
553     if (param == (lives_param_t *)(slist->data)) {
554       if (!widget) continue;
555 
556       lives_entry_set_visibility(LIVES_ENTRY(widget), FALSE);
557 
558       box = lives_widget_get_parent(widget);
559 
560       while (box && !LIVES_IS_BOX(box)) {
561         box = lives_widget_get_parent(box);
562       }
563 
564       if (!box) continue;
565 
566       if (!LIVES_IS_HBOX(box)) {
567         hbox = lives_hbox_new(FALSE, 0);
568         lives_box_pack_start(LIVES_BOX(LIVES_WIDGET(box)), hbox, FALSE, FALSE, widget_opts.packing_height);
569       } else hbox = box;
570 
571       param->widgets[2] = checkbutton = lives_standard_check_button_new(_("Display Password"), FALSE, LIVES_BOX(hbox), NULL);
572 
573       lives_button_set_focus_on_click(LIVES_BUTTON(checkbutton), FALSE);
574 
575       if (!lives_widget_is_sensitive(widget)) lives_widget_set_sensitive(checkbutton, FALSE);
576       lives_widget_show_all(hbox);
577 
578       lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
579                                       LIVES_GUI_CALLBACK(passwd_toggle_vis), (livespointer)widget);
580     }
581   }
582 }
583 
584 
after_aspect_width_changed(LiVESSpinButton * spinbutton,livespointer user_data)585 void after_aspect_width_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
586   if (lives_lock_button_get_locked(LIVES_BUTTON(aspect.lockbutton))) {
587     int width = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
588     double height = (double)width / aspect.ratio;
589     LiVESWidget *spbutton = aspect.height_param->widgets[0];
590     lives_signal_handler_block(spbutton, aspect.height_func);
591     aspect.width_param->change_blocked = TRUE;
592     height = lives_spin_button_get_snapval(LIVES_SPIN_BUTTON(spbutton), height);
593     lives_spin_button_set_value(LIVES_SPIN_BUTTON(spbutton), height);
594     lives_spin_button_update(LIVES_SPIN_BUTTON(spbutton));
595     lives_signal_handler_unblock(spbutton, aspect.height_func);
596     aspect.width_param->change_blocked = FALSE;
597   }
598 }
599 
600 
after_aspect_height_changed(LiVESToggleButton * spinbutton,livespointer user_data)601 void after_aspect_height_changed(LiVESToggleButton * spinbutton, livespointer user_data) {
602   if (lives_lock_button_get_locked(LIVES_BUTTON(aspect.lockbutton))) {
603     int height = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
604     double width = (double)height * aspect.ratio;
605     LiVESWidget *spbutton = aspect.width_param->widgets[0];
606     lives_signal_handler_block(spbutton, aspect.width_func);
607     aspect.height_param->change_blocked = TRUE;
608     width = lives_spin_button_get_snapval(LIVES_SPIN_BUTTON(spbutton), width);
609     lives_spin_button_set_value(LIVES_SPIN_BUTTON(spbutton), width);
610     lives_spin_button_update(LIVES_SPIN_BUTTON(spbutton));
611     lives_signal_handler_unblock(spbutton, aspect.width_func);
612     aspect.height_param->change_blocked = FALSE;
613   }
614 }
615 
616 
check_filewrite_overwrites(void)617 boolean check_filewrite_overwrites(void) {
618   // check all writeable files which were user edited (param->edited), to make sure we don't overwrite without permission
619   // if the value was set by the file button we would have checked there, and param->edited will be FALSE
620 
621   if (filewrite) {
622     LiVESList *slist = filewrite;
623     while (slist) {
624       lives_param_t *param = (lives_param_t *)(slist->data);
625       if (param->edited) {
626         // check for overwrite
627         if (LIVES_IS_ENTRY(param->widgets[0])) {
628           if (*(lives_entry_get_text(LIVES_ENTRY(param->widgets[0])))) {
629             if (!check_file(lives_entry_get_text(LIVES_ENTRY(param->widgets[0])), TRUE)) {
630               return FALSE;
631 	      // *INDENT-OFF*
632             }}}}
633       slist = slist->next;
634     }}
635   // *INDENT-ON*
636 
637   return TRUE;
638 }
639 
640 
special_cleanup(boolean is_ok)641 boolean special_cleanup(boolean is_ok) {
642   // free some memory now
643   if (special_inited) {
644     if (is_ok && !check_filewrite_overwrites()) return FALSE;
645     aspect.no_reset = FALSE;
646 
647     mainw->framedraw = mainw->framedraw_reset = NULL;
648     mainw->framedraw_spinbutton = NULL;
649 
650     if (mainw->fd_layer) weed_layer_free(mainw->fd_layer);
651     mainw->fd_layer = NULL;
652 
653     if (mainw->fd_layer_orig) weed_layer_free(mainw->fd_layer_orig);
654     mainw->fd_layer_orig = NULL;
655 
656     mainw->framedraw_preview = NULL;
657 
658     if (framedraw.extra_params) lives_free(framedraw.extra_params);
659     framedraw.extra_params = NULL;
660 
661     framedraw.type = LIVES_PARAM_SPECIAL_TYPE_NONE;
662 
663     if (fileread) lives_list_free(fileread);
664     fileread = NULL;
665 
666     if (filewrite) lives_list_free(filewrite);
667     filewrite = NULL;
668 
669     if (passwd_widgets) lives_list_free(passwd_widgets);
670     passwd_widgets = NULL;
671 
672     fchooser.nwidgets = 0;
673 
674     framedraw.added = FALSE;
675     special_inited = FALSE;
676   }
677   return TRUE;
678 }
679 
680 
set_aspect_ratio_widgets(lives_param_t * w,lives_param_t * h)681 LIVES_GLOBAL_INLINE void set_aspect_ratio_widgets(lives_param_t *w, lives_param_t *h) {
682   aspect.width_param = w;
683   aspect.height_param = h;
684 }
685 
686 
setmergealign(void)687 void setmergealign(void) {
688   lives_param_t *param;
689   int cb_frames = clipboard->frames;
690 
691   if (prefs->ins_resample && clipboard->fps != cfile->fps) {
692     cb_frames = count_resampled_frames(clipboard->frames, clipboard->fps, cfile->fps);
693   }
694 
695   if (cfile->end - cfile->start + 1 > (cb_frames * ((merge_opts && merge_opts->spinbutton_loops) ?
696                                        lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(merge_opts->spinbutton_loops)) : 1))
697       && !merge_opts->loop_to_fit) {
698     // set special transalign widgets to their default values
699     if (mergealign.start_param && mergealign.start_param->widgets[0] && LIVES_IS_SPIN_BUTTON
700         (mergealign.start_param->widgets[0]) && (param = mergealign.start_param)->type == LIVES_PARAM_NUM) {
701       if (param->dp) {
702         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), get_double_param(param->def));
703       } else {
704         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)get_int_param(param->def));
705       }
706     }
707     if (mergealign.end_param && mergealign.end_param->widgets[0] && LIVES_IS_SPIN_BUTTON
708         (mergealign.end_param->widgets[0]) && (param = mergealign.end_param)->type == LIVES_PARAM_NUM) {
709       if (param->dp) {
710         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), get_double_param(param->def));
711       } else {
712         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)get_int_param(param->def));
713       }
714     }
715   } else {
716     if (merge_opts->align_start) {
717       // set special transalign widgets to min/max values
718       if (mergealign.start_param && mergealign.start_param->widgets[0] && LIVES_IS_SPIN_BUTTON
719           (mergealign.start_param->widgets[0]) && (param = mergealign.start_param)->type == LIVES_PARAM_NUM) {
720         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)param->min);
721       }
722       if (mergealign.end_param && mergealign.end_param->widgets[0] && LIVES_IS_SPIN_BUTTON
723           (mergealign.end_param->widgets[0]) && (param = mergealign.end_param)->type == LIVES_PARAM_NUM) {
724         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)param->max);
725       }
726     } else {
727       // set special transalign widgets to max/min values
728       if (mergealign.start_param && mergealign.start_param->widgets[0] && LIVES_IS_SPIN_BUTTON
729           (mergealign.start_param->widgets[0]) && (param = mergealign.start_param)->type == LIVES_PARAM_NUM) {
730         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)param->max);
731       }
732       if (mergealign.end_param && mergealign.end_param->widgets[0] && LIVES_IS_SPIN_BUTTON
733           (mergealign.end_param->widgets[0]) && (param = mergealign.end_param)->type == LIVES_PARAM_NUM) {
734         lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)param->min);
735 	// *INDENT-OFF*
736       }}}
737   // *INDENT-OFF*
738 }
739 
740 
mt_framedraw(lives_mt * mt,weed_layer_t * layer)741 LiVESPixbuf *mt_framedraw(lives_mt * mt, weed_layer_t *layer) {
742   LiVESPixbuf *pixbuf = NULL;
743 
744   if (framedraw.added) {
745     switch (framedraw.type) {
746     case LIVES_PARAM_SPECIAL_TYPE_RECT_MULTIRECT:
747       if (mt->track_index == -1) {
748         // TODO - hide widgets
749       } else {
750         //
751       }
752       break;
753 
754     default:
755       break;
756     }
757 
758     // draw on top of layer
759     framedraw_redraw(&framedraw, layer);
760   }
761   return pixbuf;
762 }
763 
764 
is_perchannel_multi(lives_rfx_t * rfx,int i)765 boolean is_perchannel_multi(lives_rfx_t *rfx, int i) {
766   // updated for weed spec 1.1
767   if (rfx->params[i].multi == PVAL_MULTI_PER_CHANNEL) return TRUE;
768   return FALSE;
769 }
770 
771