1 // rfx-builder.c
2 // LiVES
3 // (c) G. Finch 2004 - 2020 <salsaman+lives@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING or www.gnu.org for licensing details
6
7 #include <errno.h>
8
9 #include "main.h"
10 #include "rfx-builder.h"
11 #include "interface.h"
12 #include "paramwindow.h"
13 #include "effects.h"
14
15 #define BG_LOAD
16
17 static LiVESWidget *make_param_dialog(int pnum, rfx_build_window_t *rfxbuilder);
18 static LiVESWidget *make_param_window_dialog(int hnum, rfx_build_window_t *rfxbuilder);
19 static LiVESWidget *make_trigger_dialog(int tnum, rfx_build_window_t *rfxbuilder);
20 static void on_table_add_row(LiVESButton *, livespointer rfxbuilder);
21 static void on_table_edit_row(LiVESButton *, livespointer rfxbuilder);
22 static void on_table_swap_row(LiVESButton *, livespointer rfxbuilder);
23 static void on_table_delete_row(LiVESButton *, livespointer rfxbuilder);
24
25 static void param_set_from_dialog(lives_param_t *copy_param, rfx_build_window_t *rfxbuilder);
26
27 static void after_param_dp_changed(LiVESSpinButton *, livespointer rfxbuilder);
28 static void after_param_min_changed(LiVESSpinButton *, livespointer rfxbuilder);
29 static void after_param_max_changed(LiVESSpinButton *, livespointer rfxbuilder);
30 static void after_param_def_changed(LiVESSpinButton *, livespointer rfxbuilder);
31 static void after_rfxbuilder_type_toggled(LiVESToggleButton *, livespointer rfxbuilder);
32 static void on_param_type_changed(LiVESCombo *, livespointer rfxbuilder);
33 static void on_paramw_kw_changed(LiVESCombo *, livespointer rfxbuilder);
34 static void on_paramw_sp_changed(LiVESCombo *, livespointer rfxbuilder);
35 static void on_paramw_spsub_changed(LiVESCombo *, livespointer rfxbuilder);
36 static void populate_script_combo(LiVESCombo *script_combo, lives_rfx_status_t status);
37 static void on_script_status_changed(LiVESCombo *status_combo, livespointer script_combo);
38
39 // builder window widgets/callbacks
40 static rfx_build_window_t *make_rfx_build_window(const char *in_script_name, lives_rfx_status_t in_status);
41 static void on_rfxbuilder_ok(LiVESButton *, livespointer);
42 static void on_rfxbuilder_cancel(LiVESButton *, livespointer);
43 static void rfxbuilder_destroy(rfx_build_window_t *);
44 static void on_list_table_clicked(LiVESButton *, livespointer rfxbuilder);
45 static void on_requirements_ok(LiVESButton *, livespointer rfxbuilder);
46 static void on_requirements_cancel(LiVESButton *, livespointer);
47 static void on_properties_clicked(LiVESButton *, livespointer rfxbuilder);
48 static void on_properties_ok(LiVESButton *, livespointer rfxbuilder);
49 static void on_params_ok(LiVESButton *, livespointer rfxbuilder);
50 static void on_params_cancel(LiVESButton *, livespointer);
51 static void on_param_window_ok(LiVESButton *, livespointer rfxbuilder);
52 static void on_param_window_cancel(LiVESButton *, livespointer);
53 static void on_code_clicked(LiVESButton *, livespointer rfxbuilder);
54 static void on_code_ok(LiVESButton *, livespointer rfxbuilder);
55 static void on_triggers_ok(LiVESButton *, livespointer rfxbuilder);
56 static void on_triggers_cancel(LiVESButton *, livespointer);
57
58 static LiVESWidget *copy_script_okbutton;
59
60 static void table_select_row(rfx_build_window_t *rfxbuilder, int row);
61
on_new_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)62 void on_new_rfx_activate(LiVESMenuItem *menuitem, livespointer user_data) {
63 rfx_build_window_t *rfxbuilder;
64
65 if (!check_builder_programs()) return;
66 rfxbuilder = make_rfx_build_window(NULL, RFX_STATUS_ANY);
67 lives_widget_show(rfxbuilder->dialog);
68 }
69
70
on_edit_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)71 void on_edit_rfx_activate(LiVESMenuItem *menuitem, livespointer user_data) {
72 rfx_build_window_t *rfxbuilder;
73 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
74 char *script_name;
75
76 if (!check_builder_programs()) return;
77 if (status != RFX_STATUS_TEST) return; // we only edit test effects currently
78
79 if ((script_name = prompt_for_script_name(NULL, RFX_STATUS_TEST)) == NULL) return;
80 if (!strlen(script_name)) {
81 lives_free(script_name);
82 return;
83 }
84 if ((rfxbuilder = make_rfx_build_window(script_name, RFX_STATUS_TEST)) == NULL) {
85 lives_free(script_name);
86 return; // script not loaded
87 }
88 lives_free(script_name);
89 rfxbuilder->mode = RFX_BUILDER_MODE_EDIT;
90 rfxbuilder->oname = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->name_entry)));
91 lives_widget_show(rfxbuilder->dialog);
92 }
93
94
on_copy_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)95 void on_copy_rfx_activate(LiVESMenuItem *menuitem, livespointer user_data) {
96 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
97
98 if (!check_builder_programs()) return;
99 if (status != RFX_STATUS_TEST) return; // we only copy to test effects currently
100
101 // prompt_for_script_name will create our builder window from the input
102 // script and set the name : note, we have no rfxbuilder reference
103
104 // TODO - use RFXBUILDER_MODE-*
105 prompt_for_script_name(NULL, RFX_STATUS_COPY);
106 }
107
108
on_rename_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)109 void on_rename_rfx_activate(LiVESMenuItem *menuitem, livespointer user_data) {
110 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
111
112 if (status != RFX_STATUS_TEST) return; // we only copy to test effects currently
113
114 prompt_for_script_name(NULL, RFX_STATUS_RENAME);
115 }
116
117
make_rfx_build_window(const char * script_name,lives_rfx_status_t status)118 rfx_build_window_t *make_rfx_build_window(const char *script_name, lives_rfx_status_t status) {
119 // TODO - set mnemonic widgets for entries
120
121 LiVESWidget *dialog_vbox;
122 LiVESWidget *hbox;
123 LiVESWidget *layout;
124 LiVESWidget *label;
125 LiVESWidget *okbutton;
126 LiVESWidget *cancelbutton;
127 LiVESWidget *scrollw;
128 LiVESWidget *top_vbox;
129
130 LiVESSList *radiobutton_type_group = NULL;
131 LiVESList *langc = NULL;
132
133 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)lives_malloc(sizeof(rfx_build_window_t));
134
135 LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
136
137 int winsize_h, winsize_v;
138
139 char *tmp, *tmp2, *title, *string;
140
141 rfxbuilder->rfx_version = lives_strdup(RFX_VERSION);
142
143 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT1; // the default
144
145 rfxbuilder->num_reqs = 0;
146 rfxbuilder->num_params = 0;
147 rfxbuilder->num_paramw_hints = 0;
148
149 rfxbuilder->num_triggers = 0;
150
151 rfxbuilder->has_init_trigger = FALSE;
152 rfxbuilder->props = 0;
153
154 rfxbuilder->plugin_version = 1;
155
156 rfxbuilder->pre_code = lives_strdup("");
157 rfxbuilder->loop_code = lives_strdup("");
158 rfxbuilder->post_code = lives_strdup("");
159
160 rfxbuilder->field_delim = lives_strdup("|");
161
162 rfxbuilder->script_name = NULL; // use default name.script
163 rfxbuilder->oname = NULL;
164
165 rfxbuilder->mode = RFX_BUILDER_MODE_NEW;
166
167 rfxbuilder->table_swap_row1 = -1;
168
169 /////////////////////////////////////////////////////////
170
171 if (!script_name) {
172 title = (_("New Test RFX"));
173 } else {
174 title = (_("Edit Test RFX"));
175 }
176
177 winsize_h = (PREF_RFXDIALOG_W < GUI_SCREEN_WIDTH - SCR_WIDTH_SAFETY / 5.) ? PREF_RFXDIALOG_W : GUI_SCREEN_WIDTH -
178 SCR_WIDTH_SAFETY / 5.;
179
180 winsize_v = (PREF_RFXDIALOG_H < GUI_SCREEN_HEIGHT - SCR_HEIGHT_SAFETY / 2.) ? PREF_RFXDIALOG_H : GUI_SCREEN_HEIGHT -
181 SCR_HEIGHT_SAFETY / 2.;
182
183 rfxbuilder->dialog = lives_standard_dialog_new(title, FALSE, winsize_h, winsize_v);
184 lives_free(title);
185
186 lives_window_add_accel_group(LIVES_WINDOW(rfxbuilder->dialog), accel_group);
187
188 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(rfxbuilder->dialog));
189 lives_container_set_border_width(LIVES_CONTAINER(lives_widget_get_parent(dialog_vbox)), widget_opts.border_width >> 1);
190
191 top_vbox = lives_vbox_new(FALSE, 0);
192
193 scrollw = lives_standard_scrolled_window_new(winsize_h, winsize_v, top_vbox);
194
195 lives_box_pack_start(LIVES_BOX(dialog_vbox), scrollw, TRUE, TRUE, 0);
196
197 // types
198 hbox = lives_hbox_new(FALSE, 0);
199 lives_box_pack_start(LIVES_BOX(top_vbox), hbox, TRUE, TRUE, 0);
200
201 label = lives_standard_label_new(_("Type:"));
202 lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, widget_opts.packing_width);
203
204 string = lives_fx_cat_to_text(LIVES_FX_CAT_EFFECT, FALSE);
205 rfxbuilder->type_effect1_radiobutton = lives_standard_radio_button_new(string, &radiobutton_type_group, LIVES_BOX(hbox), NULL);
206 lives_free(string);
207
208 string = lives_fx_cat_to_text(LIVES_FX_CAT_TRANSITION, FALSE);
209 rfxbuilder->type_effect2_radiobutton = lives_standard_radio_button_new(string, &radiobutton_type_group, LIVES_BOX(hbox), NULL);
210 lives_free(string);
211
212 string = lives_fx_cat_to_text(LIVES_FX_CAT_VIDEO_GENERATOR, FALSE);
213 rfxbuilder->type_effect0_radiobutton = lives_standard_radio_button_new(string, &radiobutton_type_group, LIVES_BOX(hbox), NULL);
214 lives_free(string);
215
216 rfxbuilder->type_tool_radiobutton = lives_standard_radio_button_new(_("tool"), &radiobutton_type_group, LIVES_BOX(hbox), NULL);
217 lives_widget_show(label);
218
219 rfxbuilder->type_utility_radiobutton = lives_standard_radio_button_new(_("utility"), &radiobutton_type_group, LIVES_BOX(hbox),
220 NULL);
221
222 layout = lives_layout_new(LIVES_BOX(top_vbox));
223 hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
224
225 // name
226
227 rfxbuilder->name_entry = lives_standard_entry_new((tmp = (_("Name: "))), NULL, -1, -1,
228 LIVES_BOX(hbox), (tmp2 = (_("The name of the plugin. No spaces allowed."))));
229 lives_free(tmp); lives_free(tmp2);
230
231 // version
232 hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
233
234 rfxbuilder->spinbutton_version = lives_standard_spin_button_new((tmp = (_("Version: "))),
235 rfxbuilder->plugin_version, rfxbuilder->plugin_version, 1000000., 1., 1., 0,
236 LIVES_BOX(hbox), (tmp2 = (_("The script version."))));
237 lives_free(tmp); lives_free(tmp2);
238
239 // author
240 hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
241
242 rfxbuilder->author_entry = lives_standard_entry_new((tmp = (_(" Author: "))), NULL, -1, -1,
243 LIVES_BOX(hbox), (tmp2 = (_("The script author."))));
244 lives_free(tmp); lives_free(tmp2);
245
246 // URL
247 hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
248
249 rfxbuilder->url_entry = lives_standard_entry_new((tmp = (_(" URL (optional): "))), NULL, -1, -1,
250 LIVES_BOX(hbox), (tmp2 = (_("URL for the plugin maintainer."))));
251 lives_free(tmp); lives_free(tmp2);
252
253 // menu entry
254 hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
255
256 rfxbuilder->menu_text_entry = lives_standard_entry_new((tmp = (_("Menu text: "))), NULL, -1, -1,
257 LIVES_BOX(hbox), (tmp2 = (_("The text to show in the menu."))));
258 lives_free(tmp); lives_free(tmp2);
259
260 rfxbuilder->action_desc_hsep = add_hsep_to_box(LIVES_BOX(top_vbox));
261
262 // action description
263
264 rfxbuilder->action_desc_hbox = lives_hbox_new(FALSE, 0);
265 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->action_desc_hbox, FALSE, FALSE, widget_opts.packing_height);
266
267 rfxbuilder->action_desc_entry = lives_standard_entry_new((tmp = (_("Action description: "))), NULL, -1, -1,
268 LIVES_BOX(rfxbuilder->action_desc_hbox),
269 (tmp2 = (_("Describe what the plugin is doing. E.g. \"Edge detecting\""))));
270 lives_free(tmp); lives_free(tmp2);
271
272 rfxbuilder->spinbutton_min_frames = lives_standard_spin_button_new((tmp = (_("Minimum frames:"))),
273 1., 1., 1000., 1., 1., 0, LIVES_BOX(top_vbox),
274 (tmp2 = (_("Minimum number of frames this effect/tool can be applied to. Normally 1."))));
275 lives_free(tmp); lives_free(tmp2);
276 rfxbuilder->min_frames_label = widget_opts.last_label;
277
278 // requirements
279
280 add_hsep_to_box(LIVES_BOX(top_vbox));
281
282 rfxbuilder->requirements_button = lives_standard_button_new_with_label(_("_Requirements..."),
283 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
284
285 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->requirements_button, TRUE, TRUE, 0);
286 lives_widget_set_tooltip_text(rfxbuilder->requirements_button,
287 (_("Enter any binaries required by the plugin.")));
288
289 add_hsep_to_box(LIVES_BOX(top_vbox));
290
291 rfxbuilder->properties_button = lives_standard_button_new_with_label(_("_Properties..."),
292 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
293
294 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->properties_button, TRUE, TRUE, 0);
295 lives_widget_set_tooltip_text(rfxbuilder->properties_button,
296 (_("Set properties for the plugin. Optional.")));
297
298 add_hsep_to_box(LIVES_BOX(top_vbox));
299
300 rfxbuilder->params_button = lives_standard_button_new_with_label(_("_Parameters..."),
301 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
302
303 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->params_button, TRUE, TRUE, 0);
304 lives_widget_set_tooltip_text(rfxbuilder->params_button,
305 (_("Set up parameters used in pre/loop/post/trigger code. Optional.")));
306
307 add_hsep_to_box(LIVES_BOX(top_vbox));
308
309 rfxbuilder->param_window_button = lives_standard_button_new_with_label(_("Parameter _Window Hints..."),
310 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
311
312 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->param_window_button, TRUE, TRUE, 0);
313 lives_widget_set_tooltip_text(rfxbuilder->param_window_button,
314 (_("Set hints about how to lay out the parameter window. Optional.")));
315
316 add_hsep_to_box(LIVES_BOX(top_vbox));
317
318 langc = lives_list_append(langc, (livespointer)"0xF0 - LiVES-Perl");
319
320 rfxbuilder->langc_combo = lives_standard_combo_new((tmp = (_("_Language code:"))), langc, LIVES_BOX(top_vbox),
321 (tmp2 = (_("Language for pre/loop/post/triggers. Optional."))));
322
323 lives_free(tmp); lives_free(tmp2);
324 lives_list_free(langc);
325
326 add_hsep_to_box(LIVES_BOX(top_vbox));
327
328 rfxbuilder->pre_button = lives_standard_button_new_with_label(_("_Pre loop code..."),
329 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
330
331 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->pre_button, TRUE, TRUE, 0);
332 lives_widget_set_tooltip_text(rfxbuilder->pre_button,
333 (_("Code to be executed before the loop. Optional.")));
334
335 add_hsep_to_box(LIVES_BOX(top_vbox));
336
337 rfxbuilder->loop_button = lives_standard_button_new_with_label(_("_Loop code..."),
338 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
339
340 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->loop_button, TRUE, TRUE, 0);
341 lives_widget_set_tooltip_text(rfxbuilder->loop_button,
342 (_("Loop code to be applied to each frame.")));
343
344 add_hsep_to_box(LIVES_BOX(top_vbox));
345
346 rfxbuilder->post_button = lives_standard_button_new_with_label(_("_Post loop code..."),
347 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
348
349 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->post_button, TRUE, TRUE, 0);
350 lives_widget_set_tooltip_text(rfxbuilder->post_button,
351 (_("Code to be executed after the loop. Optional.")));
352
353 add_hsep_to_box(LIVES_BOX(top_vbox));
354
355 rfxbuilder->trigger_button = lives_standard_button_new_with_label(_("_Trigger code..."),
356 DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
357
358 lives_box_pack_start(LIVES_BOX(top_vbox), rfxbuilder->trigger_button, TRUE, TRUE, 0);
359 lives_widget_set_tooltip_text(rfxbuilder->trigger_button,
360 (_("Set trigger code for when the parameter window is shown, or when a parameter is changed. "
361 "Optional (except for Utilities).")));
362
363 cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(rfxbuilder->dialog), LIVES_STOCK_CANCEL, NULL,
364 LIVES_RESPONSE_CANCEL);
365
366 okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(rfxbuilder->dialog), LIVES_STOCK_OK, NULL,
367 LIVES_RESPONSE_OK);
368
369 lives_button_grab_default_special(okbutton);
370
371 lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
372 LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
373
374 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
375 LIVES_GUI_CALLBACK(on_rfxbuilder_ok), (livespointer)rfxbuilder);
376
377 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
378 LIVES_GUI_CALLBACK(on_rfxbuilder_cancel), (livespointer)rfxbuilder);
379
380 lives_signal_sync_connect(rfxbuilder->requirements_button, LIVES_WIDGET_CLICKED_SIGNAL,
381 LIVES_GUI_CALLBACK(on_list_table_clicked), (livespointer)rfxbuilder);
382
383 lives_signal_sync_connect(rfxbuilder->properties_button, LIVES_WIDGET_CLICKED_SIGNAL,
384 LIVES_GUI_CALLBACK(on_properties_clicked), (livespointer)rfxbuilder);
385
386 lives_signal_sync_connect(rfxbuilder->params_button, LIVES_WIDGET_CLICKED_SIGNAL,
387 LIVES_GUI_CALLBACK(on_list_table_clicked), (livespointer)rfxbuilder);
388
389 lives_signal_sync_connect(rfxbuilder->param_window_button, LIVES_WIDGET_CLICKED_SIGNAL,
390 LIVES_GUI_CALLBACK(on_list_table_clicked), (livespointer)rfxbuilder);
391
392 lives_signal_sync_connect(rfxbuilder->trigger_button, LIVES_WIDGET_CLICKED_SIGNAL,
393 LIVES_GUI_CALLBACK(on_list_table_clicked), (livespointer)rfxbuilder);
394
395 lives_signal_sync_connect(rfxbuilder->pre_button, LIVES_WIDGET_CLICKED_SIGNAL,
396 LIVES_GUI_CALLBACK(on_code_clicked), (livespointer)rfxbuilder);
397
398 lives_signal_sync_connect(rfxbuilder->loop_button, LIVES_WIDGET_CLICKED_SIGNAL,
399 LIVES_GUI_CALLBACK(on_code_clicked), (livespointer)rfxbuilder);
400
401 lives_signal_sync_connect(rfxbuilder->post_button, LIVES_WIDGET_CLICKED_SIGNAL,
402 LIVES_GUI_CALLBACK(on_code_clicked), (livespointer)rfxbuilder);
403
404 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->type_effect1_radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
405 LIVES_GUI_CALLBACK(after_rfxbuilder_type_toggled), (livespointer)rfxbuilder);
406
407 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->type_effect2_radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
408 LIVES_GUI_CALLBACK(after_rfxbuilder_type_toggled), (livespointer)rfxbuilder);
409
410 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->type_effect0_radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
411 LIVES_GUI_CALLBACK(after_rfxbuilder_type_toggled), (livespointer)rfxbuilder);
412
413 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->type_tool_radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
414 LIVES_GUI_CALLBACK(after_rfxbuilder_type_toggled), (livespointer)rfxbuilder);
415
416 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->type_utility_radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
417 LIVES_GUI_CALLBACK(after_rfxbuilder_type_toggled), (livespointer)rfxbuilder);
418
419 // edit mode
420 if (script_name) {
421 // we assume the name is valid
422 char *script_file;
423
424 switch (status) {
425 case RFX_STATUS_CUSTOM:
426 script_file = lives_build_filename(prefs->config_datadir,
427 PLUGIN_RENDERED_EFFECTS_CUSTOM_SCRIPTS, script_name, NULL);
428 break;
429 case RFX_STATUS_BUILTIN:
430 script_file = lives_build_filename(prefs->prefix_dir, PLUGIN_SCRIPTS_DIR,
431 PLUGIN_RENDERED_EFFECTS_BUILTIN_SCRIPTS, script_name, NULL);
432 break;
433 default:
434 script_file = lives_build_filename(prefs->config_datadir,
435 PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, script_name, NULL);
436 break;
437 }
438 if (!script_to_rfxbuilder(rfxbuilder, script_file)) {
439 char *msg = lives_strdup_printf(_("\n\nUnable to parse the script file:\n%s\n%s\n"), script_file, mainw->msg);
440 // must use blocking error dialogs as the scriptname window is modal
441 do_error_dialog(msg);
442 lives_free(msg);
443 rfxbuilder_destroy(rfxbuilder);
444 lives_free(script_file);
445 return NULL;
446 }
447 lives_free(script_file);
448 switch (rfxbuilder->type) {
449 case RFX_BUILD_TYPE_TOOL:
450 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->type_tool_radiobutton), TRUE);
451 break;
452 case RFX_BUILD_TYPE_EFFECT0:
453 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->type_effect0_radiobutton), TRUE);
454 break;
455 case RFX_BUILD_TYPE_UTILITY:
456 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->type_utility_radiobutton), TRUE);
457 break;
458 case RFX_BUILD_TYPE_EFFECT2:
459 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->type_effect2_radiobutton), TRUE);
460 break;
461 default:
462 break;
463 }
464 } else {
465 lives_widget_grab_focus(rfxbuilder->name_entry);
466 }
467
468 lives_widget_show_all(rfxbuilder->dialog);
469
470 return rfxbuilder;
471 }
472
473
after_rfxbuilder_type_toggled(LiVESToggleButton * togglebutton,livespointer user_data)474 void after_rfxbuilder_type_toggled(LiVESToggleButton *togglebutton, livespointer user_data) {
475 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
476
477 lives_widget_set_sensitive(rfxbuilder->pre_button, TRUE);
478 lives_widget_set_sensitive(rfxbuilder->loop_button, TRUE);
479 lives_widget_set_sensitive(rfxbuilder->post_button, TRUE);
480 lives_widget_set_sensitive(rfxbuilder->requirements_button, TRUE);
481 lives_widget_set_sensitive(rfxbuilder->properties_button, TRUE);
482 lives_widget_show(rfxbuilder->spinbutton_min_frames);
483 lives_widget_show(rfxbuilder->min_frames_label);
484 lives_widget_show(rfxbuilder->action_desc_hbox);
485 lives_widget_show(rfxbuilder->action_desc_hsep);
486
487 if (togglebutton == LIVES_TOGGLE_BUTTON(rfxbuilder->type_effect1_radiobutton)) {
488 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT1;
489 } else if (togglebutton == LIVES_TOGGLE_BUTTON(rfxbuilder->type_effect2_radiobutton)) {
490 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT2;
491 lives_widget_set_sensitive(rfxbuilder->properties_button, FALSE);
492 } else if (togglebutton == LIVES_TOGGLE_BUTTON(rfxbuilder->type_effect0_radiobutton)) {
493 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT0;
494 lives_widget_hide(rfxbuilder->spinbutton_min_frames);
495 lives_widget_hide(rfxbuilder->min_frames_label);
496 } else if (togglebutton == LIVES_TOGGLE_BUTTON(rfxbuilder->type_tool_radiobutton)) {
497 rfxbuilder->type = RFX_BUILD_TYPE_TOOL;
498 lives_widget_hide(rfxbuilder->spinbutton_min_frames);
499 lives_widget_set_sensitive(rfxbuilder->properties_button, FALSE);
500 lives_widget_hide(rfxbuilder->min_frames_label);
501 } else if (togglebutton == LIVES_TOGGLE_BUTTON(rfxbuilder->type_utility_radiobutton)) {
502 rfxbuilder->type = RFX_BUILD_TYPE_UTILITY;
503 lives_widget_hide(rfxbuilder->spinbutton_min_frames);
504 lives_widget_set_sensitive(rfxbuilder->properties_button, FALSE);
505 lives_widget_set_sensitive(rfxbuilder->requirements_button, FALSE);
506 lives_widget_set_sensitive(rfxbuilder->pre_button, FALSE);
507 lives_widget_set_sensitive(rfxbuilder->loop_button, FALSE);
508 lives_widget_set_sensitive(rfxbuilder->post_button, FALSE);
509 lives_widget_hide(rfxbuilder->min_frames_label);
510 lives_widget_hide(rfxbuilder->action_desc_hbox);
511 lives_widget_hide(rfxbuilder->action_desc_hsep);
512 }
513 }
514
515
on_list_table_clicked(LiVESButton * button,livespointer user_data)516 static void on_list_table_clicked(LiVESButton *button, livespointer user_data) {
517 LiVESWidget *dialog;
518 LiVESWidget *dialog_vbox;
519 LiVESWidget *hbox;
520 LiVESWidget *button_box;
521
522 // buttons
523 LiVESWidget *okbutton;
524 LiVESWidget *scrolledwindow;
525 LiVESWidget *cancelbutton;
526
527 LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
528
529 char *title = NULL;
530
531 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
532
533 register int i;
534
535 if (button == LIVES_BUTTON(rfxbuilder->requirements_button)) {
536 rfxbuilder->table_type = RFX_TABLE_TYPE_REQUIREMENTS;
537 } else if (button == LIVES_BUTTON(rfxbuilder->params_button)) {
538 rfxbuilder->table_type = RFX_TABLE_TYPE_PARAMS;
539 } else if (button == LIVES_BUTTON(rfxbuilder->param_window_button)) {
540 rfxbuilder->table_type = RFX_TABLE_TYPE_PARAM_WINDOW;
541 } else if (button == LIVES_BUTTON(rfxbuilder->trigger_button)) {
542 rfxbuilder->table_type = RFX_TABLE_TYPE_TRIGGERS;
543 }
544
545 if (rfxbuilder->table_type == RFX_TABLE_TYPE_REQUIREMENTS) {
546 title = (_("RFX Requirements"));
547 rfxbuilder->onum_reqs = rfxbuilder->num_reqs;
548 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAMS) {
549 title = (_("RFX Parameters"));
550 rfxbuilder->onum_params = rfxbuilder->num_params;
551 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAM_WINDOW) {
552 title = (_("RFX Parameter Window Hints"));
553 rfxbuilder->onum_paramw_hints = rfxbuilder->num_paramw_hints;
554 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_TRIGGERS) {
555 title = (_("RFX Triggers"));
556 rfxbuilder->onum_triggers = rfxbuilder->num_triggers;
557 }
558
559 dialog = lives_standard_dialog_new(title, FALSE, DEF_DIALOG_WIDTH, DEF_DIALOG_HEIGHT);
560 lives_signal_handlers_disconnect_by_func(dialog, LIVES_GUI_CALLBACK(return_true), NULL);
561
562 if (title) lives_free(title);
563
564 lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
565
566 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
567
568 // create table and add rows
569 rfxbuilder->table_rows = 0;
570
571 if (rfxbuilder->table_type == RFX_TABLE_TYPE_REQUIREMENTS) {
572 rfxbuilder->table = lives_table_new(rfxbuilder->num_reqs, 1, FALSE);
573 for (i = 0; i < rfxbuilder->num_reqs; i++) {
574 on_table_add_row(NULL, (livespointer)rfxbuilder);
575 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry[i]), rfxbuilder->reqs[i]);
576 }
577 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAMS) {
578 rfxbuilder->copy_params = (lives_param_t *)lives_malloc(RFXBUILD_MAX_PARAMS * sizeof(lives_param_t));
579 rfxbuilder->table = lives_table_new(rfxbuilder->num_params, 3, FALSE);
580 for (i = 0; i < rfxbuilder->num_params; i++) {
581 param_copy(&rfxbuilder->copy_params[i], &rfxbuilder->params[i], FALSE);
582 on_table_add_row(NULL, (livespointer)rfxbuilder);
583 }
584 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAM_WINDOW) {
585 rfxbuilder->table = lives_table_new(rfxbuilder->table_rows, 2, FALSE);
586 for (i = 0; i < rfxbuilder->num_paramw_hints; i++) {
587 on_table_add_row(NULL, (livespointer)rfxbuilder);
588 }
589 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_TRIGGERS) {
590 rfxbuilder->copy_triggers = (rfx_trigger_t *)lives_malloc((RFXBUILD_MAX_PARAMS + 1) * sizeof(rfx_trigger_t));
591 rfxbuilder->table = lives_table_new(rfxbuilder->table_rows, 1, FALSE);
592 for (i = 0; i < rfxbuilder->num_triggers; i++) {
593 rfxbuilder->copy_triggers[i].when = rfxbuilder->triggers[i].when;
594 rfxbuilder->copy_triggers[i].code = lives_strdup(rfxbuilder->triggers[i].code);
595 on_table_add_row(NULL, (livespointer)rfxbuilder);
596 }
597 }
598
599 hbox = lives_hbox_new(FALSE, 0);
600
601 lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, TRUE, TRUE, widget_opts.packing_height);
602
603 scrolledwindow = lives_standard_scrolled_window_new(RFX_WINSIZE_H, RFX_WINSIZE_V / 4, rfxbuilder->table);
604
605 lives_box_pack_start(LIVES_BOX(hbox), scrolledwindow, TRUE, TRUE, widget_opts.packing_width);
606
607 add_vsep_to_box(LIVES_BOX(hbox));
608
609 // button box on right
610
611 button_box = lives_vbutton_box_new();
612 lives_button_box_set_layout(LIVES_BUTTON_BOX(button_box), LIVES_BUTTONBOX_START);
613
614 lives_box_pack_start(LIVES_BOX(hbox), button_box, FALSE, FALSE, 0);
615
616 rfxbuilder->new_entry_button = lives_standard_button_new_with_label(_("_New Entry"),
617 DEF_BUTTON_WIDTH,
618 DEF_BUTTON_HEIGHT);
619
620 lives_box_pack_start(LIVES_BOX(button_box), rfxbuilder->new_entry_button, FALSE, FALSE, widget_opts.packing_height);
621 lives_container_set_border_width(LIVES_CONTAINER(rfxbuilder->new_entry_button), widget_opts.border_width);
622
623 rfxbuilder->edit_entry_button = lives_standard_button_new_with_label(_("_Edit Entry"),
624 DEF_BUTTON_WIDTH,
625 DEF_BUTTON_HEIGHT);
626
627 lives_box_pack_start(LIVES_BOX(button_box), rfxbuilder->edit_entry_button, FALSE, FALSE, widget_opts.packing_height);
628 lives_container_set_border_width(LIVES_CONTAINER(rfxbuilder->edit_entry_button), widget_opts.border_width);
629
630 rfxbuilder->remove_entry_button = lives_standard_button_new_with_label(_("_Remove Entry"),
631 DEF_BUTTON_WIDTH,
632 DEF_BUTTON_HEIGHT);
633
634 lives_box_pack_start(LIVES_BOX(button_box), rfxbuilder->remove_entry_button, FALSE, FALSE, widget_opts.packing_height);
635 lives_container_set_border_width(LIVES_CONTAINER(rfxbuilder->remove_entry_button), widget_opts.border_width);
636
637 if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAM_WINDOW) {
638 rfxbuilder->move_up_button = lives_standard_button_new_with_label(_("Move _Up"),
639 DEF_BUTTON_WIDTH,
640 DEF_BUTTON_HEIGHT);
641
642 lives_box_pack_start(LIVES_BOX(button_box), rfxbuilder->move_up_button, FALSE, FALSE, widget_opts.packing_height);
643 lives_container_set_border_width(LIVES_CONTAINER(rfxbuilder->move_up_button), widget_opts.border_width);
644
645 rfxbuilder->move_down_button = lives_standard_button_new_with_label(_("Move _Down"),
646 DEF_BUTTON_WIDTH,
647 DEF_BUTTON_HEIGHT);
648
649 lives_box_pack_start(LIVES_BOX(button_box), rfxbuilder->move_down_button, FALSE, FALSE, widget_opts.packing_height);
650 lives_container_set_border_width(LIVES_CONTAINER(rfxbuilder->move_down_button), widget_opts.border_width);
651
652 lives_widget_set_sensitive(rfxbuilder->move_up_button, FALSE);
653 lives_widget_set_sensitive(rfxbuilder->move_down_button, FALSE);
654 } else {
655 rfxbuilder->move_up_button = rfxbuilder->move_down_button = NULL;
656 }
657
658 lives_widget_set_sensitive(rfxbuilder->edit_entry_button, FALSE);
659 lives_widget_set_sensitive(rfxbuilder->remove_entry_button, FALSE);
660
661 if (rfxbuilder->table_type == RFX_TABLE_TYPE_TRIGGERS) {
662 if (rfxbuilder->num_triggers > rfxbuilder->num_params) {
663 lives_widget_set_sensitive(rfxbuilder->new_entry_button, FALSE);
664 }
665 }
666
667 cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL,
668 LIVES_RESPONSE_CANCEL);
669
670 okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL,
671 LIVES_RESPONSE_OK);
672
673 lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
674 LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
675
676 lives_button_grab_default_special(okbutton);
677
678 if (rfxbuilder->table_type == RFX_TABLE_TYPE_REQUIREMENTS) {
679 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
680 LIVES_GUI_CALLBACK(on_requirements_ok), user_data);
681
682 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
683 LIVES_GUI_CALLBACK(on_requirements_cancel), user_data);
684 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAMS) {
685 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
686 LIVES_GUI_CALLBACK(on_params_ok), user_data);
687
688 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
689 LIVES_GUI_CALLBACK(on_params_cancel), user_data);
690 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAM_WINDOW) {
691 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
692 LIVES_GUI_CALLBACK(on_param_window_ok), user_data);
693
694 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
695 LIVES_GUI_CALLBACK(on_param_window_cancel),
696 user_data);
697 } else if (rfxbuilder->table_type == RFX_TABLE_TYPE_TRIGGERS) {
698 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
699 LIVES_GUI_CALLBACK(on_triggers_ok), user_data);
700
701 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
702 LIVES_GUI_CALLBACK(on_triggers_cancel), user_data);
703 }
704
705 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->new_entry_button), LIVES_WIDGET_CLICKED_SIGNAL,
706 LIVES_GUI_CALLBACK(on_table_add_row), user_data);
707
708 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->edit_entry_button), LIVES_WIDGET_CLICKED_SIGNAL,
709 LIVES_GUI_CALLBACK(on_table_edit_row), user_data);
710
711 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->remove_entry_button), LIVES_WIDGET_CLICKED_SIGNAL,
712 LIVES_GUI_CALLBACK(on_table_delete_row), user_data);
713
714 if (rfxbuilder->table_type == RFX_TABLE_TYPE_PARAM_WINDOW) {
715 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->move_up_button), LIVES_WIDGET_CLICKED_SIGNAL,
716 LIVES_GUI_CALLBACK(on_table_swap_row), user_data);
717
718 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->move_down_button), LIVES_WIDGET_CLICKED_SIGNAL,
719 LIVES_GUI_CALLBACK(on_table_swap_row), user_data);
720 }
721
722 lives_widget_show_all(dialog);
723 table_select_row(rfxbuilder, -1);
724 }
725
726
on_requirements_ok(LiVESButton * button,livespointer user_data)727 static void on_requirements_ok(LiVESButton *button, livespointer user_data) {
728 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
729
730 int i;
731 for (i = 0; i < rfxbuilder->onum_reqs; i++) {
732 lives_free(rfxbuilder->reqs[i]);
733 }
734 for (i = 0; i < rfxbuilder->num_reqs; i++) {
735 rfxbuilder->reqs[i] = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[i])));
736 }
737 lives_general_button_clicked(button, NULL);
738 }
739
740
on_requirements_cancel(LiVESButton * button,livespointer user_data)741 static void on_requirements_cancel(LiVESButton *button, livespointer user_data) {
742 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
743
744 rfxbuilder->num_reqs = rfxbuilder->onum_reqs;
745 lives_general_button_clicked(button, NULL);
746 }
747
748
on_properties_ok(LiVESButton * button,livespointer user_data)749 static void on_properties_ok(LiVESButton *button, livespointer user_data) {
750 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
751
752 if (rfxbuilder->type != RFX_BUILD_TYPE_EFFECT0) {
753 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(rfxbuilder->prop_slow))) {
754 rfxbuilder->props |= RFX_PROPS_SLOW;
755 } else if (rfxbuilder->props & RFX_PROPS_SLOW) {
756 rfxbuilder->props ^= RFX_PROPS_SLOW;
757 }
758 } else {
759 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(rfxbuilder->prop_batchg))) {
760 rfxbuilder->props |= RFX_PROPS_BATCHG;
761 } else if (rfxbuilder->props & RFX_PROPS_BATCHG) {
762 rfxbuilder->props ^= RFX_PROPS_BATCHG;
763 }
764 }
765 lives_general_button_clicked(button, NULL);
766 }
767
768
on_params_ok(LiVESButton * button,livespointer user_data)769 static void on_params_ok(LiVESButton *button, livespointer user_data) {
770 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
771
772 register int i;
773
774 for (i = 0; i < rfxbuilder->onum_params; i++) {
775 lives_free(rfxbuilder->params[i].name);
776 lives_free(rfxbuilder->params[i].label);
777 if (rfxbuilder->params[i].type == LIVES_PARAM_STRING_LIST) {
778 if (rfxbuilder->params[i].list) lives_list_free(rfxbuilder->params[i].list);
779 }
780 if (rfxbuilder->copy_params[i].def) lives_free(rfxbuilder->params[i].def);
781 }
782 if (rfxbuilder->onum_params) {
783 lives_free(rfxbuilder->params);
784 }
785 rfxbuilder->params = (lives_param_t *)lives_malloc(rfxbuilder->num_params * sizeof(lives_param_t));
786 for (i = 0; i < rfxbuilder->num_params; i++) {
787 param_copy(&rfxbuilder->params[i], &rfxbuilder->copy_params[i], FALSE);
788
789 // this is the only place these should be freed
790 lives_free(rfxbuilder->copy_params[i].name);
791 lives_free(rfxbuilder->copy_params[i].label);
792 if (rfxbuilder->copy_params[i].type == LIVES_PARAM_STRING_LIST) {
793 if (rfxbuilder->copy_params[i].list) lives_list_free(rfxbuilder->copy_params[i].list);
794 }
795 if (rfxbuilder->copy_params[i].def) lives_free(rfxbuilder->copy_params[i].def);
796 }
797 if (rfxbuilder->num_params) {
798 lives_free(rfxbuilder->copy_params);
799 }
800 lives_general_button_clicked(button, NULL);
801 }
802
on_params_cancel(LiVESButton * button,livespointer user_data)803 static void on_params_cancel(LiVESButton *button, livespointer user_data) {
804 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
805
806 for (register int i = 0; i < rfxbuilder->num_params; i++) {
807 // this is the only place these should be freed
808 lives_free(rfxbuilder->copy_params[i].name);
809 lives_free(rfxbuilder->copy_params[i].label);
810 if (rfxbuilder->copy_params[i].type == LIVES_PARAM_STRING_LIST) {
811 if (rfxbuilder->copy_params[i].list) lives_list_free(rfxbuilder->copy_params[i].list);
812 }
813 if (rfxbuilder->copy_params[i].def) lives_free(rfxbuilder->copy_params[i].def);
814 }
815 if (rfxbuilder->num_params) {
816 lives_free(rfxbuilder->copy_params);
817 }
818 rfxbuilder->num_params = rfxbuilder->onum_params;
819 lives_general_button_clicked(button, NULL);
820 }
821
822
on_param_window_ok(LiVESButton * button,livespointer user_data)823 static void on_param_window_ok(LiVESButton *button, livespointer user_data) {
824 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
825
826 register int i;
827
828 for (i = 0; i < rfxbuilder->onum_paramw_hints; i++) {
829 lives_free(rfxbuilder->paramw_hints[i]);
830 }
831 for (i = 0; i < rfxbuilder->num_paramw_hints; i++) {
832 rfxbuilder->paramw_hints[i] = lives_strdup_printf("%s%s%s", lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[i])),
833 rfxbuilder->field_delim,
834 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry2[i])));
835 }
836 lives_general_button_clicked(button, NULL);
837 }
838
on_param_window_cancel(LiVESButton * button,livespointer user_data)839 static void on_param_window_cancel(LiVESButton *button, livespointer user_data) {
840 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
841
842 rfxbuilder->num_paramw_hints = rfxbuilder->onum_paramw_hints;
843 lives_general_button_clicked(button, NULL);
844 }
845
846
on_code_ok(LiVESButton * button,livespointer user_data)847 static void on_code_ok(LiVESButton *button, livespointer user_data) {
848 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
849
850 switch (rfxbuilder->codetype) {
851 case RFX_CODE_TYPE_PRE:
852 lives_free(rfxbuilder->pre_code);
853 rfxbuilder->pre_code = lives_text_view_get_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview));
854 break;
855
856 case RFX_CODE_TYPE_LOOP:
857 lives_free(rfxbuilder->loop_code);
858 rfxbuilder->loop_code = lives_text_view_get_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview));
859 break;
860
861 case RFX_CODE_TYPE_POST:
862 lives_free(rfxbuilder->post_code);
863 rfxbuilder->post_code = lives_text_view_get_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview));
864 break;
865
866 case RFX_CODE_TYPE_STRDEF: {
867 int maxlen = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max));
868 char buf[++maxlen];
869
870 if (rfxbuilder->copy_params[rfxbuilder->edit_param].def) lives_free(
871 rfxbuilder->copy_params[rfxbuilder->edit_param].def);
872 lives_snprintf(buf, maxlen, "%s", lives_text_view_get_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview)));
873
874 rfxbuilder->copy_params[rfxbuilder->edit_param].def = subst(buf, rfxbuilder->field_delim, "");
875 break;
876 }
877 case RFX_CODE_TYPE_STRING_LIST: {
878 char *values = lives_text_view_get_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview));
879 int numlines = get_token_count(values, '\n');
880 char **lines = lives_strsplit(values, "\n", numlines);
881 int defindex = get_int_param(rfxbuilder->copy_params[rfxbuilder->edit_param].def);
882
883 if (rfxbuilder->copy_params[rfxbuilder->edit_param].list) {
884 lives_list_free(rfxbuilder->copy_params[rfxbuilder->edit_param].list);
885 rfxbuilder->copy_params[rfxbuilder->edit_param].list = NULL;
886 }
887 for (register int i = 0; i < numlines; i++) {
888 if (i < numlines - 1 || strlen(lines[i])) {
889 rfxbuilder->copy_params[rfxbuilder->edit_param].list = lives_list_append
890 (rfxbuilder->copy_params[rfxbuilder->edit_param].list, lives_strdup(lines[i]));
891 }
892 }
893 lives_strfreev(lines);
894
895 // set "default" combo - TODO - try to retain old default using string matching
896 lives_combo_populate(LIVES_COMBO(rfxbuilder->param_def_combo),
897 rfxbuilder->copy_params[rfxbuilder->edit_param].list);
898 if (!rfxbuilder->copy_params[rfxbuilder->edit_param].list ||
899 defindex > lives_list_length(rfxbuilder->copy_params[rfxbuilder->edit_param].list)) {
900 set_int_param(rfxbuilder->copy_params[rfxbuilder->edit_param].def, (defindex = 0));
901 }
902 if (rfxbuilder->copy_params[rfxbuilder->edit_param].list) {
903 lives_combo_set_active_string(LIVES_COMBO(rfxbuilder->param_def_combo),
904 (char *)lives_list_nth_data(rfxbuilder->copy_params[rfxbuilder->edit_param].list,
905 defindex));
906 // *INDENT-OFF*
907 }}}
908 // *INDENT-ON*
909
910 lives_general_button_clicked(button, NULL);
911 }
912
913
on_triggers_ok(LiVESButton * button,livespointer user_data)914 static void on_triggers_ok(LiVESButton * button, livespointer user_data) {
915 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
916
917 int i;
918 for (i = 0; i < rfxbuilder->onum_triggers; i++) {
919 lives_free(rfxbuilder->triggers[i].code);
920 }
921 if (rfxbuilder->onum_triggers) {
922 lives_free(rfxbuilder->triggers);
923 }
924 rfxbuilder->triggers = (rfx_trigger_t *)lives_malloc(rfxbuilder->num_triggers * sizeof(rfx_trigger_t));
925 for (i = 0; i < rfxbuilder->num_triggers; i++) {
926 rfxbuilder->triggers[i].when = rfxbuilder->copy_triggers[i].when;
927 rfxbuilder->triggers[i].code = lives_strdup(rfxbuilder->copy_triggers[i].code);
928 lives_free(rfxbuilder->copy_triggers[i].code);
929 }
930 if (rfxbuilder->num_triggers) {
931 lives_free(rfxbuilder->copy_triggers);
932 }
933 lives_general_button_clicked(button, NULL);
934 }
935
936
on_triggers_cancel(LiVESButton * button,livespointer user_data)937 static void on_triggers_cancel(LiVESButton * button, livespointer user_data) {
938 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
939
940 uint8_t *valid_triggers = NULL;
941
942 boolean init_trigger_valid = FALSE;
943
944 int i;
945
946 if (rfxbuilder->num_params > 0)
947 valid_triggers = (uint8_t *)lives_calloc(rfxbuilder->num_params, 1);
948
949 for (i = 0; i < rfxbuilder->num_triggers; i++) {
950 lives_free(rfxbuilder->copy_triggers[i].code);
951 }
952 if (rfxbuilder->num_triggers) {
953 lives_free(rfxbuilder->copy_triggers);
954 }
955 rfxbuilder->num_triggers = rfxbuilder->onum_triggers;
956
957 for (i = 0; i < rfxbuilder->num_triggers; i++) {
958 int when = rfxbuilder->triggers[i].when;
959 if (when == 0) init_trigger_valid = 1;
960 else valid_triggers[when - 1] = 1;
961 }
962
963 // reset onchange for anything not in triggers
964 for (i = 0; i < rfxbuilder->num_params; i++) {
965 if (!valid_triggers[i]) {
966 rfxbuilder->params[i].onchange = FALSE;
967 } else {
968 rfxbuilder->params[i].onchange = TRUE;
969 }
970 }
971
972 if (valid_triggers) lives_free(valid_triggers);
973
974 if (!init_trigger_valid) {
975 rfxbuilder->has_init_trigger = FALSE;
976 } else {
977 rfxbuilder->has_init_trigger = TRUE;
978 }
979
980 lives_general_button_clicked(button, NULL);
981 }
982
983
on_properties_clicked(LiVESButton * button,livespointer user_data)984 static void on_properties_clicked(LiVESButton * button, livespointer user_data) {
985 LiVESWidget *dialog;
986 LiVESWidget *dialog_vbox;
987 LiVESWidget *cancelbutton;
988 LiVESWidget *okbutton;
989
990 LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
991
992 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
993
994 widget_opts.transient = LIVES_WINDOW(rfxbuilder->dialog);
995 dialog = lives_standard_dialog_new(_("RFX Properties"), FALSE, -1, -1);
996 lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
997
998 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
999
1000 rfxbuilder->prop_slow = lives_standard_check_button_new(_("_Slow (hint to GUI)"), FALSE, LIVES_BOX(dialog_vbox), NULL);
1001
1002 if (rfxbuilder->type != RFX_BUILD_TYPE_EFFECT0) {
1003 lives_widget_show(rfxbuilder->prop_slow);
1004 }
1005
1006 if (rfxbuilder->props & RFX_PROPS_SLOW) {
1007 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->prop_slow), TRUE);
1008 }
1009
1010 if (rfxbuilder->type == RFX_BUILD_TYPE_EFFECT0) {
1011 rfxbuilder->prop_batchg = lives_standard_check_button_new(_("_Batch mode generator"), FALSE, LIVES_BOX(dialog_vbox), NULL);
1012 if (rfxbuilder->props & RFX_PROPS_BATCHG) {
1013 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->prop_batchg), TRUE);
1014 }
1015 }
1016
1017 cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL,
1018 LIVES_RESPONSE_CANCEL);
1019
1020 okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL,
1021 LIVES_RESPONSE_OK);
1022
1023 lives_button_grab_default_special(okbutton);
1024
1025 lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
1026 LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
1027
1028 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
1029 LIVES_GUI_CALLBACK(on_properties_ok), user_data);
1030
1031 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
1032 LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
1033
1034 lives_widget_show_all(dialog);
1035 }
1036
1037
table_select_row(rfx_build_window_t * rfxbuilder,int row)1038 static void table_select_row(rfx_build_window_t *rfxbuilder, int row) {
1039 for (register int i = 0; i < rfxbuilder->table_rows; i++) {
1040 if (i == row) {
1041 lives_widget_set_sensitive(rfxbuilder->edit_entry_button, TRUE);
1042 lives_widget_set_sensitive(rfxbuilder->remove_entry_button, TRUE);
1043 if (rfxbuilder->move_up_button) lives_widget_set_sensitive(rfxbuilder->move_up_button, i != 0);
1044 if (rfxbuilder->move_down_button) lives_widget_set_sensitive(rfxbuilder->move_down_button,
1045 i < rfxbuilder->table_rows - 1);
1046
1047 lives_widget_set_sensitive(rfxbuilder->entry[i], TRUE);
1048 if (rfxbuilder->entry2[i]) {
1049 lives_widget_set_sensitive(rfxbuilder->entry2[i], TRUE);
1050 }
1051 if (rfxbuilder->entry3[i]) {
1052 lives_widget_set_sensitive(rfxbuilder->entry3[i], TRUE);
1053 }
1054 } else {
1055 lives_editable_select_region(LIVES_EDITABLE(rfxbuilder->entry[i]), 0, 0);
1056 lives_widget_set_sensitive(rfxbuilder->entry[i], FALSE);
1057 lives_entry_set_editable(LIVES_ENTRY(rfxbuilder->entry[i]), FALSE);
1058 if (rfxbuilder->entry2[i]) {
1059 lives_editable_select_region(LIVES_EDITABLE(rfxbuilder->entry2[i]), 0, 0);
1060 lives_widget_set_sensitive(rfxbuilder->entry2[i], FALSE);
1061 }
1062 if (rfxbuilder->entry3[i]) {
1063 lives_editable_select_region(LIVES_EDITABLE(rfxbuilder->entry3[i]), 0, 0);
1064 lives_widget_set_sensitive(rfxbuilder->entry3[i], FALSE);
1065 }
1066 }
1067 }
1068 }
1069
1070
on_entry_click(LiVESWidget * widget,LiVESXEventButton * event,livespointer user_data)1071 static boolean on_entry_click(LiVESWidget * widget, LiVESXEventButton * event, livespointer user_data) {
1072 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
1073
1074 widget = lives_bin_get_child(LIVES_BIN(widget));
1075 for (register int i = 0; i < rfxbuilder->table_rows; i++) {
1076 if (widget == rfxbuilder->entry[i] || widget == rfxbuilder->entry2[i] || widget == rfxbuilder->entry3[i]) {
1077 table_select_row(rfxbuilder, i);
1078
1079 if (event->type != LIVES_BUTTON_PRESS) {
1080 //double click
1081 on_table_edit_row(NULL, rfxbuilder);
1082 }
1083 return TRUE;
1084 }
1085 }
1086 return TRUE;
1087 }
1088
1089
on_table_add_row(LiVESButton * button,livespointer user_data)1090 static void on_table_add_row(LiVESButton * button, livespointer user_data) {
1091 LiVESWidget *entry = NULL, *entry2 = NULL, *entry3 = NULL;
1092 LiVESWidget *param_dialog = NULL;
1093 LiVESWidget *param_window_dialog = NULL;
1094 LiVESWidget *trigger_dialog = NULL;
1095
1096 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
1097 lives_param_t *param = NULL;
1098
1099 register int i;
1100
1101 char *tmpx;
1102 const char *ctext;
1103
1104 LiVESWidget *ebox, *ebox2 = NULL, *ebox3 = NULL;
1105
1106 rfxbuilder->entry2[rfxbuilder->table_rows] = rfxbuilder->entry3[rfxbuilder->table_rows] = NULL;
1107
1108 switch (rfxbuilder->table_type) {
1109 case RFX_TABLE_TYPE_REQUIREMENTS:
1110 if (rfxbuilder->table_rows >= RFXBUILD_MAX_REQ) return;
1111
1112 for (i = 0; i < rfxbuilder->table_rows; i++) {
1113 lives_entry_set_editable(LIVES_ENTRY(rfxbuilder->entry[i]), FALSE);
1114 }
1115
1116 entry = rfxbuilder->entry[rfxbuilder->table_rows] = lives_standard_entry_new(NULL, NULL, -1, -1, NULL, NULL);
1117
1118 if (button)
1119 lives_entry_set_editable(LIVES_ENTRY(entry), TRUE);
1120 else
1121 lives_entry_set_editable(LIVES_ENTRY(entry), FALSE);
1122
1123 ebox = lives_event_box_new();
1124 lives_widget_set_events(ebox, LIVES_BUTTON_PRESS_MASK);
1125
1126 lives_container_add(LIVES_CONTAINER(ebox), entry);
1127
1128 lives_table_resize(LIVES_TABLE(rfxbuilder->table), ++rfxbuilder->table_rows, 1);
1129 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox, 0, 1, rfxbuilder->table_rows - 1,
1130 rfxbuilder->table_rows,
1131 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
1132 (LiVESAttachOptions)(0), 0, 0);
1133
1134 lives_widget_context_update();
1135 lives_widget_grab_focus(entry);
1136 if (button) {
1137 rfxbuilder->num_reqs++;
1138 } else goto add_row_done;
1139 break;
1140
1141 case RFX_TABLE_TYPE_PARAMS:
1142 entry = rfxbuilder->entry[rfxbuilder->table_rows] = lives_entry_new();
1143 entry2 = rfxbuilder->entry2[rfxbuilder->table_rows] = lives_entry_new();
1144
1145 if (button) {
1146 boolean param_ok = FALSE;
1147 param = &rfxbuilder->copy_params[rfxbuilder->num_params];
1148
1149 param->def = NULL;
1150 param->list = NULL;
1151 param->type = LIVES_PARAM_UNKNOWN;
1152
1153 param_dialog = make_param_dialog(-1, rfxbuilder);
1154 do {
1155 if (lives_dialog_run(LIVES_DIALOG(param_dialog)) == LIVES_RESPONSE_CANCEL) {
1156 lives_free(param->def);
1157 lives_widget_destroy(entry);
1158 lives_widget_destroy(entry2);
1159 return;
1160 }
1161 param_ok = perform_param_checks(rfxbuilder, rfxbuilder->num_params, rfxbuilder->num_params + 1);
1162 } while (!param_ok);
1163
1164 rfxbuilder->num_params++;
1165
1166 lives_entry_set_text(LIVES_ENTRY(entry2), lives_entry_get_text(LIVES_ENTRY(rfxbuilder->param_name_entry)));
1167 } else {
1168 lives_entry_set_text(LIVES_ENTRY(entry2), rfxbuilder->params[rfxbuilder->table_rows].name);
1169 }
1170
1171 lives_entry_set_text(LIVES_ENTRY(entry), (tmpx = lives_strdup_printf("p%d", rfxbuilder->table_rows)));
1172 lives_free(tmpx);
1173
1174 lives_entry_set_editable(LIVES_ENTRY(entry), FALSE);
1175
1176 ebox = lives_event_box_new();
1177 lives_widget_set_events(ebox, LIVES_BUTTON_PRESS_MASK);
1178
1179 lives_container_add(LIVES_CONTAINER(ebox), entry);
1180
1181 lives_table_resize(LIVES_TABLE(rfxbuilder->table), ++rfxbuilder->table_rows, 3);
1182
1183 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox, 0, 1, rfxbuilder->table_rows - 1,
1184 rfxbuilder->table_rows,
1185 (LiVESAttachOptions)(0),
1186 (LiVESAttachOptions)(0), 0, 0);
1187
1188 lives_entry_set_editable(LIVES_ENTRY(entry2), FALSE);
1189
1190 ebox2 = lives_event_box_new();
1191 lives_widget_set_events(ebox2, LIVES_BUTTON_PRESS_MASK);
1192 lives_container_add(LIVES_CONTAINER(ebox2), entry2);
1193
1194 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox2, 1, 2, rfxbuilder->table_rows - 1,
1195 rfxbuilder->table_rows,
1196 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
1197 (LiVESAttachOptions)(0), 0, 0);
1198
1199 entry3 = rfxbuilder->entry3[rfxbuilder->table_rows - 1] = lives_entry_new();
1200
1201 if (!button) {
1202 param = &rfxbuilder->params[rfxbuilder->table_rows - 1];
1203 } else {
1204 param_set_from_dialog((param = &rfxbuilder->copy_params[rfxbuilder->table_rows - 1]), rfxbuilder);
1205 }
1206
1207 switch (param->type) {
1208 case LIVES_PARAM_NUM:
1209 lives_entry_set_text(LIVES_ENTRY(entry3), (tmpx = lives_strdup_printf("num%d", param->dp)));
1210 lives_free(tmpx);
1211 break;
1212 case LIVES_PARAM_BOOL:
1213 lives_entry_set_text(LIVES_ENTRY(entry3), "bool");
1214 break;
1215 case LIVES_PARAM_COLRGB24:
1216 lives_entry_set_text(LIVES_ENTRY(entry3), "colRGB24");
1217 break;
1218 case LIVES_PARAM_STRING:
1219 lives_entry_set_text(LIVES_ENTRY(entry3), "string");
1220 break;
1221 case LIVES_PARAM_STRING_LIST:
1222 lives_entry_set_text(LIVES_ENTRY(entry3), "string_list");
1223 break;
1224 default:
1225 break;
1226 }
1227
1228 lives_entry_set_editable(LIVES_ENTRY(entry3), FALSE);
1229
1230 ebox3 = lives_event_box_new();
1231 lives_widget_set_events(ebox3, LIVES_BUTTON_PRESS_MASK);
1232 lives_container_add(LIVES_CONTAINER(ebox3), entry3);
1233
1234 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox3, 2, 3, rfxbuilder->table_rows - 1,
1235 rfxbuilder->table_rows,
1236 (LiVESAttachOptions)(LIVES_FILL),
1237 (LiVESAttachOptions)(0), 0, 0);
1238
1239 if (param_dialog) lives_widget_destroy(param_dialog);
1240 if (!button) goto add_row_done;
1241
1242 lives_widget_queue_resize(lives_widget_get_parent(LIVES_WIDGET(rfxbuilder->table)));
1243 break;
1244
1245 case RFX_TABLE_TYPE_PARAM_WINDOW:
1246 if (button) {
1247 param_window_dialog = make_param_window_dialog(-1, rfxbuilder);
1248 if (lives_dialog_run(LIVES_DIALOG(param_window_dialog)) == LIVES_RESPONSE_CANCEL) {
1249 return;
1250 }
1251 entry = rfxbuilder->entry[rfxbuilder->table_rows] = lives_entry_new();
1252 ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->paramw_kw_combo));
1253 lives_entry_set_text(LIVES_ENTRY(entry), ctext);
1254 rfxbuilder->num_paramw_hints++;
1255 } else {
1256 char **array = lives_strsplit(rfxbuilder->paramw_hints[rfxbuilder->table_rows], rfxbuilder->field_delim, 2);
1257 entry = rfxbuilder->entry[rfxbuilder->table_rows] = lives_entry_new();
1258 lives_entry_set_text(LIVES_ENTRY(entry), array[0]);
1259 lives_strfreev(array);
1260 }
1261
1262 lives_entry_set_editable(LIVES_ENTRY(entry), FALSE);
1263
1264 ebox = lives_event_box_new();
1265 lives_widget_set_events(ebox, LIVES_BUTTON_PRESS_MASK);
1266 lives_container_add(LIVES_CONTAINER(ebox), entry);
1267
1268 lives_table_resize(LIVES_TABLE(rfxbuilder->table), ++rfxbuilder->table_rows, 2);
1269 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox, 0, 1, rfxbuilder->table_rows - 1,
1270 rfxbuilder->table_rows,
1271 (LiVESAttachOptions)(LIVES_FILL),
1272 (LiVESAttachOptions)(0), 0, 0);
1273
1274 entry2 = rfxbuilder->entry2[rfxbuilder->table_rows - 1] = lives_entry_new();
1275
1276 if (button) {
1277 if (!strcmp(lives_entry_get_text(LIVES_ENTRY(entry)), "layout")) {
1278 lives_entry_set_text(LIVES_ENTRY(entry2), lives_entry_get_text(LIVES_ENTRY(rfxbuilder->paramw_rest_entry)));
1279 } else {
1280 // TODO - use lives_rfx_special_t->has_subtype,name,num_params
1281 ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->paramw_sp_combo));
1282 if (!strcmp(ctext, "framedraw")) {
1283 const char *ctext2 = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->paramw_spsub_combo));
1284 lives_entry_set_text(LIVES_ENTRY(entry2), (tmpx = lives_strdup_printf("%s%s%s%s%s",
1285 ctext, rfxbuilder->field_delim, ctext2,
1286 rfxbuilder->field_delim,
1287 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->paramw_rest_entry)))));
1288 } else {
1289 lives_entry_set_text(LIVES_ENTRY(entry2), (tmpx = lives_strdup_printf("%s%s%s", ctext, rfxbuilder->field_delim,
1290 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->paramw_rest_entry)))));
1291 }
1292 lives_free(tmpx);
1293 }
1294 } else {
1295 char **array = lives_strsplit(rfxbuilder->paramw_hints[rfxbuilder->table_rows - 1], rfxbuilder->field_delim, 2);
1296 lives_entry_set_text(LIVES_ENTRY(entry2), array[1]);
1297 lives_strfreev(array);
1298 }
1299
1300 lives_entry_set_editable(LIVES_ENTRY(entry2), FALSE);
1301
1302 ebox2 = lives_event_box_new();
1303 lives_widget_set_events(ebox2, LIVES_BUTTON_PRESS_MASK);
1304 lives_container_add(LIVES_CONTAINER(ebox2), entry2);
1305
1306 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox2, 1, 2, rfxbuilder->table_rows - 1,
1307 rfxbuilder->table_rows,
1308 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
1309 (LiVESAttachOptions)(0), 0, 0);
1310
1311 if (param_window_dialog) lives_widget_destroy(param_window_dialog);
1312 if (!button) goto add_row_done;
1313
1314 lives_widget_queue_resize(lives_widget_get_parent(LIVES_WIDGET(rfxbuilder->table)));
1315 lives_widget_queue_resize(LIVES_WIDGET(rfxbuilder->table));
1316 break;
1317
1318 case RFX_TABLE_TYPE_TRIGGERS:
1319 entry = rfxbuilder->entry[rfxbuilder->table_rows] = lives_entry_new();
1320
1321 if (button) {
1322 trigger_dialog = make_trigger_dialog(-1, rfxbuilder);
1323 if (lives_dialog_run(LIVES_DIALOG(trigger_dialog)) == LIVES_RESPONSE_CANCEL) {
1324 return;
1325 }
1326 lives_entry_set_text(LIVES_ENTRY(entry), lives_entry_get_text(LIVES_ENTRY(rfxbuilder->trigger_when_entry)));
1327 rfxbuilder->num_triggers++;
1328 } else {
1329 char *tmpx2 = NULL;
1330 lives_entry_set_text(LIVES_ENTRY(entry), rfxbuilder->triggers[rfxbuilder->table_rows].when ?
1331 (tmpx2 = lives_strdup_printf("%d", rfxbuilder->triggers[rfxbuilder->table_rows].when - 1)) : "init");
1332 if (tmpx2) lives_free(tmpx2);
1333 }
1334
1335 lives_entry_set_editable(LIVES_ENTRY(entry), FALSE);
1336
1337 ebox = lives_event_box_new();
1338 lives_widget_set_events(ebox, LIVES_BUTTON_PRESS_MASK);
1339 lives_container_add(LIVES_CONTAINER(ebox), entry);
1340
1341 lives_table_resize(LIVES_TABLE(rfxbuilder->table), ++rfxbuilder->table_rows, 1);
1342 lives_table_attach(LIVES_TABLE(rfxbuilder->table), ebox, 0, 1, rfxbuilder->table_rows - 1,
1343 rfxbuilder->table_rows,
1344 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
1345 (LiVESAttachOptions)(0), 0, 0);
1346
1347 if (!button) {
1348 if (trigger_dialog) lives_widget_destroy(trigger_dialog);
1349 goto add_row_done;
1350 }
1351
1352 if (rfxbuilder->num_triggers > rfxbuilder->num_params) {
1353 lives_widget_set_sensitive(rfxbuilder->new_entry_button, FALSE);
1354 }
1355
1356 rfxbuilder->copy_triggers[rfxbuilder->table_rows - 1].code = lives_text_view_get_text(LIVES_TEXT_VIEW(
1357 rfxbuilder->code_textview));
1358
1359 rfxbuilder->copy_triggers[rfxbuilder->table_rows - 1].when = atoi(lives_entry_get_text(LIVES_ENTRY(
1360 rfxbuilder->trigger_when_entry))) + 1;
1361 if (!strcmp(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->trigger_when_entry)), "init"))
1362 rfxbuilder->copy_triggers[rfxbuilder->table_rows - 1].when = 0;
1363
1364 if (!rfxbuilder->copy_triggers[rfxbuilder->table_rows - 1].when) {
1365 rfxbuilder->has_init_trigger = TRUE;
1366 } else {
1367 rfxbuilder->params[rfxbuilder->copy_triggers[rfxbuilder->table_rows - 1].when - 1].onchange = TRUE;
1368 }
1369
1370 if (trigger_dialog) lives_widget_destroy(trigger_dialog);
1371 lives_widget_queue_resize(lives_widget_get_parent(LIVES_WIDGET(rfxbuilder->table)));
1372 lives_widget_queue_resize(LIVES_WIDGET(rfxbuilder->table));
1373
1374 break;
1375 default:
1376 return;
1377 }
1378
1379 add_row_done:
1380
1381 lives_widget_show_all(rfxbuilder->table);
1382
1383 lives_event_box_set_above_child(LIVES_EVENT_BOX(ebox), TRUE);
1384
1385 lives_signal_sync_connect(LIVES_GUI_OBJECT(ebox), LIVES_WIDGET_BUTTON_PRESS_EVENT,
1386 LIVES_GUI_CALLBACK(on_entry_click), (livespointer)rfxbuilder);
1387
1388 if (palette->style & STYLE_1) {
1389 if (palette->style & STYLE_3) {
1390 lives_widget_set_bg_color(entry, LIVES_WIDGET_STATE_INSENSITIVE, &palette->menu_and_bars);
1391 lives_widget_set_fg_color(entry, LIVES_WIDGET_STATE_INSENSITIVE, &palette->menu_and_bars_fore);
1392 } else {
1393 lives_widget_set_bg_color(entry, LIVES_WIDGET_STATE_INSENSITIVE, &palette->normal_back);
1394 lives_widget_set_fg_color(entry, LIVES_WIDGET_STATE_INSENSITIVE, &palette->normal_fore);
1395 }
1396 }
1397
1398 if (entry2) {
1399 lives_event_box_set_above_child(LIVES_EVENT_BOX(ebox2), TRUE);
1400
1401 lives_signal_sync_connect(LIVES_GUI_OBJECT(ebox2), LIVES_WIDGET_BUTTON_PRESS_EVENT,
1402 LIVES_GUI_CALLBACK(on_entry_click), (livespointer)rfxbuilder);
1403
1404 if (palette->style & STYLE_1) {
1405 if (palette->style & STYLE_3) {
1406 lives_widget_set_bg_color(entry2, LIVES_WIDGET_STATE_INSENSITIVE, &palette->menu_and_bars);
1407 lives_widget_set_fg_color(entry2, LIVES_WIDGET_STATE_INSENSITIVE, &palette->menu_and_bars_fore);
1408 } else {
1409 lives_widget_set_bg_color(entry2, LIVES_WIDGET_STATE_INSENSITIVE, &palette->normal_back);
1410 lives_widget_set_fg_color(entry2, LIVES_WIDGET_STATE_INSENSITIVE, &palette->normal_fore);
1411 }
1412 }
1413 }
1414
1415 if (entry3) {
1416 lives_event_box_set_above_child(LIVES_EVENT_BOX(ebox3), TRUE);
1417
1418 lives_signal_sync_connect(LIVES_GUI_OBJECT(ebox3), LIVES_WIDGET_BUTTON_PRESS_EVENT,
1419 LIVES_GUI_CALLBACK(on_entry_click), (livespointer)rfxbuilder);
1420
1421 if (palette->style & STYLE_1) {
1422 if (palette->style & STYLE_3) {
1423 lives_widget_set_bg_color(entry3, LIVES_WIDGET_STATE_INSENSITIVE, &palette->menu_and_bars);
1424 lives_widget_set_fg_color(entry3, LIVES_WIDGET_STATE_INSENSITIVE, &palette->menu_and_bars_fore);
1425 } else {
1426 lives_widget_set_bg_color(entry3, LIVES_WIDGET_STATE_INSENSITIVE, &palette->normal_back);
1427 lives_widget_set_fg_color(entry3, LIVES_WIDGET_STATE_INSENSITIVE, &palette->normal_fore);
1428 }
1429 }
1430 }
1431
1432 if (button) {
1433 table_select_row(rfxbuilder, rfxbuilder->table_rows - 1);
1434
1435 if (rfxbuilder->table_type == RFX_TABLE_TYPE_REQUIREMENTS) {
1436 on_table_edit_row(NULL, user_data);
1437 }
1438 }
1439 }
1440
1441
param_set_from_dialog(lives_param_t * copy_param,rfx_build_window_t * rfxbuilder)1442 static void param_set_from_dialog(lives_param_t *copy_param, rfx_build_window_t *rfxbuilder) {
1443 // set parameter values from param_dialog
1444 // this is called after adding a new copy_param or editing an existing one
1445 const char *ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_type_combo));
1446
1447 copy_param->name = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->param_name_entry)));
1448 copy_param->label = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->param_label_entry)));
1449
1450 if (!strcmp(ctext, "num")) {
1451 copy_param->type = LIVES_PARAM_NUM;
1452 } else if (!strcmp(ctext, "bool")) {
1453 copy_param->type = LIVES_PARAM_BOOL;
1454 } else if (!strcmp(ctext, "colRGB24")) {
1455 copy_param->type = LIVES_PARAM_COLRGB24;
1456 } else if (!strcmp(ctext, "string")) {
1457 copy_param->type = LIVES_PARAM_STRING;
1458 } else if (!strcmp(ctext, "string_list")) {
1459 copy_param->type = LIVES_PARAM_STRING_LIST;
1460 }
1461
1462 copy_param->dp = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_dp));
1463 copy_param->group = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_group));
1464 copy_param->onchange = FALSE; // no trigger assigned yet
1465
1466 // TODO - check
1467 if (copy_param->type != LIVES_PARAM_STRING && copy_param->def) lives_free(copy_param->def);
1468 if (copy_param->type != LIVES_PARAM_STRING_LIST && copy_param->list) lives_list_free(copy_param->list);
1469
1470 switch (copy_param->type) {
1471 case LIVES_PARAM_NUM:
1472 copy_param->min = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min));
1473 copy_param->max = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max));
1474 copy_param->step_size = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step));
1475 copy_param->wrap = lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(rfxbuilder->param_wrap_checkbutton));
1476 if (!copy_param->dp) {
1477 copy_param->def = lives_malloc(sizint);
1478 set_int_param(copy_param->def, lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)));
1479 } else {
1480 copy_param->def = lives_malloc(sizdbl);
1481 set_double_param(copy_param->def, lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)));
1482 }
1483 break;
1484 case LIVES_PARAM_BOOL:
1485 copy_param->def = lives_malloc(sizint);
1486 set_bool_param(copy_param->def, lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)));
1487 copy_param->dp = 0;
1488 break;
1489 case LIVES_PARAM_STRING:
1490 copy_param->max = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max));
1491 copy_param->dp = 0;
1492 break;
1493 case LIVES_PARAM_STRING_LIST:
1494 copy_param->dp = 0;
1495 copy_param->def = lives_malloc(sizdbl);
1496 ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_def_combo));
1497 set_int_param(copy_param->def, lives_list_strcmp_index(copy_param->list, ctext, TRUE));
1498 break;
1499 case LIVES_PARAM_COLRGB24:
1500 copy_param->def = lives_malloc(3 * sizint);
1501 set_colRGB24_param(copy_param->def, lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)),
1502 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)),
1503 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)));
1504 copy_param->dp = 0;
1505 break;
1506 default:
1507 break;
1508 }
1509 }
1510
1511
on_table_edit_row(LiVESButton * button,livespointer user_data)1512 static void on_table_edit_row(LiVESButton * button, livespointer user_data) {
1513 LiVESWidget *param_dialog;
1514 LiVESWidget *paramw_dialog;
1515 LiVESWidget *trigger_dialog;
1516
1517 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
1518 lives_param_t *param;
1519
1520 int i;
1521 int found = -1;
1522 boolean param_ok = FALSE;
1523
1524 char *tmpx;
1525 const char *ctext;
1526
1527 for (i = 0; i < rfxbuilder->table_rows && found == -1; i++) {
1528 if (lives_widget_is_sensitive(rfxbuilder->entry[i])) {
1529 found = i;
1530 break;
1531 }
1532 }
1533 if (found == -1) return;
1534
1535 switch (rfxbuilder->table_type) {
1536 case RFX_TABLE_TYPE_REQUIREMENTS:
1537 for (i = 0; i < rfxbuilder->table_rows; i++) {
1538 if (found == i) {
1539 lives_entry_set_editable(LIVES_ENTRY(rfxbuilder->entry[i]), TRUE);
1540 lives_widget_context_update();
1541 lives_widget_grab_focus(rfxbuilder->entry[i]);
1542 } else {
1543 lives_entry_set_editable(LIVES_ENTRY(rfxbuilder->entry[i]), FALSE);
1544 }
1545 }
1546 break;
1547
1548 case RFX_TABLE_TYPE_PARAMS:
1549 param_dialog = make_param_dialog(found, rfxbuilder);
1550 do {
1551 if (lives_dialog_run(LIVES_DIALOG(param_dialog)) == LIVES_RESPONSE_CANCEL) {
1552 return;
1553 }
1554 param_ok = perform_param_checks(rfxbuilder, found, rfxbuilder->num_params);
1555 } while (!param_ok);
1556
1557 param_set_from_dialog((param = &rfxbuilder->copy_params[found]), rfxbuilder);
1558 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry2[found]), param->name);
1559 switch (param->type) {
1560 case LIVES_PARAM_NUM:
1561 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry3[found]), (tmpx = lives_strdup_printf("num%d", param->dp)));
1562 lives_free(tmpx);
1563 break;
1564 case LIVES_PARAM_BOOL:
1565 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry3[found]), "bool");
1566 break;
1567 case LIVES_PARAM_COLRGB24:
1568 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry3[found]), "colRGB24");
1569 break;
1570 case LIVES_PARAM_STRING:
1571 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry3[found]), "string");
1572 break;
1573 case LIVES_PARAM_STRING_LIST:
1574 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry3[found]), "string_list");
1575 break;
1576 default:
1577 break;
1578 }
1579 lives_widget_destroy(param_dialog);
1580 break;
1581
1582 case RFX_TABLE_TYPE_PARAM_WINDOW:
1583 paramw_dialog = make_param_window_dialog(found, rfxbuilder);
1584 if (lives_dialog_run(LIVES_DIALOG(paramw_dialog)) == LIVES_RESPONSE_CANCEL) {
1585 return;
1586 }
1587 ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->paramw_kw_combo));
1588 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry[found]), ctext);
1589 if (!strcmp(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[found])), "layout")) {
1590 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry2[found]),
1591 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->paramw_rest_entry)));
1592 } else {
1593 // TODO - use lives_rfx_special_t->has_subtype,name,num_params
1594 ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->paramw_sp_combo));
1595 if (!strcmp(ctext, "framedraw")) {
1596 const char *ctext2 = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->paramw_spsub_combo));
1597 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry2[found]),
1598 (tmpx = lives_strdup_printf("%s%s%s%s%s", ctext, rfxbuilder->field_delim, ctext2,
1599 rfxbuilder->field_delim,
1600 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->paramw_rest_entry)))));
1601 } else {
1602 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry2[found]),
1603 (tmpx = lives_strdup_printf("%s%s%s", ctext, rfxbuilder->field_delim, lives_entry_get_text
1604 (LIVES_ENTRY(rfxbuilder->paramw_rest_entry)))));
1605 }
1606 lives_free(tmpx);
1607 }
1608 lives_widget_destroy(paramw_dialog);
1609 break;
1610
1611 case RFX_TABLE_TYPE_TRIGGERS:
1612 trigger_dialog = make_trigger_dialog(found, rfxbuilder);
1613 if (lives_dialog_run(LIVES_DIALOG(trigger_dialog)) == LIVES_RESPONSE_CANCEL) {
1614 return;
1615 }
1616
1617 lives_free(rfxbuilder->copy_triggers[found].code);
1618 rfxbuilder->copy_triggers[found].code = lives_text_view_get_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview));
1619
1620 lives_widget_destroy(trigger_dialog);
1621 break;
1622 }
1623 }
1624
1625
on_table_swap_row(LiVESButton * button,livespointer user_data)1626 static void on_table_swap_row(LiVESButton * button, livespointer user_data) {
1627 char *entry_text;
1628 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
1629 int found = -1;
1630
1631 for (register int i = 0; i < rfxbuilder->table_rows && found == -1; i++) {
1632 if (!(lives_widget_get_state(rfxbuilder->entry[i])&LIVES_WIDGET_STATE_INSENSITIVE)) {
1633 found = i;
1634 break;
1635 }
1636 }
1637
1638 if (found == -1) if ((found = rfxbuilder->table_swap_row1) == -1) return;
1639
1640 switch (rfxbuilder->table_type) {
1641 case RFX_TABLE_TYPE_PARAM_WINDOW:
1642 if (button == LIVES_BUTTON(rfxbuilder->move_up_button)) {
1643 rfxbuilder->table_swap_row2 = found - 1;
1644 } else if (button == LIVES_BUTTON(rfxbuilder->move_down_button)) {
1645 rfxbuilder->table_swap_row2 = found + 1;
1646 }
1647 if (rfxbuilder->table_swap_row2 < 0 || rfxbuilder->table_swap_row2 >= rfxbuilder->table_rows) return;
1648
1649 entry_text = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[found])));
1650 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry[found]),
1651 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[rfxbuilder->table_swap_row2])));
1652 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry[rfxbuilder->table_swap_row2]), entry_text);
1653 lives_free(entry_text);
1654
1655 entry_text = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry2[found])));
1656 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry2[found]),
1657 lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry2[rfxbuilder->table_swap_row2])));
1658 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->entry2[rfxbuilder->table_swap_row2]), entry_text);
1659 lives_free(entry_text);
1660
1661 break;
1662 default:
1663 break;
1664 }
1665 rfxbuilder->table_swap_row1 = rfxbuilder->table_swap_row2;
1666 table_select_row(rfxbuilder, rfxbuilder->table_swap_row1);
1667 }
1668
1669
on_table_delete_row(LiVESButton * button,livespointer user_data)1670 static void on_table_delete_row(LiVESButton * button, livespointer user_data) {
1671 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
1672
1673 LiVESWidget *ebox;
1674
1675 #if !LIVES_TABLE_IS_GRID
1676 LiVESWidget *ebox2 = NULL, *ebox3 = NULL, *ebox4 = NULL;
1677 #else
1678 LiVESWidget *entry = NULL, *entry2;
1679 #endif
1680
1681 int move = 0;
1682 boolean triggers_adjusted = FALSE;
1683
1684 register int i;
1685
1686 switch (rfxbuilder->table_type) {
1687 case RFX_TABLE_TYPE_REQUIREMENTS:
1688 for (i = 0; i < rfxbuilder->table_rows; i++) {
1689 if (move > 0) {
1690 #if !LIVES_TABLE_IS_GRID
1691 if (i < rfxbuilder->table_rows - 1) ebox2 = lives_widget_get_parent(rfxbuilder->entry[i]);
1692 lives_widget_reparent(rfxbuilder->entry[i], ebox);
1693 ebox = ebox2;
1694 #endif
1695 rfxbuilder->entry[i - 1] = rfxbuilder->entry[i];
1696 } else if (!(lives_widget_get_state(rfxbuilder->entry[i])&LIVES_WIDGET_STATE_INSENSITIVE)) {
1697 #if LIVES_TABLE_IS_GRID
1698 lives_grid_remove_row(LIVES_GRID(rfxbuilder->table), i);
1699 #else
1700 ebox = lives_widget_get_parent(rfxbuilder->entry[i]);
1701 if (rfxbuilder->table_rows > 1) {
1702 lives_table_resize(LIVES_TABLE(rfxbuilder->table), rfxbuilder->table_rows - 1, 1);
1703 }
1704 lives_widget_destroy(rfxbuilder->entry[i]);
1705 #endif
1706 move = i + 1;
1707 }
1708 }
1709 if (move == 0) return;
1710 rfxbuilder->table_rows--;
1711 rfxbuilder->num_reqs--;
1712 break;
1713
1714 case RFX_TABLE_TYPE_PARAMS:
1715 for (i = 0; i < rfxbuilder->table_rows; i++) {
1716 if (move > 0) {
1717 // note - parameters become renumbered here
1718
1719 #if !LIVES_TABLE_IS_GRID
1720 // move everything up except p%d
1721 if (i < rfxbuilder->table_rows - 1) {
1722 ebox3 = lives_widget_get_parent(rfxbuilder->entry2[i]);
1723 ebox4 = lives_widget_get_parent(rfxbuilder->entry3[i]);
1724 }
1725 lives_widget_reparent(rfxbuilder->entry2[i], ebox);
1726 lives_widget_reparent(rfxbuilder->entry3[i], ebox2);
1727 ebox = ebox3;
1728 ebox2 = ebox4;
1729 #else
1730 // move p%d up so when we remove the row the numbering is ok
1731 entry2 = rfxbuilder->entry[i];
1732 ebox = lives_widget_get_parent(rfxbuilder->entry[i]);
1733 lives_widget_object_ref(entry2);
1734 lives_widget_unparent(entry2);
1735 lives_container_add(LIVES_CONTAINER(ebox), entry);
1736 lives_widget_object_unref(entry);
1737 entry = entry2;
1738 #endif
1739
1740 rfxbuilder->entry2[i - 1] = rfxbuilder->entry2[i];
1741 rfxbuilder->entry3[i - 1] = rfxbuilder->entry3[i];
1742 param_copy(&rfxbuilder->copy_params[i - 1], &rfxbuilder->copy_params[i], FALSE);
1743 lives_free(rfxbuilder->copy_params[i].name);
1744 lives_free(rfxbuilder->copy_params[i].label);
1745 lives_free(rfxbuilder->copy_params[i].def);
1746
1747 } else if (!(lives_widget_get_state(rfxbuilder->entry[i])&LIVES_WIDGET_STATE_INSENSITIVE)) {
1748 if (rfxbuilder->copy_params[i].onchange) {
1749 do_error_dialog(_("\n\nCannot remove this parameter as it has a trigger.\nPlease remove the trigger first.\n\n"));
1750 return;
1751 }
1752
1753 #if LIVES_TABLE_IS_GRID
1754 entry = rfxbuilder->entry[i];
1755 lives_widget_object_ref(entry);
1756 lives_widget_unparent(entry);
1757 lives_grid_remove_row(LIVES_GRID(rfxbuilder->table), i);
1758 #else
1759 ebox = lives_widget_get_parent(rfxbuilder->entry2[i]);
1760 ebox2 = lives_widget_get_parent(rfxbuilder->entry3[i]);
1761
1762 lives_widget_destroy(rfxbuilder->entry[rfxbuilder->table_rows - 1]);
1763 lives_widget_destroy(rfxbuilder->entry2[i]);
1764 lives_widget_destroy(rfxbuilder->entry3[i]);
1765
1766 if (rfxbuilder->table_rows > 1) {
1767 lives_table_resize(LIVES_TABLE(rfxbuilder->table), rfxbuilder->table_rows - 1, 3);
1768 }
1769 #endif
1770 lives_free(rfxbuilder->copy_params[i].name);
1771 lives_free(rfxbuilder->copy_params[i].label);
1772 lives_free(rfxbuilder->copy_params[i].def);
1773
1774 move = i + 1;
1775 }
1776 }
1777
1778 #if LIVES_TABLE_IS_GRID
1779 if (entry) lives_widget_destroy(entry);
1780 #endif
1781
1782 if (move == 0) return;
1783 rfxbuilder->table_rows--;
1784 rfxbuilder->num_params--;
1785 for (i = 0; i < rfxbuilder->num_triggers; i++) {
1786 if (rfxbuilder->triggers[i].when > move) {
1787 rfxbuilder->params[rfxbuilder->triggers[i].when - 1].onchange = FALSE;
1788 rfxbuilder->params[--rfxbuilder->triggers[i].when - 1].onchange = TRUE;
1789 }
1790 triggers_adjusted = TRUE;
1791 }
1792 if (triggers_adjusted) {
1793 do_error_dialog(_("\n\nSome triggers were adjusted.\nPlease check the trigger code.\n"));
1794 }
1795 break;
1796
1797 case RFX_TABLE_TYPE_PARAM_WINDOW:
1798 for (i = 0; i < rfxbuilder->table_rows; i++) {
1799 if (move > 0) {
1800 #if !LIVES_TABLE_IS_GRID
1801 if (i < rfxbuilder->table_rows - 1) {
1802 ebox3 = lives_widget_get_parent(rfxbuilder->entry[i]);
1803 ebox4 = lives_widget_get_parent(rfxbuilder->entry2[i]);
1804 }
1805 lives_widget_reparent(rfxbuilder->entry[i], ebox);
1806 lives_widget_reparent(rfxbuilder->entry2[i], ebox2);
1807 ebox = ebox3;
1808 ebox2 = ebox4;
1809 #endif
1810
1811 rfxbuilder->entry[i - 1] = rfxbuilder->entry[i];
1812 rfxbuilder->entry2[i - 1] = rfxbuilder->entry2[i];
1813 } else if (!(lives_widget_get_state(rfxbuilder->entry[i])&LIVES_WIDGET_STATE_INSENSITIVE)) {
1814 #if LIVES_TABLE_IS_GRID
1815 lives_grid_remove_row(LIVES_GRID(rfxbuilder->table), i);
1816 #else
1817 ebox = lives_widget_get_parent(rfxbuilder->entry[i]);
1818 ebox2 = lives_widget_get_parent(rfxbuilder->entry2[i]);
1819
1820 lives_widget_destroy(rfxbuilder->entry[i]);
1821 lives_widget_destroy(rfxbuilder->entry2[i]);
1822 if (rfxbuilder->table_rows > 1) {
1823 lives_table_resize(LIVES_TABLE(rfxbuilder->table), rfxbuilder->table_rows - 1, 1);
1824 }
1825 #endif
1826 move = i + 1;
1827 }
1828 }
1829 if (!move) return;
1830 rfxbuilder->table_rows--;
1831 rfxbuilder->num_paramw_hints--;
1832 break;
1833
1834 case RFX_TABLE_TYPE_TRIGGERS:
1835 for (i = 0; i < rfxbuilder->table_rows; i++) {
1836 if (move > 0) {
1837 #if !LIVES_TABLE_IS_GRID
1838 if (i < rfxbuilder->table_rows - 1) ebox2 = lives_widget_get_parent(rfxbuilder->entry[i]);
1839 lives_widget_reparent(rfxbuilder->entry[i], ebox);
1840 ebox = ebox2;
1841 #endif
1842
1843 rfxbuilder->entry[i - 1] = rfxbuilder->entry[i];
1844 rfxbuilder->copy_triggers[i - 1].when = rfxbuilder->copy_triggers[i].when;
1845 rfxbuilder->copy_triggers[i - 1].code = lives_strdup(rfxbuilder->copy_triggers[i].code);
1846 lives_free(rfxbuilder->copy_triggers[i].code);
1847 } else if (!(lives_widget_get_state(rfxbuilder->entry[i])&LIVES_WIDGET_STATE_INSENSITIVE)) {
1848 int when = atoi(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[i]))) + 1;
1849
1850 if (!strcmp(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[i])), "init")) rfxbuilder->has_init_trigger = FALSE;
1851 else rfxbuilder->params[when - 1].onchange = FALSE;
1852
1853 lives_free(rfxbuilder->copy_triggers[i].code);
1854
1855 #if LIVES_TABLE_IS_GRID
1856 lives_grid_remove_row(LIVES_GRID(rfxbuilder->table), i);
1857 #else
1858 ebox = lives_widget_get_parent(rfxbuilder->entry[i]);
1859 if (rfxbuilder->table_rows > 1) {
1860 lives_table_resize(LIVES_TABLE(rfxbuilder->table), rfxbuilder->table_rows - 1, 1);
1861 }
1862 lives_widget_destroy(rfxbuilder->entry[i]);
1863 #endif
1864 move = i + 1;
1865 }
1866 }
1867 if (!move) return;
1868 rfxbuilder->table_rows--;
1869 rfxbuilder->num_triggers--;
1870
1871 if (rfxbuilder->table_rows <= rfxbuilder->num_params) {
1872 lives_widget_set_sensitive(rfxbuilder->new_entry_button, TRUE);
1873 }
1874
1875 break;
1876 default:
1877 return;
1878 }
1879
1880 if (rfxbuilder->table_rows == 0) {
1881 lives_widget_set_sensitive(rfxbuilder->edit_entry_button, FALSE);
1882 lives_widget_set_sensitive(rfxbuilder->remove_entry_button, FALSE);
1883 if (rfxbuilder->move_up_button) lives_widget_set_sensitive(rfxbuilder->move_up_button, FALSE);
1884 if (rfxbuilder->move_down_button) lives_widget_set_sensitive(rfxbuilder->move_down_button, FALSE);
1885 } else {
1886 if (move >= rfxbuilder->table_rows) move = rfxbuilder->table_rows - 1;
1887 table_select_row(rfxbuilder, move);
1888 }
1889 }
1890
1891
make_param_dialog(int pnum,rfx_build_window_t * rfxbuilder)1892 LiVESWidget *make_param_dialog(int pnum, rfx_build_window_t *rfxbuilder) {
1893 LiVESWidget *dialog;
1894 LiVESWidget *dialog_vbox;
1895
1896 LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
1897
1898 LiVESList *typelist = NULL;
1899
1900 lives_colRGB48_t rgb;
1901
1902 char *tmp, *tmp2, *title;
1903
1904 if (pnum < 0) {
1905 title = (_("New RFX Parameter"));
1906 } else {
1907 title = (_("Edit RFX Parameter"));
1908 }
1909
1910 dialog = lives_standard_dialog_new(title, TRUE, -1, -1);
1911 lives_free(title);
1912
1913 lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
1914
1915 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
1916
1917 // name
1918
1919 rfxbuilder->param_name_entry = lives_standard_entry_new((tmp = (_("_Name: "))),
1920 pnum >= 0 ? rfxbuilder->copy_params[pnum].name : NULL,
1921 60.*widget_opts.scale, -1, LIVES_BOX(dialog_vbox),
1922 (tmp2 = lives_strdup((_("Name of the parameter, must be unique in the plugin.")))));
1923
1924 if (pnum < 0) lives_widget_grab_focus(rfxbuilder->param_name_entry);
1925
1926 lives_free(tmp);
1927 lives_free(tmp2);
1928
1929 // label
1930
1931 rfxbuilder->param_label_entry = lives_standard_entry_new((tmp = (_("_Label: "))),
1932 pnum >= 0 ? rfxbuilder->copy_params[pnum].label : NULL,
1933 60.*widget_opts.scale, -1, LIVES_BOX(dialog_vbox),
1934 (tmp2 = (_("Label to be shown by the parameter. "
1935 "An underscore represents mnemonic accelerator."))));
1936 lives_free(tmp);
1937 lives_free(tmp2);
1938
1939 // type
1940
1941 typelist = lives_list_append(typelist, (livespointer)"num");
1942 typelist = lives_list_append(typelist, (livespointer)"bool");
1943 typelist = lives_list_append(typelist, (livespointer)"string");
1944 typelist = lives_list_append(typelist, (livespointer)"colRGB24");
1945 typelist = lives_list_append(typelist, (livespointer)"string_list");
1946
1947 rfxbuilder->param_type_combo = lives_standard_combo_new((tmp = (_("_Type: "))), typelist,
1948 LIVES_BOX(dialog_vbox), (tmp2 = (_("Parameter type (select from list)."))));
1949 lives_free(tmp);
1950 lives_free(tmp2);
1951 lives_list_free(typelist);
1952
1953 rfxbuilder->edit_param = pnum;
1954
1955 if (pnum >= 0) {
1956 switch (rfxbuilder->copy_params[pnum].type) {
1957 case LIVES_PARAM_NUM:
1958 lives_combo_set_active_index(LIVES_COMBO(rfxbuilder->param_type_combo), 0); break;
1959 case LIVES_PARAM_BOOL:
1960 lives_combo_set_active_index(LIVES_COMBO(rfxbuilder->param_type_combo), 1); break;
1961 case LIVES_PARAM_STRING:
1962 lives_combo_set_active_index(LIVES_COMBO(rfxbuilder->param_type_combo), 2); break;
1963 case LIVES_PARAM_COLRGB24:
1964 lives_combo_set_active_index(LIVES_COMBO(rfxbuilder->param_type_combo), 3); break;
1965 case LIVES_PARAM_STRING_LIST:
1966 lives_combo_set_active_index(LIVES_COMBO(rfxbuilder->param_type_combo), 4); break;
1967 default: break;
1968 }
1969 } else rfxbuilder->edit_param = rfxbuilder->num_params;
1970
1971 // dp
1972
1973 rfxbuilder->spinbutton_param_dp = lives_standard_spin_button_new(_("Decimal _places: "),
1974 pnum >= 0 ? rfxbuilder->copy_params[pnum].dp : 0., 0., 16., 1., 1., 0, LIVES_BOX(dialog_vbox), NULL);
1975 rfxbuilder->param_dp_label = widget_opts.last_label;
1976
1977 add_hsep_to_box(LIVES_BOX(dialog_vbox));
1978
1979 // default val
1980
1981 rfxbuilder->spinbutton_param_def = lives_standard_spin_button_new(_("_Default value: "), 0., -LIVES_MAXINT, LIVES_MAXINT, 1.,
1982 1., 0, LIVES_BOX(dialog_vbox), NULL);
1983 rfxbuilder->param_def_label = widget_opts.last_label;
1984
1985 // extra bits for string/string_list
1986
1987 rfxbuilder->param_strdef_hbox = lives_hbox_new(FALSE, 0);
1988 lives_box_pack_start(LIVES_BOX(dialog_vbox), rfxbuilder->param_strdef_hbox, TRUE, TRUE, widget_opts.packing_height);
1989
1990 rfxbuilder->param_strdef_button = lives_standard_button_new(DEF_BUTTON_WIDTH, DEF_BUTTON_HEIGHT);
1991
1992 lives_box_pack_start(LIVES_BOX(rfxbuilder->param_strdef_hbox), rfxbuilder->param_strdef_button, TRUE, TRUE,
1993 widget_opts.packing_width);
1994
1995 rfxbuilder->param_strlist_hbox = lives_hbox_new(FALSE, 0);
1996 lives_box_pack_start(LIVES_BOX(dialog_vbox), rfxbuilder->param_strlist_hbox, FALSE, FALSE, widget_opts.packing_width);
1997
1998 rfxbuilder->param_def_combo = lives_standard_combo_new(_("_Default: "), NULL, LIVES_BOX(rfxbuilder->param_strlist_hbox), NULL);
1999
2000 lives_label_set_mnemonic_widget(LIVES_LABEL(rfxbuilder->param_def_label), rfxbuilder->param_def_combo);
2001
2002 if (pnum >= 0) {
2003 switch (rfxbuilder->copy_params[pnum].type) {
2004 case LIVES_PARAM_NUM:
2005 if (!rfxbuilder->copy_params[pnum].dp) {
2006 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2007 (double)get_int_param(rfxbuilder->copy_params[pnum].def));
2008 } else {
2009 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2010 get_double_param(rfxbuilder->copy_params[pnum].def));
2011 }
2012 break;
2013 case LIVES_PARAM_BOOL:
2014 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2015 (double)get_bool_param(rfxbuilder->copy_params[pnum].def));
2016 break;
2017 case LIVES_PARAM_COLRGB24:
2018 get_colRGB24_param(rfxbuilder->copy_params[pnum].def, &rgb);
2019 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), (double)rgb.red);
2020 break;
2021 default:
2022 break;
2023 }
2024 }
2025
2026 // group
2027
2028 rfxbuilder->hbox_bg = lives_hbox_new(FALSE, 0);
2029 lives_box_pack_start(LIVES_BOX(dialog_vbox), rfxbuilder->hbox_bg, FALSE, FALSE, widget_opts.packing_height);
2030
2031 rfxbuilder->spinbutton_param_group = lives_standard_spin_button_new((tmp = (_("Button _Group: "))), 0., 0., 16., 1.,
2032 1., 0, LIVES_BOX(rfxbuilder->hbox_bg),
2033 (tmp2 = (_("A non-zero value can be used to group radio buttons."))));
2034
2035 if (pnum >= 0) {
2036 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_group),
2037 (double)rfxbuilder->copy_params[pnum].group);
2038 }
2039
2040 // min
2041
2042 rfxbuilder->spinbutton_param_min = lives_standard_spin_button_new(_("_Minimum value: "), 0., -LIVES_MAXINT, LIVES_MAXINT, 1.,
2043 1., 0, LIVES_BOX(dialog_vbox), NULL);
2044 rfxbuilder->param_min_label = widget_opts.last_label;
2045
2046 // max
2047
2048 rfxbuilder->spinbutton_param_max = lives_standard_spin_button_new(_("Ma_ximum value: "), RFX_DEF_NUM_MAX, -LIVES_MAXINT,
2049 LIVES_MAXINT, 1., 1., 0, LIVES_BOX(dialog_vbox), NULL);
2050 rfxbuilder->param_max_label = widget_opts.last_label;
2051
2052 // step size
2053
2054 rfxbuilder->spinbutton_param_step = lives_standard_spin_button_new((tmp = (_(" _Step size: "))), 1., 1.,
2055 LIVES_MAXINT, 1., 1., 0, LIVES_BOX(dialog_vbox),
2056 (tmp2 = (_("How much the parameter is adjusted when the spinbutton arrows are pressed."))));
2057 rfxbuilder->param_step_label = widget_opts.last_label;
2058 lives_free(tmp);
2059 lives_free(tmp2);
2060
2061 // wrap
2062
2063 rfxbuilder->param_wrap_hbox = lives_hbox_new(FALSE, 0);
2064 lives_box_pack_start(LIVES_BOX(dialog_vbox), rfxbuilder->param_wrap_hbox, TRUE, TRUE, widget_opts.packing_height);
2065
2066 rfxbuilder->param_wrap_checkbutton = lives_standard_check_button_new((tmp = (_("_Wrap value"))), FALSE,
2067 LIVES_BOX(rfxbuilder->param_wrap_hbox),
2068 (tmp2 = (_("Whether the value wraps max->min and min->max."))));
2069
2070 lives_free(tmp);
2071 lives_free(tmp2);
2072
2073 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->param_strdef_button), LIVES_WIDGET_CLICKED_SIGNAL,
2074 LIVES_GUI_CALLBACK(on_code_clicked), (livespointer)rfxbuilder);
2075
2076 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->param_type_combo), LIVES_WIDGET_CHANGED_SIGNAL,
2077 LIVES_GUI_CALLBACK(on_param_type_changed), (livespointer)rfxbuilder);
2078
2079 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->spinbutton_param_dp), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
2080 LIVES_GUI_CALLBACK(after_param_dp_changed), (livespointer)rfxbuilder);
2081
2082 rfxbuilder->def_spin_f = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->spinbutton_param_def),
2083 LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
2084 LIVES_GUI_CALLBACK(after_param_def_changed), (livespointer)rfxbuilder);
2085
2086 rfxbuilder->min_spin_f = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->spinbutton_param_min),
2087 LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
2088 LIVES_GUI_CALLBACK(after_param_min_changed), (livespointer)rfxbuilder);
2089
2090 rfxbuilder->max_spin_f = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rfxbuilder->spinbutton_param_max),
2091 LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
2092 LIVES_GUI_CALLBACK(after_param_max_changed), (livespointer)rfxbuilder);
2093
2094 if (pnum >= 0) {
2095 switch (rfxbuilder->copy_params[pnum].type) {
2096 case LIVES_PARAM_NUM:
2097 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), rfxbuilder->copy_params[pnum].min);
2098 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), rfxbuilder->copy_params[pnum].max);
2099 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step),
2100 rfxbuilder->copy_params[pnum].step_size);
2101 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(rfxbuilder->param_wrap_checkbutton),
2102 rfxbuilder->copy_params[pnum].wrap);
2103 break;
2104 case LIVES_PARAM_COLRGB24:
2105 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), (double)rgb.green);
2106 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), (double)rgb.blue);
2107 break;
2108 case LIVES_PARAM_STRING:
2109 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), rfxbuilder->copy_params[pnum].max);
2110 break;
2111 default:
2112 break;
2113 }
2114 }
2115 lives_widget_show_all(dialog);
2116 on_param_type_changed(LIVES_COMBO(rfxbuilder->param_type_combo), (livespointer)rfxbuilder);
2117 after_param_dp_changed(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_dp), (livespointer)rfxbuilder);
2118 return dialog;
2119 }
2120
2121
after_param_dp_changed(LiVESSpinButton * spinbutton,livespointer user_data)2122 static void after_param_dp_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
2123 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2124 const char *ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_type_combo));
2125 int dp;
2126
2127 if (strcmp(ctext, "num")) return;
2128
2129 dp = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
2130
2131 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), dp);
2132 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), dp);
2133 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), dp);
2134 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step), dp);
2135
2136 if (dp > 0) {
2137 double max = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max));
2138 double min = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min));
2139 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), -LIVES_MAXFLOAT, LIVES_MAXFLOAT);
2140 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), -LIVES_MAXFLOAT, LIVES_MAXFLOAT);
2141 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), -LIVES_MAXFLOAT, LIVES_MAXFLOAT);
2142 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step), 1. / (double)lives_10pow(dp),
2143 (max - min) > 1. ? (max - min) : 1.);
2144
2145 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_step), MAXFLOATLEN + dp);
2146 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_def), MAXFLOATLEN + dp);
2147 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_min), MAXFLOATLEN + dp);
2148 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_max), MAXFLOATLEN + dp);
2149 } else {
2150 int max = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max));
2151 int min = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min));
2152 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), -LIVES_MAXINT, LIVES_MAXINT);
2153 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), -LIVES_MAXINT, LIVES_MAXINT);
2154 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), -LIVES_MAXINT, LIVES_MAXINT);
2155 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step), 1, (max - min) > 1 ? (max - min) : 1);
2156
2157 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_step), MAXINTLEN);
2158 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_def), MAXINTLEN);
2159 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_min), MAXINTLEN);
2160 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_max), MAXINTLEN);
2161 }
2162 }
2163
2164
after_param_min_changed(LiVESSpinButton * spinbutton,livespointer user_data)2165 static void after_param_min_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
2166 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2167 int dp;
2168 const char *ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_type_combo));
2169
2170 if (strcmp(ctext, "num")) return;
2171
2172 lives_signal_handler_block(rfxbuilder->spinbutton_param_max, rfxbuilder->max_spin_f);
2173 lives_signal_handler_block(rfxbuilder->spinbutton_param_def, rfxbuilder->def_spin_f);
2174
2175 if ((dp = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_dp))) > 0) {
2176 if (lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)) <
2177 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min))) {
2178 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2179 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)));
2180 }
2181
2182 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max),
2183 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)), LIVES_MAXFLOAT);
2184 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step),
2185 1. / (double)lives_10pow(dp), lives_spin_button_get_value
2186 (LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)) -
2187 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)));
2188
2189 } else {
2190 if (lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)) <
2191 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min))) {
2192 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2193 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)));
2194 }
2195
2196 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max),
2197 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)),
2198 LIVES_MAXINT);
2199 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step), 1,
2200 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)) -
2201 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)));
2202 }
2203
2204 lives_signal_handler_unblock(rfxbuilder->spinbutton_param_max, rfxbuilder->max_spin_f);
2205 lives_signal_handler_unblock(rfxbuilder->spinbutton_param_def, rfxbuilder->def_spin_f);
2206 }
2207
2208
after_param_max_changed(LiVESSpinButton * spinbutton,livespointer user_data)2209 static void after_param_max_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
2210 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2211 int dp;
2212 const char *ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_type_combo));
2213
2214 if (strcmp(ctext, "num")) return;
2215
2216 lives_signal_handler_block(rfxbuilder->spinbutton_param_min, rfxbuilder->min_spin_f);
2217 lives_signal_handler_block(rfxbuilder->spinbutton_param_def, rfxbuilder->def_spin_f);
2218
2219 if ((dp = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_dp))) > 0) {
2220 if (lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)) >
2221 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max))) {
2222 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2223 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)));
2224 }
2225
2226 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), -LIVES_MAXFLOAT,
2227 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)));
2228 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step),
2229 1. / (double)lives_10pow(dp),
2230 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)) -
2231 lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)));
2232 } else {
2233 if (lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def)) >
2234 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max))) {
2235 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def),
2236 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)));
2237 }
2238
2239 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), -LIVES_MAXINT,
2240 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max)));
2241 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step), 1,
2242 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max))
2243 - lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min)));
2244 }
2245
2246 lives_signal_handler_unblock(rfxbuilder->spinbutton_param_min, rfxbuilder->min_spin_f);
2247 lives_signal_handler_unblock(rfxbuilder->spinbutton_param_def, rfxbuilder->def_spin_f);
2248 }
2249
2250
after_param_def_changed(LiVESSpinButton * spinbutton,livespointer user_data)2251 static void after_param_def_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
2252 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2253 const char *ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_type_combo));
2254
2255 if (strcmp(ctext, "num")) return;
2256
2257 if (lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_dp))) {
2258 double dbl_def = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def));
2259 if (dbl_def < lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min))) {
2260 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), dbl_def);
2261 } else if (dbl_def > lives_spin_button_get_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max))) {
2262 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), dbl_def);
2263 }
2264 } else {
2265 int int_def = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def));
2266 if (int_def < lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min))) {
2267 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), (double)int_def);
2268 } else if (int_def > lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max))) {
2269 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), (double)int_def);
2270 }
2271 }
2272 }
2273
2274
on_param_type_changed(LiVESCombo * param_type_combo,livespointer user_data)2275 static void on_param_type_changed(LiVESCombo * param_type_combo, livespointer user_data) {
2276 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2277 int pnum = rfxbuilder->edit_param;
2278
2279 const char *ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->param_type_combo));
2280
2281 lives_widget_show(rfxbuilder->param_min_label);
2282 lives_widget_show(rfxbuilder->param_max_label);
2283 lives_widget_show(rfxbuilder->spinbutton_param_min);
2284 lives_widget_show(rfxbuilder->spinbutton_param_max);
2285 lives_widget_show(rfxbuilder->spinbutton_param_dp);
2286 lives_widget_show(rfxbuilder->spinbutton_param_def);
2287 lives_widget_show(rfxbuilder->param_dp_label);
2288 lives_widget_show(rfxbuilder->param_def_label);
2289
2290 lives_widget_hide(rfxbuilder->param_strdef_hbox);
2291 lives_widget_hide(rfxbuilder->param_strlist_hbox);
2292 lives_widget_hide(rfxbuilder->hbox_bg);
2293 lives_widget_hide(rfxbuilder->spinbutton_param_step);
2294 lives_widget_hide(rfxbuilder->param_step_label);
2295 lives_widget_hide(rfxbuilder->param_wrap_hbox);
2296
2297 if (pnum < 0) return;
2298
2299 if (!strcmp(ctext, "string_list")) {
2300 int defindex;
2301
2302 if (rfxbuilder->copy_params[pnum].type != LIVES_PARAM_STRING_LIST) {
2303 if (rfxbuilder->copy_params[pnum].def) {
2304 lives_free(rfxbuilder->copy_params[pnum].def);
2305 }
2306 rfxbuilder->copy_params[pnum].def = lives_malloc(sizint);
2307 set_int_param(rfxbuilder->copy_params[pnum].def, 0);
2308 }
2309
2310 rfxbuilder->copy_params[pnum].type = LIVES_PARAM_STRING_LIST;
2311 defindex = get_int_param(rfxbuilder->copy_params[pnum].def);
2312
2313 lives_combo_populate(LIVES_COMBO(rfxbuilder->param_def_combo), rfxbuilder->copy_params[pnum].list);
2314
2315 if (!rfxbuilder->copy_params[pnum].list || defindex > lives_list_length(rfxbuilder->copy_params[pnum].list)) {
2316 set_int_param(rfxbuilder->copy_params[pnum].def, (defindex = 0));
2317 }
2318
2319 if (rfxbuilder->copy_params[pnum].list) {
2320 lives_combo_set_active_string(LIVES_COMBO(rfxbuilder->param_def_combo),
2321 (char *)lives_list_nth_data(rfxbuilder->copy_params[pnum].list, defindex));
2322 }
2323
2324 lives_widget_hide(rfxbuilder->spinbutton_param_dp);
2325 lives_widget_hide(rfxbuilder->param_dp_label);
2326 lives_widget_hide(rfxbuilder->spinbutton_param_min);
2327 lives_widget_hide(rfxbuilder->param_min_label);
2328 lives_widget_hide(rfxbuilder->spinbutton_param_def);
2329 lives_widget_hide(rfxbuilder->param_def_label);
2330 lives_widget_hide(rfxbuilder->spinbutton_param_max);
2331 lives_widget_hide(rfxbuilder->param_max_label);
2332
2333 lives_button_set_label(LIVES_BUTTON(rfxbuilder->param_strdef_button), (_("Set _values")));
2334 lives_widget_show(rfxbuilder->param_strdef_hbox);
2335 lives_widget_show(rfxbuilder->param_strlist_hbox);
2336 } else {
2337 if (!strcmp(ctext, "num")) {
2338 rfxbuilder->copy_params[pnum].type = LIVES_PARAM_NUM;
2339 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_def_label), (_("_Default value: ")));
2340 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_min_label), (_("_Minimum value: ")));
2341 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_max_label), (_("Ma_ximum value: ")));
2342 lives_widget_show(rfxbuilder->spinbutton_param_step);
2343 lives_widget_show(rfxbuilder->param_step_label);
2344 lives_widget_show_all(rfxbuilder->param_wrap_hbox);
2345
2346 after_param_dp_changed(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_dp), (livespointer)rfxbuilder);
2347
2348 if (pnum < 0) {
2349 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), 0.);
2350 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), RFX_DEF_NUM_MAX);
2351 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0.);
2352 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_step), 1.);
2353 }
2354 } else if (!strcmp(ctext, "bool")) {
2355 rfxbuilder->copy_params[pnum].type = LIVES_PARAM_BOOL;
2356 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_def_label), (_("_Default value: ")));
2357 lives_widget_hide(rfxbuilder->param_min_label);
2358 lives_widget_hide(rfxbuilder->param_max_label);
2359 lives_widget_hide(rfxbuilder->spinbutton_param_min);
2360 lives_widget_hide(rfxbuilder->spinbutton_param_max);
2361 lives_widget_hide(rfxbuilder->spinbutton_param_dp);
2362 lives_widget_hide(rfxbuilder->param_dp_label);
2363 lives_widget_show(rfxbuilder->hbox_bg);
2364 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0, 1);
2365 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0);
2366 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), 0);
2367 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), 0);
2368 } else if (!strcmp(ctext, "colRGB24")) {
2369 rfxbuilder->copy_params[pnum].type = LIVES_PARAM_COLRGB24;
2370 lives_widget_hide(rfxbuilder->spinbutton_param_dp);
2371 lives_widget_hide(rfxbuilder->param_dp_label);
2372 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_def_label), (_("Default _Red: ")));
2373 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_min_label), (_("Default _Green:")));
2374 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_max_label), (_("Default _Blue: ")));
2375 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_def), 4);
2376 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_min), 4);
2377 lives_entry_set_width_chars(LIVES_ENTRY(rfxbuilder->spinbutton_param_max), 4);
2378 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0, 255);
2379 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), 0, 255);
2380 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), 0, 255);
2381 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0);
2382 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), 0);
2383 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), 0);
2384 if (pnum < 0) {
2385 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), 0.);
2386 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_min), 0.);
2387 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0.);
2388 }
2389 } else if (!strcmp(ctext, "string")) {
2390 rfxbuilder->copy_params[pnum].type = LIVES_PARAM_STRING;
2391 lives_widget_hide(rfxbuilder->spinbutton_param_dp);
2392 lives_widget_hide(rfxbuilder->param_dp_label);
2393 lives_widget_hide(rfxbuilder->spinbutton_param_min);
2394 lives_widget_hide(rfxbuilder->param_min_label);
2395 lives_widget_hide(rfxbuilder->spinbutton_param_def);
2396
2397 lives_button_set_label(LIVES_BUTTON(rfxbuilder->param_strdef_button), (_("Set _default")));
2398 lives_widget_show(rfxbuilder->param_strdef_hbox);
2399 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_def_label), (_("Default value: ")));
2400 lives_label_set_text(LIVES_LABEL(rfxbuilder->param_max_label), (_("Maximum length (chars): ")));
2401 lives_spin_button_set_range(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), 1, RFX_MAXSTRINGLEN);
2402 if (pnum < 0) lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), RFX_TEXT_MAGIC);
2403 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_def), 0);
2404 lives_spin_button_set_digits(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max), 0);
2405
2406 if (!rfxbuilder->copy_params[pnum].def) {
2407 rfxbuilder->copy_params[pnum].def = lives_strdup("");
2408 // *INDENT-OFF*
2409 }}}
2410 // *INDENT-ONt*
2411 }
2412
2413
make_param_window_dialog(int pnum,rfx_build_window_t * rfxbuilder)2414 LiVESWidget *make_param_window_dialog(int pnum, rfx_build_window_t *rfxbuilder) {
2415 LiVESWidget *dialog;
2416 LiVESWidget *dialog_vbox;
2417
2418 LiVESList *kwlist = NULL;
2419 LiVESList *splist = NULL;
2420 LiVESList *spsublist = NULL;
2421
2422 char *kw = NULL;
2423 char *sp = NULL;
2424 char *spsub = NULL;
2425 char *rest = NULL;
2426 char *title;
2427
2428 if (pnum < 0) {
2429 title = (_("New RFX Parameter Window Hint"));
2430 } else {
2431 title = (_("Edit RFX Parameter Window Hint"));
2432 }
2433
2434 dialog = lives_standard_dialog_new(title, TRUE, -1, -1);
2435 lives_free(title);
2436
2437 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
2438
2439 if (pnum >= 0) {
2440 kw = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry[pnum])));
2441 if (!strcmp(kw, "layout")) {
2442 rest = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry2[pnum])));
2443 } else if (!strcmp(kw, "special")) {
2444 int numtok = get_token_count(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry2[pnum])),
2445 (int)rfxbuilder->field_delim[0]);
2446 char **array = lives_strsplit(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->entry2[pnum])), rfxbuilder->field_delim, 3);
2447 sp = lives_strdup(array[0]);
2448 if (!strcmp(sp, "framedraw")) {
2449 if (numtok > 1) {
2450 spsub = lives_strdup(array[1]);
2451 }
2452 if (numtok > 2) {
2453 rest = lives_strdup(array[2]);
2454 }
2455 } else {
2456 if (numtok > 1) {
2457 rest = lives_strdup(array[1]);
2458 }
2459 }
2460 lives_strfreev(array);
2461 }
2462 }
2463
2464 // kw
2465 kwlist = lives_list_append(kwlist, (livespointer)"layout");
2466 kwlist = lives_list_append(kwlist, (livespointer)"special");
2467
2468 rfxbuilder->paramw_kw_combo = lives_standard_combo_new(_("_Keyword: "), kwlist, LIVES_BOX(dialog_vbox), NULL);
2469 lives_list_free(kwlist);
2470
2471 if (pnum >= 0 && kw) {
2472 lives_combo_set_active_string(LIVES_COMBO(rfxbuilder->paramw_kw_combo), kw);
2473 }
2474
2475 // type
2476 splist = lives_list_append(splist, (livespointer)"aspect");
2477 splist = lives_list_append(splist, (livespointer)"framedraw");
2478 splist = lives_list_append(splist, (livespointer)"fileread");
2479 splist = lives_list_append(splist, (livespointer)"filewrite");
2480 splist = lives_list_append(splist, (livespointer)"password");
2481 if (rfxbuilder->type == RFX_BUILD_TYPE_EFFECT2) {
2482 splist = lives_list_append(splist, (livespointer)"mergealign");
2483 }
2484
2485 rfxbuilder->paramw_sp_combo = lives_standard_combo_new(_("Special _Type: "), splist, LIVES_BOX(dialog_vbox), NULL);
2486 lives_list_free(splist);
2487
2488 if (pnum >= 0 && sp) {
2489 lives_combo_set_active_string(LIVES_COMBO(rfxbuilder->paramw_sp_combo), sp);
2490 }
2491
2492 // subtype
2493
2494 spsublist = lives_list_append(spsublist, (livespointer)"rectdemask");
2495 spsublist = lives_list_append(spsublist, (livespointer)"multirect");
2496 spsublist = lives_list_append(spsublist, (livespointer)"singlepoint");
2497 spsublist = lives_list_append(spsublist, (livespointer)"scaledpoint");
2498
2499 rfxbuilder->paramw_spsub_combo = lives_standard_combo_new(_("Special _Subtype: "), spsublist, LIVES_BOX(dialog_vbox),
2500 NULL);
2501 lives_list_free(spsublist);
2502
2503 if (pnum >= 0 && spsub) {
2504 lives_combo_set_active_string(LIVES_COMBO(rfxbuilder->paramw_spsub_combo), spsub);
2505 }
2506
2507 // paramwindow rest
2508
2509 rfxbuilder->paramw_rest_entry = lives_standard_entry_new(_("Row: "), pnum >= 0 && rest ? rest : NULL,
2510 -1, -1, LIVES_BOX(dialog_vbox), NULL);
2511 rfxbuilder->paramw_rest_label = widget_opts.last_label;
2512
2513 if (kw) lives_free(kw);
2514 if (sp) lives_free(sp);
2515 if (spsub) lives_free(spsub);
2516 if (rest) lives_free(rest);
2517
2518 lives_widget_grab_focus(rfxbuilder->paramw_rest_entry);
2519
2520 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->paramw_kw_combo), LIVES_WIDGET_CHANGED_SIGNAL,
2521 LIVES_GUI_CALLBACK(on_paramw_kw_changed), (livespointer)rfxbuilder);
2522
2523 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->paramw_sp_combo), LIVES_WIDGET_CHANGED_SIGNAL,
2524 LIVES_GUI_CALLBACK(on_paramw_sp_changed), (livespointer)rfxbuilder);
2525
2526 lives_signal_sync_connect(LIVES_GUI_OBJECT(rfxbuilder->paramw_spsub_combo), LIVES_WIDGET_CHANGED_SIGNAL,
2527 LIVES_GUI_CALLBACK(on_paramw_spsub_changed), (livespointer)rfxbuilder);
2528
2529 lives_widget_show_all(dialog);
2530 on_paramw_kw_changed(LIVES_COMBO(rfxbuilder->paramw_kw_combo), (livespointer)rfxbuilder);
2531
2532 return dialog;
2533 }
2534
2535
on_paramw_kw_changed(LiVESCombo * combo,livespointer user_data)2536 static void on_paramw_kw_changed(LiVESCombo * combo, livespointer user_data) {
2537 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2538 const char *ctext = lives_combo_get_active_text(combo);
2539
2540 if (!strcmp(ctext, "special")) {
2541 lives_widget_show_all(lives_widget_get_parent(rfxbuilder->paramw_sp_combo));
2542 on_paramw_sp_changed(LIVES_COMBO(rfxbuilder->paramw_sp_combo), (livespointer)rfxbuilder);
2543 lives_widget_grab_focus(lives_combo_get_entry(LIVES_COMBO(rfxbuilder->paramw_sp_combo)));
2544 } else {
2545 lives_label_set_text(LIVES_LABEL(rfxbuilder->paramw_rest_label), (_("Row: ")));
2546 lives_widget_hide(lives_widget_get_parent(rfxbuilder->paramw_sp_combo));
2547 lives_widget_hide(lives_widget_get_parent(rfxbuilder->paramw_spsub_combo));
2548 lives_widget_grab_focus(rfxbuilder->paramw_rest_entry);
2549 }
2550 }
2551
2552
paramw_set_splabel(LiVESLabel * label,int npars)2553 static void paramw_set_splabel(LiVESLabel * label, int npars) {
2554 char *tmpx;
2555
2556 if (npars == 1) {
2557 tmpx = (_("Linked parameter: "));
2558 } else {
2559 char example[256] = "0";
2560 for (register int i = 1; i < npars; i++) {
2561 char *xnew = lives_strdup_printf("|%d", i);
2562 lives_strappend(example, 256, xnew);
2563 lives_free(xnew);
2564 }
2565 tmpx = lives_strdup_printf(_("Linked parameters [%d] (example %s) :"), npars, example);
2566 }
2567 lives_label_set_text(label, tmpx);
2568 lives_free(tmpx);
2569 }
2570
2571
on_paramw_sp_changed(LiVESCombo * combo,livespointer user_data)2572 static void on_paramw_sp_changed(LiVESCombo * combo, livespointer user_data) {
2573 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2574 int npars;
2575 const char *ctext = lives_combo_get_active_text(combo);
2576
2577 if (!strcmp(ctext, "framedraw")) {
2578 lives_widget_show_all(lives_widget_get_parent(rfxbuilder->paramw_spsub_combo));
2579 on_paramw_spsub_changed(LIVES_COMBO(rfxbuilder->paramw_spsub_combo), (livespointer)rfxbuilder);
2580 lives_widget_grab_focus(lives_combo_get_entry(LIVES_COMBO(rfxbuilder->paramw_spsub_combo)));
2581 } else {
2582 if (!strcmp(ctext, "fileread") || !strcmp(ctext, "filewrite") || !strcmp(ctext, "password")) npars = 1;
2583 else npars = 2;
2584 paramw_set_splabel(LIVES_LABEL(rfxbuilder->paramw_rest_label), npars);
2585 lives_widget_hide(lives_widget_get_parent(rfxbuilder->paramw_spsub_combo));
2586 }
2587
2588 lives_widget_grab_focus(rfxbuilder->paramw_rest_entry);
2589 }
2590
2591
on_paramw_spsub_changed(LiVESCombo * combo,livespointer user_data)2592 static void on_paramw_spsub_changed(LiVESCombo * combo, livespointer user_data) {
2593 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2594 const char *ctext = lives_combo_get_active_text(combo);
2595 int npars = 0;
2596
2597 if (!strcmp(ctext, "rectdemask") || !strcmp(ctext, "multirect")) {
2598 npars = 4;
2599 } else if (!strcmp(ctext, "singlepoint")) {
2600 npars = 2;
2601 } else if (!strcmp(ctext, "scaledpoint")) {
2602 npars = 3;
2603 }
2604 paramw_set_splabel(LIVES_LABEL(rfxbuilder->paramw_rest_label), npars);
2605 }
2606
2607
make_trigger_dialog(int tnum,rfx_build_window_t * rfxbuilder)2608 LiVESWidget *make_trigger_dialog(int tnum, rfx_build_window_t *rfxbuilder) {
2609 LiVESWidget *dialog;
2610 LiVESWidget *dialog_vbox;
2611 LiVESWidget *combo;
2612 LiVESWidget *scrolledwindow;
2613
2614 LiVESList *whenlist = NULL;
2615
2616 char *title;
2617
2618 int woat;
2619 int i;
2620
2621 if (tnum < 0) {
2622 title = (_("New RFX Trigger"));
2623 } else {
2624 title = (_("Edit RFX Trigger"));
2625 }
2626
2627 dialog = lives_standard_dialog_new(title, TRUE, PREF_RFXDIALOG_W, PREF_RFXDIALOG_H);
2628 lives_free(title);
2629
2630 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
2631
2632 // when
2633
2634 if (tnum >= 0) whenlist = lives_list_append(whenlist, (livespointer)(rfxbuilder->copy_triggers[tnum].when ?
2635 lives_strdup_printf("%d", rfxbuilder->copy_triggers[tnum].
2636 when - 1) : "init"));
2637 else {
2638 if (!rfxbuilder->has_init_trigger) {
2639 whenlist = lives_list_append(whenlist, (livespointer)"init");
2640 }
2641 for (i = 0; i < rfxbuilder->num_params; i++) {
2642 if (!rfxbuilder->params[i].onchange) {
2643 whenlist = lives_list_append(whenlist, lives_strdup_printf("%d", i));
2644 }
2645 }
2646 }
2647
2648 combo = lives_standard_combo_new(_("When: "), whenlist, LIVES_BOX(dialog_vbox), NULL);
2649 lives_list_free(whenlist);
2650
2651 rfxbuilder->trigger_when_entry = lives_combo_get_entry(LIVES_COMBO(combo));
2652
2653 // code area
2654 rfxbuilder->code_textview = lives_text_view_new();
2655 lives_text_view_set_editable(LIVES_TEXT_VIEW(rfxbuilder->code_textview), TRUE);
2656 lives_text_view_set_wrap_mode(LIVES_TEXT_VIEW(rfxbuilder->code_textview), LIVES_WRAP_WORD);
2657 lives_text_view_set_cursor_visible(LIVES_TEXT_VIEW(rfxbuilder->code_textview), TRUE);
2658
2659 woat = widget_opts.apply_theme;
2660 widget_opts.apply_theme = 0;
2661 widget_opts.expand = LIVES_EXPAND_EXTRA; // prevent centering
2662 scrolledwindow = lives_standard_scrolled_window_new(RFX_WINSIZE_H * 2. / 3., RFX_WINSIZE_V / 4., rfxbuilder->code_textview);
2663 widget_opts.expand = LIVES_EXPAND_DEFAULT;
2664 widget_opts.apply_theme = woat;
2665
2666 if (palette->style & STYLE_1) {
2667 lives_widget_set_base_color(rfxbuilder->code_textview, LIVES_WIDGET_STATE_NORMAL, &palette->white);
2668 lives_widget_set_text_color(rfxbuilder->code_textview, LIVES_WIDGET_STATE_NORMAL, &palette->black);
2669 }
2670
2671 lives_box_pack_start(LIVES_BOX(dialog_vbox), scrolledwindow, TRUE, TRUE, 0);
2672
2673 if (tnum >= 0) {
2674 lives_text_view_set_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview),
2675 rfxbuilder->copy_triggers[tnum].code, -1);
2676 }
2677
2678 if (tnum >= 0 || rfxbuilder->num_params == 0) lives_widget_grab_focus(rfxbuilder->code_textview);
2679
2680 lives_widget_show_all(dialog);
2681
2682 return dialog;
2683 }
2684
2685
on_code_clicked(LiVESButton * button,livespointer user_data)2686 static void on_code_clicked(LiVESButton * button, livespointer user_data) {
2687 LiVESWidget *dialog;
2688 LiVESWidget *dialog_vbox;
2689 LiVESWidget *cancelbutton;
2690 LiVESWidget *okbutton;
2691 LiVESWidget *scrolledwindow;
2692
2693 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2694
2695 int woat;
2696
2697 char *tmpx;
2698
2699 dialog = lives_standard_dialog_new(NULL, FALSE, PREF_RFXDIALOG_W, PREF_RFXDIALOG_H);
2700
2701 dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
2702
2703 // code area
2704 rfxbuilder->code_textview = lives_text_view_new();
2705
2706 woat = widget_opts.apply_theme;
2707 widget_opts.apply_theme = 0;
2708 widget_opts.expand = LIVES_EXPAND_EXTRA; // prevent centering
2709 scrolledwindow = lives_standard_scrolled_window_new(RFX_WINSIZE_H, RFX_WINSIZE_V, rfxbuilder->code_textview);
2710 widget_opts.expand = LIVES_EXPAND_DEFAULT;
2711 widget_opts.apply_theme = woat;
2712
2713 if (palette->style & STYLE_1) {
2714 lives_widget_set_base_color(rfxbuilder->code_textview, LIVES_WIDGET_STATE_NORMAL, &palette->white);
2715 lives_widget_set_text_color(rfxbuilder->code_textview, LIVES_WIDGET_STATE_NORMAL, &palette->black);
2716 }
2717
2718 lives_box_pack_start(LIVES_BOX(dialog_vbox), scrolledwindow, TRUE, TRUE, 0);
2719
2720 lives_widget_object_ref(lives_scrolled_window_get_hadjustment(LIVES_SCROLLED_WINDOW(scrolledwindow)));
2721 lives_widget_object_ref(lives_scrolled_window_get_vadjustment(LIVES_SCROLLED_WINDOW(scrolledwindow)));
2722
2723 lives_text_view_set_editable(LIVES_TEXT_VIEW(rfxbuilder->code_textview), TRUE);
2724 lives_text_view_set_wrap_mode(LIVES_TEXT_VIEW(rfxbuilder->code_textview), LIVES_WRAP_WORD);
2725 lives_text_view_set_cursor_visible(LIVES_TEXT_VIEW(rfxbuilder->code_textview), TRUE);
2726
2727 lives_widget_grab_focus(rfxbuilder->code_textview);
2728
2729 // TODO !!
2730 /* if (glib_major_version>=2&&glib_minor_version>=4) {
2731 lives_text_view_set_accepts_tab (LIVES_TEXT_VIEW (rfxbuilder->code_textview),TRUE);
2732 } */
2733
2734 if (button == LIVES_BUTTON(rfxbuilder->pre_button)) {
2735 rfxbuilder->codetype = RFX_CODE_TYPE_PRE;
2736 lives_window_set_title(LIVES_WINDOW(dialog), _("Pre Loop Code"));
2737 lives_text_view_set_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview),
2738 rfxbuilder->pre_code, -1);
2739 }
2740
2741 else if (button == LIVES_BUTTON(rfxbuilder->loop_button)) {
2742 rfxbuilder->codetype = RFX_CODE_TYPE_LOOP;
2743 lives_window_set_title(LIVES_WINDOW(dialog), _("Loop Code"));
2744 lives_text_view_set_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview),
2745 rfxbuilder->loop_code, -1);
2746 }
2747
2748 else if (button == LIVES_BUTTON(rfxbuilder->post_button)) {
2749 rfxbuilder->codetype = RFX_CODE_TYPE_POST;
2750 lives_window_set_title(LIVES_WINDOW(dialog), _("Post Loop Code"));
2751 lives_text_view_set_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview),
2752 rfxbuilder->post_code, -1);
2753 }
2754
2755 else if (button == LIVES_BUTTON(rfxbuilder->param_strdef_button)) {
2756 if (rfxbuilder->copy_params[rfxbuilder->edit_param].type != LIVES_PARAM_STRING_LIST) {
2757 int len, maxlen = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_param_max));
2758
2759 if ((len = strlen((char *)rfxbuilder->copy_params[rfxbuilder->edit_param].def)) > maxlen) len = maxlen;
2760
2761 rfxbuilder->codetype = RFX_CODE_TYPE_STRDEF;
2762 lives_window_set_title(LIVES_WINDOW(dialog), (tmpx = lives_strdup_printf
2763 (_("Default text (max length %d)"), maxlen)));
2764 lives_free(tmpx);
2765 lives_text_view_set_wrap_mode(LIVES_TEXT_VIEW(rfxbuilder->code_textview), LIVES_WRAP_WORD);
2766
2767 lives_text_view_set_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview),
2768 (char *)rfxbuilder->copy_params[rfxbuilder->edit_param].def, len);
2769 } else {
2770 LiVESTextIter start_iter;
2771 char *string = lives_strdup(""), *string_new;
2772 register int i;
2773
2774 rfxbuilder->codetype = RFX_CODE_TYPE_STRING_LIST;
2775 lives_window_set_title(LIVES_WINDOW(dialog), (tmpx = (_("Enter values, one per line"))));
2776 lives_free(tmpx);
2777 if (rfxbuilder->copy_params[rfxbuilder->edit_param].list) {
2778 for (i = 0; i < lives_list_length(rfxbuilder->copy_params[rfxbuilder->edit_param].list); i++) {
2779 string_new = lives_strconcat(string, (char *)lives_list_nth_data(rfxbuilder->copy_params[rfxbuilder->edit_param].list, i),
2780 "\n", NULL);
2781 if (string != string_new) lives_free(string);
2782 string = string_new;
2783 }
2784 lives_text_view_set_text(LIVES_TEXT_VIEW(rfxbuilder->code_textview), string, strlen(string) - 1);
2785 lives_free(string);
2786 lives_text_buffer_get_start_iter(lives_text_view_get_buffer(LIVES_TEXT_VIEW(rfxbuilder->code_textview)), &start_iter);
2787 lives_text_buffer_place_cursor(lives_text_view_get_buffer(LIVES_TEXT_VIEW(rfxbuilder->code_textview)), &start_iter);
2788 }
2789 }
2790 }
2791
2792 cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL, LIVES_RESPONSE_CANCEL);
2793
2794 okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL, LIVES_RESPONSE_OK);
2795
2796 lives_widget_set_can_default(okbutton, TRUE);
2797
2798 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2799 LIVES_GUI_CALLBACK(on_code_ok), user_data);
2800
2801 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2802 LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
2803
2804 lives_widget_show_all(dialog);
2805 }
2806
2807
on_rfxbuilder_ok(LiVESButton * button,livespointer user_data)2808 static void on_rfxbuilder_ok(LiVESButton * button, livespointer user_data) {
2809 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2810
2811 if (!perform_rfxbuilder_checks(rfxbuilder)) return;
2812 if (!rfxbuilder_to_script(rfxbuilder)) return;
2813
2814 lives_general_button_clicked(button, NULL);
2815 rfxbuilder_destroy(rfxbuilder);
2816 }
2817
2818
on_rfxbuilder_cancel(LiVESButton * button,livespointer user_data)2819 static void on_rfxbuilder_cancel(LiVESButton * button, livespointer user_data) {
2820 rfx_build_window_t *rfxbuilder = (rfx_build_window_t *)user_data;
2821
2822 lives_general_button_clicked(button, NULL);
2823 rfxbuilder_destroy(rfxbuilder);
2824 }
2825
2826
rfxbuilder_destroy(rfx_build_window_t * rfxbuilder)2827 static void rfxbuilder_destroy(rfx_build_window_t *rfxbuilder) {
2828 register int i;
2829
2830 for (i = 0; i < rfxbuilder->num_reqs; i++) {
2831 lives_free(rfxbuilder->reqs[i]);
2832 }
2833 for (i = 0; i < rfxbuilder->num_params; i++) {
2834 lives_free(rfxbuilder->params[i].name);
2835 lives_free(rfxbuilder->params[i].label);
2836 if (rfxbuilder->params[i].type == LIVES_PARAM_STRING_LIST) {
2837 if (rfxbuilder->params[i].list)lives_list_free(rfxbuilder->params[i].list);
2838 }
2839 lives_free(rfxbuilder->params[i].def);
2840 }
2841 if (rfxbuilder->num_params) {
2842 lives_free(rfxbuilder->params);
2843 }
2844 for (i = 0; i < rfxbuilder->num_paramw_hints; i++) {
2845 lives_free(rfxbuilder->paramw_hints[i]);
2846 }
2847 for (i = 0; i < rfxbuilder->num_triggers; i++) {
2848 lives_free(rfxbuilder->triggers[i].code);
2849 }
2850 if (rfxbuilder->num_triggers) {
2851 lives_free(rfxbuilder->triggers);
2852 }
2853
2854 lives_free(rfxbuilder->pre_code);
2855 lives_free(rfxbuilder->loop_code);
2856 lives_free(rfxbuilder->post_code);
2857
2858 lives_free(rfxbuilder->field_delim);
2859
2860 if (rfxbuilder->script_name) {
2861 lives_free(rfxbuilder->script_name);
2862 }
2863 if (rfxbuilder->oname) {
2864 lives_free(rfxbuilder->oname);
2865 }
2866 lives_free(rfxbuilder->rfx_version);
2867
2868 lives_free(rfxbuilder);
2869 }
2870
2871
perform_rfxbuilder_checks(rfx_build_window_t * rfxbuilder)2872 boolean perform_rfxbuilder_checks(rfx_build_window_t *rfxbuilder) {
2873 char *name = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->name_entry)));
2874
2875 if (!strlen(name)) {
2876 do_error_dialog(_("\n\nName must not be blank.\n"));
2877 lives_widget_grab_focus(rfxbuilder->name_entry);
2878 lives_free(name);
2879 return FALSE;
2880 }
2881 if (get_token_count(name, ' ') > 1) {
2882 do_error_dialog(_("\n\nName must not contain spaces.\n"));
2883 lives_free(name);
2884 return FALSE;
2885 }
2886 if (!strlen(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->menu_text_entry)))) {
2887 do_error_dialog(_("\n\nMenu text must not be blank.\n"));
2888 lives_widget_grab_focus(rfxbuilder->menu_text_entry);
2889 lives_free(name);
2890 return FALSE;
2891 }
2892 if (!strlen(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->action_desc_entry))) &&
2893 rfxbuilder->type != RFX_BUILD_TYPE_UTILITY) {
2894 do_error_dialog(_("\n\nAction description must not be blank.\n"));
2895 lives_widget_grab_focus(rfxbuilder->action_desc_entry);
2896 lives_free(name);
2897 return FALSE;
2898 }
2899 if (!strlen(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->author_entry)))) {
2900 do_error_dialog(_("\n\nAuthor must not be blank.\n"));
2901 lives_widget_grab_focus(rfxbuilder->author_entry);
2902 lives_free(name);
2903 return FALSE;
2904 }
2905
2906 if (rfxbuilder->mode != RFX_BUILDER_MODE_NEW && !(rfxbuilder->mode == RFX_BUILDER_MODE_EDIT &&
2907 !strcmp(rfxbuilder->oname, name))) {
2908 if (find_rfx_plugin_by_name(name, RFX_STATUS_TEST) > -1 || find_rfx_plugin_by_name
2909 (name, RFX_STATUS_CUSTOM) > -1 || find_rfx_plugin_by_name(name, RFX_STATUS_BUILTIN) > -1) {
2910 do_error_dialog(_("\n\nThere is already a plugin with this name.\nName must be unique.\n"));
2911 lives_free(name);
2912 return FALSE;
2913 }
2914 }
2915
2916 if (!strlen(rfxbuilder->loop_code) && rfxbuilder->type != RFX_BUILD_TYPE_UTILITY) {
2917 do_error_dialog(_("\n\nLoop code should not be blank.\n"));
2918 lives_free(name);
2919 return FALSE;
2920 }
2921
2922 if (rfxbuilder->num_triggers == 0 && rfxbuilder->type == RFX_BUILD_TYPE_UTILITY) {
2923 do_error_dialog(_("\n\nTrigger code should not be blank for a utility.\n"));
2924 lives_free(name);
2925 return FALSE;
2926 }
2927
2928 lives_free(name);
2929 return TRUE;
2930 }
2931
2932
perform_param_checks(rfx_build_window_t * rfxbuilder,int index,int rows)2933 boolean perform_param_checks(rfx_build_window_t *rfxbuilder, int index, int rows) {
2934 register int i;
2935
2936 if (!strlen(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->param_name_entry)))) {
2937 do_error_dialog(_("\n\nParameter name must not be blank.\n"));
2938 lives_widget_grab_focus(rfxbuilder->param_name_entry);
2939 return FALSE;
2940 }
2941 for (i = 0; i < rows; i++) {
2942 if (i != index && !(strcmp(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->param_name_entry)),
2943 rfxbuilder->copy_params[i].name))) {
2944 do_error_dialog(_("\n\nDuplicate parameter name detected. Parameter names must be unique in a plugin.\n\n"));
2945 return FALSE;
2946 }
2947 }
2948 return TRUE;
2949 }
2950
2951
rfxbuilder_to_script(rfx_build_window_t * rfxbuilder)2952 boolean rfxbuilder_to_script(rfx_build_window_t *rfxbuilder) {
2953 FILE *sfile;
2954 lives_colRGB48_t rgb;
2955 char **array;
2956
2957 double stepwrap;
2958
2959 uint32_t props;
2960
2961 const char *name = lives_entry_get_text(LIVES_ENTRY(rfxbuilder->name_entry));
2962
2963 char *script_file, *script_file_dir;
2964 char *script_name = lives_strdup_printf("%s.%s", name, RFXBUILDER_SCRIPT_SUFFIX);
2965 char *new_name;
2966 char *buf, *tmp, *tmp2;
2967 const char *ctext;
2968
2969 int retval, i, j;
2970
2971 if (rfxbuilder->mode != RFX_BUILDER_MODE_EDIT) {
2972 if (!(new_name = prompt_for_script_name(script_name, RFX_STATUS_TEST))) {
2973 lives_free(script_name);
2974 return FALSE;
2975 }
2976 lives_free(script_name);
2977 script_name = new_name;
2978 }
2979
2980 script_file_dir = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, NULL);
2981
2982 if (!lives_file_test(script_file_dir, LIVES_FILE_TEST_IS_DIR)) {
2983 if (lives_mkdir_with_parents(script_file_dir, capable->umask) == -1) {
2984 lives_free(script_name);
2985 return FALSE;
2986 }
2987 }
2988
2989 script_file = lives_strdup_printf("%s%s", script_file_dir, script_name);
2990 lives_free(script_file_dir);
2991 lives_free(script_name);
2992
2993 d_print(_("Writing script file %s..."), script_file);
2994
2995 if (!check_file(script_file, TRUE)) {
2996 lives_free(script_file);
2997 d_print_failed();
2998 return FALSE;
2999 }
3000
3001 do {
3002 retval = 0;
3003 if (!(sfile = fopen(script_file, "w"))) {
3004 widget_opts.transient = LIVES_WINDOW(rfxbuilder->dialog);
3005 retval = do_write_failed_error_s_with_retry(script_file, lives_strerror(errno));
3006 widget_opts.transient = NULL;
3007
3008 if (retval == LIVES_RESPONSE_CANCEL) {
3009 lives_free(script_file);
3010 d_print_failed();
3011 return FALSE;
3012 }
3013 } else {
3014 THREADVAR(write_failed) = FALSE;
3015
3016 lives_fputs("Script file generated from LiVES\n\n", sfile);
3017 lives_fputs("<define>\n", sfile);
3018 lives_fputs(rfxbuilder->field_delim, sfile);
3019 lives_fputs(rfxbuilder->rfx_version, sfile);
3020 lives_fputs("\n</define>\n\n", sfile);
3021 lives_fputs("<name>\n", sfile);
3022 lives_fputs(name, sfile);
3023 lives_fputs("\n</name>\n\n", sfile);
3024 lives_fputs("<version>\n", sfile);
3025 buf = lives_strdup_printf("%d", lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_version)));
3026 lives_fputs(buf, sfile);
3027 lives_free(buf);
3028 lives_fputs("\n</version>\n\n", sfile);
3029 lives_fputs("<author>\n", sfile);
3030 lives_fputs(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->author_entry)), sfile);
3031 lives_fputs(rfxbuilder->field_delim, sfile);
3032 lives_fputs(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->url_entry)), sfile);
3033 lives_fputs("\n</author>\n\n", sfile);
3034 lives_fputs("<description>\n", sfile);
3035 lives_fputs(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->menu_text_entry)), sfile);
3036 lives_fputs(rfxbuilder->field_delim, sfile);
3037 lives_fputs(lives_entry_get_text(LIVES_ENTRY(rfxbuilder->action_desc_entry)), sfile);
3038 lives_fputs(rfxbuilder->field_delim, sfile);
3039 if (rfxbuilder->type == RFX_BUILD_TYPE_UTILITY) {
3040 buf = lives_strdup("-1");
3041 } else {
3042 buf = lives_strdup_printf("%d", lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_min_frames)));
3043 }
3044 lives_fputs(buf, sfile);
3045 lives_free(buf);
3046 lives_fputs(rfxbuilder->field_delim, sfile);
3047 switch (rfxbuilder->type) {
3048 case RFX_BUILD_TYPE_EFFECT2:
3049 buf = lives_strdup("2");
3050 break;
3051 case RFX_BUILD_TYPE_EFFECT0:
3052 buf = lives_strdup("0");
3053 break;
3054 default:
3055 buf = lives_strdup("1");
3056 }
3057 lives_fputs(buf, sfile);
3058 lives_free(buf);
3059 lives_fputs(rfxbuilder->field_delim, sfile);
3060 lives_fputs("\n</description>\n\n", sfile);
3061 lives_fputs("<requires>\n", sfile);
3062 for (i = 0; i < rfxbuilder->num_reqs; i++) {
3063 lives_fputs(rfxbuilder->reqs[i], sfile);
3064 if (i < rfxbuilder->num_reqs - 1)
3065 lives_fputs("\n", sfile);
3066 }
3067 lives_fputs("\n</requires>\n\n", sfile);
3068 lives_fputs("<params>\n", sfile);
3069 for (i = 0; i < rfxbuilder->num_params; i++) {
3070 lives_fputs(rfxbuilder->params[i].name, sfile);
3071 lives_fputs(rfxbuilder->field_delim, sfile);
3072 lives_fputs(rfxbuilder->params[i].label, sfile);
3073 lives_fputs(rfxbuilder->field_delim, sfile);
3074 switch (rfxbuilder->params[i].type) {
3075 case LIVES_PARAM_NUM:
3076 stepwrap = rfxbuilder->params[i].step_size;
3077 if (rfxbuilder->params[i].wrap) stepwrap = -stepwrap;
3078 lives_fputs("num", sfile);
3079 buf = lives_strdup_printf("%d", rfxbuilder->params[i].dp);
3080 lives_fputs(buf, sfile);
3081 lives_free(buf);
3082 lives_fputs(rfxbuilder->field_delim, sfile);
3083 if (!rfxbuilder->params[i].dp) {
3084 buf = lives_strdup_printf("%d", get_int_param(rfxbuilder->params[i].def));
3085 lives_fputs(buf, sfile);
3086 lives_free(buf);
3087 lives_fputs(rfxbuilder->field_delim, sfile);
3088 buf = lives_strdup_printf("%d", (int)rfxbuilder->params[i].min);
3089 lives_fputs(buf, sfile);
3090 lives_free(buf);
3091 lives_fputs(rfxbuilder->field_delim, sfile);
3092 buf = lives_strdup_printf("%d", (int)rfxbuilder->params[i].max);
3093 lives_fputs(buf, sfile);
3094 lives_free(buf);
3095 lives_fputs(rfxbuilder->field_delim, sfile);
3096 if (stepwrap != 1.) {
3097 buf = lives_strdup_printf("%d", (int)stepwrap);
3098 lives_fputs(buf, sfile);
3099 lives_free(buf);
3100 lives_fputs(rfxbuilder->field_delim, sfile);
3101 }
3102 } else {
3103 char *pattern = lives_strdup_printf("%%.%df", rfxbuilder->params[i].dp);
3104 buf = lives_strdup_printf(pattern, get_double_param(rfxbuilder->params[i].def));
3105 lives_fputs(buf, sfile);
3106 lives_free(buf);
3107 lives_fputs(rfxbuilder->field_delim, sfile);
3108 buf = lives_strdup_printf(pattern, rfxbuilder->params[i].min);
3109 lives_fputs(buf, sfile);
3110 lives_free(buf);
3111 lives_fputs(rfxbuilder->field_delim, sfile);
3112 buf = lives_strdup_printf(pattern, rfxbuilder->params[i].max);
3113 lives_fputs(buf, sfile);
3114 lives_free(buf);
3115 lives_fputs(rfxbuilder->field_delim, sfile);
3116 if (stepwrap != 1.) {
3117 buf = lives_strdup_printf(pattern, stepwrap);
3118 lives_fputs(buf, sfile);
3119 lives_free(buf);
3120 lives_fputs(rfxbuilder->field_delim, sfile);
3121 }
3122 lives_free(pattern);
3123 }
3124 break;
3125 case LIVES_PARAM_BOOL:
3126 lives_fputs("bool", sfile);
3127 lives_fputs(rfxbuilder->field_delim, sfile);
3128 buf = lives_strdup_printf("%d", get_bool_param(rfxbuilder->params[i].def));
3129 lives_fputs(buf, sfile);
3130 lives_free(buf);
3131 lives_fputs(rfxbuilder->field_delim, sfile);
3132 if (rfxbuilder->params[i].group != 0) {
3133 buf = lives_strdup_printf("%d", rfxbuilder->params[i].group);
3134 lives_fputs(buf, sfile);
3135 lives_free(buf);
3136 lives_fputs(rfxbuilder->field_delim, sfile);
3137 }
3138 break;
3139 case LIVES_PARAM_COLRGB24:
3140 lives_fputs("colRGB24", sfile);
3141 lives_fputs(rfxbuilder->field_delim, sfile);
3142 get_colRGB24_param(rfxbuilder->params[i].def, &rgb);
3143 buf = lives_strdup_printf("%d", rgb.red);
3144 lives_fputs(buf, sfile);
3145 lives_free(buf);
3146 lives_fputs(rfxbuilder->field_delim, sfile);
3147 buf = lives_strdup_printf("%d", rgb.green);
3148 lives_fputs(buf, sfile);
3149 lives_free(buf);
3150 lives_fputs(rfxbuilder->field_delim, sfile);
3151 buf = lives_strdup_printf("%d", rgb.blue);
3152 lives_fputs(buf, sfile);
3153 lives_free(buf);
3154 lives_fputs(rfxbuilder->field_delim, sfile);
3155 break;
3156 case LIVES_PARAM_STRING:
3157 lives_fputs("string", sfile);
3158 lives_fputs(rfxbuilder->field_delim, sfile);
3159 lives_fputs((tmp = U82L(tmp2 = subst((char *)rfxbuilder->params[i].def, "\n", "\\n"))), sfile);
3160 lives_free(tmp);
3161 lives_free(tmp2);
3162 lives_fputs(rfxbuilder->field_delim, sfile);
3163 buf = lives_strdup_printf("%d", (int)rfxbuilder->params[i].max);
3164 lives_fputs(buf, sfile);
3165 lives_free(buf);
3166 lives_fputs(rfxbuilder->field_delim, sfile);
3167 break;
3168 case LIVES_PARAM_STRING_LIST:
3169 lives_fputs("string_list", sfile);
3170 lives_fputs(rfxbuilder->field_delim, sfile);
3171 if (rfxbuilder->params[i].def) {
3172 buf = lives_strdup_printf("%d", get_bool_param(rfxbuilder->params[i].def));
3173 lives_fputs(buf, sfile);
3174 lives_free(buf);
3175 lives_fputs(rfxbuilder->field_delim, sfile);
3176 for (j = 0; j < lives_list_length(rfxbuilder->params[i].list); j++) {
3177 lives_fputs((tmp = U82L(tmp2 = subst((char *)lives_list_nth_data
3178 (rfxbuilder->params[i].list, j), "\n", "\\n"))), sfile);
3179 lives_free(tmp);
3180 lives_free(tmp2);
3181 lives_fputs(rfxbuilder->field_delim, sfile);
3182 }
3183 }
3184 break;
3185 default:
3186 break;
3187 }
3188 if (i < rfxbuilder->num_params - 1)
3189 lives_fputs("\n", sfile);
3190 }
3191 lives_fputs("\n</params>\n\n", sfile);
3192 lives_fputs("<param_window>\n", sfile);
3193 for (i = 0; i < rfxbuilder->num_paramw_hints; i++) {
3194 lives_fputs(rfxbuilder->paramw_hints[i], sfile);
3195 if (strlen(rfxbuilder->paramw_hints[i]) > strlen(rfxbuilder->field_delim) &&
3196 strcmp(rfxbuilder->paramw_hints[i] + strlen(rfxbuilder->paramw_hints[i])
3197 - strlen(rfxbuilder->field_delim), rfxbuilder->field_delim))
3198 lives_fputs(rfxbuilder->field_delim, sfile);
3199 lives_fputs("\n", sfile);
3200 }
3201 lives_fputs("</param_window>\n\n", sfile);
3202 lives_fputs("<properties>\n", sfile);
3203 if (rfxbuilder->type == RFX_BUILD_TYPE_TOOL) props = rfxbuilder->props | RFX_PROPS_MAY_RESIZE;
3204 else props = rfxbuilder->props;
3205
3206 if (rfxbuilder->type != RFX_BUILD_TYPE_EFFECT0 && (rfxbuilder->props & RFX_PROPS_BATCHG))
3207 rfxbuilder->props ^= RFX_PROPS_BATCHG;
3208
3209 buf = lives_strdup_printf("0x%04X", props);
3210 lives_fputs(buf, sfile);
3211 lives_free(buf);
3212 lives_fputs("\n</properties>\n\n", sfile);
3213 lives_fputs("<language_code>\n", sfile);
3214 ctext = lives_combo_get_active_text(LIVES_COMBO(rfxbuilder->langc_combo));
3215 array = lives_strsplit(ctext, " ", -1);
3216 lives_fputs(array[0], sfile);
3217 lives_strfreev(array);
3218 lives_fputs("\n</language_code>\n\n", sfile);
3219 lives_fputs("<pre>\n", sfile);
3220 lives_fputs(rfxbuilder->pre_code, sfile);
3221 if (strlen(rfxbuilder->pre_code) && strcmp(rfxbuilder->pre_code + strlen(rfxbuilder->pre_code) - 1, "\n"))
3222 lives_fputs("\n", sfile);
3223 lives_fputs("</pre>\n\n", sfile);
3224 lives_fputs("<loop>\n", sfile);
3225 lives_fputs(rfxbuilder->loop_code, sfile);
3226 if (strlen(rfxbuilder->loop_code) && strcmp(rfxbuilder->loop_code + strlen(rfxbuilder->loop_code) - 1, "\n"))
3227 lives_fputs("\n", sfile);
3228 lives_fputs("</loop>\n\n", sfile);
3229 lives_fputs("<post>\n", sfile);
3230 lives_fputs(rfxbuilder->post_code, sfile);
3231 if (strlen(rfxbuilder->post_code) && strcmp(rfxbuilder->post_code + strlen(rfxbuilder->post_code) - 1, "\n"))
3232 lives_fputs("\n", sfile);
3233 lives_fputs("</post>\n\n", sfile);
3234 lives_fputs("<onchange>\n", sfile);
3235 for (i = 0; i < rfxbuilder->num_triggers; i++) {
3236 int numtok = get_token_count(rfxbuilder->triggers[i].code, '\n');
3237 buf = rfxbuilder->triggers[i].when ? lives_strdup_printf("%d", rfxbuilder->triggers[i].when - 1) : lives_strdup("init");
3238 array = lives_strsplit(rfxbuilder->triggers[i].code, "\n", numtok);
3239 for (int j = 0; j < numtok; j++) {
3240 lives_fputs(buf, sfile);
3241 lives_fputs(rfxbuilder->field_delim, sfile);
3242 if (array[j]) lives_fputs(array[j], sfile);
3243 if (j < numtok - 1)
3244 lives_fputs("\n", sfile);
3245 }
3246 lives_fputs("\n", sfile);
3247 lives_free(buf);
3248 lives_strfreev(array);
3249 }
3250 lives_fputs("</onchange>\n\n", sfile);
3251 fclose(sfile);
3252
3253 if (THREADVAR(write_failed)) {
3254 THREADVAR(write_failed) = FALSE;
3255 widget_opts.transient = LIVES_WINDOW(rfxbuilder->dialog);
3256 retval = do_write_failed_error_s_with_retry(script_file, NULL);
3257 widget_opts.transient = NULL;
3258 if (retval == LIVES_RESPONSE_CANCEL) d_print_file_error_failed();
3259 }
3260 }
3261 } while (retval == LIVES_RESPONSE_RETRY);
3262
3263 lives_free(script_file);
3264
3265 if (retval != LIVES_RESPONSE_CANCEL) {
3266 d_print_done();
3267
3268 lives_widget_set_sensitive(mainw->promote_test_rfx, TRUE);
3269 lives_widget_set_sensitive(mainw->delete_test_rfx, TRUE);
3270 lives_widget_set_sensitive(mainw->rename_test_rfx, TRUE);
3271 lives_widget_set_sensitive(mainw->edit_test_rfx, TRUE);
3272
3273 return TRUE;
3274 }
3275 return FALSE;
3276 }
3277
3278
script_to_rfxbuilder(rfx_build_window_t * rfxbuilder,const char * script_file)3279 boolean script_to_rfxbuilder(rfx_build_window_t *rfxbuilder, const char *script_file) {
3280 LiVESList *list;
3281
3282 char **array;
3283 char *tmp;
3284 char *line;
3285 char *version;
3286
3287 int listlen;
3288 int num_channels;
3289 int tnum, found;
3290 int filled_triggers = 0;
3291 int len;
3292
3293 register int i, j;
3294
3295 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT1;
3296 if (!(list = get_script_section("define", script_file, TRUE))) {
3297 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("No <define> section found in script.\n")));
3298 return FALSE;
3299 }
3300 tmp = (char *)lives_list_nth_data(list, 0);
3301 if (strlen(tmp) < 2) {
3302 lives_list_free_all(&list);
3303 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("Bad script version.\n")));
3304 return FALSE;
3305 }
3306
3307 version = lives_strdup(tmp + 1);
3308 if (make_version_hash(version) > make_version_hash(RFX_VERSION)) {
3309 lives_list_free_all(&list);
3310 lives_free(version);
3311 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("Bad script version.\n")));
3312 return FALSE;
3313 }
3314 lives_free(version);
3315
3316 lives_memset(tmp + 1, 0, 1);
3317 lives_free(rfxbuilder->field_delim);
3318 rfxbuilder->field_delim = lives_strdup(tmp);
3319 lives_list_free_all(&list);
3320
3321 if (!(list = get_script_section("name", script_file, TRUE))) {
3322 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("No <name> section found in script.\n")));
3323 return FALSE;
3324 }
3325 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->name_entry), (char *)lives_list_nth_data(list, 0));
3326 lives_list_free_all(&list);
3327
3328 if (!(list = get_script_section("version", script_file, TRUE))) {
3329 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("No <version> section found in script.\n")));
3330 return FALSE;
3331 }
3332 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_version),
3333 (double)atoi((char *)lives_list_nth_data(list, 0)));
3334 lives_list_free_all(&list);
3335
3336 if (!(list = get_script_section("author", script_file, TRUE))) {
3337 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("No <author> section found in script.\n")));
3338 return FALSE;
3339 }
3340 array = lives_strsplit((char *)lives_list_nth_data(list, 0), rfxbuilder->field_delim, 2);
3341 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->author_entry), array[0]);
3342 if (get_token_count((char *)lives_list_nth_data(list, 0), (int)rfxbuilder->field_delim[0]) > 1) {
3343 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->url_entry), array[1]);
3344 }
3345 lives_strfreev(array);
3346 lives_list_free_all(&list);
3347
3348 if (!(list = get_script_section("description", script_file, TRUE))) {
3349 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", (_("No <description> section found in script.\n")));
3350 return FALSE;
3351 }
3352 if (get_token_count((char *)lives_list_nth_data(list, 0), (int)rfxbuilder->field_delim[0]) < 4) {
3353 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, (_("Bad description. (%s)\n")), (char *)lives_list_nth_data(list, 0));
3354 lives_list_free_all(&list);
3355 return FALSE;
3356 }
3357 array = lives_strsplit((char *)lives_list_nth_data(list, 0), rfxbuilder->field_delim, -1);
3358 lives_list_free_all(&list);
3359 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->menu_text_entry), array[0]);
3360 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->action_desc_entry), array[1]);
3361 lives_spin_button_set_value(LIVES_SPIN_BUTTON(rfxbuilder->spinbutton_min_frames), (double)atoi(array[2]));
3362 num_channels = atoi(array[3]);
3363
3364 if (num_channels == 2) {
3365 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT2;
3366 }
3367 if (num_channels == 0) {
3368 rfxbuilder->type = RFX_BUILD_TYPE_EFFECT0;
3369 }
3370 if (atoi(array[2]) == -1) rfxbuilder->type = RFX_BUILD_TYPE_UTILITY;
3371 lives_strfreev(array);
3372
3373 rfxbuilder->script_name = lives_strdup(script_file);
3374
3375 if ((list = get_script_section("requires", script_file, TRUE))) {
3376 rfxbuilder->num_reqs = lives_list_length(list);
3377 for (i = 0; i < rfxbuilder->num_reqs; i++) {
3378 rfxbuilder->reqs[i] = (char *)lives_list_nth_data(list, i);
3379 }
3380 lives_list_free(list);
3381 }
3382
3383 rfxbuilder->props = 0;
3384
3385 if ((list = get_script_section("properties", script_file, TRUE))) {
3386 if (!strncmp((char *)lives_list_nth_data(list, 0), "0x", 2) || !strncmp((char *)lives_list_nth_data(list, 0), "0x", 2)) {
3387 rfxbuilder->props = hextodec((char *)lives_list_nth_data(list, 0) + 2);
3388 } else rfxbuilder->props = atoi((char *)lives_list_nth_data(list, 0));
3389 lives_list_free_all(&list);
3390 }
3391
3392 if (rfxbuilder->props & RFX_PROPS_MAY_RESIZE) rfxbuilder->type = RFX_BUILD_TYPE_TOOL;
3393
3394 if ((list = get_script_section("params", script_file, TRUE))) {
3395 char *type;
3396
3397 listlen = lives_list_length(list);
3398 rfxbuilder->num_params = listlen;
3399 rfxbuilder->params = (lives_param_t *)lives_malloc(rfxbuilder->num_params * sizeof(lives_param_t));
3400 i = 0;
3401
3402 for (j = 0; j < listlen; j++) {
3403 line = (char *)lives_list_nth_data(list, j);
3404 len = get_token_count(line, (int)rfxbuilder->field_delim[0]); // will fail if field_delim contains repeated chars !
3405 if (len < 4) {
3406 rfxbuilder->num_params--;
3407 rfxbuilder->params = (lives_param_t *)lives_realloc(rfxbuilder->params, rfxbuilder->num_params * sizeof(lives_param_t));
3408 continue;
3409 }
3410 array = lives_strsplit(line, rfxbuilder->field_delim, -1);
3411 lives_free(line);
3412 rfxbuilder->params[i].name = lives_strdup(array[0]);
3413 rfxbuilder->params[i].label = lives_strdup(array[1]);
3414 rfxbuilder->params[i].onchange = FALSE;
3415 rfxbuilder->params[i].dp = 0;
3416 rfxbuilder->params[i].group = 0;
3417
3418 ////////////////
3419 rfxbuilder->params[i].desc = NULL;
3420 rfxbuilder->params[i].use_mnemonic = TRUE;
3421 rfxbuilder->params[i].step_size = 1.;
3422 rfxbuilder->params[i].hidden = FALSE;
3423 rfxbuilder->params[i].transition = FALSE;
3424 rfxbuilder->params[i].wrap = FALSE;
3425 ////////////////
3426
3427 type = lives_strdup(array[2]);
3428 if (!strncmp(type, "num", 3)) {
3429 if (len < 6) {
3430 lives_free(rfxbuilder->params[i].name);
3431 lives_free(rfxbuilder->params[i].label);
3432 rfxbuilder->num_params--;
3433 rfxbuilder->params = (lives_param_t *)lives_realloc(rfxbuilder->params, rfxbuilder->num_params * sizeof(lives_param_t));
3434 continue;
3435 }
3436 rfxbuilder->params[i].dp = atoi(type + 3);
3437 rfxbuilder->params[i].type = LIVES_PARAM_NUM;
3438 if (rfxbuilder->params[i].dp) {
3439 rfxbuilder->params[i].def = lives_malloc(sizint);
3440 set_double_param(rfxbuilder->params[i].def, lives_strtod(array[3], NULL));
3441 } else {
3442 rfxbuilder->params[i].def = lives_malloc(sizint);
3443 set_int_param(rfxbuilder->params[i].def, atoi(array[3]));
3444 }
3445 rfxbuilder->params[i].min = lives_strtod(array[4], NULL);
3446 rfxbuilder->params[i].max = lives_strtod(array[5], NULL);
3447 if (len > 6) {
3448 rfxbuilder->params[i].step_size = lives_strtod(array[6], NULL);
3449 if (rfxbuilder->params[i].step_size == 0.) rfxbuilder->params[i].step_size = 1.;
3450 else if (rfxbuilder->params[i].step_size < 0.) {
3451 rfxbuilder->params[i].step_size = -rfxbuilder->params[i].step_size;
3452 rfxbuilder->params[i].wrap = TRUE;
3453 }
3454 }
3455 } else if (!strcmp(type, "colRGB24")) {
3456 if (len < 6) {
3457 lives_free(rfxbuilder->params[i].name);
3458 lives_free(rfxbuilder->params[i].label);
3459 rfxbuilder->num_params--;
3460 rfxbuilder->params = (lives_param_t *)lives_realloc(rfxbuilder->params, rfxbuilder->num_params * sizeof(lives_param_t));
3461 continue;
3462 }
3463 rfxbuilder->params[i].type = LIVES_PARAM_COLRGB24;
3464 rfxbuilder->params[i].def = lives_malloc(3 * sizint);
3465 set_colRGB24_param(rfxbuilder->params[i].def, (short)atoi(array[3]),
3466 (short)atoi(array[4]), (short)atoi(array[5]));
3467 } else if (!strcmp(type, "string")) {
3468 rfxbuilder->params[i].type = LIVES_PARAM_STRING;
3469 rfxbuilder->params[i].def = subst((tmp = L2U8(array[3])), "\\n", "\n");
3470 lives_free(tmp);
3471 if (len > 4) rfxbuilder->params[i].max = (double)atoi(array[4]);
3472 else rfxbuilder->params[i].max = 1024; // TODO
3473 } else if (!strcmp(type, "string_list")) {
3474 rfxbuilder->params[i].type = LIVES_PARAM_STRING_LIST;
3475 rfxbuilder->params[i].def = lives_malloc(sizint);
3476 set_int_param(rfxbuilder->params[i].def, atoi(array[3]));
3477 if (len > 4) {
3478 rfxbuilder->params[i].list = array_to_string_list(array, 3, len);
3479 } else {
3480 rfxbuilder->params[i].list = NULL;
3481 set_int_param(rfxbuilder->params[i].def, 0);
3482 }
3483 } else {
3484 // default is bool
3485 rfxbuilder->params[i].type = LIVES_PARAM_BOOL;
3486 rfxbuilder->params[i].def = lives_malloc(sizint);
3487 set_bool_param(rfxbuilder->params[i].def, atoi(array[3]));
3488 if (len > 4) rfxbuilder->params[i].group = atoi(array[4]);
3489 }
3490 lives_free(type);
3491 lives_strfreev(array);
3492 i++;
3493 }
3494 lives_list_free(list);
3495 }
3496
3497 if ((list = get_script_section("param_window", script_file, TRUE))) {
3498 rfxbuilder->num_paramw_hints = lives_list_length(list);
3499 for (i = 0; i < rfxbuilder->num_paramw_hints; i++) {
3500 rfxbuilder->paramw_hints[i] = (char *)lives_list_nth_data(list, i);
3501 }
3502 lives_list_free(list);
3503 }
3504
3505 if ((list = get_script_section("onchange", script_file, TRUE))) {
3506 listlen = lives_list_length(list);
3507 for (i = 0; i < listlen; i++) {
3508 array = lives_strsplit((char *)lives_list_nth_data(list, i), rfxbuilder->field_delim, -1);
3509 if (!strcmp(array[0], "init")) {
3510 if (!rfxbuilder->has_init_trigger) {
3511 rfxbuilder->has_init_trigger = TRUE;
3512 rfxbuilder->num_triggers++;
3513 }
3514 } else if ((tnum = atoi(array[0]) + 1) <= rfxbuilder->num_params && tnum > 0) {
3515 if (!rfxbuilder->params[tnum - 1].onchange) {
3516 rfxbuilder->params[tnum - 1].onchange = TRUE;
3517 rfxbuilder->num_triggers++;
3518 }
3519 } else {
3520 //invalid trigger
3521 char *msg = lives_strdup_printf(_("\n\nInvalid trigger (%s)\nfound in script.\n\n"), array[0]);
3522 widget_opts.non_modal = TRUE;
3523 do_error_dialog(msg);
3524 widget_opts.non_modal = FALSE;
3525 lives_free(msg);
3526 }
3527 lives_strfreev(array);
3528 }
3529 //end pass 1
3530 rfxbuilder->triggers = (rfx_trigger_t *)lives_malloc(rfxbuilder->num_triggers * sizeof(rfx_trigger_t));
3531
3532 for (i = 0; i < rfxbuilder->num_triggers; i++) {
3533 rfxbuilder->triggers[i].when = -1;
3534 rfxbuilder->triggers[i].code = lives_strdup("");
3535 }
3536
3537 filled_triggers = 0;
3538 listlen = lives_list_length(list);
3539 for (i = 0; i < listlen; i++) {
3540 array = lives_strsplit((char *)lives_list_nth_data(list, i), rfxbuilder->field_delim, -1);
3541 if (!strcmp(array[0], "init")) {
3542 // find init trigger and concatenate code
3543 found = filled_triggers;
3544 for (j = 0; j < filled_triggers && found == filled_triggers; j++) if (rfxbuilder->triggers[j].when == 0) found = j;
3545 if (found == filled_triggers) filled_triggers++;
3546 if (!strlen(rfxbuilder->triggers[found].code)) {
3547 tmp = lives_strconcat(rfxbuilder->triggers[found].code, array[1], NULL);
3548 } else {
3549 tmp = lives_strconcat(rfxbuilder->triggers[found].code, "\n", array[1], NULL);
3550 }
3551 lives_free(rfxbuilder->triggers[found].code);
3552 rfxbuilder->triggers[found].when = 0;
3553 rfxbuilder->triggers[found].code = lives_strdup(tmp);
3554 lives_free(tmp);
3555 } else if ((tnum = atoi(array[0]) + 1) <= rfxbuilder->num_params && tnum > 0) {
3556 // find tnum trigger and concatenate code
3557 found = filled_triggers;
3558
3559 for (j = 0; j < filled_triggers && found == filled_triggers; j++) if (rfxbuilder->triggers[j].when == tnum) found = j;
3560 if (found == filled_triggers) filled_triggers++;
3561
3562 if (!strlen(rfxbuilder->triggers[found].code)) {
3563 tmp = lives_strconcat(rfxbuilder->triggers[found].code, array[1], NULL);
3564 } else {
3565 tmp = lives_strconcat(rfxbuilder->triggers[found].code, "\n", array[1], NULL);
3566 }
3567 lives_free(rfxbuilder->triggers[found].code);
3568 rfxbuilder->triggers[found].when = tnum;
3569 rfxbuilder->triggers[found].code = lives_strdup(tmp);
3570 lives_free(tmp);
3571 }
3572 lives_strfreev(array);
3573 }
3574 lives_list_free_all(&list);
3575 }
3576
3577 if ((list = get_script_section("pre", script_file, FALSE))) {
3578 listlen = lives_list_length(list);
3579 for (i = 0; i < listlen; i++) {
3580 tmp = lives_strconcat(rfxbuilder->pre_code, lives_list_nth_data(list, i), NULL);
3581 lives_free(rfxbuilder->pre_code);
3582 rfxbuilder->pre_code = tmp;
3583 }
3584 lives_list_free_all(&list);
3585 }
3586
3587 if ((list = get_script_section("loop", script_file, FALSE))) {
3588 listlen = lives_list_length(list);
3589 for (i = 0; i < listlen; i++) {
3590 tmp = lives_strconcat(rfxbuilder->loop_code, lives_list_nth_data(list, i), NULL);
3591 lives_free(rfxbuilder->loop_code);
3592 rfxbuilder->loop_code = tmp;
3593 }
3594 lives_list_free_all(&list);
3595 }
3596
3597 if ((list = get_script_section("post", script_file, FALSE))) {
3598 listlen = lives_list_length(list);
3599 for (i = 0; i < listlen; i++) {
3600 tmp = lives_strconcat(rfxbuilder->post_code, lives_list_nth_data(list, i), NULL);
3601 lives_free(rfxbuilder->post_code);
3602 rfxbuilder->post_code = tmp;
3603 }
3604 lives_list_free_all(&list);
3605 }
3606
3607 return TRUE;
3608 }
3609
3610
get_script_section(const char * section,const char * file,boolean strip)3611 LiVESList *get_script_section(const char *section, const char *file, boolean strip) {
3612 char *com = lives_strdup_printf("\"%s\" -get \"%s\" \"%s\"", EXEC_RFX_BUILDER, section, file);
3613 LiVESList *list = get_plugin_result(com, "\n", FALSE, strip);
3614 lives_free(com);
3615 return list;
3616 }
3617
3618
3619 /** @brief parse text and return non empty lines between <section> and </section>
3620
3621 similar to get_val_from_cached_list, except here we parse each line into a list.
3622 rfx + params can be built from the <params> section
3623 */
3624 /* LiVESList *get_script_section_from_text(const char *section, const char *text, boolean strip) { */
3625 /* LiVESList *list; */
3626 /* // TODO */
3627 /* return list; */
3628 /* } */
3629
3630
on_rebuild_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)3631 void on_rebuild_rfx_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3632 char *com;
3633 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
3634
3635 if (!check_builder_programs()) return;
3636
3637 do_threaded_dialog(_("Rebuilding RFX scripts"), FALSE);
3638
3639 switch (status) {
3640 case RFX_STATUS_CUSTOM:
3641 d_print(_("Rebuilding custom RFX scripts..."));
3642 com = lives_strdup_printf("%s build_rfx_plugins custom", prefs->backend_sync);
3643 lives_system(com, FALSE);
3644 lives_free(com);
3645 break;
3646 case RFX_STATUS_TEST:
3647 d_print(_("Rebuilding test RFX scripts..."));
3648 com = lives_strdup_printf("%s build_rfx_plugins test", prefs->backend_sync);
3649 lives_system(com, FALSE);
3650 lives_free(com);
3651 break;
3652 default:
3653 break;
3654 }
3655
3656 d_print(_("recreating dynamic menu entries..."));
3657 lives_widget_context_update();
3658 threaded_dialog_spin(0.);
3659 add_rfx_effects(status);
3660 threaded_dialog_spin(0.);
3661 d_print_done();
3662 end_threaded_dialog();
3663 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
3664 lives_widget_context_update();
3665 }
3666
3667
check_builder_programs(void)3668 boolean check_builder_programs(void) {
3669 #ifdef IS_MINGW
3670 return TRUE;
3671 #endif
3672
3673 // check our plugin builder routines are executable
3674 char loc[32];
3675 char *msg;
3676
3677 get_location(EXEC_RFX_BUILDER, loc, 32);
3678 if (!strlen(loc)) {
3679 msg = lives_strdup_printf(
3680 _("\n\nLiVES was unable to find the program %s.\nPlease check this program is in your path and executable.\n"),
3681 EXEC_RFX_BUILDER);
3682 do_error_dialog(msg);
3683 lives_free(msg);
3684 return FALSE;
3685 }
3686 get_location(EXEC_RFX_BUILDER_MULTI, loc, 32);
3687 if (!strlen(loc)) {
3688 msg = lives_strdup_printf(
3689 _("\n\nLiVES was unable to find the program %s.\nPlease check this program is in your path and executable.\n"),
3690 EXEC_RFX_BUILDER_MULTI);
3691 do_error_dialog(msg);
3692 lives_free(msg);
3693 return FALSE;
3694 }
3695 return TRUE;
3696 }
3697
3698
on_delete_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)3699 void on_delete_rfx_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3700 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
3701 int ret;
3702 char *rfx_script_file, *rfx_exec_dir, *rfx_script_dir;
3703 char *script_name = prompt_for_script_name(NULL, status);
3704 char *msg;
3705
3706 if (!script_name) return; // user cancelled
3707
3708 if (strlen(script_name)) {
3709 switch (status) {
3710 case RFX_STATUS_TEST:
3711 rfx_exec_dir = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_TEST, NULL);
3712 rfx_script_dir = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, NULL);
3713 rfx_script_file = lives_build_filename(rfx_script_dir, script_name, NULL);
3714 break;
3715 case RFX_STATUS_CUSTOM:
3716 rfx_exec_dir = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_CUSTOM, NULL);
3717 rfx_script_dir = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_CUSTOM_SCRIPTS, NULL);
3718 rfx_script_file = lives_build_filename(rfx_script_dir, script_name, NULL);
3719 break;
3720 default:
3721 // we will not delete builtins
3722 lives_free(script_name);
3723 return;
3724 }
3725 lives_free(script_name);
3726
3727 // double check with user
3728 msg = lives_strdup_printf(_("\n\nReally delete RFX script\n%s ?\n\n"), rfx_script_file);
3729 if (!do_warning_dialog(msg)) {
3730 lives_free(msg);
3731 lives_free(rfx_script_file);
3732 lives_free(rfx_script_dir);
3733 lives_free(rfx_exec_dir);
3734 return;
3735 }
3736 lives_free(msg);
3737
3738 d_print(_("Deleting rfx script %s..."), rfx_script_file);
3739
3740 if (!(ret = lives_rm(rfx_script_file))) {
3741 lives_rmdir(rfx_exec_dir, TRUE);
3742 d_print_done();
3743 on_rebuild_rfx_activate(NULL, LIVES_INT_TO_POINTER(status));
3744 } else {
3745 d_print_failed();
3746 msg = lives_strdup_printf(_("\n\nFailed to delete the script\n%s\nError code was %d\n"), rfx_script_file, ret);
3747 widget_opts.non_modal = TRUE;
3748 do_error_dialog(msg);
3749 widget_opts.non_modal = FALSE;
3750 lives_free(msg);
3751 }
3752 lives_free(rfx_script_file);
3753 lives_free(rfx_script_dir);
3754 lives_free(rfx_exec_dir);
3755 }
3756 }
3757
3758
on_promote_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)3759 void on_promote_rfx_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3760 char *rfx_script_from = NULL;
3761 char *rfx_script_to = NULL;
3762 char *rfx_dir_from = NULL;
3763 char *rfx_dir_to = NULL;
3764 char *script_name = prompt_for_script_name(NULL, RFX_STATUS_TEST);
3765 char *msg;
3766 int ret = 0;
3767 boolean failed = TRUE;
3768
3769 if (!script_name) return; // user cancelled
3770
3771 if (strlen(script_name)) {
3772 rfx_dir_from = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, NULL);
3773 rfx_script_from = lives_build_filename(rfx_dir_from, script_name, NULL);
3774
3775 rfx_dir_to = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_CUSTOM_SCRIPTS, NULL);
3776 rfx_script_to = lives_build_filename(rfx_dir_to, script_name, NULL);
3777
3778 if (lives_file_test(rfx_script_to, LIVES_FILE_TEST_EXISTS)) {
3779 char *msg = lives_strdup_printf(
3780 _("\nCustom script file:\n%s\nalready exists.\nPlease delete it first, or rename the test script.\n"),
3781 script_name);
3782 do_error_dialog(msg);
3783 lives_free(msg); lives_free(rfx_dir_from); lives_free(rfx_script_from);
3784 lives_free(rfx_dir_to); lives_free(rfx_script_to); lives_free(script_name);
3785 return;
3786 }
3787
3788 d_print(_("Promoting rfx test plugin %s to custom..."), script_name);
3789 lives_free(script_name);
3790
3791 lives_mkdir_with_parents(rfx_dir_to, capable->umask);
3792
3793 if (!(ret = rename(rfx_script_from, rfx_script_to))) {
3794 d_print_done();
3795 on_rebuild_rfx_activate(NULL, LIVES_INT_TO_POINTER(RFX_STATUS_CUSTOM));
3796 on_rebuild_rfx_activate(NULL, LIVES_INT_TO_POINTER(RFX_STATUS_TEST));
3797 failed = FALSE;
3798 }
3799 }
3800
3801 if (failed) {
3802 lives_rmdir(rfx_dir_to, FALSE);
3803 d_print_failed();
3804 msg = lives_strdup_printf(_("\n\nFailed to move the plugin script from\n%s to\n%s\nReturn code was %d (%s)\n"),
3805 rfx_script_from, rfx_script_to, errno, strerror(errno));
3806 widget_opts.non_modal = TRUE;
3807 do_error_dialog(msg);
3808 widget_opts.non_modal = FALSE;
3809 lives_free(msg);
3810 } else lives_rmdir(rfx_dir_from, FALSE);
3811
3812 if (rfx_script_from) {
3813 lives_free(rfx_dir_from);
3814 lives_free(rfx_script_from);
3815 lives_free(rfx_dir_to);
3816 lives_free(rfx_script_to);
3817 }
3818 }
3819
3820
on_export_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)3821 void on_export_rfx_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3822 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
3823
3824 char *script_name = prompt_for_script_name(NULL, status);
3825 char *rfx_script_from, *filename;
3826 char *tmp, *tmp2;
3827
3828 if (!script_name || !*script_name) return; // user cancelled
3829
3830 filename = choose_file(NULL, script_name, NULL, LIVES_FILE_CHOOSER_ACTION_SAVE, _("Export Script"), NULL);
3831
3832 if (!filename) return;
3833
3834 rfx_script_from = lives_build_filename(prefs->config_datadir,
3835 PLUGIN_RENDERED_EFFECTS_CUSTOM_SCRIPTS, script_name, NULL);
3836
3837 d_print(_("Copying %s to %s..."), rfx_script_from, filename);
3838
3839 lives_cp((tmp = lives_filename_from_utf8(rfx_script_from, -1, NULL, NULL, NULL)),
3840 (tmp2 = lives_filename_from_utf8(filename, -1, NULL, NULL, NULL)));
3841
3842 if (THREADVAR(com_failed)) d_print_failed();
3843 else d_print_done();
3844 lives_free(tmp); lives_free(tmp2);
3845 lives_free(rfx_script_from); lives_free(filename); lives_free(script_name);
3846 }
3847
3848
on_import_rfx_activate(LiVESMenuItem * menuitem,livespointer user_data)3849 void on_import_rfx_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3850 lives_rfx_status_t status = (lives_rfx_status_t)LIVES_POINTER_TO_INT(user_data);
3851
3852 char *rfx_script_to, *rfx_dir_to;
3853 char *tmp, *tmp2, *tmpx;
3854 char basename[PATH_MAX];
3855
3856 char *filename = choose_file(NULL, NULL, NULL, LIVES_FILE_CHOOSER_ACTION_OPEN, _("Import Script"), NULL);
3857
3858 if (!filename) return;
3859
3860 lives_snprintf(basename, PATH_MAX, "%s", filename);
3861 get_basename(basename);
3862
3863 THREADVAR(com_failed) = FALSE;
3864
3865 switch (status) {
3866 case RFX_STATUS_TEST:
3867 rfx_dir_to = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, NULL);
3868 lives_mkdir_with_parents((tmp = lives_filename_from_utf8(rfx_dir_to, -1, NULL, NULL, NULL)), capable->umask);
3869 lives_free(tmp);
3870
3871 rfx_script_to = lives_build_filename(rfx_dir_to, basename, NULL);
3872 lives_free(rfx_dir_to);
3873 break;
3874 case RFX_STATUS_CUSTOM:
3875 rfx_dir_to = lives_build_path(prefs->config_datadir, PLUGIN_RENDERED_EFFECTS_CUSTOM_SCRIPTS, NULL);
3876 lives_mkdir_with_parents((tmp = lives_filename_from_utf8(rfx_dir_to, -1, NULL, NULL, NULL)), capable->umask);
3877
3878 lives_free(tmp);
3879 rfx_script_to = lives_build_filename(rfx_dir_to, basename, NULL);
3880 lives_free(rfx_dir_to);
3881 break;
3882 default:
3883 rfx_script_to = lives_build_filename(prefs->prefix_dir, PLUGIN_SCRIPTS_DIR,
3884 PLUGIN_RENDERED_EFFECTS_BUILTIN_SCRIPTS, basename, NULL);
3885 break;
3886 }
3887
3888 if (THREADVAR(com_failed)) {
3889 lives_free(rfx_script_to);
3890 lives_free(filename);
3891 return;
3892 }
3893
3894 if (lives_file_test(rfx_script_to, LIVES_FILE_TEST_EXISTS)) {
3895 // needs switch...eventually
3896 do_error_dialog((tmpx = lives_strdup_printf
3897 (_("\nCustom script file:\n%s\nalready exists.\n"
3898 "Please delete it first, or rename the import script.\n"), basename)));
3899 lives_free(tmpx); lives_free(rfx_script_to); lives_free(filename);
3900 return;
3901 }
3902
3903 d_print(_("Copying %s to %s..."), filename, rfx_script_to);
3904
3905 lives_cp((tmp = lives_filename_from_utf8(filename, -1, NULL, NULL, NULL)),
3906 (tmp2 = lives_filename_from_utf8(rfx_script_to, -1, NULL, NULL, NULL)));
3907
3908 lives_free(tmp);
3909 lives_free(tmp2);
3910 if (THREADVAR(com_failed)) d_print_failed();
3911 else {
3912 d_print_done();
3913 on_rebuild_rfx_activate(NULL, LIVES_INT_TO_POINTER(status));
3914 }
3915 lives_free(rfx_script_to);
3916 lives_free(filename);
3917 }
3918
3919
prompt_for_script_name(const char * sname,lives_rfx_status_t status)3920 char *prompt_for_script_name(const char *sname, lives_rfx_status_t status) {
3921 // show dialog to get script name of rfx plugin dependant on type
3922 // set type to RFX_STATUS_ANY to let user pick type as well
3923 // return value should be lives_free'd after use
3924 // beware: if the user cancels, return value is NULL
3925
3926 // sname is suggested name, set it to NULL to prompt for a name from
3927 // status list
3928
3929 // in copy mode, there are extra entries and the selected script will be copied
3930 // to test
3931
3932 // in rename mode a test script will be copied to another test script
3933
3934 char *name = NULL;
3935 char *from_name;
3936 char *from_status;
3937 char *rfx_script_from;
3938 char *rfx_script_to;
3939
3940 rfx_build_window_t *rfxbuilder;
3941
3942 LiVESWidget *vbox;
3943 LiVESWidget *hbox;
3944 LiVESWidget *label;
3945 LiVESWidget *script_combo = NULL;
3946 LiVESWidget *name_entry = NULL;
3947 LiVESWidget *script_combo_entry = NULL;
3948 LiVESWidget *status_combo = NULL;
3949 LiVESWidget *status_combo_entry = NULL;
3950 LiVESWidget *dialog;
3951
3952 LiVESList *status_list = NULL;
3953
3954 boolean copy_mode = FALSE;
3955 boolean rename_mode = FALSE;
3956 boolean OK;
3957
3958 if (status == RFX_STATUS_COPY) {
3959 copy_mode = TRUE;
3960 status_list = lives_list_append(status_list, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_BUILTIN]));
3961 status_list = lives_list_append(status_list, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_CUSTOM]));
3962 status_list = lives_list_append(status_list, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_TEST]));
3963 }
3964
3965 dialog = lives_standard_dialog_new(NULL, FALSE, -1, -1);
3966
3967 vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
3968
3969 hbox = lives_hbox_new(FALSE, 0);
3970 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3971
3972 vbox = lives_vbox_new(FALSE, 0);
3973 lives_box_pack_start(LIVES_BOX(hbox), vbox, FALSE, FALSE, widget_opts.packing_width);
3974
3975 add_fill_to_box(LIVES_BOX(vbox));
3976
3977 hbox = lives_hbox_new(FALSE, 0);
3978 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
3979
3980 add_fill_to_box(LIVES_BOX(vbox));
3981
3982 if (copy_mode) {
3983 lives_window_set_title(LIVES_WINDOW(dialog), _("Copy RFX Script"));
3984
3985 status_combo = lives_standard_combo_new(_("_From type: "), status_list, LIVES_BOX(hbox), NULL);
3986
3987 status_combo_entry = lives_combo_get_entry(LIVES_COMBO(status_combo));
3988
3989 lives_list_free_all(&status_list);
3990 } else {
3991 if (status == RFX_STATUS_RENAME) {
3992 lives_window_set_title(LIVES_WINDOW(dialog), _("Rename Test RFX Script"));
3993 label = lives_standard_label_new(_("From script: "));
3994 rename_mode = TRUE;
3995 status = RFX_STATUS_TEST;
3996 } else {
3997 lives_window_set_title(LIVES_WINDOW(dialog), _("RFX Script Name"));
3998 label = lives_standard_label_new(_("Script name: "));
3999 }
4000 lives_box_pack_start(LIVES_BOX(hbox), label, FALSE, FALSE, 0);
4001 }
4002
4003 if (!sname || copy_mode || rename_mode) {
4004 script_combo = lives_standard_combo_new(copy_mode ? _("Script:") : NULL, NULL, LIVES_BOX(hbox), NULL);
4005 name_entry = script_combo_entry = lives_combo_get_entry(LIVES_COMBO(script_combo));
4006 }
4007 if (sname || copy_mode || rename_mode) {
4008 // name_entry becomes a normal lives_entry
4009 if (copy_mode || rename_mode) {
4010 hbox = lives_hbox_new(FALSE, 0);
4011 lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
4012 }
4013
4014 name_entry = lives_standard_entry_new(copy_mode ? _("New name:") : rename_mode ? _("New script name:") : NULL,
4015 sname, -1, 128, LIVES_BOX(hbox), NULL);
4016
4017 if (copy_mode) {
4018 lives_signal_sync_connect(LIVES_GUI_OBJECT(status_combo), LIVES_WIDGET_CHANGED_SIGNAL,
4019 LIVES_GUI_CALLBACK(on_script_status_changed), (livespointer)script_combo);
4020 }
4021 }
4022 lives_widget_grab_focus(name_entry);
4023 lives_entry_set_activates_default(LIVES_ENTRY(name_entry), TRUE);
4024
4025 lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL, LIVES_RESPONSE_CANCEL);
4026
4027 copy_script_okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL, LIVES_RESPONSE_OK);
4028
4029 lives_button_grab_default_special(copy_script_okbutton);
4030
4031 lives_widget_show_all(dialog);
4032
4033 if (status_combo) on_script_status_changed(LIVES_COMBO(status_combo), (livespointer)script_combo);
4034 else if (script_combo) populate_script_combo(LIVES_COMBO(script_combo), status);
4035
4036 do {
4037 OK = TRUE;
4038 if (lives_dialog_run(LIVES_DIALOG(dialog)) == LIVES_RESPONSE_OK) {
4039 if (name) lives_free(name);
4040 name = lives_strdup(lives_entry_get_text(LIVES_ENTRY(name_entry)));
4041 if (copy_mode) {
4042 if (find_rfx_plugin_by_name(name, RFX_STATUS_TEST) > -1 ||
4043 find_rfx_plugin_by_name(name, RFX_STATUS_CUSTOM) > -1 ||
4044 find_rfx_plugin_by_name(name, RFX_STATUS_BUILTIN) > -1) {
4045 do_error_dialog(_("\n\nThere is already a plugin with this name.\nName must be unique.\n"));
4046 OK = FALSE;
4047 }
4048 //copy selected script to test
4049 else {
4050 from_name = lives_strdup(lives_entry_get_text(LIVES_ENTRY(script_combo_entry)));
4051 from_status = lives_strdup(lives_entry_get_text(LIVES_ENTRY(status_combo_entry)));
4052 if (!strcmp(from_status, mainw->string_constants[LIVES_STRING_CONSTANT_BUILTIN])) status = RFX_STATUS_BUILTIN;
4053 else {
4054 if (!strcmp(from_status, mainw->string_constants[LIVES_STRING_CONSTANT_CUSTOM])) status = RFX_STATUS_CUSTOM;
4055 else status = RFX_STATUS_TEST;
4056 }
4057
4058 if ((rfxbuilder = make_rfx_build_window(from_name, status)) == NULL) {
4059 // invalid name
4060 OK = FALSE;
4061 }
4062
4063 lives_free(from_name);
4064 lives_free(from_status);
4065
4066 if (OK) {
4067 lives_entry_set_text(LIVES_ENTRY(rfxbuilder->name_entry), name);
4068 rfxbuilder->mode = RFX_BUILDER_MODE_COPY;
4069 lives_widget_show(rfxbuilder->dialog);
4070 }
4071 }
4072 }
4073 if (rename_mode) {
4074 LiVESList *nmlist = NULL;
4075 char *xname = ensure_extension(name, LIVES_FILE_EXT_RFX_SCRIPT);
4076
4077 if (name && lives_list_find((nmlist = get_script_list(status)), xname)) {
4078 do_error_dialog(_("\n\nThere is already a test script with this name.\nScript name must be unique.\n"));
4079 OK = FALSE;
4080 } else {
4081 int ret;
4082 from_name = lives_strdup(lives_entry_get_text(LIVES_ENTRY(script_combo_entry)));
4083 rfx_script_from = lives_build_filename(prefs->config_datadir,
4084 PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, from_name, NULL);
4085 rfx_script_to = lives_build_filename(prefs->config_datadir,
4086 PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, xname, NULL);
4087 d_print(_("Renaming RFX test script %s to %s..."), from_name, xname);
4088 lives_free(from_name);
4089
4090 if ((ret = rename(rfx_script_from, rfx_script_to))) {
4091 d_print_failed();
4092 widget_opts.non_modal = TRUE;
4093 do_error_dialogf(_("\n\nFailed to move the plugin script from\n%s to\n%s\n"
4094 "Return code was %d\n"),
4095 rfx_script_from, rfx_script_to, ret);
4096 widget_opts.non_modal = FALSE;
4097 } else {
4098 d_print_done();
4099 }
4100 lives_free(rfx_script_from);
4101 lives_free(rfx_script_to);
4102 }
4103 if (nmlist) {
4104 lives_list_free_all(&nmlist);
4105 }
4106 lives_free(xname);
4107 }
4108 }
4109 } while (!OK);
4110
4111 lives_widget_destroy(dialog);
4112 return name;
4113 }
4114
4115
populate_script_combo(LiVESCombo * script_combo,lives_rfx_status_t status)4116 static void populate_script_combo(LiVESCombo * script_combo, lives_rfx_status_t status) {
4117 LiVESList *list = NULL;
4118 lives_combo_populate(script_combo, (list = get_script_list(status)));
4119 if (list) {
4120 lives_combo_set_active_index(script_combo, 0);
4121 lives_widget_set_sensitive(copy_script_okbutton, TRUE);
4122 lives_list_free_all(&list);
4123 } else {
4124 lives_combo_set_active_string(script_combo, "");
4125 lives_widget_set_sensitive(copy_script_okbutton, FALSE);
4126 }
4127 }
4128
4129
on_script_status_changed(LiVESCombo * status_combo,livespointer user_data)4130 static void on_script_status_changed(LiVESCombo * status_combo, livespointer user_data) {
4131 const char *text = lives_combo_get_active_text(status_combo);
4132 LiVESWidget *script_combo = (LiVESWidget *)user_data;
4133
4134 if (!script_combo || !LIVES_IS_COMBO(script_combo)) return;
4135
4136 if (!(strcmp(text, mainw->string_constants[LIVES_STRING_CONSTANT_BUILTIN]))) {
4137 populate_script_combo(LIVES_COMBO(script_combo), RFX_STATUS_BUILTIN);
4138 } else {
4139 if (!(strcmp(text, mainw->string_constants[LIVES_STRING_CONSTANT_CUSTOM]))) {
4140 populate_script_combo(LIVES_COMBO(script_combo), RFX_STATUS_CUSTOM);
4141 } else {
4142 if (!(strcmp(text, mainw->string_constants[LIVES_STRING_CONSTANT_TEST]))) {
4143 populate_script_combo(LIVES_COMBO(script_combo), RFX_STATUS_TEST);
4144 }
4145 }
4146 }
4147 }
4148
4149
get_script_list(lives_rfx_status_t status)4150 LiVESList *get_script_list(lives_rfx_status_t status) {
4151 LiVESList *script_list = NULL;
4152
4153 switch (status) {
4154 case RFX_STATUS_TEST:
4155 script_list = get_plugin_list(PLUGIN_RENDERED_EFFECTS_TEST_SCRIPTS, TRUE, NULL, LIVES_FILE_EXT_RFX_SCRIPT);
4156 break;
4157 case RFX_STATUS_CUSTOM:
4158 script_list = get_plugin_list(PLUGIN_RENDERED_EFFECTS_CUSTOM_SCRIPTS, TRUE, NULL, LIVES_FILE_EXT_RFX_SCRIPT);
4159 break;
4160 case RFX_STATUS_BUILTIN:
4161 case RFX_STATUS_COPY:
4162 script_list = get_plugin_list(PLUGIN_RENDERED_EFFECTS_BUILTIN_SCRIPTS, TRUE, NULL, LIVES_FILE_EXT_RFX_SCRIPT);
4163 break;
4164 default:
4165 break;
4166 }
4167 return script_list;
4168 }
4169
4170 static int rfx_slot_count = 0;
4171
add_rfx_effects(lives_rfx_status_t status)4172 void add_rfx_effects(lives_rfx_status_t status) {
4173 // scan render plugin directories, create a rfx array, and add each to the appropriate menu area
4174 LiVESList *rfx_builtin_list = NULL, *rfx_custom_list = NULL, *rfx_test_list = NULL;
4175
4176 lives_rfx_t *rfx = NULL;
4177 lives_rfx_t *rendered_fx;
4178
4179 #if LIVES_HAS_IMAGE_MENU_ITEM
4180 LiVESWidget *rfx_image;
4181 #endif
4182 int i, plugin_idx;
4183
4184 int rfx_builtin_list_length, rfx_custom_list_length, rfx_test_list_length;
4185 int rfx_list_length, old_list_length;
4186
4187 // reset / reload values
4188 if (status == RFX_STATUS_ANY)
4189 mainw->num_rendered_effects_builtin = 0;
4190 if (status != RFX_STATUS_TEST)
4191 mainw->num_rendered_effects_custom = 0;
4192 if (status != RFX_STATUS_CUSTOM)
4193 mainw->num_rendered_effects_test = 0;
4194
4195 rfx_builtin_list_length = mainw->num_rendered_effects_builtin;
4196 rfx_custom_list_length = mainw->num_rendered_effects_custom;
4197 rfx_test_list_length = mainw->num_rendered_effects_test;
4198
4199 old_list_length = rfx_builtin_list_length + rfx_custom_list_length + rfx_test_list_length;
4200
4201 if (status != RFX_STATUS_TEST) {
4202 mainw->has_custom_effects = mainw->has_custom_tools = mainw->has_custom_gens = mainw->has_custom_utilities = FALSE;
4203 }
4204
4205 if (status != RFX_STATUS_ANY) {
4206 for (i = 1; i <= mainw->num_rendered_effects_builtin + mainw->num_rendered_effects_custom
4207 + mainw->num_rendered_effects_test; i++) {
4208 if (mainw->rendered_fx[i].status == status) {
4209 if (mainw->rendered_fx[i].menuitem) {
4210 lives_widget_destroy(mainw->rendered_fx[i].menuitem);
4211 mainw->rendered_fx[i].menuitem = NULL;
4212 }
4213 }
4214 }
4215 threaded_dialog_spin(0.);
4216 }
4217
4218 if (status == RFX_STATUS_CUSTOM) {
4219 if (mainw->custom_effects_separator) lives_widget_destroy(mainw->custom_effects_separator);
4220 if (mainw->custom_effects_menu) lives_widget_destroy(mainw->custom_effects_menu);
4221 if (mainw->custom_effects_submenu) lives_widget_destroy(mainw->custom_effects_submenu);
4222 if (mainw->custom_gens_menu) lives_widget_destroy(mainw->custom_gens_menu);
4223 if (mainw->custom_gens_submenu) lives_widget_destroy(mainw->custom_gens_submenu);
4224 if (mainw->gens_menu) lives_widget_destroy(mainw->gens_menu);
4225
4226 if (mainw->custom_utilities_separator) lives_widget_destroy(mainw->custom_utilities_separator);
4227 if (mainw->custom_utilities_menu) lives_widget_destroy(mainw->custom_utilities_menu);
4228 if (mainw->custom_utilities_submenu) lives_widget_destroy(mainw->custom_utilities_submenu);
4229 if (mainw->custom_tools_menu) lives_widget_destroy(mainw->custom_tools_menu);
4230 if (mainw->utilities_menu) lives_widget_destroy(mainw->utilities_menu);
4231
4232 mainw->custom_effects_separator = mainw->custom_effects_menu = mainw->custom_effects_submenu
4233 = mainw->custom_gens_menu = mainw->custom_gens_submenu = mainw->gens_menu =
4234 mainw->custom_utilities_separator = mainw->custom_utilities_menu
4235 = mainw->custom_utilities_submenu
4236 = mainw->custom_tools_menu = mainw->utilities_menu = NULL;
4237 }
4238
4239 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4240
4241 // reset / reload values
4242 if (status == RFX_STATUS_ANY)
4243 mainw->num_rendered_effects_builtin = 0;
4244 if (status != RFX_STATUS_TEST)
4245 mainw->num_rendered_effects_custom = 0;
4246 if (status != RFX_STATUS_CUSTOM)
4247 mainw->num_rendered_effects_test = 0;
4248
4249 //if (status != RFX_STATUS_TEST) make_custom_submenus();
4250
4251 if (status != RFX_STATUS_CUSTOM) {
4252 //mainw->run_test_rfx_menu = lives_standard_menu_new();
4253 rfx_test_list = get_plugin_list(PLUGIN_RENDERED_EFFECTS_TEST, FALSE, NULL, NULL);
4254 rfx_test_list_length = lives_list_length(rfx_test_list);
4255 }
4256
4257 if (status != RFX_STATUS_TEST) {
4258 rfx_custom_list = get_plugin_list(PLUGIN_RENDERED_EFFECTS_CUSTOM, FALSE, NULL, NULL);
4259 rfx_custom_list_length = lives_list_length(rfx_custom_list);
4260 }
4261
4262 if (prefs->load_rfx_builtin) {
4263 if (status == RFX_STATUS_ANY) {
4264 if (!(rfx_builtin_list = get_plugin_list(PLUGIN_RENDERED_EFFECTS_BUILTIN, FALSE, NULL, NULL))) {
4265 do_rendered_fx_dialog();
4266 } else {
4267 rfx_builtin_list_length = lives_list_length(rfx_builtin_list);
4268 }
4269 }
4270 }
4271
4272 rfx_list_length = rfx_builtin_list_length + rfx_custom_list_length + rfx_test_list_length;
4273
4274 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4275
4276 rendered_fx = (lives_rfx_t *)lives_calloc((rfx_list_length + 1), sizeof(lives_rfx_t));
4277
4278 if (status != RFX_STATUS_ANY) {
4279 // add others to rendered_fx
4280 for (i = 0; i <= old_list_length; i++) {
4281 if (mainw->rendered_fx[i].status != status) {
4282 rfx_copy(&rendered_fx[rfx_slot_count++], &mainw->rendered_fx[i], FALSE);
4283 }
4284 }
4285 lives_free(mainw->rendered_fx);
4286 mainw->rendered_fx = NULL;
4287 } else {
4288 rendered_fx[0].name = lives_strdup("realtime_fx");
4289 rendered_fx[0].menu_text = (_("_Apply Real Time Effects to Selection"));
4290 rendered_fx[0].action_desc = (_("Applying Current Real Time Effects to"));
4291
4292 rendered_fx[0].props = 0;
4293 rendered_fx[0].rfx_version[0] = 0;
4294 rendered_fx[0].num_params = 0;
4295 rendered_fx[0].num_in_channels = 1;
4296 rendered_fx[0].menuitem = NULL;
4297 rendered_fx[0].params = NULL;
4298 rendered_fx[0].flags = 0;
4299 rendered_fx[0].gui_strings = NULL;
4300 rendered_fx[0].onchange_strings = NULL;
4301 rendered_fx[0].status = RFX_STATUS_WEED;
4302 rendered_fx[0].is_template = FALSE;
4303 rendered_fx[0].min_frames = 1;
4304 rendered_fx[0].source = NULL;
4305 rendered_fx[0].source_type = LIVES_RFX_SOURCE_RFX;
4306 rfx_slot_count = 1;
4307 }
4308
4309 if (rfx_list_length) {
4310 LiVESList *define = NULL;
4311 LiVESList *description = NULL;
4312 LiVESList *props = NULL;
4313 LiVESList *rfx_list = rfx_builtin_list;
4314
4315 lives_rfx_status_t xstatus = RFX_STATUS_BUILTIN;
4316
4317 char *type = lives_strdup(PLUGIN_RENDERED_EFFECTS_BUILTIN);
4318 char *plugin_name;
4319 char *def = NULL;
4320 char delim[2];
4321
4322 int offset = 0;
4323
4324 for (plugin_idx = 0; plugin_idx < rfx_list_length; plugin_idx++) {
4325 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4326 #ifndef BG_LOAD
4327 if (!mainw->splash_window) lives_widget_context_update();
4328 #endif
4329 if (plugin_idx == rfx_builtin_list_length) {
4330 lives_free(type);
4331 type = lives_strdup(PLUGIN_RENDERED_EFFECTS_CUSTOM);
4332 xstatus = RFX_STATUS_CUSTOM;
4333 rfx_list = rfx_custom_list;
4334 offset = rfx_builtin_list_length;
4335 }
4336 if (plugin_idx == rfx_builtin_list_length + rfx_custom_list_length) {
4337 lives_free(type);
4338 type = lives_strdup(PLUGIN_RENDERED_EFFECTS_TEST);
4339 xstatus = RFX_STATUS_TEST;
4340 rfx_list = rfx_test_list;
4341 offset += rfx_custom_list_length;
4342 }
4343
4344 if (status != RFX_STATUS_ANY && xstatus != status) continue;
4345
4346 plugin_name = lives_strdup((char *)lives_list_nth_data(rfx_list, plugin_idx - offset));
4347
4348 #ifndef BG_LOAD
4349 if (mainw->splash_window) {
4350 splash_msg((tmp = lives_strdup_printf(_("Loading rendered effect %s..."), plugin_name)), SPLASH_LEVEL_LOAD_RFX);
4351 lives_free(tmp);
4352 }
4353 #endif
4354
4355 #ifdef DEBUG_RENDER_FX
4356 g_print("Checking plugin %s\n", plugin_name);
4357 #endif
4358
4359 if ((define = plugin_request_by_line(type, plugin_name, "get_define")) == NULL) {
4360 #ifdef DEBUG_RENDER_FX
4361 g_print("No get_define in %s\n", plugin_name);
4362 #endif
4363 lives_free(plugin_name);
4364 continue;
4365 }
4366
4367 def = lives_strdup((char *)lives_list_nth_data(define, 0));
4368 lives_list_free_all(&define);
4369
4370 if (strlen(def) < 2) {
4371 #ifdef DEBUG_RENDER_FX
4372 g_print("Invalid get_define in %s\n", plugin_name);
4373 #endif
4374 lives_free(plugin_name);
4375 lives_free(def);
4376 continue;
4377 }
4378 if (make_version_hash(def + 1) > make_version_hash(RFX_VERSION)) {
4379 #ifdef DEBUG_RENDER_FX
4380 g_print("Invalid version %s instead of %s in %s\n", def + 1, RFX_VERSION, plugin_name);
4381 #endif
4382 lives_free(plugin_name);
4383 lives_free(def);
4384 continue;
4385 }
4386
4387 delim[0] = def[0];
4388 delim[1] = 0;
4389
4390 if ((description = plugin_request_common(type, plugin_name, "get_description", delim, TRUE)) &&
4391 (props = plugin_request_common(type, plugin_name, "get_capabilities", delim, FALSE)) &&
4392 lives_list_length(description) > 3) {
4393 rfx = &rendered_fx[rfx_slot_count++];
4394 rfx->name = lives_strdup(plugin_name);
4395 lives_memcpy(rfx->delim, delim, 2);
4396 rfx->menu_text = lives_strdup((char *)lives_list_nth_data(description, 0));
4397 rfx->action_desc = lives_strdup((char *)lives_list_nth_data(description, 1));
4398 if (!(rfx->min_frames = atoi((char *)lives_list_nth_data(description, 2)))) rfx->min_frames = 1;
4399 rfx->num_in_channels = atoi((char *)lives_list_nth_data(description, 3));
4400 rfx->status = xstatus;
4401 lives_snprintf(rfx->rfx_version, 64, "%s", def + 1);
4402 rfx->props = atoi((char *)lives_list_nth_data(props, 0));
4403 rfx->num_params = 0;
4404 rfx->is_template = FALSE;
4405 rfx->params = NULL;
4406 rfx->source = NULL;
4407 rfx->source_type = LIVES_RFX_SOURCE_RFX;
4408 rfx->flags = 0;
4409 rfx->gui_strings = NULL;
4410 rfx->onchange_strings = NULL;
4411 rfx->is_template = FALSE;
4412 if (!check_rfx_for_lives(rfx)) rfx_slot_count--;
4413 }
4414
4415 lives_free(plugin_name);
4416 if (props) {
4417 lives_list_free_all(&props);
4418 props = NULL;
4419 }
4420 if (description) {
4421 lives_list_free_all(&description);
4422 description = NULL;
4423 }
4424 lives_free(def);
4425 }
4426
4427 if (rfx_builtin_list) lives_list_free_all(&rfx_builtin_list);
4428 if (rfx_custom_list) lives_list_free_all(&rfx_custom_list);
4429 if (rfx_test_list) lives_list_free_all(&rfx_test_list);
4430
4431 lives_free(type);
4432 }
4433
4434 lives_freep((void **)&mainw->rendered_fx);
4435
4436 rfx_slot_count--;
4437
4438 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4439
4440 // sort menu text by alpha order (apart from [0]) and create mainw->rendered_fx
4441 sort_rfx_array(rendered_fx, rfx_slot_count); // each rendered_fx is copied and free()d
4442 lives_free(rendered_fx);
4443
4444 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4445
4446 // now we need to add to the effects menu and set a callback
4447 for (rfx = &mainw->rendered_fx[(plugin_idx = 1)]; plugin_idx <= rfx_slot_count; rfx = &mainw->rendered_fx[++plugin_idx]) {
4448 if (status != RFX_STATUS_ANY && rfx->status != status) continue;
4449
4450 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4451
4452 render_fx_get_params(rfx, rfx->name, rfx->status);
4453 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4454 rfx->source = NULL;
4455 rfx->flags = 0;
4456 rfx->gui_strings = NULL;
4457 rfx->onchange_strings = NULL;
4458 rfx->menuitem = NULL;
4459
4460 switch (rfx->status) {
4461 case RFX_STATUS_BUILTIN:
4462 mainw->num_rendered_effects_builtin++; break;
4463 case RFX_STATUS_CUSTOM:
4464 mainw->num_rendered_effects_custom++; break;
4465 case RFX_STATUS_TEST:
4466 mainw->num_rendered_effects_test++; break;
4467 default: break;
4468 }
4469 }
4470
4471 if (status != RFX_STATUS_ANY) {
4472 if (mainw->num_rendered_effects_test) {
4473 lives_widget_set_sensitive(mainw->run_test_rfx_submenu, TRUE);
4474 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->run_test_rfx_submenu), mainw->run_test_rfx_menu);
4475 add_rfx_effects2(status);
4476 }
4477 }
4478 }
4479
4480
add_rfx_effects2(lives_rfx_status_t status)4481 void add_rfx_effects2(lives_rfx_status_t status) {
4482 LiVESWidget *menuitem;
4483 lives_rfx_t *rfx;
4484 char txt[64]; // menu text
4485 int plugin_idx, tool_posn = RFX_TOOL_MENU_POSN;
4486
4487 if (status == RFX_STATUS_ANY) {
4488 // recreate effects menu
4489 LiVESWidget *menuitem = lives_standard_menu_item_new_with_label(mainw->rendered_fx[0].menu_text);
4490
4491 lives_widget_set_sensitive(menuitem, FALSE);
4492 lives_widget_set_tooltip_text(menuitem, _("See: VJ - show VJ keys. Set the realtime effects, and then apply them here."));
4493
4494 lives_widget_add_accelerator(menuitem, LIVES_WIDGET_ACTIVATE_SIGNAL, mainw->accel_group,
4495 LIVES_KEY_e, LIVES_CONTROL_MASK, LIVES_ACCEL_VISIBLE);
4496
4497 lives_signal_sync_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4498 LIVES_GUI_CALLBACK(on_realfx_activate), &mainw->rendered_fx[0]);
4499
4500 mainw->rendered_fx[0].menuitem = menuitem;
4501 mainw->rendered_fx[0].num_in_channels = 1;
4502
4503 if (!LIVES_IS_PLAYING && mainw->current_file > 0 &&
4504 ((has_video_filters(TRUE) && !has_video_filters(FALSE)) ||
4505 (cfile->achans > 0 && prefs->audio_src == AUDIO_SRC_INT && has_audio_filters(AF_TYPE_ANY)) ||
4506 mainw->agen_key != 0)) {
4507 lives_widget_set_sensitive(menuitem, TRUE);
4508 } else lives_widget_set_sensitive(menuitem, FALSE);
4509 }
4510
4511 if (mainw->num_rendered_effects_test) {
4512 lives_widget_set_sensitive(mainw->run_test_rfx_submenu, TRUE);
4513 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->run_test_rfx_submenu), mainw->run_test_rfx_menu);
4514 }
4515
4516 if (status != RFX_STATUS_TEST) make_custom_submenus();
4517
4518 if (status == RFX_STATUS_TEST && mainw->run_test_rfx_menu) {
4519 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->run_test_rfx_submenu), NULL);
4520 if (LIVES_IS_WIDGET(mainw->run_test_rfx_menu)) lives_widget_destroy(mainw->run_test_rfx_menu);
4521 }
4522
4523 if (status != RFX_STATUS_TEST) {
4524 mainw->custom_effects_menu = lives_standard_menu_new();
4525 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->custom_effects_submenu), mainw->custom_effects_menu);
4526
4527 mainw->custom_tools_menu = lives_standard_menu_new();
4528 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->custom_tools_submenu), mainw->custom_tools_menu);
4529 }
4530
4531 if (status == RFX_STATUS_ANY && mainw->rendered_fx[0].menuitem) {
4532 lives_container_add(LIVES_CONTAINER(mainw->effects_menu), mainw->rendered_fx[0].menuitem);
4533 mainw->rte_separator = lives_menu_add_separator(LIVES_MENU(mainw->effects_menu));
4534 }
4535
4536 if (status != RFX_STATUS_TEST) {
4537 lives_menu_shell_insert(LIVES_MENU_SHELL(mainw->effects_menu), mainw->custom_effects_submenu, 2);
4538 mainw->custom_effects_separator = lives_menu_item_new();
4539 lives_widget_set_sensitive(mainw->custom_effects_separator, FALSE);
4540 lives_menu_shell_insert(LIVES_MENU_SHELL(mainw->effects_menu), mainw->custom_effects_separator, 3);
4541 }
4542
4543 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4544
4545 if (status != RFX_STATUS_TEST) {
4546 // recreate menus for effects, utilities, generators
4547 mainw->utilities_menu = lives_standard_menu_new();
4548 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->utilities_submenu), mainw->utilities_menu);
4549
4550 mainw->custom_utilities_menu = lives_standard_menu_new();
4551 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->custom_utilities_submenu), mainw->custom_utilities_menu);
4552
4553 lives_container_add(LIVES_CONTAINER(mainw->utilities_menu), mainw->custom_utilities_submenu);
4554 mainw->custom_utilities_separator = lives_menu_add_separator(LIVES_MENU(mainw->utilities_menu));
4555
4556 mainw->gens_menu = lives_standard_menu_new();
4557 if (!mainw->multitrack)
4558 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->gens_submenu), mainw->gens_menu);
4559 else
4560 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->multitrack->gens_submenu), mainw->gens_menu);
4561
4562 mainw->custom_gens_menu = lives_standard_menu_new();
4563 lives_menu_item_set_submenu(LIVES_MENU_ITEM(mainw->custom_gens_submenu), mainw->custom_gens_menu);
4564 lives_container_add(LIVES_CONTAINER(mainw->gens_menu), mainw->custom_gens_submenu);
4565
4566 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4567
4568 if (mainw->fx_candidates[FX_CANDIDATE_RESIZER].delegate == -1) mainw->resize_menuitem = NULL;
4569 }
4570
4571 if (rfx_slot_count) {
4572 for (rfx = &mainw->rendered_fx[(plugin_idx = 1)]; plugin_idx <= rfx_slot_count; rfx = &mainw->rendered_fx[++plugin_idx]) {
4573 if (rfx->status == RFX_STATUS_TEST) {
4574 if (status == RFX_STATUS_CUSTOM) continue;
4575 } else if (status == RFX_STATUS_TEST) continue;
4576
4577 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4578
4579 lives_snprintf(txt, 61, "_%s", _(rfx->menu_text));
4580 if (rfx->num_params) lives_strappend(txt, 64, "...");
4581 menuitem = lives_standard_menu_item_new_with_label(txt);
4582 rfx->menuitem = menuitem;
4583
4584 if ((rfx->props & RFX_PROPS_MAY_RESIZE && rfx->num_in_channels == 1) || rfx->min_frames < 0) {
4585 // add resizing effects to tools menu
4586 if (!strcmp(rfx->name, "resize")) {
4587 if (mainw->fx_candidates[FX_CANDIDATE_RESIZER].delegate == -1) {
4588 mainw->resize_menuitem = menuitem;
4589 } else continue;
4590 }
4591
4592 switch (rfx->status) {
4593 case RFX_STATUS_BUILTIN:
4594 if (rfx->min_frames >= 0) {
4595 if (status == RFX_STATUS_CUSTOM) continue;
4596 lives_menu_shell_insert(LIVES_MENU_SHELL(mainw->tools_menu), menuitem, tool_posn++);
4597 } else {
4598 lives_container_add(LIVES_CONTAINER(mainw->utilities_menu), menuitem);
4599 }
4600 break;
4601 case RFX_STATUS_CUSTOM:
4602 if (rfx->min_frames >= 0) {
4603 lives_container_add(LIVES_CONTAINER(mainw->custom_tools_menu), menuitem);
4604 mainw->has_custom_tools = TRUE;
4605 } else {
4606 lives_container_add(LIVES_CONTAINER(mainw->custom_utilities_menu), menuitem);
4607 mainw->has_custom_utilities = TRUE;
4608 }
4609 break;
4610 case RFX_STATUS_TEST:
4611 lives_container_add(LIVES_CONTAINER(mainw->run_test_rfx_menu), menuitem);
4612 break;
4613 default:
4614 break;
4615 }
4616
4617 if (menuitem != mainw->resize_menuitem) {
4618 if (!rfx->params) {
4619 lives_signal_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4620 LIVES_GUI_CALLBACK(on_render_fx_activate), (livespointer)rfx);
4621 } else {
4622 lives_signal_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4623 LIVES_GUI_CALLBACK(on_render_fx_pre_activate), (livespointer)rfx);
4624 }
4625 } else {
4626 mainw->fx_candidates[FX_CANDIDATE_RESIZER].func
4627 = lives_signal_sync_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4628 LIVES_GUI_CALLBACK(on_render_fx_pre_activate), (livespointer)rfx);
4629 }
4630
4631 if (rfx->min_frames >= 0) lives_widget_set_sensitive(menuitem, FALSE);
4632 } else {
4633 if (rfx->num_in_channels == 0) {
4634 // non-realtime generator
4635 switch (rfx->status) {
4636 case RFX_STATUS_BUILTIN:
4637 lives_container_add(LIVES_CONTAINER(mainw->gens_menu), menuitem); break;
4638 case RFX_STATUS_CUSTOM:
4639 lives_container_add(LIVES_CONTAINER(mainw->custom_gens_menu), menuitem);
4640 mainw->has_custom_gens = TRUE; break;
4641 case RFX_STATUS_TEST:
4642 lives_container_add(LIVES_CONTAINER(mainw->run_test_rfx_menu), menuitem); break;
4643 default: break;
4644 }
4645 lives_signal_sync_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4646 LIVES_GUI_CALLBACK(on_render_fx_pre_activate), (livespointer)rfx);
4647 } else {
4648 #if LIVES_HAS_IMAGE_MENU_ITEM
4649 rfx_image = NULL;
4650 if (rfx->props & RFX_PROPS_SLOW) {
4651 rfx_image = lives_image_new_from_stock(LIVES_STOCK_NO, LIVES_ICON_SIZE_MENU);
4652 } else {
4653 rfx_image = lives_image_new_from_stock(LIVES_STOCK_YES, LIVES_ICON_SIZE_MENU);
4654 }
4655 lives_image_menu_item_set_image(LIVES_IMAGE_MENU_ITEM(menuitem), rfx_image);
4656 #endif
4657 if (rfx->num_in_channels == 1) {
4658 lives_container_add(LIVES_CONTAINER(mainw->effects_menu), menuitem);
4659 }
4660 if (!rfx->params) {
4661 lives_signal_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4662 LIVES_GUI_CALLBACK(on_render_fx_activate), (livespointer)rfx);
4663 } else {
4664 lives_signal_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
4665 LIVES_GUI_CALLBACK(on_render_fx_pre_activate), (livespointer)rfx);
4666 }
4667 if (rfx->min_frames >= 0) lives_widget_set_sensitive(menuitem, FALSE);
4668 // *INDENT-OFF*
4669 }}}}
4670 // *INDENT-ON*
4671
4672 if (status != RFX_STATUS_ANY) threaded_dialog_spin(0.);
4673
4674 update_rfx_menus();
4675
4676 if (status != RFX_STATUS_ANY) {
4677 threaded_dialog_spin(0.);
4678 if (CURRENT_CLIP_IS_VALID && !LIVES_IS_PLAYING) sensitize_rfx();
4679 threaded_dialog_spin(0.);
4680 }
4681 }
4682
4683
update_rfx_menus(void)4684 void update_rfx_menus(void) {
4685 if (prefs->show_gui) {
4686 if (!mainw->has_custom_effects) {
4687 if (mainw->custom_effects_separator)
4688 lives_widget_hide(mainw->custom_effects_separator);
4689 } else {
4690 lives_widget_set_no_show_all(mainw->custom_effects_submenu, FALSE);
4691 lives_widget_show_all(mainw->custom_effects_submenu);
4692 lives_widget_show(mainw->custom_effects_separator);
4693 }
4694
4695 if (mainw->has_custom_tools) {
4696 lives_widget_set_no_show_all(mainw->custom_tools_submenu, FALSE);
4697 } else {
4698 lives_widget_set_no_show_all(mainw->custom_tools_submenu, TRUE);
4699 lives_widget_hide(mainw->custom_tools_submenu);
4700 }
4701
4702 if (mainw->has_custom_utilities) {
4703 lives_widget_set_no_show_all(mainw->custom_utilities_submenu, FALSE);
4704 }
4705
4706 lives_widget_show_all(mainw->tools_menu);
4707
4708 if (!mainw->has_custom_utilities) {
4709 if (mainw->custom_utilities_separator) lives_widget_hide(mainw->custom_utilities_separator);
4710 }
4711
4712 if (!mainw->has_custom_tools) {
4713 lives_widget_hide(mainw->custom_tools_separator);
4714 }
4715
4716 if (mainw->has_custom_gens) {
4717 lives_widget_set_no_show_all(mainw->custom_gens_submenu, FALSE);
4718 }
4719 lives_widget_show_all(mainw->gens_submenu);
4720 if (mainw->multitrack) lives_widget_show_all(mainw->multitrack->gens_submenu);
4721 }
4722
4723 if (mainw->num_rendered_effects_custom > 0) {
4724 lives_widget_set_sensitive(mainw->delete_custom_rfx, TRUE);
4725 lives_widget_set_sensitive(mainw->export_custom_rfx, TRUE);
4726 } else {
4727 lives_widget_set_sensitive(mainw->delete_custom_rfx, FALSE);
4728 lives_widget_set_sensitive(mainw->export_custom_rfx, FALSE);
4729 }
4730
4731 if (mainw->num_rendered_effects_test > 0) {
4732 lives_widget_show_all(mainw->run_test_rfx_submenu);
4733 lives_widget_set_sensitive(mainw->run_test_rfx_submenu, TRUE);
4734 lives_widget_set_sensitive(mainw->promote_test_rfx, TRUE);
4735 lives_widget_set_sensitive(mainw->delete_test_rfx, TRUE);
4736 lives_widget_set_sensitive(mainw->rename_test_rfx, TRUE);
4737 lives_widget_set_sensitive(mainw->edit_test_rfx, TRUE);
4738 } else {
4739 lives_widget_set_sensitive(mainw->run_test_rfx_submenu, FALSE);
4740 lives_widget_set_sensitive(mainw->promote_test_rfx, FALSE);
4741 lives_widget_set_sensitive(mainw->delete_test_rfx, FALSE);
4742 lives_widget_set_sensitive(mainw->rename_test_rfx, FALSE);
4743 lives_widget_set_sensitive(mainw->edit_test_rfx, FALSE);
4744 }
4745 lives_widget_show_all(mainw->effects_menu);
4746 }
4747
4748