1 // paramwindow.c
2 // LiVES
3 // (c) G. Finch 2004 - 2018 <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
9 #include "main.h"
10 #include "paramwindow.h"
11 #include "callbacks.h"
12 #include "resample.h"
13 #include "effects.h"
14 #include "rte_window.h"
15 #include "framedraw.h"
16 #include "ce_thumbs.h"
17 #include "interface.h"
18
19 #ifdef ENABLE_GIW
20 #include "giw/giwknob.h"
21 #endif
22
23 static int ireinit = 0;
24
25 extern boolean do_effect(lives_rfx_t *, boolean is_preview); //effects.c in LiVES
26 extern void on_realfx_activate(LiVESMenuItem *, livespointer rfx); // effects.c in LiVES
27
28 static void after_param_text_buffer_changed(LiVESTextBuffer *textbuffer, lives_rfx_t *rfx);
29
30 // TODO -
31 // use list of these in case we have multiple windows open
32 // right now this is single threaded because of this
33 static LiVESSList *usrgrp_to_livesgrp[2] = {NULL, NULL}; // ordered list of lives_widget_group_t
34
do_onchange_init(lives_rfx_t * rfx)35 LiVESList *do_onchange_init(lives_rfx_t *rfx) {
36 LiVESList *onchange = NULL;
37 LiVESList *retvals = NULL;
38 char **array;
39 char *type;
40
41 register int i;
42
43 if (rfx->status == RFX_STATUS_WEED) return NULL;
44
45 switch (rfx->status) {
46 case RFX_STATUS_SCRAP:
47 type = lives_strdup(PLUGIN_RFX_SCRAP);
48 break;
49 case RFX_STATUS_BUILTIN:
50 type = lives_strdup(PLUGIN_RENDERED_EFFECTS_BUILTIN);
51 break;
52 case RFX_STATUS_CUSTOM:
53 type = lives_strdup(PLUGIN_RENDERED_EFFECTS_CUSTOM);
54 break;
55 default:
56 type = lives_strdup_printf(PLUGIN_RENDERED_EFFECTS_TEST);
57 break;
58 }
59 if ((onchange = plugin_request_by_line(type, rfx->name, "get_onchange")) != NULL) {
60 for (i = 0; i < lives_list_length(onchange); i++) {
61 array = lives_strsplit((char *)lives_list_nth_data(onchange, i), rfx->delim, -1);
62 if (!strcmp(array[0], "init")) {
63 // onchange is init
64 // create dummy object with data
65 LiVESWidget *dummy_widget = lives_label_new(NULL);
66 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(dummy_widget), PARAM_NUMBER_KEY,
67 LIVES_INT_TO_POINTER(-1));
68 retvals = do_onchange(LIVES_WIDGET_OBJECT(dummy_widget), rfx);
69 lives_widget_destroy(dummy_widget);
70 lives_strfreev(array);
71 break;
72 }
73 lives_strfreev(array);
74 }
75 lives_list_free_all(&onchange);
76 }
77 lives_free(type);
78
79 return retvals;
80 }
81
82
on_paramwindow_button_clicked2(LiVESButton * button,lives_rfx_t * rfx)83 static void on_paramwindow_button_clicked2(LiVESButton *button, lives_rfx_t *rfx) {
84 // close from rte window
85 on_paramwindow_button_clicked(button, rfx);
86 lives_freep((void **)&fx_dialog[1]);
87 }
88
89
on_paramwindow_button_clicked(LiVESButton * button,lives_rfx_t * rfx)90 void on_paramwindow_button_clicked(LiVESButton *button, lives_rfx_t *rfx) {
91 LiVESWidget *dialog = NULL;
92 boolean def_ok = FALSE;
93 int i;
94
95 if (button) {
96 lives_widget_set_sensitive(LIVES_WIDGET(button), FALSE);
97 dialog = lives_widget_get_toplevel(LIVES_WIDGET(button));
98 }
99
100 if (dialog && LIVES_IS_DIALOG(dialog)) {
101 if (lives_dialog_get_response_for_widget(LIVES_DIALOG(dialog), LIVES_WIDGET(button)) == LIVES_RESPONSE_OK) {
102 def_ok = TRUE;
103 }
104 }
105
106 if (mainw->textwidget_focus && LIVES_IS_WIDGET_OBJECT(mainw->textwidget_focus)) {
107 // make sure text widgets are updated if they activate the default
108 LiVESWidget *textwidget =
109 (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(mainw->textwidget_focus), TEXTWIDGET_KEY);
110 after_param_text_changed(textwidget, rfx);
111 }
112
113 if (!special_cleanup(def_ok)) {
114 lives_dialog_response(LIVES_DIALOG(lives_widget_get_toplevel(LIVES_WIDGET(button))), LIVES_RESPONSE_RETRY);
115 if (button) lives_widget_set_sensitive(LIVES_WIDGET(button), TRUE);
116 return;
117 }
118
119 mainw->textwidget_focus = NULL;
120
121 if (def_ok && rfx && rfx->status != RFX_STATUS_SCRAP) mainw->keep_pre = mainw->did_rfx_preview;
122
123 mainw->block_param_updates = TRUE;
124
125 if (mainw->did_rfx_preview) {
126 if (def_ok) {
127 for (i = 0; i < rfx->num_params; i++) {
128 if (rfx->params[i].changed) {
129 mainw->keep_pre = FALSE;
130 break;
131 }
132 }
133 }
134
135 if (!mainw->keep_pre) {
136 lives_kill_subprocesses(cfile->handle, TRUE);
137
138 if (cfile->start == 0) {
139 cfile->start = 1;
140 cfile->end = cfile->frames;
141 }
142
143 do_rfx_cleanup(rfx);
144 mainw->did_rfx_preview = FALSE;
145 }
146 mainw->show_procd = TRUE;
147 }
148
149 if (!def_ok) {
150 if (rfx && mainw->is_generating && rfx->source_type == LIVES_RFX_SOURCE_NEWCLIP &&
151 CURRENT_CLIP_IS_NORMAL && rfx->source == cfile &&
152 rfx->name && rfx->status != RFX_STATUS_WEED && rfx->status != RFX_STATUS_SCRAP &&
153 rfx->num_in_channels == 0 && rfx->min_frames >= 0 && !rfx->is_template) {
154 // for a generator, we silently close the (now) temporary file we would have generated frames into
155 mainw->suppress_dprint = TRUE;
156 close_current_file(mainw->pre_src_file);
157 mainw->suppress_dprint = FALSE;
158 if (mainw->multitrack) mainw->pre_src_file = -1;
159 mainw->is_generating = FALSE;
160 rfx->source = NULL;
161 rfx->source_type = LIVES_RFX_SOURCE_RFX;
162 }
163 mainw->keep_pre = FALSE;
164 }
165
166 if (!rfx) {
167 if (usrgrp_to_livesgrp[1]) lives_slist_free(usrgrp_to_livesgrp[1]);
168 usrgrp_to_livesgrp[1] = NULL;
169 } else {
170 if (rfx->status == RFX_STATUS_WEED) {
171 if (usrgrp_to_livesgrp[1]) lives_slist_free(usrgrp_to_livesgrp[1]);
172 usrgrp_to_livesgrp[1] = NULL;
173 if (rfx != mainw->fx_candidates[FX_CANDIDATE_RESIZER].rfx) {
174 rfx_free(rfx);
175 lives_free(rfx);
176 }
177 } else {
178 if (usrgrp_to_livesgrp[0]) lives_slist_free(usrgrp_to_livesgrp[0]);
179 usrgrp_to_livesgrp[0] = NULL;
180 }
181 }
182
183 mainw->block_param_updates = FALSE;
184
185 if (def_ok && rfx && rfx->status == RFX_STATUS_SCRAP) return;
186
187 if (button)
188 if (dialog) {
189 // prevent a gtk+ crash by removing the focus before detroying the dialog
190 LiVESWidget *content_area = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
191 lives_container_set_focus_child(LIVES_CONTAINER(content_area), NULL);
192 }
193
194 lives_general_button_clicked(button, NULL);
195
196 if (def_ok) {
197 if (rfx->status == RFX_STATUS_WEED) on_realfx_activate(NULL, rfx);
198 else on_render_fx_activate(NULL, rfx);
199 }
200
201 if (mainw->multitrack) {
202 polymorph(mainw->multitrack, POLY_NONE);
203 polymorph(mainw->multitrack, POLY_CLIPS);
204 mt_sensitise(mainw->multitrack);
205 }
206 }
207
208
209 /**
210 get a (radiobutton) list from an index
211 */
get_group(lives_rfx_t * rfx,lives_param_t * param)212 static lives_widget_group_t *get_group(lives_rfx_t *rfx, lives_param_t *param) {
213 if (rfx->status == RFX_STATUS_WEED) {
214 return livesgrp_from_usrgrp(usrgrp_to_livesgrp[1], param->group);
215 } else {
216 return livesgrp_from_usrgrp(usrgrp_to_livesgrp[0], param->group);
217 }
218 return NULL;
219 }
220
221
on_render_fx_activate(LiVESMenuItem * menuitem,lives_rfx_t * rfx)222 void on_render_fx_activate(LiVESMenuItem *menuitem, lives_rfx_t *rfx) {
223 uint32_t chk_mask = 0;
224
225 if (menuitem && rfx->num_in_channels > 0) {
226 chk_mask = WARN_MASK_LAYOUT_ALTER_FRAMES;
227 if (!check_for_layout_errors(NULL, mainw->current_file, cfile->start, cfile->end, &chk_mask)) {
228 return;
229 }
230 }
231
232 // do onchange|init
233 if (menuitem) {
234 LiVESList *retvals = do_onchange_init(rfx);
235 lives_list_free_all(&retvals);
236 }
237 if (rfx->min_frames > -1) {
238 do_effect(rfx, FALSE);
239 }
240
241 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
242 }
243
244
gen_width_changed(LiVESSpinButton * spin,livespointer user_data)245 static void gen_width_changed(LiVESSpinButton *spin, livespointer user_data) {
246 weed_plant_t *ctmpl = (weed_plant_t *)user_data;
247 int val = lives_spin_button_get_value_as_int(spin);
248 int error, old_val = 0;
249 int step;
250 // value in chantmp in pixels, not macropixels
251 if (weed_plant_has_leaf(ctmpl, WEED_LEAF_HOST_WIDTH)) old_val = weed_get_int_value(ctmpl, WEED_LEAF_HOST_WIDTH, &error);
252 if (val == old_val) return;
253 step = 1;
254 if (weed_plant_has_leaf(ctmpl, WEED_LEAF_HSTEP)) step = weed_get_int_value(ctmpl, WEED_LEAF_HSTEP, &error);
255
256 val = ALIGN_CEIL(val, step);
257 weed_set_int_value(ctmpl, WEED_LEAF_HOST_WIDTH, val);
258 lives_spin_button_set_value(spin, (double)val);
259 }
260
261
gen_height_changed(LiVESSpinButton * spin,livespointer user_data)262 static void gen_height_changed(LiVESSpinButton *spin, livespointer user_data) {
263 weed_plant_t *ctmpl = (weed_plant_t *)user_data;
264 int val = lives_spin_button_get_value_as_int(spin);
265 int error, old_val = 0;
266 int step;
267
268 if (weed_plant_has_leaf(ctmpl, WEED_LEAF_HOST_HEIGHT)) old_val = weed_get_int_value(ctmpl, WEED_LEAF_HOST_HEIGHT, &error);
269
270 if (val == old_val) return;
271 step = 1;
272 if (weed_plant_has_leaf(ctmpl, WEED_LEAF_HSTEP)) step = weed_get_int_value(ctmpl, WEED_LEAF_HSTEP, &error);
273
274 val = ALIGN_CEIL(val, step);
275 weed_set_int_value(ctmpl, WEED_LEAF_HOST_HEIGHT, val);
276 lives_spin_button_set_value(spin, (double)val);
277 }
278
279
gen_fps_changed(LiVESSpinButton * spin,livespointer user_data)280 static void gen_fps_changed(LiVESSpinButton *spin, livespointer user_data) {
281 weed_plant_t *filter = (weed_plant_t *)user_data;
282 double val = lives_spin_button_get_value(spin);
283 weed_set_double_value(filter, WEED_LEAF_HOST_FPS, val);
284 }
285
286
trans_in_out_pressed(lives_rfx_t * rfx,boolean in)287 static void trans_in_out_pressed(lives_rfx_t *rfx, boolean in) {
288 weed_plant_t **in_params;
289
290 weed_plant_t *inst = (weed_plant_t *)rfx->source;
291 weed_plant_t *filter = weed_instance_get_filter(inst, TRUE);
292 weed_plant_t *tparam;
293 weed_plant_t *tparamtmpl;
294
295 int key = -1;
296 int ptype, nparams;
297 int trans = get_transition_param(filter, FALSE);
298
299 do {
300 // handle compound fx
301 if (weed_plant_has_leaf(inst, WEED_LEAF_IN_PARAMETERS)) {
302 nparams = weed_leaf_num_elements(inst, WEED_LEAF_IN_PARAMETERS);
303 if (trans < nparams) break;
304 trans -= nparams;
305 }
306 } while (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE) &&
307 (inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL)) != NULL);
308
309 in_params = weed_instance_get_in_params(inst, NULL);
310 tparam = in_params[trans];
311 tparamtmpl = weed_param_get_template(tparam);
312 ptype = weed_paramtmpl_get_type(tparamtmpl);
313
314 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
315 if (!filter_mutex_trylock(key)) {
316 if (ptype == WEED_PARAM_INTEGER) {
317 if (in) weed_set_int_value(tparam, WEED_LEAF_VALUE, weed_get_int_value(tparamtmpl, WEED_LEAF_MIN, NULL));
318 else weed_set_int_value(tparam, WEED_LEAF_VALUE, weed_get_int_value(tparamtmpl, WEED_LEAF_MAX, NULL));
319 } else {
320 if (in) weed_set_double_value(tparam, WEED_LEAF_VALUE, weed_get_double_value(tparamtmpl, WEED_LEAF_MIN, NULL));
321 else weed_set_double_value(tparam, WEED_LEAF_VALUE, weed_get_double_value(tparamtmpl, WEED_LEAF_MAX, NULL));
322 }
323 filter_mutex_unlock(key);
324 set_copy_to(inst, trans, rfx, TRUE);
325 }
326
327 update_visual_params(rfx, FALSE);
328 lives_free(in_params);
329 activate_mt_preview(mainw->multitrack);
330 }
331
332
transition_in_pressed(LiVESToggleButton * tbut,livespointer rfx)333 static void transition_in_pressed(LiVESToggleButton *tbut, livespointer rfx) {
334 trans_in_out_pressed((lives_rfx_t *)rfx, TRUE);
335 }
336
337
transition_out_pressed(LiVESToggleButton * tbut,livespointer rfx)338 static void transition_out_pressed(LiVESToggleButton *tbut, livespointer rfx) {
339 trans_in_out_pressed((lives_rfx_t *)rfx, FALSE);
340 }
341
342
after_transaudio_toggled(LiVESToggleButton * togglebutton,livespointer rfx)343 static void after_transaudio_toggled(LiVESToggleButton *togglebutton, livespointer rfx) {
344 weed_plant_t *init_event = mainw->multitrack->init_event;
345
346 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(togglebutton)))
347 weed_set_boolean_value(init_event, WEED_LEAF_HOST_AUDIO_TRANSITION, WEED_TRUE);
348 else weed_set_boolean_value(init_event, WEED_LEAF_HOST_AUDIO_TRANSITION, WEED_FALSE);
349 }
350
351
transition_add_in_out(LiVESBox * vbox,lives_rfx_t * rfx,boolean add_audio_check)352 void transition_add_in_out(LiVESBox *vbox, lives_rfx_t *rfx, boolean add_audio_check) {
353 // add in/out radios for multitrack transitions
354 LiVESWidget *radiobutton_in;
355 LiVESWidget *radiobutton_out;
356 LiVESWidget *radiobutton_dummy;
357 LiVESWidget *hbox, *hbox2;
358 LiVESWidget *hseparator;
359
360 LiVESSList *radiobutton_group = NULL;
361
362 weed_plant_t *filter = weed_instance_get_filter((weed_plant_t *)rfx->source, TRUE);
363 int trans = get_transition_param(filter, FALSE);
364
365 char *tmp, *tmp2;
366
367 hbox = lives_hbox_new(FALSE, 0);
368 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_width);
369
370 if (add_audio_check) {
371 int error;
372
373 LiVESWidget *checkbutton;
374
375 hbox2 = lives_hbox_new(FALSE, 0);
376
377 if (has_video_chans_in(filter, FALSE))
378 lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, FALSE, widget_opts.packing_width);
379
380 checkbutton = lives_standard_check_button_new((tmp = (_("_Crossfade audio"))),
381 weed_plant_has_leaf(mainw->multitrack->init_event, WEED_LEAF_HOST_AUDIO_TRANSITION) &&
382 weed_get_boolean_value(mainw->multitrack->init_event, WEED_LEAF_HOST_AUDIO_TRANSITION, &error) == WEED_TRUE,
383 LIVES_BOX(hbox2), (tmp2 = lives_strdup(
384 _("If checked, audio from both layers is mixed relative to the transition parameter.\n"
385 "The setting is applied instantly to the entire transition."))));
386
387 lives_free(tmp);
388 lives_free(tmp2);
389
390 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
391 LIVES_GUI_CALLBACK(after_transaudio_toggled),
392 (livespointer)rfx);
393
394 after_transaudio_toggled(LIVES_TOGGLE_BUTTON(checkbutton), (livespointer)rfx);
395 }
396
397 // dummy radiobutton so we can have neither in nor out set
398 radiobutton_dummy = lives_standard_radio_button_new(NULL, &radiobutton_group, LIVES_BOX(hbox), NULL);
399 lives_widget_set_no_show_all(radiobutton_dummy, TRUE);
400
401 widget_opts.pack_end = TRUE;
402 radiobutton_out = lives_standard_radio_button_new((tmp = (_("Transition _Out"))),
403 &radiobutton_group, LIVES_BOX(hbox),
404 (tmp2 = (_("Click to set the transition parameter to show only the rear frame"))));
405
406 lives_free(tmp);
407 lives_free(tmp2);
408
409 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(radiobutton_out), LIVES_WIDGET_TOGGLED_SIGNAL,
410 LIVES_GUI_CALLBACK(transition_out_pressed),
411 (livespointer)rfx);
412
413 radiobutton_in = lives_standard_radio_button_new((tmp = (_("Transition _In"))),
414 &radiobutton_group, LIVES_BOX(hbox),
415 (tmp2 = (_("Click to set the transition parameter to show only the front frame"))));
416 lives_free(tmp); lives_free(tmp2);
417
418 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(radiobutton_in), LIVES_WIDGET_TOGGLED_SIGNAL,
419 LIVES_GUI_CALLBACK(transition_in_pressed), (livespointer)rfx);
420
421 widget_opts.pack_end = FALSE;
422
423 if (palette->style & STYLE_1) {
424 lives_widget_set_fg_color(hbox, LIVES_WIDGET_STATE_NORMAL, &palette->normal_fore);
425 }
426
427 hseparator = lives_hseparator_new();
428 lives_box_pack_start(vbox, hseparator, FALSE, FALSE, 0);
429
430 rfx->params[trans].widgets[WIDGET_RB_IN] = radiobutton_in;
431 rfx->params[trans].widgets[WIDGET_RB_OUT] = radiobutton_out;
432 rfx->params[trans].widgets[WIDGET_RB_DUMMY] = radiobutton_dummy;
433 }
434
435
add_sizes(LiVESBox * vbox,boolean add_fps,boolean has_param,lives_rfx_t * rfx)436 static boolean add_sizes(LiVESBox *vbox, boolean add_fps, boolean has_param, lives_rfx_t *rfx) {
437 // add size settings for generators and resize effects
438 LiVESWidget *label, *hbox;
439 LiVESWidget *spinbuttonh = NULL, *spinbuttonw = NULL;
440 LiVESWidget *spinbuttonf;
441 int num_chans = 0;
442
443 weed_plant_t *filter = weed_instance_get_filter((weed_plant_t *)rfx->source, TRUE), *tmpl;
444 weed_plant_t **ctmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_chans);
445
446 double def_fps = 0.;
447
448 char *cname, *ltxt;
449
450 boolean chk_params = (vbox == NULL);
451 boolean added = FALSE;
452
453 int def_width = 0, max_width, width_step;
454 int def_height = 0, max_height, height_step;
455 int wopw = widget_opts.packing_width;
456
457 register int i;
458
459 if (chk_params) {
460 if (add_fps) return TRUE;
461 } else {
462 if (!has_param) lives_widget_set_size_request(LIVES_WIDGET(vbox), RFX_WINSIZE_H, RFX_WINSIZE_V);
463
464 if (add_fps) {
465 added = TRUE;
466
467 hbox = lives_hbox_new(FALSE, 0);
468 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height * 2);
469
470 add_fill_to_box(LIVES_BOX(hbox));
471
472 if (weed_plant_has_leaf(filter, WEED_LEAF_HOST_FPS)) def_fps = weed_get_double_value(filter, WEED_LEAF_HOST_FPS, NULL);
473 else if (weed_plant_has_leaf(filter, WEED_LEAF_PREFERRED_FPS))
474 def_fps = weed_get_double_value(filter, WEED_LEAF_PREFERRED_FPS, NULL);
475
476 if (def_fps == 0.) def_fps = prefs->default_fps;
477
478 spinbuttonf = lives_standard_spin_button_new(_("Target _FPS (plugin may override this)"),
479 def_fps, 1., FPS_MAX, 1., 10., 3, LIVES_BOX(hbox), NULL);
480
481 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbuttonf), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
482 LIVES_GUI_CALLBACK(gen_fps_changed), filter);
483
484 add_fill_to_box(LIVES_BOX(hbox));
485 }
486 }
487
488 for (i = 0; i < num_chans; i++) {
489 tmpl = ctmpls[i];
490
491 // TODO ***: allow alteration of "host_disabled" under some circumstances
492 // (e.g. allow enabling a first or second in channel, or first out_channel, or more for alphas)
493
494 // make this into function called from here and from effects with optional enable-able channels
495 if (weed_get_boolean_value(tmpl, WEED_LEAF_HOST_DISABLED, NULL) == WEED_TRUE) continue;
496 if (weed_get_int_value(tmpl, WEED_LEAF_WIDTH, NULL)) continue;
497 if (weed_get_int_value(tmpl, WEED_LEAF_HEIGHT, NULL)) continue;
498
499 if (chk_params) return TRUE;
500
501 added = TRUE;
502
503 if (rfx->is_template) {
504 cname = weed_get_string_value(tmpl, WEED_LEAF_NAME, NULL);
505 ltxt = lives_strdup_printf(_("%s : size"), cname);
506 lives_free(cname);
507 } else {
508 ltxt = (_("New size (pixels)"));
509 }
510
511 label = lives_standard_label_new(ltxt);
512 lives_free(ltxt);
513
514 hbox = lives_hbox_new(FALSE, 0);
515 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
516 lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
517
518 def_width = weed_get_int_value(tmpl, WEED_LEAF_HOST_WIDTH, NULL);
519 if (!def_width) def_width = DEF_GEN_WIDTH;
520 max_width = weed_get_int_value(tmpl, WEED_LEAF_MAXWIDTH, NULL);
521 if (!max_width) max_width = INT_MAX;
522 if (def_width > max_width) def_width = max_width;
523 width_step = weed_get_int_value(tmpl, WEED_LEAF_HSTEP, NULL);
524 if (!width_step) width_step = 4;
525
526 spinbuttonw = lives_standard_spin_button_new(_("_Width"), def_width, width_step, max_width, width_step,
527 width_step, 0, LIVES_BOX(hbox), NULL);
528 lives_spin_button_set_snap_to_multiples(LIVES_SPIN_BUTTON(spinbuttonw), width_step);
529 lives_spin_button_update(LIVES_SPIN_BUTTON(spinbuttonw));
530
531 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbuttonw), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
532 LIVES_GUI_CALLBACK(gen_width_changed), tmpl);
533 weed_leaf_delete(tmpl, WEED_LEAF_HOST_WIDTH); // force a reset
534 gen_width_changed(LIVES_SPIN_BUTTON(spinbuttonw), tmpl);
535
536 widget_opts.packing_width >>= 1;
537 add_fill_to_box(LIVES_BOX(hbox));
538 widget_opts.packing_width = wopw;
539
540 def_height = weed_get_int_value(tmpl, WEED_LEAF_HOST_HEIGHT, NULL);
541 if (!def_height) def_height = DEF_GEN_HEIGHT;
542 max_height = weed_get_int_value(tmpl, WEED_LEAF_MAXHEIGHT, NULL);
543 if (!max_height) max_height = INT_MAX;
544 if (def_height > max_height) def_height = max_height;
545 height_step = weed_get_int_value(tmpl, WEED_LEAF_VSTEP, NULL);
546 if (!height_step) height_step = 4;
547
548 spinbuttonh = lives_standard_spin_button_new(_("_Height"), def_height, height_step, max_height, height_step,
549 height_step, 0, LIVES_BOX(hbox), NULL);
550 lives_spin_button_set_snap_to_multiples(LIVES_SPIN_BUTTON(spinbuttonh), height_step);
551 lives_spin_button_update(LIVES_SPIN_BUTTON(spinbuttonh));
552
553 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbuttonh), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
554 LIVES_GUI_CALLBACK(gen_height_changed), tmpl);
555 weed_leaf_delete(tmpl, WEED_LEAF_HOST_HEIGHT); // force a reset
556 gen_height_changed(LIVES_SPIN_BUTTON(spinbuttonh), tmpl);
557 }
558
559 if (!rfx->is_template && num_chans == 1) {
560 if (chk_params) return TRUE;
561 added = TRUE;
562 // add "aspectratio" widget
563 add_aspect_ratio_button(LIVES_SPIN_BUTTON(spinbuttonw), LIVES_SPIN_BUTTON(spinbuttonh), LIVES_BOX(vbox));
564 }
565
566 if (added) {
567 if (has_param) {
568 add_fill_to_box(LIVES_BOX(vbox));
569 add_hsep_to_box(vbox);
570 } else has_param = TRUE;
571 }
572 return has_param;
573 }
574
575
add_gen_to(LiVESBox * vbox,lives_rfx_t * rfx)576 static void add_gen_to(LiVESBox *vbox, lives_rfx_t *rfx) {
577 // add "generate to clipboard/new clip" for rendered generators
578 LiVESSList *radiobutton_group = NULL;
579
580 LiVESWidget *radiobutton;
581 LiVESWidget *hseparator;
582
583 LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
584
585 char *tmp, *tmp2;
586
587 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
588
589 radiobutton = lives_standard_radio_button_new((tmp = (_("Generate to _Clipboard"))),
590 &radiobutton_group, LIVES_BOX(hbox),
591 (tmp2 = (_("Generate frames to the clipboard"))));
592
593 lives_free(tmp);
594 lives_free(tmp2);
595
596 widget_opts.pack_end = TRUE;
597 radiobutton = lives_standard_radio_button_new((tmp = (_("Generate to _New Clip"))),
598 &radiobutton_group, LIVES_BOX(hbox),
599 (tmp2 = (_("Generate frames to a new clip"))));
600 widget_opts.pack_end = FALSE;
601
602 lives_free(tmp);
603 lives_free(tmp2);
604
605 hseparator = lives_hseparator_new();
606 lives_box_pack_start(vbox, hseparator, FALSE, FALSE, 0);
607
608 toggle_toggles_var(LIVES_TOGGLE_BUTTON(radiobutton), &mainw->gen_to_clipboard, TRUE);
609 }
610
611
xspinw_changed(LiVESSpinButton * spinbutton,livespointer user_data)612 static void xspinw_changed(LiVESSpinButton *spinbutton, livespointer user_data) {
613 cfile->ohsize = cfile->hsize = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
614 reset_framedraw_preview();
615 }
616
xspinh_changed(LiVESSpinButton * spinbutton,livespointer user_data)617 static void xspinh_changed(LiVESSpinButton *spinbutton, livespointer user_data) {
618 cfile->ovsize = cfile->vsize = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
619 reset_framedraw_preview();
620 }
621
xspinfr_changed(LiVESSpinButton * spinbutton,livespointer user_data)622 static void xspinfr_changed(LiVESSpinButton *spinbutton, livespointer user_data) {
623 cfile->end = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
624 }
625
xspinfps_changed(LiVESSpinButton * spinbutton,livespointer user_data)626 static void xspinfps_changed(LiVESSpinButton *spinbutton, livespointer user_data) {
627 cfile->pb_fps = cfile->fps = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
628 reset_framedraw_preview();
629 }
630
add_genparams(LiVESWidget * vbox,lives_rfx_t * rfx)631 static void add_genparams(LiVESWidget *vbox, lives_rfx_t *rfx) {
632 // add nframes, fps, width, heights
633 LiVESWidget *sp_width, *sp_height, *sp_frames, *sp_fps;
634 LiVESWidget *frame = add_video_options(&sp_width, cfile->hsize, &sp_height, cfile->vsize, &sp_fps, cfile->fps,
635 &sp_frames, cfile->end, TRUE, NULL);
636 lives_box_pack_start(LIVES_BOX(vbox), frame, FALSE, TRUE, 0);
637
638 lives_spin_button_update(LIVES_SPIN_BUTTON(sp_width));
639 lives_spin_button_update(LIVES_SPIN_BUTTON(sp_height));
640 if (sp_frames) lives_spin_button_update(LIVES_SPIN_BUTTON(sp_frames));
641 lives_spin_button_update(LIVES_SPIN_BUTTON(sp_fps));
642 cfile->ohsize = cfile->hsize = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_width));
643 cfile->ovsize = cfile->vsize = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(sp_height));
644
645 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(sp_width), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
646 LIVES_GUI_CALLBACK(xspinw_changed), NULL);
647 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(sp_height), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
648 LIVES_GUI_CALLBACK(xspinh_changed), NULL);
649 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(sp_frames), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
650 LIVES_GUI_CALLBACK(xspinfr_changed), NULL);
651 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(sp_fps), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
652 LIVES_GUI_CALLBACK(xspinfps_changed), NULL);
653 }
654
655
on_render_fx_pre_activate(LiVESMenuItem * menuitem,lives_rfx_t * rfx)656 LIVES_GLOBAL_INLINE void on_render_fx_pre_activate(LiVESMenuItem *menuitem, lives_rfx_t *rfx) {
657 _fx_dialog *fxdialog;
658 uint32_t chk_mask;
659 int start, end;
660
661 if (!check_storage_space(mainw->current_file, FALSE)) return;
662 if ((rfx->props & RFX_PROPS_MAY_RESIZE && rfx->num_in_channels == 1) || rfx->min_frames < 0) {
663 start = 1;
664 end = 0;
665 } else {
666 start = cfile->start;
667 end = cfile->end;
668 }
669
670 if (rfx->num_in_channels > 0) {
671 chk_mask = WARN_MASK_LAYOUT_ALTER_FRAMES;
672 if (!check_for_layout_errors(NULL, mainw->current_file, start, end, &chk_mask)) {
673 return;
674 }
675 }
676 fxdialog = on_fx_pre_activate(rfx, FALSE, NULL);
677 if (fxdialog) {
678 if (menuitem == LIVES_MENU_ITEM(mainw->resize_menuitem)) add_resnn_label(LIVES_DIALOG(fxdialog->dialog));
679 /* do { */
680 /* resp = lives_dialog_run(LIVES_DIALOG(fxdialog->dialog)); */
681 /* } while (resp == LIVES_RESPONSE_RETRY); */
682 }
683
684 }
685
686
on_fx_pre_activate(lives_rfx_t * rfx,boolean is_realtime,LiVESWidget * pbox)687 _fx_dialog *on_fx_pre_activate(lives_rfx_t *rfx, boolean is_realtime, LiVESWidget *pbox) {
688 // render a pre dialog for: rendered effects (fx_dialog[0]), or rte(fx_dialog[1]), or encoder plugin, or vpp (fx_dialog[1])
689 LiVESWidget *top_dialog_vbox = NULL;
690 LiVESAccelGroup *fxw_accel_group;
691 LiVESList *retvals = NULL;
692
693 char *txt;
694
695 boolean no_process = FALSE;
696 boolean is_defaults = FALSE;
697 boolean add_reset_ok = FALSE;
698 boolean has_param;
699
700 int scrw, didx = 0;
701
702 if (mainw->multitrack) {
703 if (mainw->multitrack->idlefunc > 0) {
704 lives_source_remove(mainw->multitrack->idlefunc);
705 mainw->multitrack->idlefunc = 0;
706 }
707 mt_desensitise(mainw->multitrack);
708 }
709
710 if (is_realtime) {
711 didx = 1;
712 no_process = TRUE;
713 } else if (rfx->status != RFX_STATUS_WEED) {
714 retvals = do_onchange_init(rfx);
715 }
716 if (rfx->min_frames < 0) no_process = TRUE;
717
718 if (!no_process && rfx->num_in_channels == 0) {
719 int new_file;
720 mainw->pre_src_file = mainw->current_file;
721
722 // create a new file to generate frames into
723 if (!get_new_handle((new_file = mainw->first_free_file), NULL)) {
724 if (mainw->multitrack) {
725 mt_sensitise(mainw->multitrack);
726 mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
727 }
728
729 lives_list_free_all(&retvals);
730
731 return NULL;
732 }
733
734 if (CURRENT_CLIP_IS_NORMAL) {
735 mainw->files[new_file]->hsize = cfile->hsize;
736 mainw->files[new_file]->vsize = cfile->vsize;
737 mainw->files[new_file]->fps = cfile->fps;
738 } else {
739 mainw->files[new_file]->hsize = DEF_GEN_WIDTH;
740 mainw->files[new_file]->vsize = DEF_GEN_HEIGHT;
741 mainw->files[new_file]->fps = DEF_FPS;
742 }
743
744 mainw->is_generating = TRUE;
745 mainw->current_file = new_file;
746 rfx->source_type = LIVES_RFX_SOURCE_NEWCLIP;
747 rfx->source = cfile;
748
749 cfile->ohsize = cfile->hsize;
750 cfile->ovsize = cfile->vsize;
751 cfile->pb_fps = cfile->fps;
752
753 // dummy values
754 cfile->start = 1;
755 cfile->end = 100;
756 }
757
758 if (!no_process && rfx->num_in_channels > 0) {
759 // check we have a real clip open
760 if (!CURRENT_CLIP_IS_VALID) {
761 lives_list_free_all(&retvals);
762 return NULL;
763 }
764 if (cfile->end - cfile->start + 1 < rfx->min_frames) {
765 lives_list_free_all(&retvals);
766 txt = lives_strdup_printf(_("\nYou must select at least %d frames to use this effect.\n\n"),
767 rfx->min_frames);
768 do_error_dialog(txt);
769 lives_free(txt);
770 return NULL;
771 }
772
773 // here we invalidate cfile->ohsize, cfile->ovsize
774 cfile->ohsize = cfile->hsize;
775 cfile->ovsize = cfile->vsize;
776
777 if (cfile->undo_action == UNDO_RESIZABLE) {
778 set_undoable(NULL, FALSE);
779 }
780 }
781
782 if (rfx->status == RFX_STATUS_WEED && rfx->is_template) is_defaults = TRUE;
783
784 if (!pbox) {
785 char *title, *defstr;
786
787 // width works well with scale 0.7
788 if (rfx->status == RFX_STATUS_WEED || no_process || (rfx->num_in_channels == 0 &&
789 rfx->props & RFX_PROPS_BATCHG)) scrw = RFX_WINSIZE_H * 2. * widget_opts.scale;
790 else scrw = GUI_SCREEN_WIDTH - SCR_WIDTH_SAFETY;
791
792 fx_dialog[didx] = (_fx_dialog *)lives_malloc(sizeof(_fx_dialog));
793 fx_dialog[didx]->okbutton = fx_dialog[didx]->cancelbutton = fx_dialog[didx]->resetbutton = NULL;
794 fx_dialog[didx]->rfx = NULL;
795 fx_dialog[didx]->key = fx_dialog[didx]->mode = -1;
796 if (is_defaults) defstr = (_("Defaults for "));
797 else defstr = lives_strdup("");
798 title = lives_strdup_printf("%s%s", defstr, _(rfx->menu_text[0] == '_' ? rfx->menu_text + 1 : rfx->menu_text));
799
800 fx_dialog[didx]->dialog = lives_standard_dialog_new(title, FALSE, scrw, RFX_WINSIZE_V);
801 lives_free(defstr);
802 lives_free(title);
803 pbox = top_dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(fx_dialog[didx]->dialog));
804 fx_dialog[didx]->rfx = rfx;
805 lives_widget_set_hexpand(pbox, TRUE);
806 }
807
808 if (rfx->status != RFX_STATUS_WEED && !no_process) {
809 // rendered fx preview
810
811 LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
812 lives_box_pack_start(LIVES_BOX(top_dialog_vbox), hbox, TRUE, TRUE, 0);
813
814 lives_widget_set_hexpand(hbox, TRUE);
815 lives_widget_set_vexpand(hbox, TRUE);
816
817 pbox = lives_vbox_new(FALSE, 0);
818 lives_box_pack_start(LIVES_BOX(hbox), pbox, TRUE, TRUE, 0);
819
820 lives_widget_set_hexpand(pbox, TRUE);
821 lives_widget_set_vexpand(pbox, TRUE);
822
823 // add preview window
824 if (rfx->num_in_channels > 0 || !(rfx->props & RFX_PROPS_BATCHG)) {
825 mainw->framedraw_frame = cfile->start;
826 widget_add_framedraw(LIVES_VBOX(pbox), cfile->start, cfile->end, !(rfx->props & RFX_PROPS_MAY_RESIZE),
827 cfile->hsize, cfile->vsize, rfx);
828 if (rfx->props & RFX_PROPS_MAY_RESIZE) mainw->fd_max_frame = cfile->end;
829 }
830
831 if (!(rfx->props & RFX_PROPS_BATCHG)) {
832 // connect spinbutton to preview
833 fd_connect_spinbutton(rfx);
834 }
835 }
836
837 // add the param widgets; here we also set parameters for any special widgets in the framedraw
838 //main_thread_execute((lives_funcptr_t)make_param_box, WEED_SEED_BOOLEAN, &has_param, "vv", pbox, rfx);
839 has_param = make_param_box(LIVES_VBOX(pbox), rfx);
840
841 // update widgets from onchange_init here
842 if (top_dialog_vbox) {
843 fxw_accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
844 lives_window_add_accel_group(LIVES_WINDOW(fx_dialog[didx]->dialog), fxw_accel_group);
845
846 if (!no_process || is_defaults || rfx->status == RFX_STATUS_SCRAP) {
847 if (!is_defaults) {
848 fx_dialog[didx]->cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(fx_dialog[didx]->dialog),
849 LIVES_STOCK_CANCEL, NULL, LIVES_RESPONSE_CANCEL);
850 fx_dialog[didx]->okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(fx_dialog[didx]->dialog),
851 LIVES_STOCK_OK, NULL, LIVES_RESPONSE_OK);
852 } else add_reset_ok = TRUE;
853 } else {
854 if (rfx->status == RFX_STATUS_WEED) {
855 add_reset_ok = TRUE;
856 }
857 }
858
859 if (add_reset_ok) {
860 fx_dialog[didx]->resetbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(fx_dialog[didx]->dialog),
861 LIVES_STOCK_REVERT_TO_SAVED, _("Reset"), LIVES_RESPONSE_RESET);
862 fx_dialog[didx]->okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(fx_dialog[didx]->dialog), LIVES_STOCK_APPLY,
863 _("Set as default"), LIVES_RESPONSE_OK);
864 if (!has_param) {
865 lives_widget_set_sensitive(fx_dialog[didx]->resetbutton, FALSE);
866 lives_widget_set_sensitive(fx_dialog[didx]->okbutton, FALSE);
867 }
868 }
869
870 if (fx_dialog[didx]->cancelbutton == NULL) {
871 fx_dialog[didx]->cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(fx_dialog[didx]->dialog), LIVES_STOCK_CLOSE,
872 _("_Close Window"), LIVES_RESPONSE_CANCEL);
873 }
874 lives_widget_add_accelerator(fx_dialog[didx]->cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, fxw_accel_group,
875 LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
876
877 if (fx_dialog[didx]->okbutton) {
878 lives_button_grab_default_special(fx_dialog[didx]->okbutton);
879 } else {
880 lives_button_grab_default_special(fx_dialog[didx]->cancelbutton);
881 }
882
883 if (no_process && !is_defaults) {
884 if (!is_realtime) {
885 if (fx_dialog[didx]->okbutton)
886 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
887 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked), rfx);
888 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
889 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked), rfx);
890 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->dialog), LIVES_WIDGET_DELETE_EVENT,
891 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked), rfx);
892 } else {
893 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
894 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked2), rfx);
895 if (rfx->status == RFX_STATUS_SCRAP)
896 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
897 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked2), rfx);
898 else {
899 if (fx_dialog[didx]->okbutton)
900 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
901 LIVES_GUI_CALLBACK(rte_set_key_defs), rfx);
902 if (fx_dialog[didx]->resetbutton) {
903 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(fx_dialog[didx]->resetbutton), LIVES_WIDGET_CLICKED_SIGNAL,
904 LIVES_GUI_CALLBACK(rte_reset_defs_clicked), rfx);
905 }
906 }
907 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->dialog), LIVES_WIDGET_DELETE_EVENT,
908 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked2), rfx);
909 }
910 } else {
911 if (!is_defaults) {
912 if (fx_dialog[didx]->okbutton)
913 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
914 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked), (livespointer)rfx);
915 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
916 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked), (livespointer)rfx);
917 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->dialog), LIVES_WIDGET_DELETE_EVENT,
918 LIVES_GUI_CALLBACK(on_paramwindow_button_clicked), (livespointer)rfx);
919 } else {
920 if (fx_dialog[didx]->okbutton)
921 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(fx_dialog[didx]->okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
922 LIVES_GUI_CALLBACK(rte_set_defs_ok), rfx);
923 if (fx_dialog[didx]->resetbutton) {
924 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(fx_dialog[didx]->resetbutton), LIVES_WIDGET_CLICKED_SIGNAL,
925 LIVES_GUI_CALLBACK(rte_reset_defs_clicked), rfx);
926 }
927 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
928 LIVES_GUI_CALLBACK(rte_set_defs_cancel), rfx);
929 lives_signal_sync_connect(LIVES_GUI_OBJECT(fx_dialog[didx]->dialog), LIVES_WIDGET_DELETE_EVENT,
930 LIVES_GUI_CALLBACK(rte_set_defs_cancel), rfx);
931 }
932 }
933 }
934
935 // tweak some things to do with framedraw preview
936 if (mainw->framedraw) fd_tweak(rfx);
937
938 if (!mainw->ce_thumbs)
939 lives_widget_show_all(fx_dialog[didx]->dialog);
940
941 if (retvals) {
942 // now apply visually anything we got from onchange_init
943 param_demarshall(rfx, retvals, TRUE, TRUE);
944 lives_list_free_all(&retvals);
945 }
946 return fx_dialog[didx];
947 }
948
949
check_hidden_gui(weed_plant_t * inst,lives_param_t * param,int idx)950 static void check_hidden_gui(weed_plant_t *inst, lives_param_t *param, int idx) {
951 weed_plant_t *wparam;
952 if (param->type == LIVES_PARAM_UNDISPLAYABLE || param->type == LIVES_PARAM_UNKNOWN)
953 param->hidden |= HIDDEN_UNDISPLAYABLE;
954 if ((param->reinit & REINIT_FUNCTIONAL)
955 && weed_get_int_value(inst, WEED_LEAF_HOST_REFS, NULL) >= 2) {
956 // effect is running and user is editing the params, we should hide reinit params
957 // so as not to disturb the flow !
958 param->hidden |= HIDDEN_NEEDS_REINIT;
959 } else param->hidden &= ~HIDDEN_NEEDS_REINIT;
960
961 if (is_hidden_param(inst, idx)) param->hidden |= HIDDEN_GUI_PERM;
962
963 wparam = weed_inst_in_param(inst, idx, FALSE, FALSE);
964
965 if (wparam) {
966 if (weed_param_is_hidden(wparam, WEED_FALSE) == WEED_FALSE) {
967 if (weed_param_is_hidden(wparam, WEED_TRUE)) param->hidden |= HIDDEN_GUI_TEMP;
968 else param->hidden &= ~HIDDEN_GUI_TEMP;
969 }
970 }
971 }
972
973
num_in_params_for_nth_instance(weed_plant_t * inst,int idx)974 static int num_in_params_for_nth_instance(weed_plant_t *inst, int idx) {
975 // get number of params for nth instance in a compound effect - gives an offset for param number within the compound
976 while (--idx > 0) inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL);
977 return weed_leaf_num_elements(inst, WEED_LEAF_IN_PARAMETERS);
978 }
979
980
fmt_match(char * fmt_string)981 static boolean fmt_match(char *fmt_string) {
982 const char *myfmt = fmt_string, *xfmt = myfmt + FMT_STRING_SIZE;
983 size_t xlen = lives_strlen(myfmt), ylen;
984
985 // g_print("\nROW\n");
986 if (xlen == 0) {
987 //g_print("HSEP\n");
988 return FALSE;
989 }
990 ylen = lives_strlen(xfmt);
991 if (ylen == 0) {
992 //g_print("2HSEP\n");
993 return FALSE;
994 }
995
996 if (xlen < ylen) ylen = xlen;
997
998 for (int j = 0; j < ylen; j++) {
999 //g_print(" CF %d %d", myfmt[j], xfmt[j]);
1000 if (xfmt[j] != -1 && myfmt[j] != -1 && xfmt[j] != myfmt[j]) return FALSE;
1001 if ((xfmt[j] == -2 || myfmt[j] == -2) && xfmt[j] != myfmt[j]) return FALSE;
1002 }
1003
1004 //g_print("\nMATch\n");
1005 return TRUE;
1006 }
1007
1008
1009 /**
1010 @brief make a dynamic parameter window
1011
1012 if top_vbox is NULL: we just check for displayable params, returning FALSE there are none to be shown.
1013 otherwise, adds widgets to top_vbox, returning FALSE if nothing was added
1014 */
make_param_box(LiVESVBox * top_vbox,lives_rfx_t * rfx)1015 boolean make_param_box(LiVESVBox *top_vbox, lives_rfx_t *rfx) {
1016 lives_param_t *param = NULL;
1017
1018 LiVESWidget *param_vbox = NULL;
1019 LiVESWidget *top_hbox = NULL;
1020 LiVESWidget *hbox = NULL;
1021 LiVESWidget *last_label = NULL;
1022 LiVESWidget *layoutx = NULL;
1023 LiVESWidget *dummy_label = NULL;
1024
1025 // put whole thing in scrolled window
1026 LiVESWidget *scrolledwindow;
1027
1028 LiVESList *hints = NULL;
1029 LiVESList *onchange = NULL;
1030 LiVESList *layout = NULL;
1031 LiVESList *list;
1032
1033 char **array;
1034 char label_text[256]; // max length of a label in layout hints
1035
1036 char *line;
1037 char *type = NULL;
1038 char *format = NULL;
1039
1040 char fmt_strings[MAX_FMT_STRINGS][FMT_STRING_SIZE];
1041
1042 size_t fmtlen, ll;
1043
1044 boolean used[rfx->num_params];
1045 boolean has_box = FALSE;
1046 boolean internal = FALSE;
1047 boolean noslid;
1048 boolean has_param = FALSE;
1049 boolean chk_params = FALSE;
1050 boolean needs_sizes = FALSE;
1051 boolean layout_mode = FALSE;
1052 boolean keepsmall;
1053
1054 int pnum;
1055 int length;
1056 int poffset = 0, inum = 0;
1057 int wofl = widget_opts.filler_len;
1058
1059 int num_tok;
1060
1061 int c_fmt_strings = 0;
1062 int pass;
1063 int woph = widget_opts.packing_height;
1064
1065 int i, j, k;
1066
1067 char sepnpnum[1024];
1068 size_t sepnpnumlen;
1069
1070 lives_snprintf(sepnpnum, 1024, "s%s", rfx->delim);
1071 sepnpnumlen = strlen(sepnpnum);
1072
1073 if (!top_vbox) {
1074 // just check how many non-hidden params without displaying
1075 chk_params = TRUE;
1076 } else {
1077 dummy_label = lives_label_new(NULL);
1078 lives_widget_object_ref_sink(LIVES_WIDGET_OBJECT(dummy_label));
1079
1080 mainw->textwidget_focus = NULL;
1081
1082 // initialise special widgets
1083 init_special();
1084
1085 if (rfx->status == RFX_STATUS_WEED) usrgrp_to_livesgrp[1] = NULL;
1086 else usrgrp_to_livesgrp[0] = NULL;
1087
1088 // paramwindow start, everything goes in top_hbox
1089 top_hbox = lives_hbox_new(FALSE, widget_opts.packing_width);
1090
1091 // param_vbox holds the dynamic parameters
1092 param_vbox = lives_vbox_new(FALSE, widget_opts.packing_height);
1093 lives_widget_set_halign(param_vbox, LIVES_ALIGN_FILL);
1094 lives_widget_set_valign(param_vbox, LIVES_ALIGN_CENTER);
1095 lives_box_pack_start(LIVES_BOX(top_hbox), param_vbox, TRUE, TRUE, widget_opts.packing_width);
1096
1097 for (i = 0; i < rfx->num_params; i++) {
1098 used[i] = FALSE;
1099 for (j = 0; j < MAX_PARAM_WIDGETS; j++) {
1100 if (rfx->params[i].transition && j > 0 && j < 4) continue;
1101 rfx->params[i].widgets[j] = NULL;
1102 }
1103 }
1104 }
1105
1106 switch (rfx->status) {
1107 case RFX_STATUS_BUILTIN:
1108 if (!chk_params) type = lives_strdup(PLUGIN_RENDERED_EFFECTS_BUILTIN);
1109 break;
1110 case RFX_STATUS_CUSTOM:
1111 if (!chk_params) type = lives_strdup(PLUGIN_RENDERED_EFFECTS_CUSTOM);
1112 break;
1113 case RFX_STATUS_SCRAP:
1114 if (!chk_params) type = lives_strdup(PLUGIN_RFX_SCRAP);
1115 break;
1116 case RFX_STATUS_WEED:
1117 if (!mainw->multitrack && rfx->is_template) {
1118 weed_plant_t *filter = weed_instance_get_filter((weed_plant_t *)rfx->source, TRUE);
1119 if (enabled_in_channels(filter, FALSE) == 0 && enabled_out_channels(filter, FALSE) > 0
1120 && has_video_chans_out(filter, TRUE)) {
1121 // out channel size(s) and target_fps for generators
1122 needs_sizes = TRUE;
1123 }
1124 }
1125 // extras for converters
1126 if (weed_instance_is_resizer((weed_plant_t *)rfx->source)) {
1127 has_param = add_sizes(LIVES_BOX(param_vbox), FALSE, FALSE, rfx);
1128 if (chk_params && has_param) return TRUE;
1129 }
1130 internal = TRUE;
1131 break;
1132 default:
1133 if (!chk_params) type = lives_strdup(PLUGIN_RENDERED_EFFECTS_TEST);
1134 break;
1135 }
1136
1137 if (internal) {
1138 if (mainw->multitrack) {
1139 // extras for multitrack
1140 weed_plant_t *filter = weed_instance_get_filter((weed_plant_t *)rfx->source, TRUE);
1141 if (enabled_in_channels(filter, FALSE) == 2 && get_transition_param(filter, FALSE) != -1) {
1142 // add in/out for multitrack transition
1143 if (chk_params) return TRUE;
1144 has_param = TRUE;
1145 transition_add_in_out(LIVES_BOX(param_vbox), rfx, (mainw->multitrack->opts.pertrack_audio));
1146 }
1147 }
1148 if (!chk_params) hints = get_external_window_hints(rfx);
1149 } else {
1150 if (rfx->status != RFX_STATUS_SCRAP && rfx->num_in_channels == 0 && rfx->min_frames > -1) {
1151 if (!mainw->multitrack) {
1152 if (chk_params) return TRUE;
1153 add_gen_to(LIVES_BOX(param_vbox), rfx);
1154 } else mainw->gen_to_clipboard = FALSE;
1155 /// add nframes, fps, width, height
1156 add_genparams(param_vbox, rfx);
1157 has_param = TRUE;
1158 }
1159
1160 if (!chk_params) {
1161 // do onchange|init
1162 if ((onchange = plugin_request_by_line(type, rfx->name, "get_onchange"))) {
1163 for (i = 0; i < lives_list_length(onchange); i++) {
1164 array = lives_strsplit((char *)lives_list_nth_data(onchange, i), rfx->delim, -1);
1165 if (strcmp(array[0], "init")) {
1166 // note other onchanges so we don't have to keep parsing the list
1167 int which = atoi(array[0]);
1168 if (which >= 0 && which < rfx->num_params) {
1169 rfx->params[which].onchange = TRUE;
1170 }
1171 }
1172 lives_strfreev(array);
1173 }
1174 lives_list_free_all(&onchange);
1175 }
1176 hints = plugin_request_by_line(type, rfx->name, "get_param_window");
1177 lives_free(type);
1178 }
1179 }
1180
1181 // do param window hints
1182 if (hints) {
1183 LiVESList *list;
1184 char *lstring = lives_strconcat("layout", rfx->delim, NULL);
1185 char *sstring = lives_strconcat("special", rfx->delim, NULL);
1186 char *istring = lives_strconcat("internal", rfx->delim, NULL);
1187 for (list = hints; list; list = list->next) {
1188 char *line = (char *)list->data;
1189 if (!lives_strncmp(line, lstring, 7)) {
1190 layout = lives_list_append(layout, lives_strdup(line + 7));
1191 } else if (!lives_strncmp(line, istring, 9)) {
1192 layout = lives_list_append(layout, lives_strdup(line + 9));
1193 } else if (!lives_strncmp(line, sstring, 8)) {
1194 add_to_special(line + 8, rfx); // add any special actions to the framedraw preview
1195 }
1196 }
1197 lives_list_free_all(&hints);
1198 lives_free(lstring);
1199 lives_free(sstring);
1200 lives_free(istring);
1201 }
1202
1203 lives_memset(fmt_strings, 0, MAX_FMT_STRINGS * FMT_STRING_SIZE);
1204
1205 for (pass = 0; pass < 2; pass++) {
1206 // in this mode we do 2 passes: first check if the row is similar to the following row
1207 // (ignoring any rows with just labels or hseparators)
1208 // if so we mark it as 'layoutable'
1209
1210 // to compare: make a string with the following vals: paramtype, or label (-2), or fill (-1)
1211 // following this we compare the strings
1212
1213 // if the string has the same value as its successor we will create or extend the layout
1214 if (chk_params) pass = 1;
1215 //g_print("in pass %d\n", pass);
1216
1217 list = layout;
1218 // use layout hints to build as much as we can
1219 for (i = 0; list; i++) {
1220 line = (char *)list->data;
1221 list = list->next;
1222 layout_mode = FALSE;
1223 has_box = FALSE;
1224 last_label = NULL;
1225 noslid = FALSE;
1226 if (i < MAX_FMT_STRINGS - 1) {
1227 format = fmt_strings[i];
1228 if (pass == 1 && !chk_params && (i > 0 || list)) {
1229 if (fmt_match((char *)fmt_strings[list == NULL ? i - 1 : i])) {
1230 layout_mode = TRUE;
1231 if (!layoutx) {
1232 widget_opts.packing_height *= 2;
1233 layoutx = lives_layout_new(LIVES_BOX(param_vbox));
1234 lives_widget_set_halign(layoutx, LIVES_ALIGN_CENTER);
1235 widget_opts.packing_height = woph;
1236 }
1237 //g_print("LAYOUT MODE\n");
1238 }
1239 }
1240 } else if (pass == 0) break;
1241
1242 num_tok = get_token_count(line, (unsigned int)rfx->delim[0]);
1243 // ignore | inside strings
1244 array = lives_strsplit(line, rfx->delim, num_tok);
1245 if (!*(array[num_tok - 1])) num_tok--;
1246
1247 for (j = 0; j < num_tok; j++) {
1248 if (!strcmp(array[j], "nextfilter")) {
1249 // handling for compound fx - add an offset to the param number
1250 poffset += num_in_params_for_nth_instance((weed_plant_t *)rfx->source, inum);
1251 inum++;
1252 continue;
1253 }
1254
1255 if (!strcmp(array[j], "hseparator")) {
1256 // hseparator ///////////////
1257 if (pass == 1 && !chk_params) {
1258 // add a separator
1259 if (layoutx) lives_layout_add_separator(LIVES_LAYOUT(layoutx), TRUE);
1260 else add_hsep_to_box(LIVES_BOX(param_vbox));
1261 }
1262 break; // ignore anything after hseparator
1263 }
1264
1265 if (!strncmp(array[j], "p", 1) && (pnum = atoi((char *)(array[j] + 1))) >= 0
1266 && (pnum = pnum + poffset) < rfx->num_params && !used[pnum]) {
1267 // parameter, eg. p1 ////////////////////////////
1268 param = &rfx->params[pnum];
1269 if (!chk_params && !(rfx->flags & RFX_FLAGS_NO_RESET)) {
1270 rfx->params[pnum].changed = FALSE;
1271 }
1272 if (rfx->source_type == LIVES_RFX_SOURCE_WEED) {
1273 check_hidden_gui((weed_plant_t *)rfx->source, param, pnum);
1274 if (param->hidden & HIDDEN_STRUCTURAL) continue;
1275 }
1276
1277 has_param = TRUE;
1278
1279 if (pass == 0) {
1280 if ((fmtlen = lives_strlen((const char *)format)) < FMT_STRING_SIZE - 1) format[fmtlen] = (unsigned char)param->type;
1281 } else {
1282 used[pnum] = TRUE;
1283 if (!has_box) {
1284 // add a new row if needed
1285 if (layoutx) lives_layout_add_row(LIVES_LAYOUT(layoutx));
1286 else {
1287 hbox = lives_hbox_new(FALSE, 0);
1288 lives_box_pack_start(LIVES_BOX(param_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1289 }
1290 has_box = TRUE;
1291 } else {
1292 widget_opts.filler_len >>= 2;
1293 if (layoutx) lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1294 else add_fill_to_box(LIVES_BOX(hbox));
1295 widget_opts.filler_len = wofl;
1296 }
1297
1298 if (last_label) {
1299 lives_widget_set_halign(last_label, LIVES_ALIGN_START);
1300 }
1301 if (layoutx) hbox = lives_layout_hbox_new(LIVES_LAYOUT(layoutx));
1302 if (add_param_to_box(LIVES_BOX(hbox), rfx, pnum, (j == (num_tok - 1)) && !noslid)) noslid = TRUE;
1303 }
1304 } else if (!strncmp(array[j], "fill", 4)) {
1305 //// fill //////////////////
1306 // (can be filln)
1307
1308 if (strlen(array[j]) == 4 || (length = atoi(array[j] + 4)) == 0) length = 1;
1309
1310 if (pass == 1) {
1311 if (!has_box) {
1312 // add a new row if needed
1313 if (layoutx) lives_layout_add_row(LIVES_LAYOUT(layoutx));
1314 else {
1315 hbox = lives_hbox_new(FALSE, 0);
1316 lives_box_pack_start(LIVES_BOX(param_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1317 }
1318 if (layoutx) lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1319 else add_fill_to_box(LIVES_BOX(hbox));
1320 has_box = TRUE;
1321 } else {
1322 if (last_label) lives_widget_set_halign(last_label, LIVES_ALIGN_START);
1323 widget_opts.filler_len >>= 1;
1324 if (layoutx) {
1325 lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1326 lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1327 } else {
1328 add_fill_to_box(LIVES_BOX(hbox));
1329 add_fill_to_box(LIVES_BOX(hbox));
1330 }
1331 widget_opts.filler_len = wofl;
1332 }
1333 }
1334
1335 for (k = 1; k < length; k++) {
1336 if (pass == 1) {
1337 widget_opts.filler_len >>= 1;
1338 if (layoutx) {
1339 lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1340 lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1341 } else {
1342 add_fill_to_box(LIVES_BOX(hbox));
1343 add_fill_to_box(LIVES_BOX(hbox));
1344 }
1345 widget_opts.filler_len = wofl;
1346 } else if ((fmtlen = lives_strlen((const char *)format)) < FMT_STRING_SIZE) format[fmtlen] = -1;
1347 }
1348 } else if (*array[j] == '"') {
1349 // add a label
1350 if (pass == 0) {
1351 if ((fmtlen = lives_strlen((const char *)format)) < FMT_STRING_SIZE) format[fmtlen] = -2;
1352 if (has_box) last_label = dummy_label;
1353 continue;
1354 }
1355
1356 if (!has_box) {
1357 // add a new row if needed
1358 if (layoutx) lives_layout_add_row(LIVES_LAYOUT(layoutx));
1359 else {
1360 hbox = lives_hbox_new(FALSE, 0);
1361 lives_box_pack_start(LIVES_BOX(param_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1362 }
1363 has_box = TRUE;
1364 } else {
1365 widget_opts.filler_len >>= 1;
1366 if (layoutx) lives_layout_add_fill(LIVES_LAYOUT(layoutx), TRUE);
1367 else add_fill_to_box(LIVES_BOX(hbox));
1368 widget_opts.filler_len = wofl;
1369 }
1370
1371 ll = lives_snprintf(label_text, 256, "%s", array[j] + 1);
1372 if (ll > 255) ll = 255;
1373
1374 while (j < num_tok - 1 && label_text[ll - 1] != '"') {
1375 // handle separators within label text
1376 ll += lives_strappend(label_text, 256, rfx->delim);
1377 ll += lives_strappend(label_text, 256, array[++j]);
1378 }
1379
1380 keepsmall = TRUE;
1381 if (!last_label && !has_param) {
1382 if (j == num_tok - 1 || strncmp(array[j + 1], sepnpnum, sepnpnumlen)) keepsmall = TRUE;
1383 }
1384
1385 if (ll) {
1386 if (label_text[ll - 1] == '"') label_text[ll - 1] = 0;
1387
1388 if (!keepsmall) widget_opts.justify = LIVES_JUSTIFY_CENTER;
1389 else if (last_label) {
1390 lives_widget_set_halign(last_label, LIVES_ALIGN_START);
1391 lives_widget_set_hexpand(last_label, FALSE);
1392 }
1393
1394 if (layoutx) {
1395 last_label = lives_layout_add_label(LIVES_LAYOUT(layoutx), label_text, keepsmall);
1396 } else last_label = add_param_label_to_box(LIVES_BOX(hbox), !keepsmall, label_text);
1397 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1398 lives_widget_set_hexpand(last_label, TRUE);
1399 }
1400 }
1401 }
1402 if (!layout_mode) layoutx = NULL;
1403 lives_strfreev(array);
1404 }
1405
1406 if (!chk_params) {
1407 c_fmt_strings = i;
1408 if (pass == 1) lives_list_free_all(&layout);
1409 }
1410
1411 // add any unused parameters
1412 for (i = 0; i < rfx->num_params; i++) {
1413 if (!chk_params && !(rfx->flags & RFX_FLAGS_NO_RESET)) {
1414 rfx->params[i].changed = FALSE;
1415 if (used[i]) continue;
1416 }
1417
1418 layout_mode = FALSE;
1419 format = NULL;
1420
1421 if (c_fmt_strings + i < MAX_FMT_STRINGS - 1) {
1422 format = fmt_strings[c_fmt_strings + i];
1423 if (pass == 1 && !chk_params) {
1424 if (fmt_match((char *)fmt_strings[i + c_fmt_strings])) {
1425 layout_mode = TRUE;
1426 if (!layoutx) {
1427 widget_opts.packing_height *= 2;
1428 layoutx = lives_layout_new(LIVES_BOX(param_vbox));
1429 lives_widget_set_halign(layoutx, LIVES_ALIGN_CENTER);
1430 widget_opts.packing_height = woph;
1431 }
1432 //g_print("LAYOUT MODE\n");
1433 }
1434 }
1435 } else if (pass == 0) break;
1436
1437 if (rfx->source_type == LIVES_RFX_SOURCE_WEED) {
1438 check_hidden_gui((weed_plant_t *)rfx->source, &rfx->params[i], i);
1439 if (rfx->params[i].hidden & HIDDEN_STRUCTURAL) continue;
1440 }
1441
1442 if (chk_params) return TRUE;
1443
1444 has_param = TRUE;
1445 if (pass == 0) {
1446 if ((fmtlen = lives_strlen((const char *)format)) < FMT_STRING_SIZE) format[fmtlen] =
1447 (unsigned char)(rfx->params[i].type);
1448 } else {
1449 if (layoutx) {
1450 add_param_to_box(LIVES_BOX(lives_layout_row_new(LIVES_LAYOUT(layoutx))), rfx, i, TRUE);
1451 } else add_param_to_box(LIVES_BOX(param_vbox), rfx, i, TRUE);
1452 }
1453 if (!layout_mode) layoutx = NULL;
1454 }
1455 }
1456
1457 if (needs_sizes) has_param = add_sizes(chk_params ? NULL : LIVES_BOX(top_vbox), TRUE, has_param, rfx);
1458 if (chk_params) return has_param;
1459
1460 if (!has_param) {
1461 widget_opts.justify = LIVES_JUSTIFY_CENTER;
1462 LiVESWidget *label = lives_standard_label_new(_("No parameters"));
1463 hbox = lives_hbox_new(FALSE, 0);
1464 lives_box_pack_start(LIVES_BOX(param_vbox), hbox, TRUE, FALSE, 0);
1465 lives_box_pack_start(LIVES_BOX(hbox), label, TRUE, FALSE, 0);
1466 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1467 }
1468
1469 if (!mainw->multitrack || rfx->status != RFX_STATUS_WEED) {
1470 float box_scale = 1.;
1471 // for resize effects we add the framedraw to get its widgets, but hide it, so the box should get extra width and less height
1472 if (rfx->props & RFX_PROPS_MAY_RESIZE) box_scale = 1.5 * widget_opts.scale;
1473 scrolledwindow = lives_standard_scrolled_window_new(RFX_WINSIZE_H * box_scale, RFX_WINSIZE_V >> 1, top_hbox);
1474 } else scrolledwindow = lives_standard_scrolled_window_new(-1, -1, top_hbox);
1475
1476 lives_box_pack_start(LIVES_BOX(top_vbox), scrolledwindow, TRUE, TRUE, 0);
1477 lives_widget_destroy(dummy_label);
1478 if (has_param)
1479 update_widget_vis(rfx, -1, -1);
1480 return has_param;
1481 }
1482
1483
add_param_to_box(LiVESBox * box,lives_rfx_t * rfx,int pnum,boolean add_slider)1484 boolean add_param_to_box(LiVESBox *box, lives_rfx_t *rfx, int pnum, boolean add_slider) {
1485 // box here is vbox inside top_hbox inside top_dialog
1486
1487 // add paramter pnum for rfx to box
1488
1489 LiVESWidget *label;
1490 LiVESWidget *checkbutton;
1491 LiVESWidget *radiobutton;
1492 LiVESWidget *spinbutton;
1493 LiVESWidget *scale = NULL;
1494 LiVESWidget *spinbutton_red;
1495 LiVESWidget *spinbutton_green;
1496 LiVESWidget *spinbutton_blue;
1497 LiVESWidget *cbutton;
1498 LiVESWidget *entry = NULL;
1499 LiVESWidget *hbox;
1500 LiVESWidget *combo;
1501 //LiVESWidget *dlabel = NULL;
1502 LiVESWidget *textview = NULL;
1503 LiVESWidget *scrolledwindow;
1504 LiVESWidget *layout = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(box),
1505 WH_LAYOUT_KEY);
1506
1507 LiVESAdjustment *spinbutton_adj;
1508
1509 LiVESTextBuffer *textbuffer = NULL;
1510
1511 lives_param_t *param;
1512 lives_widget_group_t *group;
1513 LiVESSList *rbgroup;
1514
1515 lives_colRGB48_t rgb;
1516 lives_colRGBA64_t rgba;
1517
1518 char *name;
1519 char *txt;//, *tmp;
1520 //char *disp_string;
1521
1522 int wcount = 0;
1523
1524 boolean use_mnemonic;
1525 boolean was_num = FALSE;
1526
1527 boolean add_scalers = TRUE;
1528
1529 if (pnum >= rfx->num_params) {
1530 add_param_label_to_box(box, FALSE, (_("Invalid parameter")));
1531 return FALSE;
1532 }
1533
1534 param = &rfx->params[pnum];
1535
1536 name = lives_strdup_printf("%s", param->label);
1537 use_mnemonic = param->use_mnemonic;
1538
1539 // reinit can cause the window to be redrawn, which invalidates the slider adjustment...and bang !
1540 // so dont add sliders for such params
1541 if (param->reinit) add_scalers = FALSE;
1542
1543 // for plugins (encoders and video playback) sliders look silly
1544 if (rfx->flags & RFX_FLAGS_NO_SLIDERS) add_scalers = FALSE;
1545
1546 if (LIVES_IS_HBOX(LIVES_WIDGET(box))) {
1547 hbox = LIVES_WIDGET(box);
1548 } else {
1549 hbox = lives_hbox_new(FALSE, 0);
1550 lives_box_pack_start(LIVES_BOX(box), hbox, FALSE, FALSE, widget_opts.packing_height);
1551 }
1552
1553 // see if there were any 'special' hints
1554 if (!layout)
1555 check_for_special_type(rfx, param, LIVES_BOX(lives_widget_get_parent(LIVES_WIDGET(box))));
1556 else
1557 check_for_special_type(rfx, param, LIVES_BOX(lives_widget_get_parent(layout)));
1558
1559 switch (param->type) {
1560 case LIVES_PARAM_BOOL:
1561 if (!param->group) {
1562 widget_opts.mnemonic_label = use_mnemonic;
1563 checkbutton = lives_standard_check_button_new(name, get_bool_param(param->value), (LiVESBox *)hbox, param->desc);
1564 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(checkbutton), LIVES_WIDGET_TOGGLED_SIGNAL,
1565 LIVES_GUI_CALLBACK(after_boolean_param_toggled),
1566 (livespointer)rfx);
1567 widget_opts.mnemonic_label = TRUE;
1568
1569 // store parameter so we know whose trigger to use
1570 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(checkbutton), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1571 param->widgets[0] = checkbutton;
1572 } else {
1573 group = get_group(rfx, param);
1574
1575 if (group) rbgroup = group->rbgroup;
1576 else rbgroup = NULL;
1577
1578 widget_opts.mnemonic_label = use_mnemonic;
1579 radiobutton = lives_standard_radio_button_new(name, &rbgroup, LIVES_BOX(hbox), param->desc);
1580 widget_opts.mnemonic_label = TRUE;
1581
1582 if (group == NULL) {
1583 if (rfx->status == RFX_STATUS_WEED) {
1584 usrgrp_to_livesgrp[1] = add_usrgrp_to_livesgrp(usrgrp_to_livesgrp[1],
1585 rbgroup, param->group);
1586 } else {
1587 usrgrp_to_livesgrp[0] = add_usrgrp_to_livesgrp(usrgrp_to_livesgrp[0],
1588 rbgroup, param->group);
1589 }
1590 }
1591
1592 group = get_group(rfx, param);
1593
1594 if (group) {
1595 group->rbgroup = rbgroup;
1596 if (get_bool_param(param->value)) {
1597 group->active_param = pnum + 1;
1598 }
1599 } else LIVES_WARN("Button group was NULL");
1600
1601 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton), get_bool_param(param->value));
1602
1603 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
1604 LIVES_GUI_CALLBACK(after_boolean_param_toggled), (livespointer)rfx);
1605
1606 // store parameter so we know whose trigger to use
1607 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(radiobutton), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1608 param->widgets[0] = radiobutton;
1609 }
1610 param->widgets[1] = widget_opts.last_label;
1611 break;
1612
1613 case LIVES_PARAM_NUM:
1614 was_num = TRUE;
1615
1616 widget_opts.mnemonic_label = use_mnemonic;
1617 if (param->dp) {
1618 spinbutton = lives_standard_spin_button_new(name, get_double_param(param->value), param->min,
1619 param->max, param->step_size, param->step_size, param->dp,
1620 (LiVESBox *)hbox, param->desc);
1621 } else {
1622 spinbutton = lives_standard_spin_button_new(name, (double)get_int_param(param->value), param->min,
1623 param->max, param->step_size, param->step_size, param->dp,
1624 (LiVESBox *)hbox, param->desc);
1625 }
1626 widget_opts.mnemonic_label = TRUE;
1627
1628 lives_spin_button_set_wrap(LIVES_SPIN_BUTTON(spinbutton), param->wrap);
1629
1630 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
1631 LIVES_GUI_CALLBACK(after_param_value_changed), (livespointer)rfx);
1632
1633 // store parameter so we know whose trigger to use
1634 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1635 param->widgets[0] = spinbutton;
1636 param->widgets[++wcount] = widget_opts.last_label;
1637 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(param->widgets[0]), RFX_KEY, rfx);
1638
1639 if (add_scalers) {
1640 spinbutton_adj = lives_spin_button_get_adjustment(LIVES_SPIN_BUTTON(spinbutton));
1641 #ifdef ENABLE_GIW
1642 if (prefs->lamp_buttons) {
1643 scale = giw_knob_new(LIVES_ADJUSTMENT(spinbutton_adj));
1644 giw_knob_set_wrap(GIW_KNOB(scale), param->wrap);
1645 lives_widget_set_size_request(scale, GIW_KNOB_WIDTH, GIW_KNOB_HEIGHT);
1646 giw_knob_set_legends_digits(GIW_KNOB(scale), 0);
1647 if (layout) {
1648 hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1649 lives_layout_pack(LIVES_HBOX(hbox), scale);
1650 lives_widget_set_show_hide_with(spinbutton, hbox);
1651 } else
1652 lives_box_pack_start(LIVES_BOX(hbox), scale, FALSE, FALSE, widget_opts.packing_width >> 1);
1653 if (param->desc) lives_widget_set_tooltip_text(scale, param->desc);
1654 lives_widget_set_fg_color(scale, LIVES_WIDGET_STATE_NORMAL, &palette->white);
1655 lives_widget_set_fg_color(scale, LIVES_WIDGET_STATE_PRELIGHT, &palette->dark_orange);
1656 lives_widget_set_bg_color(scale, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
1657 param->widgets[++wcount] = scale;
1658 }
1659 #endif
1660
1661 if (add_slider && !param->wrap && (param->dp || param->transition)) {
1662 spinbutton_adj = lives_spin_button_get_adjustment(LIVES_SPIN_BUTTON(spinbutton));
1663 scale = lives_standard_hscale_new(LIVES_ADJUSTMENT(spinbutton_adj));
1664 lives_widget_set_size_request(scale, DEF_SLIDER_WIDTH, -1);
1665 if (layout) {
1666 hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
1667 lives_layout_pack(LIVES_HBOX(hbox), scale);
1668 lives_widget_set_show_hide_with(spinbutton, hbox);
1669 } else {
1670 lives_box_pack_start(LIVES_BOX(hbox), scale, TRUE, TRUE, widget_opts.packing_width >> 1);
1671 if (!LIVES_IS_HBOX(LIVES_WIDGET(box))) add_fill_to_box(LIVES_BOX(hbox));
1672 }
1673 lives_widget_apply_theme(scale, LIVES_WIDGET_STATE_NORMAL);
1674 if (param->desc) lives_widget_set_tooltip_text(scale, param->desc);
1675 param->widgets[++wcount] = scale;
1676 }
1677 }
1678
1679 if (param->desc) lives_widget_set_tooltip_text(scale, param->desc);
1680 break;
1681
1682 case LIVES_PARAM_COLRGB24:
1683 get_colRGB24_param(param->value, &rgb);
1684
1685 rgba.red = rgb.red << 8;
1686 rgba.green = rgb.green << 8;
1687 rgba.blue = rgb.blue << 8;
1688 rgba.alpha = 65535;
1689
1690 widget_opts.mnemonic_label = use_mnemonic;
1691 cbutton = lives_standard_color_button_new(LIVES_BOX(hbox), _(name), FALSE, &rgba, &spinbutton_red, &spinbutton_green,
1692 &spinbutton_blue, NULL);
1693 widget_opts.mnemonic_label = TRUE;
1694 lives_widget_set_size_request(cbutton, DEF_BUTTON_WIDTH / 2, -1);
1695
1696 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(cbutton), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1697 if (param->desc) lives_widget_set_tooltip_text(cbutton, param->desc);
1698
1699 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_red), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
1700 LIVES_GUI_CALLBACK(after_param_red_changed), (livespointer)rfx);
1701 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_green), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
1702 LIVES_GUI_CALLBACK(after_param_green_changed), (livespointer)rfx);
1703 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(spinbutton_blue), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
1704 LIVES_GUI_CALLBACK(after_param_blue_changed), (livespointer)rfx);
1705
1706 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(cbutton), LIVES_WIDGET_COLOR_SET_SIGNAL,
1707 LIVES_GUI_CALLBACK(on_pwcolsel), (livespointer)rfx);
1708
1709 // store parameter so we know whose trigger to use
1710 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_red), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1711 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_green), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1712 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(spinbutton_blue), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1713
1714 param->widgets[0] = spinbutton_red;
1715 param->widgets[1] = spinbutton_green;
1716 param->widgets[2] = spinbutton_blue;
1717 //param->widgets[3]=spinbutton_alpha;
1718 param->widgets[4] = cbutton;
1719 param->widgets[5] = widget_opts.last_label;
1720 break;
1721
1722 case LIVES_PARAM_STRING:
1723 if (param->max == 0.) txt = lives_strdup((char *)param->value);
1724 else txt = lives_strndup((char *)param->value, (int)param->max);
1725
1726 if (((int)param->max > RFX_TEXT_MAGIC || param->max == 0.) &&
1727 param->special_type != LIVES_PARAM_SPECIAL_TYPE_FILEREAD
1728 && param->special_type != LIVES_PARAM_SPECIAL_TYPE_FONT_CHOOSER
1729 && param->special_type != LIVES_PARAM_SPECIAL_TYPE_FILEWRITE) {
1730 LiVESWidget *vbox = lives_vbox_new(FALSE, 0);
1731 int woat = widget_opts.apply_theme;
1732
1733 widget_opts.justify = LIVES_JUSTIFY_CENTER;
1734 if (use_mnemonic) label = lives_standard_label_new_with_mnemonic_widget(_(name), NULL);
1735 else label = lives_standard_label_new(_(name));
1736 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
1737
1738 lives_box_pack_start(LIVES_BOX(hbox), vbox, TRUE, TRUE, widget_opts.packing_width);
1739 if (layout) lives_layout_expansion_row_new(LIVES_LAYOUT(layout), vbox);
1740
1741 lives_box_pack_start(LIVES_BOX(vbox), label, FALSE, FALSE, widget_opts.packing_height >> 1);
1742
1743 hbox = lives_hbox_new(FALSE, 0);
1744 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height >> 1);
1745
1746 param->widgets[0] = textview = lives_text_view_new();
1747 if (param->desc) lives_widget_set_tooltip_text(textview, param->desc);
1748 textbuffer = lives_text_view_get_buffer(LIVES_TEXT_VIEW(textview));
1749
1750 lives_signal_sync_connect_after(LIVES_WIDGET_OBJECT(textbuffer), LIVES_WIDGET_CHANGED_SIGNAL,
1751 LIVES_GUI_CALLBACK(after_param_text_buffer_changed),
1752 (livespointer) rfx);
1753
1754 lives_text_view_set_editable(LIVES_TEXT_VIEW(textview), TRUE);
1755 lives_text_view_set_wrap_mode(LIVES_TEXT_VIEW(textview), LIVES_WRAP_WORD);
1756 lives_text_view_set_cursor_visible(LIVES_TEXT_VIEW(textview), TRUE);
1757
1758 lives_text_buffer_set_text(textbuffer, txt, -1);
1759
1760 widget_opts.apply_theme = 0;
1761 widget_opts.expand = LIVES_EXPAND_EXTRA;
1762 scrolledwindow = lives_standard_scrolled_window_new(-1, RFX_TEXT_SCROLL_HEIGHT, textview);
1763 widget_opts.expand = LIVES_EXPAND_DEFAULT;
1764 widget_opts.apply_theme = woat;
1765
1766 if (mainw->multitrack == NULL)
1767 lives_widget_apply_theme3(textview, LIVES_WIDGET_STATE_NORMAL);
1768 else
1769 lives_widget_apply_theme2(textview, LIVES_WIDGET_STATE_NORMAL, TRUE);
1770
1771 lives_box_pack_start(LIVES_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
1772
1773 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(textbuffer), "textview", textview);
1774 } else {
1775 if (use_mnemonic) label = lives_standard_label_new_with_mnemonic_widget(_(name), NULL);
1776 else label = lives_standard_label_new(_(name));
1777
1778 lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
1779 param->widgets[0] = entry = lives_standard_entry_new(NULL, txt, (int)param->max,
1780 (int)param->max, LIVES_BOX(hbox), param->desc);
1781
1782 if (rfx->status == RFX_STATUS_WEED && param->special_type != LIVES_PARAM_SPECIAL_TYPE_FILEREAD) {
1783 lives_signal_sync_connect_after(LIVES_WIDGET_OBJECT(entry), LIVES_WIDGET_CHANGED_SIGNAL,
1784 LIVES_GUI_CALLBACK(after_param_text_changed), (livespointer)rfx);
1785 }
1786 }
1787 param->widgets[1] = widget_opts.last_label;
1788
1789 if (param->desc) lives_widget_set_tooltip_text(label, param->desc);
1790
1791 lives_signal_sync_connect_after(LIVES_WIDGET_OBJECT(hbox), LIVES_WIDGET_SET_FOCUS_CHILD_SIGNAL,
1792 LIVES_GUI_CALLBACK(after_param_text_focus_changed),
1793 (livespointer)rfx);
1794
1795 if (use_mnemonic) lives_label_set_mnemonic_widget(LIVES_LABEL(label), param->widgets[0]);
1796
1797 lives_free(txt);
1798
1799 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(hbox), TEXTWIDGET_KEY, (livespointer)param->widgets[0]);
1800 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(param->widgets[0]), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1801 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(param->widgets[0]), RFX_KEY, rfx);
1802
1803 param->widgets[1] = label;
1804
1805 break;
1806
1807 case LIVES_PARAM_STRING_LIST:
1808 widget_opts.expand = LIVES_EXPAND_EXTRA;
1809 widget_opts.mnemonic_label = use_mnemonic;
1810
1811 combo = lives_standard_combo_new(name, param->list, (LiVESBox *)hbox, param->desc);
1812 widget_opts.mnemonic_label = TRUE;
1813 widget_opts.expand = LIVES_EXPAND_DEFAULT;
1814
1815 if (param->list) {
1816 lives_combo_set_active_string(LIVES_COMBO(combo),
1817 (char *)lives_list_nth_data(param->list, get_int_param(param->value)));
1818 }
1819
1820 lives_signal_sync_connect_after(LIVES_WIDGET_OBJECT(combo), LIVES_WIDGET_CHANGED_SIGNAL,
1821 LIVES_GUI_CALLBACK(after_string_list_changed), (livespointer)rfx);
1822
1823 // store parameter so we know whose trigger to use
1824 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(combo), PARAM_NUMBER_KEY, LIVES_INT_TO_POINTER(pnum));
1825 param->widgets[0] = combo;
1826 param->widgets[1] = widget_opts.last_label;
1827 break;
1828
1829 default:
1830 break;
1831 }
1832
1833 // see if there were any 'special' hints
1834 if (!layout) {
1835 check_for_special(rfx, param, LIVES_BOX(lives_widget_get_parent(LIVES_WIDGET(box))));
1836 } else {
1837 check_for_special(rfx, param, LIVES_BOX(lives_widget_get_parent(layout)));
1838 }
1839 lives_free(name);
1840 return was_num;
1841 }
1842
1843
add_param_label_to_box(LiVESBox * box,boolean do_trans,const char * text)1844 LiVESWidget *add_param_label_to_box(LiVESBox *box, boolean do_trans, const char *text) {
1845 LiVESWidget *label;
1846
1847 lives_box_set_homogeneous(LIVES_BOX(box), FALSE);
1848
1849 if (do_trans) {
1850 char *markup;
1851 #ifdef GUI_GTK
1852 markup = g_markup_printf_escaped("<span weight=\"bold\" style=\"italic\"> %s </span>", _(text));
1853 #endif
1854 #ifdef GUI_QT
1855 QString qs = QString("<span weight=\"bold\" style=\"italic\"> %s </span>").arg(_(text));
1856 markup = strdup((const char *)qs.toHtmlEscaped().constData());
1857 #endif
1858 label = lives_standard_label_new(NULL);
1859 lives_label_set_markup(LIVES_LABEL(label), markup);
1860 lives_free(markup);
1861 } else label = lives_standard_label_new_with_mnemonic_widget(text, NULL);
1862
1863 if (LIVES_IS_HBOX(LIVES_WIDGET(box)))
1864 lives_box_pack_start(box, label, FALSE, FALSE, widget_opts.packing_width);
1865 else
1866 lives_box_pack_start(box, label, FALSE, FALSE, widget_opts.packing_height);
1867
1868 return label;
1869 }
1870
1871
add_usrgrp_to_livesgrp(LiVESSList * u2l,LiVESSList * rbgroup,int usr_number)1872 LiVESSList *add_usrgrp_to_livesgrp(LiVESSList *u2l, LiVESSList *rbgroup, int usr_number) {
1873 lives_widget_group_t *wgroup = (lives_widget_group_t *)lives_malloc(sizeof(lives_widget_group_t));
1874 wgroup->usr_number = usr_number;
1875 wgroup->rbgroup = rbgroup;
1876 wgroup->active_param = 0;
1877 u2l = lives_slist_append(u2l, (livespointer)wgroup);
1878 return u2l;
1879 }
1880
1881
livesgrp_from_usrgrp(LiVESSList * u2l,int usrgrp)1882 lives_widget_group_t *livesgrp_from_usrgrp(LiVESSList *u2l, int usrgrp) {
1883 lives_widget_group_t *group;
1884 LiVESSList *list = u2l;
1885 for (; list; list = list->next) {
1886 group = (lives_widget_group_t *)list->data;
1887 if (group->usr_number == usrgrp) return group;
1888 }
1889 return NULL;
1890 }
1891
1892
update_widget_vis(lives_rfx_t * rfx,int key,int mode)1893 boolean update_widget_vis(lives_rfx_t *rfx, int key, int mode) {
1894 weed_plant_t *wparam = NULL, *inst;
1895 int keyw, modew;
1896 lives_param_t *param;
1897
1898 if (mainw->multitrack == NULL) {
1899 if (fx_dialog[1]) {
1900 rfx = fx_dialog[1]->rfx;
1901 if (!rfx->is_template) {
1902 keyw = fx_dialog[1]->key;
1903 modew = fx_dialog[1]->mode;
1904 }
1905 if (!rfx->is_template && (key != keyw && mode != modew)) return FALSE;
1906 }
1907 }
1908
1909 if ((!fx_dialog[1] && !mainw->multitrack) || !rfx || rfx->status != RFX_STATUS_WEED) return FALSE;
1910 inst = (weed_plant_t *)rfx->source;
1911 for (int i = 0; i < rfx->num_params; i++) {
1912 param = &rfx->params[i];
1913 if ((wparam = weed_inst_in_param(inst, i, FALSE, FALSE)) != NULL) {
1914 check_hidden_gui(inst, param, i);
1915 if (param->hidden & HIDDEN_STRUCTURAL) continue;
1916 for (int j = 0; j < RFX_MAX_NORM_WIDGETS; j++) {
1917 if (param->type == LIVES_PARAM_COLRGB24 && j == 3 && !param->widgets[j]) continue;
1918 if (!param->widgets[j]) break;
1919 if (param->hidden) {
1920 lives_widget_hide(param->widgets[j]);
1921 lives_widget_set_no_show_all(param->widgets[j], TRUE);
1922 } else {
1923 lives_widget_set_no_show_all(param->widgets[j], FALSE);
1924 lives_widget_show_all(param->widgets[j]);
1925 // *INDENT-OFF*
1926 }}}}
1927 // *INDENT-ON*
1928
1929 return TRUE;
1930 }
1931
1932
after_any_changed_1(lives_rfx_t * rfx,int param_number,int index)1933 static void after_any_changed_1(lives_rfx_t *rfx, int param_number, int index) {
1934 weed_plant_t *inst = (weed_plant_t *)rfx->source;
1935 weed_plant_t *wparam = weed_inst_in_param(inst, param_number, FALSE, FALSE), *paramtmpl;
1936 int numvals = weed_leaf_num_elements(wparam, WEED_LEAF_VALUE);
1937 int *ign, nvals;
1938 //// update pt. 1:
1939 /// fill param vals and set "ignore" values
1940 if (index >= numvals) {
1941 paramtmpl = weed_param_get_template(wparam);
1942 fill_param_vals_to(wparam, paramtmpl, index);
1943 numvals = index + 1;
1944 }
1945
1946 if (mainw->multitrack && is_perchannel_multi(rfx, param_number)) {
1947 if (weed_plant_has_leaf(wparam, WEED_LEAF_IGNORE)) {
1948 ign = weed_get_boolean_array_counted(wparam, WEED_LEAF_IGNORE, &nvals);
1949 if (index >= 0 && index < nvals) {
1950 ign[index] = WEED_FALSE;
1951 weed_set_boolean_array(wparam, WEED_LEAF_IGNORE, nvals, ign);
1952 }
1953 lives_freep((void **)&ign);
1954 }
1955 }
1956 }
1957
1958
1959 /**
1960 @brief part 2 function for updating params visually
1961 */
after_any_changed_2(lives_rfx_t * rfx,lives_param_t * param,boolean needs_update)1962 static void after_any_changed_2(lives_rfx_t *rfx, lives_param_t *param, boolean needs_update) {
1963 weed_plant_t *wparam = NULL, *gui, *inst = NULL;
1964 lives_filter_error_t retval = FILTER_SUCCESS;
1965
1966 /// update widgets on screen (as a result of copying values or triggers)
1967 if (needs_update) update_visual_params(rfx, FALSE);
1968 needs_update = FALSE;
1969
1970 /// only the first param in the chain can reinit
1971 if (--ireinit > 0) {
1972 param->changed = TRUE;
1973 param->change_blocked = FALSE;
1974 return;
1975 }
1976
1977 /// plugin is allowed to show / hide params during its init_func()
1978 /// so here we record the state b4 calling it; if any changes occur we want to refresh the whole window.
1979 if (rfx->status == RFX_STATUS_WEED) {
1980 if (mainw->multitrack) {
1981 for (int i = 0; i < rfx->num_params; i++) {
1982 if ((wparam = weed_inst_in_param(inst, i, FALSE, FALSE)) != NULL) {
1983 if ((gui = weed_param_get_gui(wparam, FALSE)) != NULL) {
1984 if (retval != FILTER_INFO_REDRAWN) {
1985 if (weed_get_boolean_value(gui, "host_hidden_backup", NULL) != weed_get_boolean_value(gui, WEED_LEAF_HIDDEN, NULL))
1986 needs_update = TRUE;
1987 }
1988 weed_leaf_delete(gui, "host_hidden_backup");
1989 // *INDENT-OFF*
1990 }}}}
1991 // *INDENT-ON*
1992
1993 inst = (weed_plant_t *)rfx->source;
1994 if (rfx->needs_reinit) {
1995 if (!(rfx->needs_reinit & REINIT_FUNCTIONAL)) {
1996 weed_instance_set_flags(inst, weed_instance_get_flags(inst) | WEED_INSTANCE_UPDATE_GUI_ONLY);
1997 }
1998
1999 retval = weed_reinit_effect(inst, FALSE);
2000
2001 if (!(rfx->needs_reinit & REINIT_FUNCTIONAL)) {
2002 weed_instance_set_flags(inst, weed_instance_get_flags(inst) ^ WEED_INSTANCE_UPDATE_GUI_ONLY);
2003 }
2004 rfx->needs_reinit = 0;
2005 }
2006 }
2007
2008 needs_update = FALSE;
2009 rfx->needs_reinit = 0;
2010
2011 if (fx_dialog[1]) {
2012 // transfer param changes from rte_window to ce_thumbs window, and vice-versa
2013 lives_rfx_t *rte_rfx = fx_dialog[1]->rfx;
2014 int key = fx_dialog[1]->key;
2015 int mode = fx_dialog[1]->mode;
2016 mainw->block_param_updates = TRUE;
2017 if (rfx == rte_rfx && mainw->ce_thumbs) ce_thumbs_update_visual_params(key);
2018 else if (mode == rte_key_getmode(key + 1)) ce_thumbs_check_for_rte(rfx, rte_rfx, key);
2019 mainw->block_param_updates = FALSE;
2020 }
2021
2022 if (!weed_param_value_irrelevant(wparam)) {
2023 param->changed = TRUE;
2024 }
2025
2026 if (mainw->multitrack && rfx->status == RFX_STATUS_WEED) {
2027 update_widget_vis(rfx, -1, -1);
2028 activate_mt_preview(mainw->multitrack);
2029 }
2030
2031 param->change_blocked = FALSE;
2032 }
2033
2034
after_boolean_param_toggled(LiVESToggleButton * togglebutton,lives_rfx_t * rfx)2035 void after_boolean_param_toggled(LiVESToggleButton * togglebutton, lives_rfx_t *rfx) {
2036 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(togglebutton), PARAM_NUMBER_KEY));
2037 LiVESList *retvals = NULL;
2038 weed_plant_t *inst = NULL;
2039 lives_param_t *param = &rfx->params[param_number];
2040 boolean old_bool = get_bool_param(param->value), new_bool;
2041 boolean needs_update = FALSE;
2042 int copyto = -1;
2043
2044 new_bool = lives_toggle_button_get_active(togglebutton);
2045 if (old_bool == new_bool) return;
2046
2047 if (mainw->block_param_updates) {
2048 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2049 return; // updates are blocked until all params are ready
2050 }
2051
2052 ireinit++;
2053
2054 set_bool_param(param->value, new_bool);
2055 if (mainw->framedraw_preview) reset_framedraw_preview();
2056 param->change_blocked = TRUE;
2057
2058 if (rfx->status == RFX_STATUS_WEED) {
2059 inst = (weed_plant_t *)rfx->source;
2060 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2061 //char *disp_string;
2062 int index = 0, numvals;
2063 int key = -1;
2064 weed_plant_t *wparam = weed_inst_in_param(inst, param_number, FALSE, FALSE);
2065 int *valis = weed_get_boolean_array(wparam, WEED_LEAF_VALUE, NULL);
2066
2067 if (mainw->multitrack && is_perchannel_multi(rfx, param_number)) {
2068 index = mainw->multitrack->track_index;
2069 }
2070
2071 after_any_changed_1(rfx, param_number, index);
2072
2073 valis[index] = new_bool;
2074 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2075 numvals = weed_leaf_num_elements(wparam, WEED_LEAF_VALUE);
2076 if (!filter_mutex_trylock(key)) {
2077 weed_set_boolean_array(wparam, WEED_LEAF_VALUE, numvals, valis);
2078 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2079 filter_mutex_unlock(key); \
2080 if (copyto != -1) needs_update = TRUE;
2081 }
2082 lives_freep((void **)&valis);
2083
2084 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2085 // if we are recording, add this change to our event_list
2086 rec_param_change(inst, param_number);
2087 }
2088 if (param->reinit) rfx->needs_reinit |= param->reinit;
2089 }
2090 }
2091
2092 if (get_bool_param(param->value) != old_bool && param->onchange) {
2093 param->change_blocked = TRUE;
2094 retvals = do_onchange(LIVES_WIDGET_OBJECT(togglebutton), rfx);
2095 lives_list_free_all(&retvals);
2096 needs_update = TRUE;
2097 }
2098 after_any_changed_2(rfx, param, needs_update);
2099 }
2100
2101
after_param_value_changed(LiVESSpinButton * spinbutton,lives_rfx_t * rfx)2102 void after_param_value_changed(LiVESSpinButton * spinbutton, lives_rfx_t *rfx) {
2103 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), PARAM_NUMBER_KEY));
2104 LiVESList *retvals = NULL;
2105 lives_param_t *param = &rfx->params[param_number];
2106 double new_double = 0., old_double = 0.;
2107 int new_int = 0, old_int = 0;
2108 boolean needs_update = FALSE;
2109 int copyto = -1;
2110
2111 lives_spin_button_update(LIVES_SPIN_BUTTON(spinbutton));
2112
2113 if (param->dp > 0) {
2114 old_double = get_double_param(param->value);
2115 new_double = lives_spin_button_get_value(LIVES_SPIN_BUTTON(spinbutton));
2116 if (old_double == new_double) return;
2117 } else {
2118 old_int = get_int_param(param->value);
2119 new_int = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
2120 if (old_int == new_int) return;
2121 }
2122
2123 if (mainw->block_param_updates) {
2124 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2125 return; // updates are blocked until all params are ready
2126 }
2127
2128 ireinit++;
2129
2130 if (mainw->framedraw_preview) reset_framedraw_preview();
2131
2132 if (rfx->status == RFX_STATUS_WEED && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING &&
2133 (prefs->rec_opts & REC_EFFECTS)) {
2134 // if we are recording, add this (pre)change to our event_list
2135 rec_param_change((weed_plant_t *)rfx->source, param_number);
2136 copyto = set_copy_to((weed_plant_t *)rfx->source, param_number, rfx, FALSE);
2137 }
2138
2139 if (param->dp > 0) {
2140 set_double_param(param->value, new_double);
2141 } else {
2142 set_int_param(param->value, new_int);
2143 }
2144
2145 param->change_blocked = TRUE;
2146
2147 if (rfx->status == RFX_STATUS_WEED) {
2148 weed_plant_t *inst = (weed_plant_t *)rfx->source;
2149 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2150 weed_plant_t *wparam = weed_inst_in_param(inst, param_number, FALSE, FALSE);
2151 int index = 0, numvals;
2152 int key = -1;
2153 double *valds;
2154 int *valis;
2155
2156 // update transition in/out radios
2157 if (mainw->multitrack) {
2158 weed_plant_t *filter = weed_instance_get_filter(inst, TRUE);
2159 if (enabled_in_channels(filter, FALSE) == 2 && param->transition) {
2160 if (param->dp == 0) {
2161 if (new_int == (int)param->min)
2162 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[WIDGET_RB_IN]), TRUE);
2163 else if (new_int == (int)param->max)
2164 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[WIDGET_RB_OUT]), TRUE);
2165 else lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[WIDGET_RB_DUMMY]), TRUE);
2166 } else {
2167 if (new_double == param->min)
2168 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[WIDGET_RB_IN]), TRUE);
2169 else if (new_double == param->max)
2170 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[WIDGET_RB_OUT]), TRUE);
2171 else lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[WIDGET_RB_DUMMY]), TRUE);
2172 }
2173 }
2174 }
2175
2176 if (mainw->multitrack && is_perchannel_multi(rfx, param_number)) {
2177 index = mainw->multitrack->track_index;
2178 }
2179
2180 after_any_changed_1(rfx, param_number, index);
2181
2182 numvals = weed_leaf_num_elements(wparam, WEED_LEAF_VALUE);
2183 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2184 if (weed_leaf_seed_type(wparam, WEED_LEAF_VALUE) == WEED_SEED_DOUBLE) {
2185 valds = weed_get_double_array(wparam, WEED_LEAF_VALUE, NULL);
2186 if (param->dp > 0) valds[index] = new_double;
2187 else valds[index] = (double)new_int;
2188 if (!filter_mutex_trylock(key)) {
2189 weed_set_double_array(wparam, WEED_LEAF_VALUE, numvals, valds);
2190 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2191 filter_mutex_unlock(key);
2192 if (copyto != -1) needs_update = TRUE;
2193 }
2194 lives_freep((void **)&valds);
2195 } else {
2196 valis = weed_get_int_array(wparam, WEED_LEAF_VALUE, NULL);
2197 valis[index] = new_int;
2198 weed_set_int_array(wparam, WEED_LEAF_VALUE, numvals, valis);
2199 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2200 filter_mutex_unlock(key);
2201 if (copyto != -1) needs_update = TRUE;
2202 lives_freep((void **)&valis);
2203 }
2204 }
2205
2206 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2207 // if we are recording, add this change to our event_list
2208 rec_param_change(inst, param_number);
2209 }
2210 if (param->reinit) rfx->needs_reinit |= param->reinit;
2211 }
2212
2213 if (((param->dp > 0 && (get_double_param(param->value) != old_double)) || (param->dp == 0 &&
2214 (get_int_param(param->value) != old_int))) && param->onchange) {
2215 param->change_blocked = TRUE;
2216 retvals = do_onchange(LIVES_WIDGET_OBJECT(spinbutton), rfx);
2217 lives_list_free_all(&retvals);
2218 needs_update = TRUE;
2219 }
2220
2221 after_any_changed_2(rfx, param, needs_update);
2222 }
2223
2224
update_weed_color_value(weed_plant_t * plant,int pnum,int c1,int c2,int c3,int c4,lives_rfx_t * rfx)2225 void update_weed_color_value(weed_plant_t *plant, int pnum, int c1, int c2, int c3, int c4, lives_rfx_t *rfx) {
2226 weed_plant_t *ptmpl;
2227 weed_plant_t *param = NULL;
2228
2229 int *maxs = NULL, *mins = NULL;
2230 int cols[4] = {c1, c2, c3, c4};
2231 int cspace;
2232 int rmax, rmin, gmax, gmin, bmax, bmin;
2233
2234 boolean is_default = WEED_PLANT_IS_FILTER_CLASS(plant);
2235 boolean is_int;
2236
2237 double *maxds = NULL, *minds = NULL;
2238 double colds[4];
2239 double rmaxd, rmind, gmaxd, gmind, bmaxd, bmind;
2240
2241 if (!is_default) {
2242 param = weed_inst_in_param(plant, pnum, FALSE, FALSE);
2243 ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, NULL);
2244 } else {
2245 // called only from rte_set_defs_ok
2246 ptmpl = weed_filter_in_paramtmpl(plant, pnum, FALSE);
2247 }
2248
2249 if (mainw->block_param_updates) return; // updates are blocked until all params are ready
2250
2251 is_int = (weed_leaf_seed_type(ptmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT);
2252 cspace = weed_get_int_value(ptmpl, WEED_LEAF_COLORSPACE, NULL);
2253
2254 switch (cspace) {
2255 // TODO - other cspaces
2256 case WEED_COLORSPACE_RGB:
2257 if (is_int) {
2258 if (weed_leaf_num_elements(ptmpl, WEED_LEAF_MAX) == 3) {
2259 maxs = weed_get_int_array(ptmpl, WEED_LEAF_MAX, NULL);
2260 rmax = maxs[0];
2261 gmax = maxs[1];
2262 bmax = maxs[2];
2263 lives_free(maxs);
2264 } else rmax = gmax = bmax = weed_get_int_value(ptmpl, WEED_LEAF_MAX, NULL);
2265 if (weed_leaf_num_elements(ptmpl, WEED_LEAF_MIN) == 3) {
2266 mins = weed_get_int_array(ptmpl, WEED_LEAF_MIN, NULL);
2267 rmin = mins[0];
2268 gmin = mins[1];
2269 bmin = mins[2];
2270 lives_free(mins);
2271 } else rmin = gmin = bmin = weed_get_int_value(ptmpl, WEED_LEAF_MIN, NULL);
2272
2273 cols[0] = rmin + (int)((double)cols[0] / 255.*(double)(rmax - rmin));
2274 cols[1] = gmin + (int)((double)cols[1] / 255.*(double)(gmax - gmin));
2275 cols[2] = bmin + (int)((double)cols[2] / 255.*(double)(bmax - bmin));
2276 if (is_default) {
2277 weed_set_int_array(ptmpl, WEED_LEAF_HOST_DEFAULT, 3, cols);
2278 } else {
2279 int index = 0, numvals;
2280 int *valis;
2281
2282 if (mainw->multitrack && is_perchannel_multiw(ptmpl)) {
2283 index = mainw->multitrack->track_index;
2284 }
2285 numvals = weed_leaf_num_elements(param, WEED_LEAF_VALUE);
2286 if (index * 3 >= numvals) {
2287 weed_plant_t *paramtmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, NULL);
2288 fill_param_vals_to(param, paramtmpl, index);
2289 numvals = (index + 1) * 3;
2290 }
2291
2292 if (mainw->multitrack && is_perchannel_multi(rfx, pnum)) {
2293 if (weed_plant_has_leaf(param, WEED_LEAF_IGNORE)) {
2294 int nvals = weed_leaf_num_elements(param, WEED_LEAF_IGNORE);
2295 if (index >= 0 && index < nvals) {
2296 int *ign = weed_get_boolean_array(param, WEED_LEAF_IGNORE, NULL);
2297 ign[index] = WEED_FALSE;
2298 weed_set_boolean_array(param, WEED_LEAF_IGNORE, nvals, ign);
2299 lives_free(ign);
2300 }
2301 }
2302 }
2303
2304 valis = weed_get_int_array(param, WEED_LEAF_VALUE, NULL);
2305 valis[index * 3] = cols[0];
2306 valis[index * 3 + 1] = cols[1];
2307 valis[index * 3 + 2] = cols[2];
2308 weed_set_int_array(param, WEED_LEAF_VALUE, numvals, valis);
2309 lives_free(valis);
2310 }
2311 break;
2312 } else {
2313 // double
2314 if (weed_leaf_num_elements(ptmpl, WEED_LEAF_MAX) == 3) {
2315 maxds = weed_get_double_array(ptmpl, WEED_LEAF_MAX, NULL);
2316 rmaxd = maxds[0];
2317 gmaxd = maxds[1];
2318 bmaxd = maxds[2];
2319 lives_free(maxds);
2320 } else rmaxd = gmaxd = bmaxd = weed_get_double_value(ptmpl, WEED_LEAF_MAX, NULL);
2321 if (weed_leaf_num_elements(ptmpl, WEED_LEAF_MIN) == 3) {
2322 minds = weed_get_double_array(ptmpl, WEED_LEAF_MIN, NULL);
2323 rmind = minds[0];
2324 gmind = minds[1];
2325 bmind = minds[2];
2326 lives_free(minds);
2327 } else rmind = gmind = bmind = weed_get_double_value(ptmpl, WEED_LEAF_MIN, NULL);
2328 colds[0] = rmind + (double)cols[0] / 255.*(rmaxd - rmind);
2329 colds[1] = gmind + (double)cols[1] / 255.*(gmaxd - gmind);
2330 colds[2] = bmind + (double)cols[2] / 255.*(bmaxd - bmind);
2331 if (is_default) {
2332 weed_set_double_array(ptmpl, WEED_LEAF_HOST_DEFAULT, 3, colds);
2333 } else {
2334 int index = 0, numvals;
2335 double *valds;
2336
2337 if (mainw->multitrack && is_perchannel_multiw(ptmpl)) {
2338 index = mainw->multitrack->track_index;
2339 }
2340 numvals = weed_leaf_num_elements(param, WEED_LEAF_VALUE);
2341 if (index * 3 >= numvals) {
2342 weed_plant_t *paramtmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, NULL);
2343 fill_param_vals_to(param, paramtmpl, index);
2344 numvals = (index + 1) * 3;
2345 }
2346
2347 if (mainw->multitrack && is_perchannel_multi(rfx, pnum)) {
2348 if (weed_plant_has_leaf(param, WEED_LEAF_IGNORE)) {
2349 int nvals = weed_leaf_num_elements(param, WEED_LEAF_IGNORE);
2350 if (index >= 0 && index < nvals) {
2351 int *ign = weed_get_boolean_array(param, WEED_LEAF_IGNORE, NULL);
2352 ign[index] = WEED_FALSE;
2353 weed_set_boolean_array(param, WEED_LEAF_IGNORE, nvals, ign);
2354 lives_free(ign);
2355 }
2356 }
2357 }
2358
2359 valds = weed_get_double_array(param, WEED_LEAF_VALUE, NULL);
2360 valds[index * 3] = colds[0];
2361 valds[index * 3 + 1] = colds[1];
2362 valds[index * 3 + 2] = colds[2];
2363 weed_set_double_array(param, WEED_LEAF_VALUE, numvals, valds);
2364 lives_free(valds);
2365 }
2366 }
2367 break;
2368 }
2369 }
2370
2371
after_param_red_changed(LiVESSpinButton * spinbutton,lives_rfx_t * rfx)2372 void after_param_red_changed(LiVESSpinButton * spinbutton, lives_rfx_t *rfx) {
2373 LiVESList *retvals = NULL;
2374 lives_colRGB48_t old_value;
2375 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), PARAM_NUMBER_KEY));
2376 int new_red;
2377 boolean needs_update = FALSE;
2378 int copyto = -1;
2379 lives_param_t *param = &rfx->params[param_number];
2380
2381 get_colRGB24_param(param->value, &old_value);
2382 new_red = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
2383 if (old_value.red == new_red) return;
2384
2385 if (mainw->block_param_updates) {
2386 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2387 return; // updates are blocked until all params are ready
2388 }
2389
2390 ireinit++;
2391
2392 if (rfx->status == RFX_STATUS_WEED && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING &&
2393 (prefs->rec_opts & REC_EFFECTS)) {
2394 // if we are recording, add this change to our event_list
2395
2396 rec_param_change((weed_plant_t *)rfx->source, param_number);
2397 copyto = set_copy_to((weed_plant_t *)rfx->source, param_number, rfx, FALSE);
2398 }
2399
2400 set_colRGB24_param(param->value, new_red, old_value.green, old_value.blue);
2401
2402 if (mainw->framedraw_preview) reset_framedraw_preview();
2403 param->change_blocked = TRUE;
2404
2405 if (rfx->status == RFX_STATUS_WEED) {
2406 int key = -1;
2407 weed_plant_t *inst = (weed_plant_t *)rfx->source;
2408 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2409 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2410 if (!filter_mutex_trylock(key)) {
2411 update_weed_color_value(inst, param_number, new_red, old_value.green, old_value.blue, 0, rfx);
2412 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2413 filter_mutex_unlock(key);
2414 if (copyto != -1) needs_update = TRUE;
2415 }
2416
2417 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2418 // if we are recording, add this change to our event_list
2419 rec_param_change(inst, param_number);
2420 }
2421 if (param->reinit) rfx->needs_reinit |= param->reinit;
2422 }
2423 }
2424
2425 if (new_red != old_value.red && param->onchange) {
2426 param->change_blocked = TRUE;
2427 retvals = do_onchange(LIVES_WIDGET_OBJECT(spinbutton), rfx);
2428 lives_list_free_all(&retvals);
2429 needs_update = TRUE;
2430 }
2431 after_any_changed_2(rfx, param, needs_update);
2432 }
2433
2434
after_param_green_changed(LiVESSpinButton * spinbutton,lives_rfx_t * rfx)2435 void after_param_green_changed(LiVESSpinButton * spinbutton, lives_rfx_t *rfx) {
2436 LiVESList *retvals = NULL;
2437 lives_colRGB48_t old_value;
2438 int new_green;
2439 int copyto = -1;
2440 boolean needs_update = FALSE;
2441 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), PARAM_NUMBER_KEY));
2442 lives_param_t *param = &rfx->params[param_number];
2443
2444 get_colRGB24_param(param->value, &old_value);
2445 new_green = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
2446 if (old_value.green == new_green) return;
2447
2448 if (mainw->block_param_updates) {
2449 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2450 return; // updates are blocked until all params are ready
2451 }
2452
2453 ireinit++;
2454
2455 if (rfx->status == RFX_STATUS_WEED && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING &&
2456 (prefs->rec_opts & REC_EFFECTS)) {
2457 // if we are recording, add this change to our event_list
2458 rec_param_change((weed_plant_t *)rfx->source, param_number);
2459 copyto = set_copy_to((weed_plant_t *)rfx->source, param_number, rfx, FALSE);
2460 }
2461
2462 set_colRGB24_param(param->value, old_value.red, new_green, old_value.blue);
2463
2464 if (mainw->framedraw_preview) reset_framedraw_preview();
2465 param->change_blocked = TRUE;
2466
2467 if (rfx->status == RFX_STATUS_WEED) {
2468 int key = -1;
2469 weed_plant_t *inst = (weed_plant_t *)rfx->source;
2470 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2471 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2472 if (!filter_mutex_trylock(key)) {
2473 update_weed_color_value(inst, param_number, old_value.red, new_green, old_value.blue, 0, rfx);
2474 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2475 filter_mutex_unlock(key);
2476 if (copyto != -1) needs_update = TRUE;
2477 }
2478
2479 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2480 // if we are recording, add this change to our event_list
2481 rec_param_change(inst, param_number);
2482 }
2483 rfx->needs_reinit |= param->reinit;
2484 }
2485 }
2486
2487 if (new_green != old_value.green && param->onchange) {
2488 param->change_blocked = TRUE;
2489 retvals = do_onchange(LIVES_WIDGET_OBJECT(spinbutton), rfx);
2490 lives_list_free_all(&retvals);
2491 needs_update = TRUE;
2492 }
2493 after_any_changed_2(rfx, param, needs_update);
2494 }
2495
2496
after_param_blue_changed(LiVESSpinButton * spinbutton,lives_rfx_t * rfx)2497 void after_param_blue_changed(LiVESSpinButton * spinbutton, lives_rfx_t *rfx) {
2498 LiVESList *retvals = NULL;
2499 lives_colRGB48_t old_value;
2500 int new_blue;
2501 int copyto = -1;
2502 boolean needs_update = FALSE;
2503 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), PARAM_NUMBER_KEY));
2504 lives_param_t *param = &rfx->params[param_number];
2505
2506 get_colRGB24_param(param->value, &old_value);
2507 new_blue = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
2508 if (old_value.blue == new_blue) return;
2509
2510 if (mainw->block_param_updates) {
2511 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2512 return; // updates are blocked until all params are ready
2513 }
2514
2515 ireinit++;
2516
2517 if (rfx->status == RFX_STATUS_WEED && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING &&
2518 (prefs->rec_opts & REC_EFFECTS)) {
2519 // if we are recording, add this change to our event_list
2520 rec_param_change((weed_plant_t *)rfx->source, param_number);
2521 }
2522
2523 set_colRGB24_param(param->value, old_value.red, old_value.green, new_blue);
2524
2525 if (mainw->framedraw_preview) reset_framedraw_preview();
2526 param->change_blocked = TRUE;
2527
2528 if (rfx->status == RFX_STATUS_WEED) {
2529 int key = -1;
2530 weed_plant_t *inst = (weed_plant_t *)rfx->source;
2531 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2532 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2533 if (!filter_mutex_trylock(key)) {
2534 update_weed_color_value(inst, param_number, old_value.red, old_value.green, new_blue, 0, rfx);
2535 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2536 filter_mutex_unlock(key);
2537 if (copyto != -1) needs_update = TRUE;
2538 }
2539
2540 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2541 // if we are recording, add this change to our event_list
2542 rec_param_change(inst, param_number);
2543 }
2544 rfx->needs_reinit |= param->reinit;
2545 }
2546 }
2547
2548 if (new_blue != old_value.blue && param->onchange) {
2549 param->change_blocked = TRUE;
2550 retvals = do_onchange(LIVES_WIDGET_OBJECT(spinbutton), rfx);
2551 lives_list_free_all(&retvals);
2552 needs_update = TRUE;
2553 }
2554 after_any_changed_2(rfx, param, needs_update);
2555 }
2556
2557
after_param_alpha_changed(LiVESSpinButton * spinbutton,lives_rfx_t * rfx)2558 void after_param_alpha_changed(LiVESSpinButton * spinbutton, lives_rfx_t *rfx) {
2559 // not used yet
2560 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(spinbutton), PARAM_NUMBER_KEY));
2561 LiVESList *retvals = NULL;
2562 lives_param_t *param = &rfx->params[param_number];
2563 lives_colRGBA64_t old_value;
2564 int new_alpha = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
2565 int copyto = -1;
2566 boolean needs_update = FALSE;
2567
2568 if (mainw->block_param_updates) {
2569 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2570 return; // updates are blocked until all params are ready
2571 }
2572
2573 ireinit++;
2574
2575 if (rfx->status == RFX_STATUS_WEED && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING &&
2576 (prefs->rec_opts & REC_EFFECTS)) {
2577 // if we are recording, add this change to our event_list
2578 rec_param_change((weed_plant_t *)rfx->source, param_number);
2579 copyto = set_copy_to((weed_plant_t *)rfx->source, param_number, rfx, FALSE);
2580 }
2581
2582 get_colRGBA32_param(param->value, &old_value);
2583
2584 if (mainw->framedraw_preview) reset_framedraw_preview();
2585
2586 set_colRGBA32_param(param->value, old_value.red, old_value.green, old_value.blue, new_alpha);
2587 param->change_blocked = TRUE;
2588
2589 if (rfx->status == RFX_STATUS_WEED && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING &&
2590 (prefs->rec_opts & REC_EFFECTS)) {
2591 // if we are recording, add this change to our event_list
2592 rec_param_change((weed_plant_t *)rfx->source, param_number);
2593 if (copyto != -1) rec_param_change((weed_plant_t *)rfx->source, copyto);
2594 }
2595
2596 if (new_alpha != old_value.alpha && param->onchange) {
2597 param->change_blocked = TRUE;
2598 retvals = do_onchange(LIVES_WIDGET_OBJECT(spinbutton), rfx);
2599 lives_list_free_all(&retvals);
2600 needs_update = TRUE;
2601 }
2602 after_any_changed_2(rfx, param, needs_update);
2603 }
2604
2605
after_param_text_focus_changed(LiVESWidget * hbox,LiVESWidget * child,lives_rfx_t * rfx)2606 boolean after_param_text_focus_changed(LiVESWidget * hbox, LiVESWidget * child, lives_rfx_t *rfx) {
2607 // for non realtime effects
2608 // we don't usually want to run the trigger every single time the user presses a key in a text widget
2609 // so we only update when the user clicks OK or focusses out of the widget
2610
2611 LiVESWidget *textwidget;
2612
2613 if (rfx == NULL) return FALSE;
2614
2615 if (mainw->multitrack) {
2616 if (child)
2617 lives_window_remove_accel_group(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), mainw->multitrack->accel_group);
2618 else
2619 lives_window_add_accel_group(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), mainw->multitrack->accel_group);
2620 }
2621
2622 if (mainw->textwidget_focus) {
2623 textwidget = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(mainw->textwidget_focus), TEXTWIDGET_KEY);
2624 after_param_text_changed(textwidget, rfx);
2625 }
2626
2627 if (hbox) {
2628 mainw->textwidget_focus = hbox;
2629 }
2630
2631 return FALSE;
2632 }
2633
2634
after_param_text_changed(LiVESWidget * textwidget,lives_rfx_t * rfx)2635 void after_param_text_changed(LiVESWidget * textwidget, lives_rfx_t *rfx) {
2636 //LiVESTextBuffer *textbuffer = NULL;
2637 weed_plant_t *inst = NULL, *wparam = NULL;
2638 LiVESList *retvals = NULL;
2639 lives_param_t *param;
2640 char *old_text;
2641 const char *new_text;
2642 int copyto = -1;
2643 boolean needs_update = FALSE;
2644 int param_number;
2645
2646 if (rfx == NULL || rfx->params == NULL || textwidget == NULL) return;
2647
2648
2649 param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(textwidget), PARAM_NUMBER_KEY));
2650 param = &rfx->params[param_number];
2651 old_text = (char *)param->value;
2652
2653 if (LIVES_IS_TEXT_VIEW(textwidget)) {
2654 new_text = lives_text_view_get_text(LIVES_TEXT_VIEW(textwidget));
2655 if (!lives_strcmp(new_text, old_text)) return;
2656 } else {
2657 new_text = lives_entry_get_text(LIVES_ENTRY(textwidget));
2658 if (!lives_strcmp(new_text, old_text)) return;
2659 }
2660
2661 if (mainw->block_param_updates) {
2662 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2663 return; // updates are blocked until all params are ready
2664 }
2665
2666 ireinit++;
2667
2668 param->value = lives_strdup(new_text);
2669
2670 if (mainw->framedraw_preview) reset_framedraw_preview();
2671 param->change_blocked = TRUE;
2672
2673 if (rfx->status == RFX_STATUS_WEED) {
2674 inst = (weed_plant_t *)rfx->source;
2675 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2676 char **valss;
2677 int index = 0, numvals, key = -1;
2678 wparam = weed_inst_in_param(inst, param_number, FALSE, FALSE);
2679
2680 if (mainw->multitrack && is_perchannel_multi(rfx, param_number)) {
2681 index = mainw->multitrack->track_index;
2682 }
2683
2684 after_any_changed_1(rfx, param_number, index);
2685
2686 numvals = weed_leaf_num_elements(wparam, WEED_LEAF_VALUE);
2687
2688 valss = weed_get_string_array(wparam, WEED_LEAF_VALUE, NULL);
2689 valss[index] = lives_strdup((char *)param->value);
2690
2691 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2692 if (!filter_mutex_trylock(key)) {
2693 weed_set_string_array(wparam, WEED_LEAF_VALUE, numvals, valss);
2694 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2695 filter_mutex_unlock(key);
2696 if (copyto != -1) needs_update = TRUE;
2697 }
2698 for (int i = 0; i < numvals; i++) lives_free(valss[i]);
2699 lives_free(valss);
2700
2701 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2702 // if we are recording, add this change to our event_list
2703 rec_param_change(inst, param_number);
2704 //if (copyto != -1) rec_param_change(inst, copyto);
2705 }
2706 rfx->needs_reinit |= param->reinit;
2707 }
2708 }
2709
2710 if (lives_strcmp(old_text, (char *)param->value) && param->onchange) {
2711 param->change_blocked = TRUE;
2712 retvals = do_onchange(LIVES_WIDGET_OBJECT(textwidget), rfx);
2713 lives_list_free_all(&retvals);
2714 needs_update = TRUE;
2715 }
2716 after_any_changed_2(rfx, param, needs_update);
2717 }
2718
2719
after_param_text_buffer_changed(LiVESTextBuffer * textbuffer,lives_rfx_t * rfx)2720 static void after_param_text_buffer_changed(LiVESTextBuffer * textbuffer, lives_rfx_t *rfx) {
2721 LiVESWidget *textview = (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(textbuffer), "textview");
2722 after_param_text_changed(textview, rfx);
2723 }
2724
2725
after_string_list_changed(LiVESWidget * entry,lives_rfx_t * rfx)2726 void after_string_list_changed(LiVESWidget * entry, lives_rfx_t *rfx) {
2727 LiVESList *retvals = NULL;
2728 int param_number = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(entry), PARAM_NUMBER_KEY));
2729 LiVESCombo *combo = (LiVESCombo *)(rfx->params[param_number].widgets[0]);
2730 lives_param_t *param = &rfx->params[param_number];
2731 const char *txt = lives_combo_get_active_text(combo);
2732 int old_index = get_int_param(param->value);
2733 int new_index = lives_list_strcmp_index(param->list, txt, TRUE);
2734 boolean needs_update = FALSE;
2735 int copyto = -1;
2736
2737 if (new_index == -1) return;
2738 if (new_index == old_index) return;
2739
2740 if (mainw->block_param_updates) {
2741 if (rfx->status == RFX_STATUS_WEED && param->reinit) rfx->needs_reinit |= param->reinit;
2742 return; // updates are blocked until all params are ready
2743 }
2744
2745 ireinit++;
2746
2747 set_int_param(param->value, new_index);
2748
2749 if (mainw->framedraw_preview) reset_framedraw_preview();
2750 param->change_blocked = TRUE;
2751 if (rfx->status == RFX_STATUS_WEED) {
2752 weed_plant_t *inst = (weed_plant_t *)rfx->source;
2753 if (inst && WEED_PLANT_IS_FILTER_INSTANCE(inst)) {
2754 //char *disp_string = get_weed_display_string(inst, param_number);
2755 weed_plant_t *wparam = weed_inst_in_param(inst, param_number, FALSE, FALSE);
2756 int index = 0, numvals;
2757 int key = -1;
2758 int *valis;
2759
2760 if (mainw->multitrack && is_perchannel_multi(rfx, param_number)) {
2761 index = mainw->multitrack->track_index;
2762 }
2763
2764 after_any_changed_1(rfx, param_number, index);
2765
2766 valis = weed_get_int_array(wparam, WEED_LEAF_VALUE, NULL);
2767 valis[index] = new_index;
2768 numvals = weed_leaf_num_elements(wparam, WEED_LEAF_VALUE);
2769 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2770 if (!filter_mutex_trylock(key)) {
2771 weed_set_int_array(wparam, WEED_LEAF_VALUE, numvals, valis);
2772 copyto = set_copy_to(inst, param_number, rfx, TRUE);
2773 filter_mutex_unlock(key);
2774 if (copyto != -1) needs_update = TRUE;
2775 }
2776 lives_free(valis);
2777
2778 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
2779 // if we are recording, add this change to our event_list
2780 rec_param_change(inst, param_number);
2781 //if (copyto != -1) rec_param_change(inst, copyto);
2782 }
2783 rfx->needs_reinit |= param->reinit;
2784 }
2785 }
2786
2787 if (old_index != new_index && param->onchange) {
2788 param->change_blocked = TRUE;
2789 retvals = do_onchange(LIVES_WIDGET_OBJECT(combo), rfx);
2790 lives_list_free_all(&retvals);
2791 needs_update = TRUE;
2792 }
2793 after_any_changed_2(rfx, param, needs_update);
2794 }
2795
2796
param_marshall_to_argv(lives_rfx_t * rfx)2797 char **param_marshall_to_argv(lives_rfx_t *rfx) {
2798 // this function will marshall all parameters into a argv array
2799 // last array element will be NULL
2800
2801 // the returned **argv should be lives_free()'ed after use
2802
2803 lives_colRGB48_t rgb;
2804
2805 char **argv = (char **)lives_malloc((rfx->num_params + 1) * (sizeof(char *)));
2806
2807 char *tmp;
2808
2809 register int i;
2810
2811 for (i = 0; i < rfx->num_params; i++) {
2812 switch (rfx->params[i].type) {
2813 case LIVES_PARAM_COLRGB24:
2814 get_colRGB24_param(rfx->params[i].value, &rgb);
2815 argv[i] = lives_strdup_printf("%u", (((rgb.red << 8) + rgb.green) << 8) + rgb.blue);
2816 break;
2817
2818 case LIVES_PARAM_STRING:
2819 // escape strings
2820 argv[i] = lives_strdup_printf("%s", (tmp = U82L((char *)rfx->params[i].value)));
2821 lives_free(tmp);
2822 break;
2823
2824 case LIVES_PARAM_STRING_LIST:
2825 // escape strings
2826 argv[i] = lives_strdup_printf("%d", get_int_param(rfx->params[i].value));
2827 break;
2828
2829 default:
2830 if (rfx->params[i].dp) {
2831 char *return_pattern = lives_strdup_printf("%%.%df", rfx->params[i].dp);
2832 argv[i] = lives_strdup_printf(return_pattern, get_double_param(rfx->params[i].value));
2833 lives_free(return_pattern);
2834 } else {
2835 argv[i] = lives_strdup_printf("%d", get_int_param(rfx->params[i].value));
2836 }
2837 }
2838 }
2839 argv[i] = NULL;
2840 return argv;
2841 }
2842
2843
param_marshall(lives_rfx_t * rfx,boolean with_min_max)2844 char *param_marshall(lives_rfx_t *rfx, boolean with_min_max) {
2845 // this function will marshall all parameters into a space separated string
2846 // in case of string parameters, these will be surrounded by " and all
2847 // quotes will be escaped \"
2848
2849 // the returned string should be lives_free()'ed after use
2850 lives_colRGB48_t rgb;
2851
2852 char *new_return = lives_strdup("");
2853 char *old_return = new_return;
2854 char *return_pattern;
2855 char *tmp, *mysubst, *mysubst2;
2856
2857 for (int i = 0; i < rfx->num_params; i++) {
2858 switch (rfx->params[i].type) {
2859 case LIVES_PARAM_UNKNOWN:
2860 continue;
2861 case LIVES_PARAM_COLRGB24:
2862 get_colRGB24_param(rfx->params[i].value, &rgb);
2863 if (!with_min_max) {
2864 new_return = lives_strdup_printf("%s %u", old_return, (((rgb.red << 8) + rgb.green) << 8) + rgb.blue);
2865 } else {
2866 new_return = lives_strdup_printf("%s %d %d %d", old_return, rgb.red, rgb.green, rgb.blue);
2867 }
2868 lives_free(old_return);
2869 old_return = new_return;
2870 break;
2871
2872 case LIVES_PARAM_STRING:
2873 // we need to doubly escape strings
2874 mysubst = subst((char *)rfx->params[i].value, "\\", "\\\\\\\\");
2875 mysubst2 = subst(mysubst, "\"", "\\\\\\\"");
2876 lives_free(mysubst);
2877 mysubst = subst(mysubst2, "`", "\\`");
2878 lives_free(mysubst2);
2879 mysubst2 = subst(mysubst, "'", "\\`");
2880 lives_free(mysubst);
2881 new_return = lives_strdup_printf("%s \"%s\"", old_return, (tmp = U82L(mysubst2)));
2882 lives_free(tmp);
2883 lives_free(mysubst2);
2884 lives_free(old_return);
2885 old_return = new_return;
2886 break;
2887
2888 case LIVES_PARAM_STRING_LIST:
2889 new_return = lives_strdup_printf("%s %d", old_return, get_int_param(rfx->params[i].value));
2890 lives_free(old_return);
2891 old_return = new_return;
2892 break;
2893
2894 default:
2895 if (rfx->params[i].dp) {
2896 return_pattern = lives_strdup_printf("%%s %%.%df", rfx->params[i].dp);
2897 new_return = lives_strdup_printf(return_pattern, old_return, get_double_param(rfx->params[i].value));
2898 if (with_min_max) {
2899 lives_free(old_return);
2900 old_return = new_return;
2901 new_return = lives_strdup_printf(return_pattern, old_return, rfx->params[i].min);
2902 lives_free(old_return);
2903 old_return = new_return;
2904 new_return = lives_strdup_printf(return_pattern, old_return, rfx->params[i].max);
2905 }
2906 lives_free(return_pattern);
2907 } else {
2908 new_return = lives_strdup_printf("%s %d", old_return, get_int_param(rfx->params[i].value));
2909 if (with_min_max && rfx->params[i].type != LIVES_PARAM_BOOL) {
2910 lives_free(old_return);
2911 old_return = new_return;
2912 new_return = lives_strdup_printf("%s %d", old_return, (int)rfx->params[i].min);
2913 lives_free(old_return);
2914 old_return = new_return;
2915 new_return = lives_strdup_printf("%s %d", old_return, (int)rfx->params[i].max);
2916 }
2917 }
2918 lives_free(old_return);
2919 old_return = new_return;
2920 }
2921 }
2922 if (mainw->current_file > 0 && with_min_max) {
2923 if (rfx->num_in_channels < 2) {
2924 new_return = lives_strdup_printf("%s %d %d %d %d %d", old_return, cfile->hsize, cfile->vsize, cfile->start,
2925 cfile->end, cfile->frames);
2926 } else {
2927 // for transitions, change the end to indicate the merge section
2928 // this is better for length calculations
2929 int cb_frames = clipboard->frames;
2930 int start = cfile->start, end = cfile->end, ttl;
2931
2932 if (prefs->ins_resample && clipboard->fps != cfile->fps) {
2933 cb_frames = count_resampled_frames(clipboard->frames, clipboard->fps, cfile->fps);
2934 }
2935
2936 if (merge_opts->spinbutton_loops
2937 && cfile->end - cfile->start + 1 > (cb_frames * (ttl = lives_spin_button_get_value_as_int
2938 (LIVES_SPIN_BUTTON(merge_opts->spinbutton_loops)))) &&
2939 !merge_opts->loop_to_fit) {
2940 end = cb_frames * ttl;
2941 if (!merge_opts->align_start) {
2942 start = cfile->end - end + 1;
2943 end = cfile->end;
2944 } else {
2945 start = cfile->start;
2946 end += start - 1;
2947 }
2948 }
2949 new_return = lives_strdup_printf("%s %d %d %d %d %d %d %d", old_return, cfile->hsize, cfile->vsize, start, end,
2950 cfile->frames, clipboard->hsize, clipboard->vsize);
2951 }
2952 } else {
2953 new_return = lives_strdup(old_return);
2954 }
2955 lives_free(old_return);
2956
2957 return new_return;
2958 }
2959
2960
reconstruct_string(LiVESList * plist,int start,int * offs)2961 char *reconstruct_string(LiVESList * plist, int start, int *offs) {
2962 // convert each piece from locale to utf8
2963 // concat list entries to get reconstruct
2964 // replace \" with "
2965
2966 char *word = NULL;
2967 char *ret = lives_strdup(""), *ret2;
2968 char *tmp;
2969
2970 boolean lastword = FALSE;
2971
2972 register int i;
2973
2974 word = L2U8((char *)lives_list_nth_data(plist, start));
2975
2976 if (!word || !*word || word[0] != '\"') {
2977 if (word) lives_free(word);
2978 return 0;
2979 }
2980
2981 word++;
2982
2983 for (i = start; i < lives_list_length(plist); i++) {
2984 size_t wl = lives_strlen(word);
2985 if (wl > 0) {
2986 if ((word[wl - 1] == '\"') && (wl == 1 || word[wl - 2] != '\\')) {
2987 lastword = TRUE;
2988 lives_memset(word + wl - 1, 0, 1);
2989 }
2990 }
2991
2992 ret2 = lives_strconcat(ret, (tmp = subst(word, "\\\"", "\"")), " ", NULL);
2993 lives_free(tmp);
2994 if (ret2 != ret) lives_free(ret);
2995 ret = ret2;
2996
2997 if (i == start) word--;
2998 lives_free(word);
2999
3000 if (lastword) break;
3001
3002 if (i < lives_list_length(plist) - 1) word = L2U8((char *)lives_list_nth_data(plist, i + 1));
3003 }
3004
3005 set_int_param(offs, i - start + 1);
3006
3007 // remove trailing space
3008 lives_memset(ret + lives_strlen(ret) - 1, 0, 1);
3009 return ret;
3010 }
3011
3012
param_demarshall(lives_rfx_t * rfx,LiVESList * plist,boolean with_min_max,boolean upd)3013 void param_demarshall(lives_rfx_t *rfx, LiVESList * plist, boolean with_min_max, boolean upd) {
3014 int i;
3015 int pnum = 0;
3016 lives_param_t *param;
3017
3018 // here we take a LiVESList * of param values, set them in rfx, and if upd is TRUE we also update their visual appearance
3019
3020 // param->widgets[n] are only valid if upd==TRUE
3021
3022 if (plist == NULL) return;
3023
3024 for (i = 0; i < rfx->num_params; i++) {
3025 param = &rfx->params[i];
3026 pnum = set_param_from_list(plist, param, pnum, with_min_max, upd);
3027 }
3028 }
3029
3030
argv_to_marshalled_list(lives_rfx_t * rfx,int argc,char ** argv)3031 LiVESList *argv_to_marshalled_list(lives_rfx_t *rfx, int argc, char **argv) {
3032 LiVESList *plist = NULL;
3033
3034 char *tmp, *tmp2, *tmp3;
3035
3036 register int i;
3037
3038 if (argc == 0) return plist;
3039
3040 for (i = 0; i <= argc && argv[i]; i++) {
3041 if (rfx->params[i].type == LIVES_PARAM_STRING) {
3042 tmp = lives_strdup_printf("\"%s\"", (tmp2 = U82L(tmp3 = subst(argv[i], "\"", "\\\""))));
3043 plist = lives_list_append(plist, tmp);
3044 lives_free(tmp2);
3045 lives_free(tmp3);
3046 } else {
3047 plist = lives_list_append(plist, lives_strdup(argv[i]));
3048 }
3049 }
3050 return plist;
3051 }
3052
3053
3054 /**
3055 @brief update values for param using values in plist
3056 if upd is TRUE, the widgets for that param also are updated;
3057 otherwise, we do not update the widgets, but we do update the default
3058
3059 for LIVES_PARAM_NUM, setting pnum negative avoids having to send min,max
3060 - deprecated, use with_min_max = FALSE
3061 (other types dont have a min/max anyway)
3062
3063 pnum here is not param number, but rather the offset of the element in plist
3064 */
set_param_from_list(LiVESList * plist,lives_param_t * param,int pnum,boolean with_min_max,boolean upd)3065 int set_param_from_list(LiVESList * plist, lives_param_t *param, int pnum, boolean with_min_max, boolean upd) {
3066 char *tmp;
3067 char *strval;
3068 int red, green, blue;
3069 int offs = 0;
3070 int maxlen = lives_list_length(plist) - 1;
3071
3072 if (ABS(pnum) > maxlen) return 0;
3073
3074 switch (param->type) {
3075 case LIVES_PARAM_BOOL:
3076 if (param->change_blocked) {
3077 pnum++;
3078 break;
3079 }
3080 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3081 if (upd) {
3082 if (param->widgets[0] && LIVES_IS_TOGGLE_BUTTON(param->widgets[0])) {
3083 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(param->widgets[0]), atoi(tmp));
3084 }
3085 } else set_bool_param(param->def, (atoi(tmp)));
3086 if (upd && param->widgets[0] && LIVES_IS_TOGGLE_BUTTON(param->widgets[0])) {
3087 set_bool_param(param->value,
3088 lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(param->widgets[0])));
3089 } else set_bool_param(param->value, (atoi(tmp)));
3090 lives_free(tmp);
3091 break;
3092 case LIVES_PARAM_NUM:
3093 if (param->change_blocked) {
3094 pnum++;
3095 if (with_min_max) pnum += 2;
3096 break;
3097 }
3098 if (param->dp) {
3099 double double_val;
3100 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3101 double_val = lives_strtod(tmp, NULL);
3102 lives_free(tmp);
3103 if (with_min_max) {
3104 if (ABS(pnum) > maxlen) return 1;
3105 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3106 param->min = lives_strtod(tmp, NULL);
3107 lives_free(tmp);
3108 if (ABS(pnum) > maxlen) return 2;
3109 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3110 param->max = lives_strtod(tmp, NULL);
3111 lives_free(tmp);
3112 if (double_val < param->min) double_val = param->min;
3113 if (double_val > param->max) double_val = param->max;
3114 }
3115 if (upd) {
3116 if (param->widgets[0] && LIVES_IS_SPIN_BUTTON(param->widgets[0])) {
3117 lives_rfx_t *rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(param->widgets[0]), RFX_KEY);
3118 lives_signal_handlers_block_by_func(param->widgets[0], (livespointer)after_param_value_changed, (livespointer)rfx);
3119 lives_spin_button_set_range(LIVES_SPIN_BUTTON(param->widgets[0]), param->min, param->max);
3120 lives_spin_button_update(LIVES_SPIN_BUTTON(param->widgets[0]));
3121 lives_signal_handlers_unblock_by_func(param->widgets[0], (livespointer)after_param_value_changed, (livespointer)rfx);
3122 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), double_val);
3123 lives_spin_button_update(LIVES_SPIN_BUTTON(param->widgets[0]));
3124 }
3125 } else set_double_param(param->def, double_val);
3126 if (upd && param->widgets[0] && LIVES_IS_SPIN_BUTTON(param->widgets[0])) {
3127 set_double_param(param->value,
3128 lives_spin_button_get_value(LIVES_SPIN_BUTTON(param->widgets[0])));
3129 } else set_double_param(param->value, double_val);
3130 } else {
3131 int int_value;
3132 int int_min, int_max;
3133 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3134 int_value = atoi(tmp);
3135 lives_free(tmp);
3136 if (param->step_size > 1.)
3137 int_value = (int)((double)int_value / param->step_size + .5) * (int)param->step_size;
3138 int_min = (int)param->min;
3139 int_max = (int)param->max;
3140 if (int_value < int_min) int_value = int_min;
3141 if (int_value > int_max) int_value = int_max;
3142
3143 if (with_min_max) {
3144 if (ABS(pnum) > maxlen) return 1;
3145 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3146 int_min = atoi(tmp);
3147 lives_free(tmp);
3148 if (ABS(pnum) > maxlen) return 2;
3149 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3150 int_max = atoi(tmp);
3151 lives_free(tmp);
3152 if (int_value < int_min) int_value = int_min;
3153 if (int_value > int_max) int_value = int_max;
3154 param->min = (double)int_min;
3155 param->max = (double)int_max;
3156 }
3157 if (upd) {
3158 if (param->widgets[0] && LIVES_IS_SPIN_BUTTON(param->widgets[0])) {
3159 lives_rfx_t *rfx = (lives_rfx_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(param->widgets[0]), RFX_KEY);
3160 lives_signal_handlers_block_by_func(param->widgets[0], (livespointer)after_param_value_changed, (livespointer)rfx);
3161 lives_spin_button_set_range(LIVES_SPIN_BUTTON(param->widgets[0]), param->min, param->max);
3162 lives_spin_button_update(LIVES_SPIN_BUTTON(param->widgets[0]));
3163 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)int_value);
3164 lives_spin_button_update(LIVES_SPIN_BUTTON(param->widgets[0]));
3165 lives_signal_handlers_unblock_by_func(param->widgets[0], (livespointer)after_param_value_changed, (livespointer)rfx);
3166 }
3167 } else set_int_param(param->def, int_value);
3168 if (upd && param->widgets[0] && LIVES_IS_SPIN_BUTTON(param->widgets[0])) {
3169 set_int_param(param->value,
3170 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(param->widgets[0])));
3171 } else set_int_param(param->value, int_value);
3172 }
3173 break;
3174 case LIVES_PARAM_COLRGB24:
3175 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3176 red = atoi(tmp);
3177 lives_free(tmp);
3178 if (ABS(pnum) > maxlen) return 1;
3179 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3180 green = atoi(tmp);
3181 lives_free(tmp);
3182 if (ABS(pnum) > maxlen) return 2;
3183 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3184 blue = atoi(tmp);
3185 lives_free(tmp);
3186 if (param->change_blocked) break;
3187 if (upd) {
3188 if (param->widgets[0] && LIVES_IS_SPIN_BUTTON(param->widgets[0])) {
3189 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)red);
3190 }
3191 if (param->widgets[1] && LIVES_IS_SPIN_BUTTON(param->widgets[1])) {
3192 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[1]), (double)green);
3193 }
3194 if (param->widgets[2] && LIVES_IS_SPIN_BUTTON(param->widgets[2])) {
3195 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[2]), (double)blue);
3196 }
3197 } else set_colRGB24_param(param->def, red, green, blue);
3198 if (upd && param->widgets[0] && LIVES_IS_SPIN_BUTTON(param->widgets[0])
3199 && param->widgets[1] && LIVES_IS_SPIN_BUTTON(param->widgets[1])
3200 && param->widgets[2] && LIVES_IS_SPIN_BUTTON(param->widgets[2])) {
3201 set_colRGB24_param(param->value,
3202 lives_spin_button_get_value(LIVES_SPIN_BUTTON(param->widgets[0])),
3203 lives_spin_button_get_value(LIVES_SPIN_BUTTON(param->widgets[1])),
3204 lives_spin_button_get_value(LIVES_SPIN_BUTTON(param->widgets[2])));
3205 } else set_colRGB24_param(param->value, red, green, blue);
3206 break;
3207 case LIVES_PARAM_STRING:
3208 strval = reconstruct_string(plist, pnum, &offs);
3209 pnum += offs;
3210 if (param->change_blocked) {
3211 lives_free(strval);
3212 break;
3213 }
3214 if (upd) {
3215 if (param->widgets[0]) {
3216 if (LIVES_IS_TEXT_VIEW(param->widgets[0])) {
3217 lives_text_view_set_text(LIVES_TEXT_VIEW(param->widgets[0]), strval, -1);
3218 } else {
3219 lives_entry_set_text(LIVES_ENTRY(param->widgets[0]), strval);
3220
3221 }
3222 }
3223 } else {
3224 if (param->def) lives_free(param->def);
3225 param->def = (void *)lives_strdup(strval);
3226 }
3227 if (param->value) lives_free(param->value);
3228
3229 /// read value back from widget in case some callback changed the value
3230 if (upd && param->widgets[0] && (LIVES_IS_TEXT_VIEW(param->widgets[0])
3231 || LIVES_IS_ENTRY(param->widgets[0]))) {
3232 lives_free(strval);
3233 if (LIVES_IS_TEXT_VIEW(param->widgets[0])) {
3234 param->value = lives_strdup(lives_text_view_get_text(LIVES_TEXT_VIEW(param->widgets[0])));
3235 } else {
3236 param->value = lives_strdup(lives_entry_get_text(LIVES_ENTRY(param->widgets[0])));
3237 }
3238 } else {
3239 param->value = strval;
3240 }
3241 break;
3242 case LIVES_PARAM_STRING_LIST: {
3243 int int_value;
3244 tmp = lives_strdup((char *)lives_list_nth_data(plist, pnum++));
3245 int_value = atoi(tmp);
3246 lives_free(tmp);
3247 if (param->change_blocked) break;
3248 if (upd && param->widgets[0] && LIVES_IS_COMBO(param->widgets[0]) && int_value < lives_list_length(param->list))
3249 lives_combo_set_active_string(LIVES_COMBO(param->widgets[0]), (char *)lives_list_nth_data(param->list, int_value));
3250 if (!upd) set_int_param(param->def, int_value);
3251 if (upd && param->widgets[0] && LIVES_IS_COMBO(param->widgets[0])) {
3252 const char *txt = lives_combo_get_active_text(LIVES_COMBO(param->widgets[0]));
3253 int new_index = lives_list_strcmp_index(param->list, txt, TRUE);
3254 set_int_param(param->value, new_index);
3255 } else set_int_param(param->value, int_value);
3256 break;
3257 }
3258 default:
3259 break;
3260 }
3261 return pnum;
3262 }
3263
3264
do_onchange(LiVESWidgetObject * object,lives_rfx_t * rfx)3265 LiVESList *do_onchange(LiVESWidgetObject * object, lives_rfx_t *rfx) {
3266 LiVESList *retvals;
3267
3268 int which = LIVES_POINTER_TO_INT(lives_widget_object_get_data(object, PARAM_NUMBER_KEY));
3269 int width = 0, height = 0;
3270
3271 const char *handle = "";
3272
3273 char *plugdir;
3274 char *com, *tmp;
3275
3276 // weed plugins do not have triggers
3277 if (rfx->status == RFX_STATUS_WEED) return NULL;
3278
3279 if (which < 0) {
3280 // init
3281 switch (rfx->status) {
3282 case RFX_STATUS_BUILTIN:
3283 plugdir = lives_build_filename(prefs->lib_dir, PLUGIN_EXEC_DIR, PLUGIN_RENDERED_EFFECTS_BUILTIN, NULL);
3284 break;
3285 case RFX_STATUS_CUSTOM:
3286 plugdir = lives_build_filename(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_CUSTOM, NULL);
3287 break;
3288 case RFX_STATUS_TEST:
3289 plugdir = lives_build_filename(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_TEST, NULL);
3290 break;
3291 default:
3292 plugdir = lives_strdup_printf("%s", prefs->workdir);
3293 }
3294
3295 if (mainw->current_file > 0) {
3296 width = cfile->hsize;
3297 height = cfile->vsize;
3298 handle = cfile->handle;
3299 }
3300
3301 com = lives_strdup_printf("%s \"fxinit_%s\" \"%s\" \"%s\" %d %d %s", prefs->backend_sync, rfx->name, handle, plugdir,
3302 width, height, (tmp = param_marshall(rfx, TRUE)));
3303 retvals = plugin_request_by_space(NULL, NULL, com);
3304
3305 lives_free(tmp);
3306 lives_free(plugdir);
3307 } else {
3308 com = lives_strdup_printf("onchange_%d%s", which, param_marshall(rfx, TRUE));
3309 switch (rfx->status) {
3310 case RFX_STATUS_BUILTIN:
3311 retvals = plugin_request_by_space(PLUGIN_RENDERED_EFFECTS_BUILTIN, rfx->name, com);
3312 break;
3313 case RFX_STATUS_CUSTOM:
3314 retvals = plugin_request_by_space(PLUGIN_RENDERED_EFFECTS_CUSTOM, rfx->name, com);
3315 break;
3316 case RFX_STATUS_TEST:
3317 retvals = plugin_request_by_space(PLUGIN_RENDERED_EFFECTS_TEST, rfx->name, com);
3318 break;
3319 default:
3320 retvals = plugin_request_by_space(PLUGIN_RFX_SCRAP, rfx->name, com);
3321 }
3322 }
3323
3324 if (retvals) {
3325 param_demarshall(rfx, retvals, TRUE, which >= 0);
3326 } else {
3327 if (which <= 0 && mainw->error) {
3328 mainw->error = FALSE;
3329 do_error_dialog(lives_strdup_printf("\n\n%s\n\n", mainw->msg));
3330 }
3331 }
3332 lives_free(com);
3333
3334 return retvals;
3335 }
3336
3337
on_pwcolsel(LiVESButton * button,lives_rfx_t * rfx)3338 void on_pwcolsel(LiVESButton * button, lives_rfx_t *rfx) {
3339 LiVESWidgetColor selected;
3340
3341 int pnum = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(button), PARAM_NUMBER_KEY));
3342 int r, g, b;
3343
3344 lives_param_t *param = &rfx->params[pnum];
3345
3346 lives_color_button_get_color(LIVES_COLOR_BUTTON(button), &selected);
3347
3348 r = (int)((double)(selected.red + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
3349 g = (int)((double)(selected.green + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
3350 b = (int)((double)(selected.blue + LIVES_WIDGET_COLOR_SCALE_255(0.5)) / (double)LIVES_WIDGET_COLOR_SCALE_255(1.));
3351
3352 set_colRGB24_param(param->value, r, g, b);
3353
3354 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[0]), (double)r);
3355 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[1]), (double)g);
3356 lives_spin_button_set_value(LIVES_SPIN_BUTTON(param->widgets[2]), (double)b);
3357 lives_color_button_set_color(LIVES_COLOR_BUTTON(param->widgets[4]), &selected);
3358 }
3359
3360
update_visual_params(lives_rfx_t * rfx,boolean update_hidden)3361 void update_visual_params(lives_rfx_t *rfx, boolean update_hidden) {
3362 // update parameters visually from an rfx object
3363 LiVESList *list;
3364
3365 weed_plant_t **in_params, *in_param;
3366 weed_plant_t *inst = (weed_plant_t *)rfx->source;
3367 weed_plant_t *paramtmpl;
3368
3369 int *colsi, *colsis, *valis;
3370 int *maxis = NULL, *minis = NULL;
3371
3372 double *colsd, *colsds, *valds;
3373 double *maxds = NULL, *minds = NULL;
3374
3375 double red_maxd, green_maxd, blue_maxd;
3376 double red_mind, green_mind, blue_mind;
3377 double vald, mind, maxd;
3378
3379 char **valss;
3380
3381 char *vals, *pattern;
3382 char *tmp, *tmp2;
3383
3384 int cspace;
3385 int error;
3386 int num_params = 0;
3387 int param_type;
3388 int vali, mini, maxi;
3389
3390 int red_max, green_max, blue_max;
3391 int red_min, green_min, blue_min;
3392
3393 int index, numvals;
3394 int key = -1;
3395
3396 register int i, j;
3397
3398 if (rfx->source_type != LIVES_RFX_SOURCE_WEED) return;
3399
3400 in_params = weed_instance_get_in_params(inst, &num_params);
3401 if (num_params == 0) return;
3402
3403 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, &error);
3404
3405 for (i = 0; i < num_params; i++) {
3406 if (!is_hidden_param(inst, i) || (!(rfx->params[i].hidden & HIDDEN_STRUCTURAL) && update_hidden)) {
3407 // by default we dont update hidden or reinit params
3408 in_param = in_params[i];
3409 paramtmpl = weed_param_get_template(in_param);
3410 param_type = weed_paramtmpl_get_type(paramtmpl);
3411 list = NULL;
3412
3413 // assume index is 0, unless we are a framedraw multi parameter
3414 // most of the time this will be ok, as other such multivalued parameters should be hidden
3415 index = 0;
3416
3417 if (mainw->multitrack && is_perchannel_multi(rfx, i)) {
3418 index = mainw->multitrack->track_index;
3419 }
3420
3421 filter_mutex_lock(key);
3422
3423 numvals = weed_leaf_num_elements(in_param, WEED_LEAF_VALUE);
3424
3425 if (param_type != WEED_PARAM_COLOR && index >= numvals) {
3426 fill_param_vals_to(in_param, paramtmpl, index);
3427 numvals = index + 1;
3428 }
3429
3430 switch (param_type) {
3431 case WEED_PARAM_INTEGER:
3432 valis = weed_get_int_array(in_param, WEED_LEAF_VALUE, &error);
3433 vali = valis[index];
3434 lives_free(valis);
3435
3436 mini = weed_get_int_value(paramtmpl, WEED_LEAF_MIN, &error);
3437 maxi = weed_get_int_value(paramtmpl, WEED_LEAF_MAX, &error);
3438
3439 list = lives_list_append(list, lives_strdup_printf("%d", vali));
3440 list = lives_list_append(list, lives_strdup_printf("%d", mini));
3441 list = lives_list_append(list, lives_strdup_printf("%d", maxi));
3442 set_param_from_list(list, &rfx->params[i], 0, TRUE, TRUE);
3443 lives_list_free_all(&list);
3444
3445 break;
3446 case WEED_PARAM_FLOAT:
3447 valds = weed_get_double_array(in_param, WEED_LEAF_VALUE, &error);
3448 vald = valds[index];
3449 lives_free(valds);
3450
3451 mind = weed_get_double_value(paramtmpl, WEED_LEAF_MIN, &error);
3452 maxd = weed_get_double_value(paramtmpl, WEED_LEAF_MAX, &error);
3453
3454 pattern = lives_strdup("%.2f");
3455
3456 if (weed_plant_has_leaf(paramtmpl, WEED_LEAF_GUI)) {
3457 weed_plant_t *gui = weed_get_plantptr_value(paramtmpl, WEED_LEAF_GUI, &error);
3458 if (weed_plant_has_leaf(gui, WEED_LEAF_DECIMALS)) {
3459 int dp = weed_get_int_value(gui, WEED_LEAF_DECIMALS, &error);
3460 lives_free(pattern);
3461 pattern = lives_strdup_printf("%%.%df", dp);
3462 }
3463 }
3464
3465 list = lives_list_append(list, lives_strdup_printf(pattern, vald));
3466 list = lives_list_append(list, lives_strdup_printf(pattern, mind));
3467 list = lives_list_append(list, lives_strdup_printf(pattern, maxd));
3468
3469 lives_free(pattern);
3470
3471 set_param_from_list(list, &rfx->params[i], 0, TRUE, TRUE);
3472 lives_list_free_all(&list);
3473
3474 break;
3475 case WEED_PARAM_SWITCH:
3476 valis = weed_get_boolean_array(in_param, WEED_LEAF_VALUE, &error);
3477 vali = valis[index];
3478 lives_free(valis);
3479
3480 list = lives_list_append(list, lives_strdup_printf("%d", vali));
3481 set_param_from_list(list, &rfx->params[i], 0, FALSE, TRUE);
3482 lives_list_free_all(&list);
3483
3484 break;
3485 case WEED_PARAM_TEXT:
3486 valss = weed_get_string_array(in_param, WEED_LEAF_VALUE, &error);
3487 vals = valss[index];
3488 list = lives_list_append(list, lives_strdup_printf("\"%s\"", (tmp = U82L(tmp2 = subst(vals, "\"", "\\\"")))));
3489 lives_free(tmp);
3490 lives_free(tmp2);
3491 set_param_from_list(list, &rfx->params[i], 0, FALSE, TRUE);
3492 for (j = 0; j < numvals; j++) {
3493 lives_free(valss[j]);
3494 }
3495 lives_free(valss);
3496 lives_list_free_all(&list);
3497
3498 break;
3499 case WEED_PARAM_COLOR:
3500 cspace = weed_get_int_value(paramtmpl, WEED_LEAF_COLORSPACE, &error);
3501 switch (cspace) {
3502 case WEED_COLORSPACE_RGB:
3503 numvals = weed_leaf_num_elements(in_param, WEED_LEAF_VALUE);
3504 if (index * 3 >= numvals) fill_param_vals_to(in_param, paramtmpl, index);
3505
3506 if (weed_leaf_seed_type(paramtmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT) {
3507 colsis = weed_get_int_array(in_param, WEED_LEAF_VALUE, &error);
3508 colsi = &colsis[3 * index];
3509
3510 if (weed_leaf_num_elements(paramtmpl, WEED_LEAF_MAX) == 1) {
3511 red_max = green_max = blue_max = weed_get_int_value(paramtmpl, WEED_LEAF_MAX, &error);
3512 } else {
3513 maxis = weed_get_int_array(paramtmpl, WEED_LEAF_MAX, &error);
3514 red_max = maxis[0];
3515 green_max = maxis[1];
3516 blue_max = maxis[2];
3517 }
3518 if (weed_leaf_num_elements(paramtmpl, WEED_LEAF_MIN) == 1) {
3519 red_min = green_min = blue_min = weed_get_int_value(paramtmpl, WEED_LEAF_MIN, &error);
3520 } else {
3521 minis = weed_get_int_array(paramtmpl, WEED_LEAF_MIN, &error);
3522 red_min = minis[0];
3523 green_min = minis[1];
3524 blue_min = minis[2];
3525 }
3526
3527 colsi[0] = (int)((double)(colsi[0] - red_min) / (double)(red_max - red_min) * 255. + .5);
3528 colsi[1] = (int)((double)(colsi[1] - green_min) / (double)(green_max - green_min) * 255. + .5);
3529 colsi[2] = (int)((double)(colsi[2] - blue_min) / (double)(blue_max - blue_min) * 255. + .5);
3530
3531 if (colsi[0] < red_min) colsi[0] = red_min;
3532 if (colsi[1] < green_min) colsi[1] = green_min;
3533 if (colsi[2] < blue_min) colsi[2] = blue_min;
3534 if (colsi[0] > red_max) colsi[0] = red_max;
3535 if (colsi[1] > green_max) colsi[1] = green_max;
3536 if (colsi[2] > blue_max) colsi[2] = blue_max;
3537
3538 list = lives_list_append(list, lives_strdup_printf("%d", colsi[0]));
3539 list = lives_list_append(list, lives_strdup_printf("%d", colsi[1]));
3540 list = lives_list_append(list, lives_strdup_printf("%d", colsi[2]));
3541
3542 set_param_from_list(list, &rfx->params[i], 0, FALSE, TRUE);
3543
3544 lives_list_free_all(&list);
3545 lives_free(colsis);
3546 if (maxis) lives_free(maxis);
3547 if (minis) lives_free(minis);
3548 } else {
3549 colsds = weed_get_double_array(in_param, WEED_LEAF_VALUE, &error);
3550 colsd = &colsds[3 * index];
3551 if (weed_leaf_num_elements(paramtmpl, WEED_LEAF_MAX) == 1) {
3552 red_maxd = green_maxd = blue_maxd = weed_get_double_value(paramtmpl, WEED_LEAF_MAX, &error);
3553 } else {
3554 maxds = weed_get_double_array(paramtmpl, WEED_LEAF_MAX, &error);
3555 red_maxd = maxds[0];
3556 green_maxd = maxds[1];
3557 blue_maxd = maxds[2];
3558 }
3559 if (weed_leaf_num_elements(paramtmpl, WEED_LEAF_MIN) == 1) {
3560 red_mind = green_mind = blue_mind = weed_get_double_value(paramtmpl, WEED_LEAF_MIN, &error);
3561 } else {
3562 minds = weed_get_double_array(paramtmpl, WEED_LEAF_MIN, &error);
3563 red_mind = minds[0];
3564 green_mind = minds[1];
3565 blue_mind = minds[2];
3566 }
3567 colsd[0] = (colsd[0] - red_mind) / (red_maxd - red_mind) * 255. + .5;
3568 colsd[1] = (colsd[1] - green_mind) / (green_maxd - green_mind) * 255. + .5;
3569 colsd[2] = (colsd[2] - blue_mind) / (blue_maxd - blue_mind) * 255. + .5;
3570
3571 if (colsd[0] < red_mind) colsd[0] = red_mind;
3572 if (colsd[1] < green_mind) colsd[1] = green_mind;
3573 if (colsd[2] < blue_mind) colsd[2] = blue_mind;
3574 if (colsd[0] > red_maxd) colsd[0] = red_maxd;
3575 if (colsd[1] > green_maxd) colsd[1] = green_maxd;
3576 if (colsd[2] > blue_maxd) colsd[2] = blue_maxd;
3577
3578 list = lives_list_append(list, lives_strdup_printf("%.2f", colsd[0]));
3579 list = lives_list_append(list, lives_strdup_printf("%.2f", colsd[1]));
3580 list = lives_list_append(list, lives_strdup_printf("%.2f", colsd[2]));
3581 set_param_from_list(list, &rfx->params[i], 0, FALSE, TRUE);
3582
3583 lives_list_free_all(&list);
3584 lives_free(colsds);
3585 if (maxds) lives_free(maxds);
3586 if (minds) lives_free(minds);
3587 }
3588 break;
3589 // TODO - other color spaces, e.g. RGBA24
3590 }
3591 break;
3592 } // hint
3593 }
3594 filter_mutex_unlock(key);
3595 }
3596 lives_free(in_params);
3597 }
3598