1 // effects-data.c
2 // LiVES (lives-exe)
3 // (c) G. Finch 2005 - 2019 (salsaman+lives@gmail.com)
4 // Released under the GPL 3 or later
5 // see file ../COPYING for licensing details
6
7 // functions for chaining and data passing between fx plugins
8
9 //#define DEBUG_PCONX
10
11 #include "main.h"
12 #include "effects.h"
13 #include "ce_thumbs.h"
14 #include "omc-learn.h"
15
16 static lives_pconnect_t *spconx;
17 static lives_cconnect_t *scconx;
18
19 static boolean do_chan_connected_query(lives_conx_w *, int okey, int omode, int ocnum, boolean is_same_key);
20 static boolean do_param_connected_query(lives_conx_w *, int okey, int omode, int opnum, boolean is_same_key);
21 static void do_param_incompatible_error(lives_conx_w *);
22
23 static void ptable_row_add_standard_widgets(lives_conx_w *, int idx);
24 static void ptable_row_add_variable_widgets(lives_conx_w *, int idx, int row, int pidx);
25
26 static void ctable_row_add_standard_widgets(lives_conx_w *, int idx);
27 static void ctable_row_add_variable_widgets(lives_conx_w *, int idx, int row, int cidx);
28
29 static void padd_clicked(LiVESWidget *button, livespointer user_data);
30 static void cadd_clicked(LiVESWidget *button, livespointer user_data);
31
32 static void dfxp_changed(LiVESWidget *, livespointer conxwp);
33
34 static weed_plant_t *active_dummy = NULL;
35
36 static LiVESTreeModel *pmodel;
37 static LiVESTreeModel *cmodel;
38
39 static char *lctext;
40
41 #define BW (40. * widget_opts.scale)
42 #define BH (40. * widget_opts.scale)
43
44 #ifdef DEBUG_PCONX
dump_connections(void)45 static void dump_connections(void) {
46 lives_pconnect_t *pconx = mainw->pconx;
47 while (pconx) {
48 int p = 0;
49 for (int i = 0; i < pconx->nparams; i++) {
50 int pnum = pconx->params[i];
51 for (int j = 0; j < pconx->nconns[i + 1]; j++) {
52 p++;
53 // *INDENT-OFF*
54 }}
55 // *INDENT-ON*
56 pconx = pconx->next;
57 }
58 }
59 #endif
60
get_param_name(weed_plant_t * param,int pnum,boolean is_in)61 static char *get_param_name(weed_plant_t *param, int pnum, boolean is_in) {
62 char *name = weed_get_string_value(param, WEED_LEAF_NAME, NULL);
63 if (!*name) {
64 lives_free(name);
65 name = NULL;
66 }
67 if (!name) {
68 if (is_in) name = lives_strdup_printf(_("In param %d"), pnum);
69 else name = lives_strdup_printf(_("Out param %d"), pnum);
70 }
71 return name;
72 }
73
74
get_chan_name(weed_plant_t * chan,int cnum,boolean is_in)75 static char *get_chan_name(weed_plant_t *chan, int cnum, boolean is_in) {
76 char *name = weed_get_string_value(chan, WEED_LEAF_NAME, NULL);
77 if (!*name) {
78 lives_free(name);
79 name = NULL;
80 }
81 if (!name) {
82 if (is_in) name = lives_strdup_printf(_("In channel %d"), cnum);
83 else name = lives_strdup_printf(_("Out channel %d"), cnum);
84 }
85 return name;
86 }
87
88
switch_fx_state(int hotkey)89 static void switch_fx_state(int hotkey) {
90 // switch effect state when a connection to ACTIVATE is present
91 uint32_t last_grabbable_effect = mainw->last_grabbable_effect;
92 // use -hotkey to indicate auto
93 rte_key_toggle(-hotkey);
94 mainw->last_grabbable_effect = last_grabbable_effect;
95 }
96
97
override_if_active_input(int hotkey)98 void override_if_active_input(int hotkey) {
99 // if we have a connection to ACTIVATE, allow override if the user changes the state from the kbd
100 lives_pconnect_t *pconx = mainw->pconx;
101
102 int totcons;
103 int imode = rte_key_getmode(hotkey);
104
105 int i, j;
106
107 while (pconx) {
108 totcons = 0;
109 j = 0;
110 for (i = 0; i < pconx->nparams; i++) {
111 totcons += pconx->nconns[i];
112 for (; j < totcons; j++) {
113 if (pconx->ikey[j] == hotkey && pconx->imode[j] == imode && pconx->ipnum[j] == FX_DATA_PARAM_ACTIVE) {
114 // out param is "ACTIVATED"
115 // abuse "autoscale" for this
116 pconx->autoscale[j] = TRUE;
117 return;
118 // *INDENT-OFF*
119 }}}
120 pconx = pconx->next;
121 // *INDENT-ON*
122 }
123 }
124
125
end_override_if_activate_output(int hotkey)126 void end_override_if_activate_output(int hotkey) {
127 // if we activate an effect and it is connected to ACTIVATE another effect, end any user override
128 lives_pconnect_t *pconx = mainw->pconx;
129
130 int totcons;
131 int omode = rte_key_getmode(hotkey);
132
133 int j;
134
135 while (pconx) {
136 if (pconx->okey == hotkey && pconx->omode == omode) {
137 totcons = 0;
138 j = 0;
139 for (int i = 0; i < pconx->nparams; i++) {
140 totcons += pconx->nconns[i];
141 for (; j < totcons; j++) {
142 if (pconx->ipnum[j] == FX_DATA_PARAM_ACTIVE) {
143 // abuse "autoscale" for this
144 pconx->autoscale[j] = FALSE;
145 // *INDENT-OFF*
146 }}}}
147 // *INDENT-ON*
148 pconx = pconx->next;
149 }
150 }
151
152
pconx_delete_all(void)153 void pconx_delete_all(void) {
154 lives_pconnect_t *pconx = mainw->pconx, *pconx_next;
155 int i;
156
157 for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_lock(&mainw->fx_mutex[i]);
158
159 while (pconx) {
160 pconx_next = pconx->next;
161 lives_free(pconx->params); lives_free(pconx->nconns); lives_free(pconx->last_boolval);
162 lives_free(pconx->ikey); lives_free(pconx->imode); lives_free(pconx->ipnum);
163 lives_free(pconx->autoscale); lives_free(pconx);
164 pconx = pconx_next;
165 }
166 mainw->pconx = NULL;
167
168 for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_unlock(&mainw->fx_mutex[i]);
169 }
170
171
pconx_new(int okey,int omode)172 static lives_pconnect_t *pconx_new(int okey, int omode) {
173 lives_pconnect_t *pconx = (lives_pconnect_t *)lives_calloc(sizeof(struct _lives_pconnect_t), 1);
174 pconx->okey = okey;
175 pconx->omode = omode;
176 return pconx;
177 }
178
179
pconx_copy(lives_pconnect_t * spconx)180 static lives_pconnect_t *pconx_copy(lives_pconnect_t *spconx) {
181 lives_pconnect_t *pconx = NULL, *dpconx, *last_dpconx;
182
183 int totcons = 0;
184
185 int j = 0;
186
187 while (spconx) {
188 dpconx = pconx_new(spconx->okey, spconx->omode);
189 if (!pconx) pconx = dpconx;
190 else last_dpconx->next = dpconx;
191
192 dpconx->nparams = spconx->nparams;
193
194 dpconx->nconns = (int *)lives_malloc(dpconx->nparams * sizint);
195 dpconx->params = (int *)lives_malloc(dpconx->nparams * sizint);
196 dpconx->last_boolval = (int *)lives_malloc(dpconx->nparams * sizint);
197
198 dpconx->ikey = dpconx->imode = dpconx->ipnum = NULL;
199 dpconx->autoscale = NULL;
200
201 j = 0;
202
203 for (int i = 0; i < dpconx->nparams; i++) {
204 dpconx->params[i] = spconx->params[i];
205 dpconx->nconns[i] = spconx->nconns[i];
206 dpconx->last_boolval[i] = spconx->last_boolval[i];
207 totcons += dpconx->nconns[i];
208
209 dpconx->ikey = (int *)lives_realloc(dpconx->ikey, totcons * sizint);
210 dpconx->imode = (int *)lives_realloc(dpconx->imode, totcons * sizint);
211 dpconx->ipnum = (int *)lives_realloc(dpconx->ipnum, totcons * sizint);
212 dpconx->autoscale = (boolean *)lives_realloc(dpconx->autoscale, totcons * sizint);
213
214 while (j < totcons) {
215 dpconx->ikey[j] = spconx->ikey[j];
216 dpconx->imode[j] = spconx->imode[j];
217 dpconx->ipnum[j] = spconx->ipnum[j];
218 dpconx->autoscale[j] = spconx->autoscale[j];
219 j++;
220 }
221 }
222
223 spconx = spconx->next;
224 last_dpconx = dpconx;
225 }
226
227 return pconx;
228 }
229
230
pconx_list(int okey,int omode,int opnum)231 char *pconx_list(int okey, int omode, int opnum) {
232 char *st1 = lives_strdup(""), *st2;
233 lives_pconnect_t *pconx = mainw->pconx;
234 int totcons = 0;
235
236 while (pconx) {
237 if (pconx->okey == okey && pconx->omode == omode) {
238 for (int i = 0; i < pconx->nparams; i++) {
239 if (pconx->params[i] == opnum) {
240 for (int j = totcons; j < totcons + pconx->nconns[i]; j++) {
241 if (!*st1)
242 st2 = lives_strdup_printf("%d %d %d %d", pconx->ikey[j] + 1, pconx->imode[j] + 1, pconx->ipnum[j],
243 pconx->autoscale[j]);
244 else
245 st2 = lives_strdup_printf("%s %d %d %d %d", st1, pconx->ikey[j] + 1, pconx->imode[j] + 1,
246 pconx->ipnum[j], pconx->autoscale[j]);
247 lives_free(st1);
248 st1 = st2;
249 }
250 return st1;
251 }
252 totcons += pconx->nconns[i];
253 }
254 return st1;
255 }
256 pconx = pconx->next;
257 }
258 return st1;
259 }
260
261
pconx_delete(int okey,int omode,int opnum,int ikey,int imode,int ipnum)262 void pconx_delete(int okey, int omode, int opnum, int ikey, int imode, int ipnum) {
263 lives_pconnect_t *pconx = mainw->pconx, *pconx_next, *pconx_prev = NULL;
264
265 int i, j = 0, k;
266 int totcons = 0, maxcons = 0;
267
268 if (okey >= 0 && okey != FX_DATA_WILDCARD)
269 for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++)
270 pthread_mutex_lock(&mainw->fx_mutex[i]);
271
272 while (pconx) {
273 pconx_next = pconx->next;
274
275 #ifdef DEBUG_PCONX
276 g_print("Deletion check, want %d / %d, found %d / %d\n", okey, omode, pconx->okey, pconx->omode);
277 #endif
278 if ((okey == FX_DATA_WILDCARD || pconx->okey == okey) && (omode == FX_DATA_WILDCARD || pconx->omode == omode)) {
279
280 #ifdef DEBUG_PCONX
281 g_print("GOT MATCH\n");
282 #endif
283 if (opnum == FX_DATA_WILDCARD && ikey == FX_DATA_WILDCARD && imode == FX_DATA_WILDCARD
284 && ipnum == FX_DATA_WILDCARD) {
285 //g_print("rem all cons from %d %d to any param\n",okey,omode);
286
287 // delete entire node
288 lives_free(pconx->params); lives_free(pconx->last_boolval); lives_free(pconx->nconns);
289 lives_free(pconx->ikey); lives_free(pconx->imode); lives_free(pconx->ipnum);
290 lives_free(pconx->autoscale); lives_free(pconx);
291 if (mainw->pconx == pconx) mainw->pconx = pconx_next;
292 else pconx_prev->next = pconx_next;
293 if (okey >= 0 && okey != FX_DATA_WILDCARD) for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++)
294 pthread_mutex_unlock(&mainw->fx_mutex[i]);
295 return;
296 }
297
298 maxcons = 0;
299 totcons = 0;
300 j = 0;
301
302 for (i = 0; i < pconx->nparams; i++) {
303 maxcons += pconx->nconns[i];
304 }
305
306 for (i = 0; pconx && i < pconx->nparams; i++) {
307 #ifdef DEBUG_PCONX
308 g_print("Checking oparams, want %d, got %d with %d connections\n", opnum, pconx->params[i], pconx->nconns[i]);
309 #endif
310 totcons += pconx->nconns[i];
311
312 if (opnum != FX_DATA_WILDCARD && pconx->params[i] != opnum) {
313 j = totcons;
314 continue;
315 }
316
317 for (; j < totcons; j++) {
318 #ifdef DEBUG_PCONX
319 g_print("For inputs, want %d / %d (%d), found %d / %d (%d)\n", ikey, imode, ipnum, pconx->ikey[j], pconx->imode[j],
320 pconx->ipnum[j]);
321 #endif
322 if ((ikey == FX_DATA_WILDCARD || pconx->ikey[j] == ikey)
323 && (imode == FX_DATA_WILDCARD || pconx->imode[j] == imode)
324 && (ipnum == FX_DATA_WILDCARD
325 || (ipnum == FX_DATA_WILDCARD_KEEP_ACTIVATED && pconx->ipnum[j] != FX_DATA_PARAM_ACTIVE)
326 || pconx->ipnum[j] == ipnum)) {
327 #ifdef DEBUG_PCONX
328 g_print("removing connection to %d / %d param (%d)\n", ikey, imode, ipnum);
329 #endif
330 maxcons--;
331 for (k = j; k < maxcons; k++) {
332 pconx->ikey[k] = pconx->ikey[k + 1];
333 pconx->imode[k] = pconx->imode[k + 1];
334 pconx->ipnum[k] = pconx->ipnum[k + 1];
335 pconx->autoscale[k] = pconx->autoscale[k + 1];
336 }
337
338 pconx->ikey = (int *)lives_realloc(pconx->ikey, maxcons * sizint);
339 pconx->imode = (int *)lives_realloc(pconx->imode, maxcons * sizint);
340 pconx->ipnum = (int *)lives_realloc(pconx->ipnum, maxcons * sizint);
341 pconx->autoscale = (boolean *)lives_realloc(pconx->autoscale, maxcons * sizint);
342
343 pconx->nconns[i]--;
344
345 if (pconx->nconns[i] == 0) {
346 pconx->nparams--;
347 for (k = i; k < pconx->nparams; k++) {
348 pconx->params[k] = pconx->params[k + 1];
349 pconx->last_boolval[k] = pconx->last_boolval[k + 1];
350 pconx->nconns[k] = pconx->nconns[k + 1];
351 }
352
353 if (pconx->nparams == 0) {
354 // delete entire node
355 lives_free(pconx->params); lives_free(pconx->nconns); lives_free(pconx->ikey);
356 lives_free(pconx->imode); lives_free(pconx->ipnum); lives_free(pconx->last_boolval);
357 lives_free(pconx->autoscale);
358 lives_free(pconx);
359 if (mainw->pconx == pconx) {
360 mainw->pconx = pconx_next;
361 pconx = NULL;
362 } else {
363 pconx = pconx_prev;
364 pconx->next = pconx_next;
365 }
366 } else {
367 pconx->nconns = (int *)lives_realloc(pconx->nconns, pconx->nparams * sizint);
368 // *INDENT-OFF*
369 }}}}}}
370 // *INDENT-ON*
371
372 pconx_prev = pconx;
373 pconx = pconx_next;
374 }
375 if (okey >= 0 && okey != FX_DATA_WILDCARD)
376 for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_unlock(&mainw->fx_mutex[i]);
377 }
378
379
pconx_remap_mode(int key,int omode,int nmode)380 void pconx_remap_mode(int key, int omode, int nmode) {
381 lives_pconnect_t *pconx = mainw->pconx;
382
383 register int i, j, totcons;
384
385 while (pconx) {
386 if (pconx->okey == key && pconx->omode == omode) {
387 pconx->omode = nmode;
388 }
389 j = 0;
390 totcons = 0;
391 for (i = 0; i < pconx->nparams; i++) {
392 totcons += pconx->nconns[i];
393 for (; j < totcons; j++) {
394 if (pconx->ikey[j] == key && pconx->imode[j] == omode) {
395 pconx->imode[j] = nmode;
396 // *INDENT-OFF*
397 }}}
398 // *INDENT-ON*
399 pconx = pconx->next;
400 }
401 }
402
403
pconx_append(lives_pconnect_t * pconx)404 static void pconx_append(lives_pconnect_t *pconx) {
405 lives_pconnect_t *opconx = mainw->pconx;
406 lives_pconnect_t *last_pconx = opconx;
407
408 while (opconx) {
409 last_pconx = opconx;
410 opconx = opconx->next;
411 }
412
413 if (last_pconx) last_pconx->next = pconx;
414 if (!mainw->pconx) mainw->pconx = pconx;
415 }
416
417
pconx_find(int okey,int omode)418 static lives_pconnect_t *pconx_find(int okey, int omode) {
419 //
420 lives_pconnect_t *pconx = mainw->pconx;
421 while (pconx) {
422 if (pconx->okey == okey && pconx->omode == omode) {
423 return pconx;
424 }
425 pconx = pconx->next;
426 }
427 return NULL;
428 }
429
430
pconx_get_numcons(lives_conx_w * conxwp,int pnum)431 static int pconx_get_numcons(lives_conx_w * conxwp, int pnum) {
432 // get displayed number
433 int totcons = 0;
434
435 if (pnum != FX_DATA_WILDCARD) return conxwp->dispp[pnum + EXTRA_PARAMS_OUT];
436
437 for (int j = 0; j < conxwp->num_params; j++) {
438 totcons += conxwp->dispp[j];
439 }
440
441 return totcons;
442 }
443
444
pconx_get_nconns(lives_pconnect_t * pconx,int pnum)445 static int pconx_get_nconns(lives_pconnect_t *pconx, int pnum) {
446 // get actual number of connections
447 int totcons = 0;
448
449 if (!pconx) return 0;
450
451 for (int j = 0; j < pconx->nparams; j++) {
452 if (pnum != FX_DATA_WILDCARD) {
453 if (pconx->params[j] == pnum) return pconx->nconns[j];
454 } else totcons += pconx->nconns[j];
455 }
456 return totcons;
457 }
458
459
pconx_add_connection_private(int okey,int omode,int opnum,int ikey,int imode,int ipnum,boolean autoscale)460 static lives_pconnect_t *pconx_add_connection_private(int okey, int omode, int opnum, int ikey, int imode, int ipnum,
461 boolean autoscale) {
462 lives_pconnect_t *pconx;
463 int posn = 0, totcons = 0;
464 int i, j;
465
466 // delete any existing connection to the input param
467 pconx_delete(FX_DATA_WILDCARD, FX_DATA_WILDCARD, FX_DATA_WILDCARD, ikey, imode, ipnum);
468 pconx = pconx_find(okey, omode);
469
470 if (ikey >= 0) for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_lock(&mainw->fx_mutex[i]);
471
472 if (!pconx) {
473 // add whole new node
474 pconx = pconx_new(okey, omode);
475 pconx_append(pconx);
476 } else {
477 // see if already in params
478 for (i = 0; i < pconx->nparams; i++) {
479 if (pconx->params[i] == opnum) {
480 // located !
481 // add connection to existing
482
483 for (j = 0; j < pconx->nparams; j++) {
484 if (j < i) {
485 // calc posn
486 posn += pconx->nconns[j];
487 }
488 totcons += pconx->nconns[j];
489 }
490
491 // if already there, do not add again, just update autoscale
492 for (j = posn; j < posn + pconx->nconns[i]; j++) {
493 if (pconx->ikey[j] == ikey && pconx->imode[j] == imode && pconx->ipnum[j] == ipnum) {
494 pconx->autoscale[j] = autoscale;
495 if (ikey >= 0) for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_unlock(&mainw->fx_mutex[i]);
496 return pconx;
497 }
498
499 // add in order key/mode/chan
500 if (pconx->ikey[j] > ikey || (pconx->ikey[j] == ikey && pconx->imode[j] > imode) ||
501 (pconx->ikey[j] == ikey && pconx->imode[j] == imode && pconx->ipnum[j] > ipnum)) break;
502 }
503
504 // increment nconns for this param
505 pconx->nconns[i]++;
506
507 totcons++;
508
509 posn = j;
510
511 // make space for new
512 pconx->ikey = (int *)lives_realloc(pconx->ikey, totcons * sizint);
513 pconx->imode = (int *)lives_realloc(pconx->imode, totcons * sizint);
514 pconx->ipnum = (int *)lives_realloc(pconx->ipnum, totcons * sizint);
515 pconx->autoscale = (boolean *)lives_realloc(pconx->autoscale, totcons * sizint);
516
517 // move up 1
518 for (j = totcons - 1; j > posn; j--) {
519 pconx->ikey[j] = pconx->ikey[j - 1];
520 pconx->imode[j] = pconx->imode[j - 1];
521 pconx->ipnum[j] = pconx->ipnum[j - 1];
522 pconx->autoscale[j] = pconx->autoscale[j - 1];
523 }
524
525 // insert at posn
526 pconx->ikey[posn] = ikey;
527 pconx->imode[posn] = imode;
528 pconx->ipnum[posn] = ipnum;
529 pconx->autoscale[posn] = autoscale;
530
531 if (ikey >= 0) for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_unlock(&mainw->fx_mutex[i]);
532
533 return pconx;
534 }
535 }
536
537 // so, we have data for key/mode but this is a new param to be mapped
538
539 for (i = 0; i < pconx->nparams; i++) {
540 totcons += pconx->nconns[i];
541 }
542
543 totcons++;
544
545 pconx->nparams++;
546 posn = pconx->nparams;
547
548 // make space for new
549 pconx->nconns = (int *)lives_realloc(pconx->nconns, posn * sizint);
550 pconx->params = (int *)lives_realloc(pconx->params, posn * sizint);
551 pconx->last_boolval = (int *)lives_realloc(pconx->last_boolval, posn * sizint);
552
553 pconx->ikey = (int *)lives_realloc(pconx->ikey, totcons * sizint);
554 pconx->imode = (int *)lives_realloc(pconx->imode, totcons * sizint);
555 pconx->ipnum = (int *)lives_realloc(pconx->ipnum, totcons * sizint);
556 pconx->autoscale = (boolean *)lives_realloc(pconx->autoscale, totcons * sizint);
557
558 pconx->params[posn - 1] = opnum;
559
560 pconx->last_boolval[posn - 1] = WEED_FALSE; // TODO ***: get value from default
561
562 pconx->nconns[posn - 1] = 1;
563
564 posn = totcons - 1;
565
566 // insert at posn
567 pconx->ikey[posn] = ikey;
568 pconx->imode[posn] = imode;
569 pconx->ipnum[posn] = ipnum;
570 pconx->autoscale[posn] = autoscale;
571
572 #ifdef DEBUG_PCONX
573 g_print("added another pconx from %d %d %d to %d %d %d\n", okey, omode, opnum, ikey, imode, ipnum);
574 dump_connections();
575 #endif
576
577 if (ikey >= 0) for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_unlock(&mainw->fx_mutex[i]);
578
579 return pconx;
580 }
581
582 // add new
583
584 totcons = pconx_get_nconns(pconx, FX_DATA_WILDCARD) + 1;
585 pconx->nparams++;
586
587 pconx->nconns = (int *)lives_realloc(pconx->params, pconx->nparams * sizint);
588 pconx->nconns[pconx->nparams - 1] = 1;
589
590 pconx->params = (int *)lives_realloc(pconx->params, pconx->nparams * sizint);
591 pconx->params[pconx->nparams - 1] = opnum;
592
593 pconx->last_boolval = (int *)lives_realloc(pconx->last_boolval, pconx->nparams * sizint);
594 pconx->last_boolval[pconx->nparams - 1] = WEED_FALSE; // TODO: ****
595
596 pconx->ikey = (int *)lives_realloc(pconx->ikey, totcons * sizint);
597 pconx->ikey[totcons - 1] = ikey;
598
599 pconx->imode = (int *)lives_realloc(pconx->imode, totcons * sizint);
600 pconx->imode[totcons - 1] = imode;
601
602 pconx->ipnum = (int *)lives_realloc(pconx->ipnum, totcons * sizint);
603 pconx->ipnum[totcons - 1] = ipnum;
604
605 pconx->autoscale = (boolean *)lives_realloc(pconx->autoscale, totcons * sizint);
606 pconx->autoscale[totcons - 1] = autoscale;
607
608 #ifdef DEBUG_PCONX
609 g_print("added new pconx from %d %d %d to %d %d %d (%d)\n", okey, omode, opnum, ikey, imode, ipnum, autoscale);
610 #endif
611
612 if (ikey >= 0) for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) pthread_mutex_unlock(&mainw->fx_mutex[i]);
613
614 return pconx;
615 }
616
617
pconx_add_connection(int okey,int omode,int opnum,int ikey,int imode,int ipnum,boolean autoscale)618 void pconx_add_connection(int okey, int omode, int opnum, int ikey, int imode, int ipnum, boolean autoscale) {
619 pconx_add_connection_private(okey, omode, opnum, ikey, imode, ipnum, autoscale);
620 }
621
622
pconx_get_out_param(boolean use_filt,int ikey,int imode,int ipnum,int * okey,int * omode,int * opnum,int * autoscale)623 static weed_plant_t *pconx_get_out_param(boolean use_filt, int ikey, int imode, int ipnum, int *okey, int *omode, int *opnum,
624 int *autoscale) {
625 // walk all pconx and find one which has ikey/imode/ipnum as destination
626 // then all we need do is copy the "value" leaf
627
628 // use_filt is TRUE if we should use the filter template (otherwise we use the instance)
629
630 // TODO: OMC
631
632 lives_pconnect_t *pconx = mainw->pconx;
633 weed_plant_t *inst = NULL, *filter = NULL;
634 int totcons, i, j;
635
636 while (pconx) {
637 if (!use_filt) {
638 if (mainw->is_rendering) return NULL;
639 else {
640 inst = rte_keymode_get_instance(pconx->okey + 1, pconx->omode);
641 }
642 if (inst) filter = weed_instance_get_filter(inst, TRUE); // inst could be NULL if we connected to "Activated"
643 else filter = NULL;
644 } else {
645 inst = NULL;
646 filter = rte_keymode_get_filter(pconx->okey + 1, pconx->omode);
647 if (!filter) {
648 pconx = pconx->next;
649 continue;
650 }
651 }
652 totcons = 0;
653 j = 0;
654 for (i = 0; i < pconx->nparams; i++) {
655 totcons += pconx->nconns[i];
656 for (; j < totcons; j++) {
657 if (pconx->ikey[j] == ikey && pconx->imode[j] == imode && pconx->ipnum[j] == ipnum) {
658 weed_plant_t *param = NULL;
659
660 // out param is "ACTIVATED"
661 if (pconx->params[i] == FX_DATA_PARAM_ACTIVE) {
662 weed_plant_t *gui = weed_instance_get_gui(inst, FALSE);
663 pthread_mutex_lock(&mainw->fxd_active_mutex);
664 if (!active_dummy) {
665 active_dummy = weed_plant_new(WEED_PLANT_PARAMETER);
666 weed_set_plantptr_value(active_dummy, WEED_LEAF_TEMPLATE, NULL);
667 }
668
669 weed_set_boolean_value(active_dummy, WEED_LEAF_VALUE, inst != NULL
670 && (!gui || !weed_plant_has_leaf(gui, WEED_LEAF_EASE_OUT)));
671 param = active_dummy;
672 pthread_mutex_unlock(&mainw->fxd_active_mutex);
673 } else {
674 if (use_filt) {
675 weed_plant_t **outparams = weed_get_plantptr_array(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, NULL);
676 if (pconx->params[i] < weed_leaf_num_elements(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES)) {
677 param = outparams[pconx->params[i]];
678 }
679 lives_free(outparams);
680 } else {
681 if (!inst) return NULL;
682 param = weed_inst_out_param(inst, pconx->params[i]);
683 }
684 }
685 if (okey) *okey = pconx->okey;
686 if (omode) *omode = pconx->omode;
687 if (opnum) *opnum = pconx->params[i];
688 if (autoscale) *autoscale = pconx->autoscale[j];
689 if (inst) weed_instance_unref(inst);
690 return param;
691 }
692 }
693 }
694 pconx = pconx->next;
695 if (inst) weed_instance_unref(inst);
696 }
697
698 return NULL;
699 }
700
701
params_compatible(weed_plant_t * sparam,weed_plant_t * dparam)702 static boolean params_compatible(weed_plant_t *sparam, weed_plant_t *dparam) {
703 // allowed conversions
704 // type -> type
705
706 // bool -> double, bool -> int, bool -> string, (bool -> int64)
707 // int -> double, int -> string, (int -> int64)
708 // double -> string
709 // (int64 -> string)
710
711 // int[3x]/double[3x] -> colourRGB
712 // int[4x]/double[4x] -> colourRGBA
713 //
714
715 weed_plant_t *dptmpl = NULL;
716
717 int dtype = 0, stype = 0;
718 int ndvals = 0, nsvals = 0;
719 int ptype, dflags = 0;
720
721 if (dparam == active_dummy) {
722 dptmpl = NULL;
723 dtype = WEED_SEED_BOOLEAN;
724 ndvals = 1;
725 } else {
726 if (WEED_PLANT_IS_PARAMETER(dparam)) {
727 dptmpl = weed_get_plantptr_value(dparam, WEED_LEAF_TEMPLATE, NULL);
728 dtype = weed_leaf_seed_type(dparam, WEED_LEAF_VALUE);
729 ndvals = weed_leaf_num_elements(dparam, WEED_LEAF_VALUE);
730 } else {
731 dptmpl = dparam;
732 dtype = weed_leaf_seed_type(dparam, WEED_LEAF_DEFAULT);
733 ndvals = weed_leaf_num_elements(dparam, WEED_LEAF_DEFAULT);
734 }
735 }
736
737 if (sparam == active_dummy) {
738 stype = WEED_SEED_BOOLEAN;
739 nsvals = 1;
740 } else {
741 if (WEED_PLANT_IS_PARAMETER(sparam)) {
742 stype = weed_leaf_seed_type(sparam, WEED_LEAF_VALUE);
743 nsvals = weed_leaf_num_elements(sparam, WEED_LEAF_VALUE);
744 } else {
745 stype = weed_leaf_seed_type(sparam, WEED_LEAF_DEFAULT);
746 nsvals = weed_leaf_num_elements(sparam, WEED_LEAF_DEFAULT);
747 }
748 }
749
750 if (dptmpl) {
751 ptype = weed_paramtmpl_get_type(dptmpl);
752 dflags = weed_paramtmpl_get_flags(dptmpl);
753
754 if (ptype == WEED_PARAM_COLOR) {
755 int cspace = weed_get_int_value(dptmpl, WEED_LEAF_COLORSPACE, NULL);
756 if (cspace == WEED_COLORSPACE_RGB) {
757 if (!(nsvals & 3)) return FALSE;
758 } else if (nsvals & 3) return FALSE;
759 }
760 }
761
762 if (ndvals > nsvals) {
763 if (!((dflags & WEED_PARAMETER_VARIABLE_SIZE) && !(dflags & WEED_PARAMETER_VALUE_PER_CHANNEL))) return FALSE;
764 }
765
766 if (dtype == stype) return TRUE;
767
768 switch (stype) {
769 case WEED_SEED_DOUBLE:
770 if (dtype == WEED_SEED_STRING) return TRUE;
771 return FALSE;
772 case WEED_SEED_INT:
773 if (dtype == WEED_SEED_DOUBLE || dtype == WEED_SEED_STRING) return TRUE;
774 return FALSE;
775 case WEED_SEED_BOOLEAN:
776 if (dtype == WEED_SEED_DOUBLE || dtype == WEED_SEED_INT || dtype == WEED_SEED_STRING) return TRUE;
777 return FALSE;
778 default:
779 return FALSE;
780 }
781
782 return FALSE;
783 }
784
785
pconx_convert_value_data(weed_plant_t * inst,int pnum,int key,weed_plant_t * dparam,int okey,weed_plant_t * sparam,boolean autoscale,boolean is_audio_thread,boolean * toggle_fx)786 static boolean pconx_convert_value_data(weed_plant_t *inst, int pnum, int key, weed_plant_t *dparam, int okey,
787 weed_plant_t *sparam, boolean autoscale, boolean is_audio_thread, boolean * toggle_fx) {
788 // try to convert values of various type, if we succeed, copy the "value" and return TRUE (if changed)
789 weed_plant_t *dptmpl = NULL, *sptmpl;
790
791 double ratio;
792
793 int dtype = 0, stype, nsvals, ndvals = 0;
794 int ondvals = 0;
795 int nsmin = 0, nsmax = 0;
796 int minct = 0, maxct = 0;
797 int sminct = 0, smaxct = 0;
798 int nmax = 0, nmin = 0;
799 boolean retval = FALSE;
800
801 int i;
802
803 if (toggle_fx) *toggle_fx = FALSE;
804
805 if (dparam == sparam && (dparam != active_dummy || !active_dummy)) return FALSE;
806
807 if (sparam == active_dummy) {
808 nsvals = 1;
809 sptmpl = NULL;
810 stype = WEED_SEED_BOOLEAN;
811 }
812
813 nsvals = weed_leaf_num_elements(sparam, WEED_LEAF_VALUE);
814 if (nsvals == 0) return FALSE;
815 sptmpl = weed_param_get_template(sparam);
816 stype = weed_leaf_seed_type(sparam, WEED_LEAF_VALUE);
817
818 if (dparam != active_dummy) {
819 ondvals = ndvals = weed_leaf_num_elements(dparam, WEED_LEAF_VALUE);
820 dptmpl = weed_param_get_template(dparam);
821 dtype = weed_leaf_seed_type(dparam, WEED_LEAF_VALUE);
822 } else {
823 dtype = WEED_SEED_BOOLEAN;
824 ondvals = ndvals = 1;
825 dptmpl = NULL;
826 }
827
828 if (!params_compatible(sparam, dparam)) return FALSE;
829
830 if (ndvals > nsvals) ndvals = nsvals;
831
832 if (dparam != active_dummy && sparam != active_dummy) {// && autoscale) {
833 if (weed_plant_has_leaf(sptmpl, WEED_LEAF_MIN) && weed_plant_has_leaf(sptmpl, WEED_LEAF_MAX)) {
834 nsmin = weed_leaf_num_elements(sptmpl, WEED_LEAF_MIN);
835 nsmax = weed_leaf_num_elements(sptmpl, WEED_LEAF_MAX);
836 }
837 }
838
839 if (dptmpl && weed_plant_has_leaf(dptmpl, WEED_LEAF_MAX)) {
840 nmax = weed_leaf_num_elements(dptmpl, WEED_LEAF_MAX);
841 nmin = weed_leaf_num_elements(dptmpl, WEED_LEAF_MIN);
842 }
843
844 switch (stype) {
845 case WEED_SEED_STRING:
846 switch (dtype) {
847 case WEED_SEED_STRING: {
848 char **valsS, **valss;
849 if ((valsS = weed_get_string_array(sparam, WEED_LEAF_VALUE, NULL)) == NULL) return retval;
850 if ((valss = weed_get_string_array(dparam, WEED_LEAF_VALUE, NULL)) == NULL) return retval;
851
852 if (ndvals > ondvals) valss = (char **)lives_realloc(valss, ndvals * sizeof(char *));
853
854 for (i = 0; i < ndvals; i++) {
855 if (i >= ondvals || strcmp(valss[i], valsS[i])) {
856 retval = TRUE;
857 if (i < ondvals) lives_free(valss[i]);
858 valss[i] = valsS[i];
859 } else lives_free(valsS[i]);
860 }
861 if (!retval) {
862 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
863 lives_free(valss);
864 lives_free(valsS);
865 return FALSE;
866 }
867
868 weed_set_string_array(dparam, WEED_LEAF_VALUE, ndvals, valss);
869
870 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
871 lives_free(valss);
872 lives_free(valsS);
873 }
874 return TRUE;
875 default:
876 return retval;
877 }
878 case WEED_SEED_DOUBLE:
879 switch (dtype) {
880 case WEED_SEED_DOUBLE: {
881 double *valsD = weed_get_double_array(sparam, WEED_LEAF_VALUE, NULL);
882 double *valsd = weed_get_double_array(dparam, WEED_LEAF_VALUE, NULL);
883
884 double *maxd = weed_get_double_array(dptmpl, WEED_LEAF_MAX, NULL);
885 double *mind = weed_get_double_array(dptmpl, WEED_LEAF_MIN, NULL);
886
887 double *mins = NULL, *maxs = NULL;
888
889 if (autoscale) {
890 mins = weed_get_double_array(sptmpl, WEED_LEAF_MIN, NULL);
891 maxs = weed_get_double_array(sptmpl, WEED_LEAF_MAX, NULL);
892 }
893
894 if (ndvals > ondvals) valsd = (double *)lives_realloc(valsd, ndvals * sizeof(double));
895
896 for (i = 0; i < ndvals; i++) {
897 if (autoscale) {
898 ratio = (valsD[i] - mins[sminct]) / (maxs[smaxct] - mins[sminct]);
899 valsD[i] = mind[minct] + (maxd[maxct] - mind[minct]) * ratio;
900 if (++smaxct == nsmax) smaxct = 0;
901 if (++sminct == nsmin) sminct = 0;
902
903 if (valsD[i] > maxd[maxct]) valsD[i] = maxd[maxct];
904 if (valsD[i] < mind[minct]) valsD[i] = mind[minct];
905 }
906
907 if (i >= ondvals || valsd[i] != valsD[i]) {
908 retval = TRUE;
909 valsd[i] = valsD[i];
910 }
911 if (++maxct == nmax) maxct = 0;
912 if (++minct == nmin) minct = 0;
913 }
914
915 if (mins) {
916 lives_free(mins);
917 lives_free(maxs);
918 }
919
920 if (retval) {
921 if (inst && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
922 // if we are recording, add this change to our event_list
923 rec_param_change(inst, pnum);
924 }
925
926 weed_set_double_array(dparam, WEED_LEAF_VALUE, ndvals, valsd);
927 }
928 lives_free(maxd); lives_free(mind); lives_free(valsD); lives_free(valsd);
929 }
930 return retval;
931
932 case WEED_SEED_STRING: {
933 char *opstring, *tmp, *bit;
934 double *valsd = weed_get_double_array(sparam, WEED_LEAF_VALUE, NULL);
935 char **valss, *vals;
936
937 if (ndvals == 1) {
938 opstring = lives_strdup("");
939 vals = weed_get_string_value(dparam, WEED_LEAF_VALUE, NULL);
940 for (i = 0; i < nsvals; i++) {
941 bit = lives_strdup_printf("%.4f", valsd[i]);
942 if (!*opstring)
943 tmp = lives_strconcat(opstring, bit, NULL);
944 else
945 tmp = lives_strconcat(opstring, " ", bit, NULL);
946 lives_free(bit);
947 lives_free(opstring);
948 opstring = tmp;
949 }
950 if (strcmp(vals, opstring)) {
951 weed_set_string_value(dparam, WEED_LEAF_VALUE, opstring);
952 retval = TRUE;
953 }
954 lives_free(vals); lives_free(valsd); lives_free(opstring);
955 return retval;
956 }
957
958 valss = weed_get_string_array(dparam, WEED_LEAF_VALUE, NULL);
959
960 if (ndvals > ondvals) valss = (char **)lives_realloc(valsd, ndvals * sizeof(char *));
961
962 for (i = 0; i < ndvals; i++) {
963 bit = lives_strdup_printf("%.4f", valsd[i]);
964 if (i >= ondvals || strcmp(valss[i], bit)) {
965 retval = TRUE;
966 if (i < ondvals) lives_free(valss[i]);
967 valss[i] = bit;
968 } else lives_free(bit);
969 }
970 if (!retval) {
971 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
972 lives_free(valss);
973 lives_free(valsd);
974 return FALSE;
975 }
976
977 weed_set_string_array(dparam, WEED_LEAF_VALUE, ndvals, valss);
978
979 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
980 lives_free(valss);
981 lives_free(valsd);
982 }
983 return TRUE;
984 default: break;
985 }
986
987 break;
988
989 case WEED_SEED_INT:
990 switch (dtype) {
991 case WEED_SEED_STRING: {
992 char *opstring, *tmp, *bit;
993 int *valsi = weed_get_int_array(sparam, WEED_LEAF_VALUE, NULL);
994
995 char **valss, *vals;
996
997 if (ndvals == 1) {
998 opstring = lives_strdup("");
999 vals = weed_get_string_value(dparam, WEED_LEAF_VALUE, NULL);
1000 for (i = 0; i < nsvals; i++) {
1001 bit = lives_strdup_printf("%d", valsi[i]);
1002 if (!*opstring)
1003 tmp = lives_strconcat(opstring, bit, NULL);
1004 else
1005 tmp = lives_strconcat(opstring, " ", bit, NULL);
1006 lives_free(bit);
1007 lives_free(opstring);
1008 opstring = tmp;
1009 }
1010 if (strcmp(vals, opstring)) {
1011 weed_set_string_value(dparam, WEED_LEAF_VALUE, opstring);
1012 retval = TRUE;
1013 }
1014 lives_free(vals); lives_free(valsi); lives_free(opstring);
1015 return retval;
1016 }
1017
1018 valss = weed_get_string_array(dparam, WEED_LEAF_VALUE, NULL);
1019
1020 if (ndvals > ondvals) valss = (char **)lives_realloc(valss, ndvals * sizeof(char *));
1021
1022 for (i = 0; i < ndvals; i++) {
1023 bit = lives_strdup_printf("%d", valsi[i]);
1024 if (i >= ondvals || strcmp(valss[i], bit)) {
1025 retval = TRUE;
1026 if (i < ondvals) lives_free(valss[i]);
1027 valss[i] = bit;
1028 } else lives_free(bit);
1029 }
1030 if (!retval) {
1031 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
1032 lives_free(valss); lives_free(valsi);
1033 return FALSE;
1034 }
1035
1036 weed_set_string_array(dparam, WEED_LEAF_VALUE, ndvals, valss);
1037
1038 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
1039 lives_free(valss);
1040 lives_free(valsi);
1041 }
1042 return retval;
1043 case WEED_SEED_DOUBLE: {
1044 int *valsi = weed_get_int_array(sparam, WEED_LEAF_VALUE, NULL);
1045 double *valsd = weed_get_double_array(dparam, WEED_LEAF_VALUE, NULL);
1046
1047 double *maxd = weed_get_double_array(dptmpl, WEED_LEAF_MAX, NULL);
1048 double *mind = weed_get_double_array(dptmpl, WEED_LEAF_MIN, NULL);
1049 double vald;
1050
1051 int *mins = NULL, *maxs = NULL;
1052
1053 if (autoscale) {
1054 mins = weed_get_int_array(sptmpl, WEED_LEAF_MIN, NULL);
1055 maxs = weed_get_int_array(sptmpl, WEED_LEAF_MAX, NULL);
1056 }
1057
1058 if (ndvals > ondvals) valsd = (double *)lives_realloc(valsd, ndvals * sizeof(double));
1059
1060 for (i = 0; i < ndvals; i++) {
1061 if (autoscale) {
1062 ratio = (double)(valsi[i] - mins[sminct]) / (double)(maxs[smaxct] - mins[sminct]);
1063 vald = mind[minct] + (maxd[maxct] - mind[minct]) * ratio;
1064 if (++smaxct == nsmax) smaxct = 0;
1065 if (++sminct == nsmin) sminct = 0;
1066
1067 if (vald > maxd[maxct]) vald = maxd[maxct];
1068 if (vald < mind[minct]) vald = mind[minct];
1069 } else vald = (double)valsi[i];
1070
1071 if (i >= ondvals || valsd[i] != vald) {
1072 retval = TRUE;
1073 valsd[i] = vald;
1074 }
1075 if (++maxct == nmax) maxct = 0;
1076 if (++minct == nmin) minct = 0;
1077 }
1078
1079 if (mins) {
1080 lives_free(mins);
1081 lives_free(maxs);
1082 }
1083
1084 if (retval) {
1085 if (inst && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
1086 // if we are recording, add this change to our event_list
1087 rec_param_change(inst, pnum);
1088 }
1089
1090 weed_set_double_array(dparam, WEED_LEAF_VALUE, ndvals, valsd);
1091 }
1092 lives_free(maxd); lives_free(mind);
1093 lives_free(valsi); lives_free(valsd);
1094 }
1095 return retval;
1096
1097 case WEED_SEED_INT: {
1098 int *valsI, *valsi, *maxi, *mini;
1099 int *mins = NULL, *maxs = NULL;
1100
1101 if ((valsI = weed_get_int_array(sparam, WEED_LEAF_VALUE, NULL)) == NULL) return retval;
1102 if ((valsi = weed_get_int_array(dparam, WEED_LEAF_VALUE, NULL)) == NULL) return retval;
1103 if ((maxi = weed_get_int_array(dptmpl, WEED_LEAF_MAX, NULL)) == NULL) return retval;
1104 if ((mini = weed_get_int_array(dptmpl, WEED_LEAF_MIN, NULL)) == NULL) return retval;
1105
1106 if (autoscale) {
1107 mins = weed_get_int_array(sptmpl, WEED_LEAF_MIN, NULL);
1108 maxs = weed_get_int_array(sptmpl, WEED_LEAF_MAX, NULL);
1109 }
1110
1111 if (ndvals > ondvals) valsi = (int *)lives_realloc(valsi, ndvals * sizeof(int));
1112
1113 for (i = 0; i < ndvals; i++) {
1114 if (autoscale) {
1115 ratio = (double)(valsI[i] - mins[sminct]) / (double)(maxs[smaxct] - mins[sminct]);
1116 valsI[i] = myround(mini[minct] + (double)(maxi[maxct] - mini[minct]) * ratio);
1117 if (++smaxct == nsmax) smaxct = 0;
1118 if (++sminct == nsmin) sminct = 0;
1119
1120 if (valsI[i] > maxi[maxct]) valsI[i] = maxi[maxct];
1121 if (valsI[i] < mini[minct]) valsI[i] = mini[minct];
1122 }
1123
1124 if (i >= ondvals || valsi[i] != valsI[i]) {
1125 retval = TRUE;
1126 valsi[i] = valsI[i];
1127 }
1128 if (++maxct == nmax) maxct = 0;
1129 if (++minct == nmin) minct = 0;
1130 }
1131
1132 if (mins) {
1133 lives_free(mins);
1134 lives_free(maxs);
1135 }
1136
1137 if (retval) {
1138 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
1139 // if we are recording, add this change to our event_list
1140 rec_param_change(inst, pnum);
1141 }
1142
1143 weed_set_int_array(dparam, WEED_LEAF_VALUE, ndvals, valsi);
1144 }
1145 lives_free(maxi); lives_free(mini);
1146 lives_free(valsI); lives_free(valsi);
1147 }
1148 return retval;
1149 }
1150 break;
1151
1152 case WEED_SEED_BOOLEAN: {
1153 int *valsb;
1154 if (dparam == active_dummy) {
1155 // ACTIVATE / DEACTIVATE
1156 if (!autoscale) { // autoscale is now "user override"
1157 int valb = weed_get_boolean_value(sparam, WEED_LEAF_VALUE, NULL);
1158 if ((valb == WEED_TRUE && (mainw->rte & (GU641 << (key))) == 0) ||
1159 (valb == WEED_FALSE && (mainw->rte & (GU641 << (key)))) != 0) {
1160 if (toggle_fx) *toggle_fx = TRUE;
1161 }
1162 }
1163 return retval;
1164 }
1165 valsb = weed_get_boolean_array(sparam, WEED_LEAF_VALUE, NULL);
1166 switch (dtype) {
1167 case WEED_SEED_STRING: {
1168 char *opstring, *tmp, *bit;
1169 char **valss, *vals;
1170
1171 if (ndvals == 1) {
1172 opstring = lives_strdup("");
1173 vals = weed_get_string_value(dparam, WEED_LEAF_VALUE, NULL);
1174 for (i = 0; i < nsvals; i++) {
1175 bit = lives_strdup_printf("%d", valsb[i]);
1176 if (!*opstring)
1177 tmp = lives_strconcat(opstring, bit, NULL);
1178 else
1179 tmp = lives_strconcat(opstring, " ", bit, NULL);
1180 lives_free(bit);
1181 lives_free(opstring);
1182 opstring = tmp;
1183 }
1184 if (strcmp(vals, opstring)) {
1185 weed_set_string_value(dparam, WEED_LEAF_VALUE, opstring);
1186 retval = TRUE;
1187 }
1188 lives_free(vals); lives_free(valsb); lives_free(opstring);
1189 return retval;
1190 }
1191
1192 valss = weed_get_string_array(dparam, WEED_LEAF_VALUE, NULL);
1193 if (ndvals > ondvals) valss = (char **)lives_realloc(valss, ndvals * sizeof(char *));
1194
1195 for (i = 0; i < ndvals; i++) {
1196 bit = lives_strdup_printf("%d", valsb[i]);
1197 if (i >= ondvals || strcmp(valss[i], bit)) {
1198 retval = TRUE;
1199 if (i < ondvals) lives_free(valss[i]);
1200 valss[i] = bit;
1201 } else lives_free(bit);
1202 }
1203 if (!retval) {
1204 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
1205 lives_free(valss);
1206 lives_free(valsb);
1207 return FALSE;
1208 }
1209
1210 weed_set_string_array(dparam, WEED_LEAF_VALUE, ndvals, valss);
1211
1212 for (i = 0; i < ndvals; i++) lives_free(valss[i]);
1213 lives_free(valss);
1214 lives_free(valsb);
1215 }
1216 return retval;
1217 case WEED_SEED_DOUBLE: {
1218 double *valsd = weed_get_double_array(dparam, WEED_LEAF_VALUE, NULL);
1219 double *maxd = weed_get_double_array(dptmpl, WEED_LEAF_MAX, NULL);
1220 double *mind = weed_get_double_array(dptmpl, WEED_LEAF_MIN, NULL);
1221 double vald;
1222
1223 if (ndvals > ondvals) valsd = (double *)lives_realloc(valsd, ndvals * sizeof(double));
1224
1225 for (i = 0; i < ndvals; i++) {
1226 if (autoscale) {
1227 if (valsb[i] == WEED_TRUE) vald = maxd[maxct];
1228 else vald = mind[minct];
1229 } else {
1230 vald = (double)valsb[i];
1231 if (vald > maxd[maxct]) vald = maxd[maxct];
1232 if (vald < mind[minct]) vald = mind[minct];
1233 }
1234 if (i >= ondvals || valsd[i] != vald) {
1235 retval = TRUE;
1236 valsd[i] = vald;
1237 }
1238 if (++maxct == nmax) maxct = 0;
1239 if (++minct == nmin) minct = 0;
1240 }
1241 if (retval) {
1242 if (inst && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
1243 // if we are recording, add this change to our event_list
1244 rec_param_change(inst, pnum);
1245 }
1246
1247 weed_set_double_array(dparam, WEED_LEAF_VALUE, ndvals, valsd);
1248 }
1249 lives_free(maxd); lives_free(mind);
1250 lives_free(valsb); lives_free(valsd);
1251 }
1252 return retval;
1253 case WEED_SEED_INT: {
1254 int *valsi = weed_get_int_array(dparam, WEED_LEAF_VALUE, NULL);
1255 int *maxi = weed_get_int_array(dptmpl, WEED_LEAF_MAX, NULL);
1256 int *mini = weed_get_int_array(dptmpl, WEED_LEAF_MIN, NULL);
1257
1258 if (ndvals > ondvals) valsi = (int *)lives_realloc(valsi, ndvals * sizeof(int));
1259
1260 for (i = 0; i < ndvals; i++) {
1261 if (autoscale) {
1262 if (valsb[i] == WEED_TRUE) valsb[i] = maxi[maxct];
1263 else valsb[i] = mini[minct];
1264 } else {
1265 if (valsb[i] > maxi[maxct]) valsb[i] = maxi[maxct];
1266 if (valsb[i] < mini[minct]) valsb[i] = mini[maxct];
1267 }
1268 if (i >= ondvals || valsi[i] != valsb[i]) {
1269 retval = TRUE;
1270 valsi[i] = valsb[i];
1271 }
1272 if (++maxct == nmax) maxct = 0;
1273 if (++minct == nmin) minct = 0;
1274 }
1275 if (retval) {
1276 if (inst && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
1277 // if we are recording, add this change to our event_list
1278 rec_param_change(inst, pnum);
1279 }
1280
1281 weed_set_int_array(dparam, WEED_LEAF_VALUE, ndvals, valsi);
1282 }
1283 lives_free(maxi); lives_free(mini);
1284 lives_free(valsi); lives_free(valsb);
1285 }
1286 return retval;
1287
1288 case WEED_SEED_BOOLEAN: {
1289 int *valsB = weed_get_boolean_array(dparam, WEED_LEAF_VALUE, NULL);
1290
1291 if (ndvals > ondvals) valsB = (int *)lives_realloc(valsB, ndvals * sizeof(int));
1292
1293 for (i = 0; i < ndvals; i++) {
1294 if (i >= ondvals || valsB[i] != valsb[i]) {
1295 retval = TRUE;
1296 valsB[i] = valsb[i];
1297 }
1298 }
1299 if (retval) {
1300 if (inst && mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
1301 // if we are recording, add this change to our event_list
1302 rec_param_change(inst, pnum);
1303 }
1304 weed_set_boolean_array(dparam, WEED_LEAF_VALUE, ndvals, valsB);
1305 }
1306 lives_free(valsb);
1307 lives_free(valsB);
1308 }
1309 return retval;
1310 default:
1311 lives_free(valsb);
1312 break;
1313 }
1314 break;
1315 }
1316 default: break;
1317 }
1318
1319 return retval;
1320 }
1321
1322
pconx_chain_data_omc(weed_plant_t * inst,int okey,int omode)1323 int pconx_chain_data_omc(weed_plant_t *inst, int okey, int omode) {
1324 // push anything to connected OMC macros
1325 lives_pconnect_t *pconx = mainw->pconx;
1326
1327 char *valstr = NULL;
1328
1329 int totcons, pidx;
1330 int actions = 0;
1331
1332 boolean cbval, lbval;
1333
1334 int i, j;
1335
1336 if (!inst) return 0;
1337
1338 if (mainw->event_list && !mainw->record && !mainw->record_paused) return 0;
1339
1340 // check for any inkeys == FX_DATA_KEY_OMC_MACRO and matching okey, omode
1341 // for each match we construct a string and send it to the OMC learner
1342
1343 while (pconx) {
1344 if (pconx->okey == okey && pconx->omode == omode) {
1345 totcons = 0;
1346 j = 0;
1347 for (i = 0; i < pconx->nparams; i++) {
1348 totcons += pconx->nconns[i];
1349 pidx = pconx->params[i];
1350 lbval = pconx->last_boolval[i];
1351 for (; j < totcons; j++) {
1352 if (pconx->ikey[j] == FX_DATA_KEY_OMC_MACRO) {
1353 // out param is "ACTIVATED"
1354 if (pidx >= 0) {
1355 weed_plant_t *oparam = weed_inst_out_param(inst, pidx);
1356 switch (weed_leaf_seed_type(oparam, WEED_LEAF_VALUE)) {
1357 case WEED_SEED_BOOLEAN:
1358 cbval = weed_get_boolean_value(oparam, WEED_LEAF_VALUE, NULL);
1359 if (cbval == WEED_TRUE && lbval == WEED_FALSE) {
1360 // state changed, so trigger act
1361 valstr = lives_strdup_printf("%d", cbval);
1362 }
1363 pconx->last_boolval[i] = cbval;
1364 break;
1365 default: break;
1366 }
1367 } else {
1368 valstr = lives_strdup_printf("%d", WEED_TRUE);
1369 pconx->last_boolval[i] = WEED_TRUE;
1370 }
1371 }
1372 if (valstr) {
1373 // construct string to pass
1374 char *msgstring = lives_strdup_printf("%d %d %d %s", OMC_INTERNAL, pconx->imode[j], pconx->ipnum[j], valstr);
1375 lives_free(valstr);
1376 valstr = NULL;
1377 omc_process_string(OMC_INTERNAL, (const char *)msgstring, FALSE, NULL);
1378 actions++;
1379 lives_free(msgstring);
1380 // *INDENT-OFF*
1381 }}}}
1382 // *INDENT-ON*
1383
1384 pconx = pconx->next;
1385 }
1386 return actions;
1387 }
1388
1389
pconx_chain_data(int key,int mode,boolean is_audio_thread)1390 boolean pconx_chain_data(int key, int mode, boolean is_audio_thread) {
1391 weed_plant_t **inparams = NULL;
1392 weed_plant_t *oparam, *inparam = NULL;
1393 weed_plant_t *inst = NULL;
1394
1395 boolean changed, reinit_inst = FALSE;
1396
1397 int nparams = 0, start = 0;
1398 int autoscale;
1399 int pflags;
1400 int okey, omode;
1401 boolean toggle_fx = FALSE;
1402 int i;
1403
1404 if (mainw->is_rendering) return FALSE;
1405
1406 if (key == FX_DATA_KEY_PLAYBACK_PLUGIN) {
1407 // playback plugin
1408 if (!mainw->vpp) return FALSE;
1409 inparams = mainw->vpp->play_params;
1410 nparams = mainw->vpp->num_play_params;
1411 } else {
1412 filter_mutex_lock(key);
1413 inst = rte_keymode_get_instance(key + 1, mode);
1414 if (!inst) filter_mutex_unlock(key);
1415 start = -EXTRA_PARAMS_IN;
1416 }
1417
1418 if (inst) {
1419 if (weed_plant_has_leaf(inst, WEED_LEAF_IN_PARAMETERS))
1420 inparams = weed_get_plantptr_array_counted(inst, WEED_LEAF_IN_PARAMETERS, &nparams);
1421 } else {
1422 if (rte_keymode_get_filter_idx(key + 1, mode) == -1) return FALSE;
1423 }
1424
1425
1426 for (i = start; i < nparams; i++) {
1427 //g_print("NOW at %d %d\n ", key, mode);
1428 if ((oparam = pconx_get_out_param(FALSE, key, mode, i, &okey, &omode, NULL, &autoscale))) {
1429 //#define DEBUG_PCONX
1430 #ifdef DEBUG_PCONX
1431 g_print("got pconx to %d %d %d\n", key, mode, i);
1432 #endif
1433 if (i == FX_DATA_PARAM_ACTIVE) {
1434 pthread_mutex_lock(&mainw->fxd_active_mutex);
1435 if (!active_dummy) {
1436 active_dummy = weed_plant_new(WEED_PLANT_PARAMETER);
1437 weed_set_plantptr_value(active_dummy, WEED_LEAF_TEMPLATE, NULL);
1438 }
1439 inparam = active_dummy;
1440 pthread_mutex_unlock(&mainw->fxd_active_mutex);
1441 } else inparam = inparams[i];
1442
1443 /// we need to keep these locked for as little time as possible so as not to hang up the video / audio thread
1444 filter_mutex_lock(okey);
1445 if (oparam != active_dummy) {
1446 weed_plant_t *oinst = rte_keymode_get_instance(okey + 1, omode);
1447 if (!oinst) {
1448 filter_mutex_unlock(okey);
1449 if (inst) {
1450 weed_instance_unref(inst);
1451 filter_mutex_unlock(key);
1452 }
1453 return FALSE;
1454 }
1455 weed_instance_unref(oinst);
1456 }
1457
1458 changed = pconx_convert_value_data(inst, i, key, key == FX_DATA_KEY_PLAYBACK_PLUGIN
1459 ? (weed_plant_t *)pp_get_param(mainw->vpp->play_params, i)
1460 : inparam, okey, oparam, autoscale, is_audio_thread, &toggle_fx);
1461
1462 if (toggle_fx) {
1463 if (is_audio_thread) {
1464 // in the audio thread, don't activate / dectivate video fx. It could cause an underflow if it takes too long
1465 // let the video thread handle it
1466 weed_plant_t *filter = rte_keymode_get_filter(key + 1, rte_key_getmode(key + 1));
1467 if (!is_pure_audio(filter, FALSE)) {
1468 if (inst) {
1469 weed_instance_unref(inst);
1470 inst = NULL;
1471 filter_mutex_unlock(key);
1472 }
1473 filter_mutex_unlock(okey);
1474 return FALSE;
1475 }
1476 }
1477 if (inst) {
1478 weed_instance_unref(inst);
1479 inst = NULL;
1480 filter_mutex_unlock(key);
1481 }
1482 switch_fx_state(key + 1);
1483 filter_mutex_unlock(okey);
1484 } else {
1485 filter_mutex_unlock(okey);
1486 if (changed && inst && key > -1) {
1487 // only store value if it changed; for int, double or colour, store old value too
1488
1489 //copyto = set_copy_to(inst, i, TRUE);
1490 if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS)) {
1491 // if we are recording, add this change to our event_list
1492 rec_param_change(inst, i);
1493 //if (copyto != -1) rec_param_change(inst, copyto);
1494 }
1495
1496 pflags = weed_get_int_value(inparams[i], WEED_LEAF_FLAGS, NULL);
1497 if (pflags & WEED_PARAMETER_REINIT_ON_VALUE_CHANGE) reinit_inst = TRUE;
1498
1499 if (fx_dialog[1] && !reinit_inst) {
1500 lives_rfx_t *rfx = fx_dialog[1]->rfx;
1501 if (!rfx->is_template) {
1502 int keyw = fx_dialog[1]->key;
1503 int modew = fx_dialog[1]->mode;
1504 if (keyw == key && modew == mode)
1505 // ask the main thread to update the param window
1506 mainw->vrfx_update = rfx;
1507 }
1508 }
1509 if (mainw->ce_thumbs) ce_thumbs_register_rfx_change(key, mode);
1510 // *INDENT-OFF*
1511 }}}}
1512 // *INDENT-ON*
1513
1514 if (inst) {
1515 weed_instance_unref(inst);
1516 inst = NULL;
1517 filter_mutex_unlock(key);
1518 }
1519
1520 if (key != FX_DATA_KEY_PLAYBACK_PLUGIN && inparams) lives_free(inparams);
1521 return reinit_inst;
1522 }
1523
1524
pconx_chain_data_internal(weed_plant_t * inst)1525 boolean pconx_chain_data_internal(weed_plant_t *inst) {
1526 // special version for compound fx internal connections
1527 weed_plant_t **in_params;
1528
1529 boolean autoscale, reinit_inst = FALSE;
1530
1531 int nparams = 0, pflags, i;
1532
1533 nparams = num_in_params(inst, FALSE, FALSE);
1534 if (!nparams) return FALSE;
1535
1536 in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
1537
1538 for (i = 0; i < nparams; i++) {
1539 if (weed_plant_has_leaf(in_params[i], WEED_LEAF_HOST_INTERNAL_CONNECTION)) {
1540 autoscale = FALSE;
1541 if (weed_plant_has_leaf(in_params[i], WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE) &&
1542 weed_get_boolean_value(in_params[i],
1543 WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE, NULL) == WEED_TRUE) autoscale = TRUE;
1544 if (pconx_convert_value_data(inst, i, -1, in_params[i], -1, weed_get_plantptr_value(in_params[i],
1545 WEED_LEAF_HOST_INTERNAL_CONNECTION, NULL), autoscale, FALSE, NULL)) {
1546
1547 pflags = weed_get_int_value(in_params[i], WEED_LEAF_FLAGS, NULL);
1548 if (pflags & WEED_PARAMETER_REINIT_ON_VALUE_CHANGE) reinit_inst = TRUE;
1549 }
1550 }
1551 }
1552
1553 lives_free(in_params);
1554 return reinit_inst;
1555 }
1556
1557 // alpha channs
1558
1559
cconx_delete_all(void)1560 void cconx_delete_all(void) {
1561 lives_cconnect_t *cconx = mainw->cconx, *cconx_next;
1562 while (cconx) {
1563 cconx_next = cconx->next;
1564 if (cconx->nchans > 0) {
1565 lives_free(cconx->chans);
1566 lives_free(cconx->nconns);
1567 lives_free(cconx->ikey);
1568 lives_free(cconx->imode);
1569 lives_free(cconx->icnum);
1570 }
1571 lives_free(cconx);
1572 cconx = cconx_next;
1573 }
1574 mainw->cconx = NULL;
1575 }
1576
1577
cconx_new(int okey,int omode)1578 static lives_cconnect_t *cconx_new(int okey, int omode) {
1579 lives_cconnect_t *cconx = (lives_cconnect_t *)lives_calloc(sizeof(struct _lives_cconnect_t), 1);
1580 cconx->next = NULL;
1581 cconx->okey = okey;
1582 cconx->omode = omode;
1583 cconx->nchans = 0;
1584 cconx->nconns = NULL;
1585 return cconx;
1586 }
1587
1588
cconx_copy(lives_cconnect_t * scconx)1589 static lives_cconnect_t *cconx_copy(lives_cconnect_t *scconx) {
1590 lives_cconnect_t *cconx = NULL, *dcconx, *last_dcconx;
1591
1592 int totcons = 0;
1593
1594 register int i, j = 0;
1595
1596 while (scconx) {
1597 dcconx = cconx_new(scconx->okey, scconx->omode);
1598 if (!cconx) cconx = dcconx;
1599 else last_dcconx->next = dcconx;
1600
1601 dcconx->nchans = scconx->nchans;
1602
1603 dcconx->nconns = (int *)lives_malloc(dcconx->nchans * sizint);
1604 dcconx->chans = (int *)lives_malloc(dcconx->nchans * sizint);
1605
1606 dcconx->ikey = dcconx->imode = dcconx->icnum = NULL;
1607
1608 j = 0;
1609
1610 for (i = 0; i < dcconx->nchans; i++) {
1611 dcconx->chans[i] = scconx->chans[i];
1612 dcconx->nconns[i] = scconx->nconns[i];
1613 totcons += dcconx->nconns[i];
1614
1615 dcconx->ikey = (int *)lives_realloc(dcconx->ikey, totcons * sizint);
1616 dcconx->imode = (int *)lives_realloc(dcconx->imode, totcons * sizint);
1617 dcconx->icnum = (int *)lives_realloc(dcconx->icnum, totcons * sizint);
1618
1619 while (j < totcons) {
1620 dcconx->ikey[j] = scconx->ikey[j];
1621 dcconx->imode[j] = scconx->imode[j];
1622 dcconx->icnum[j] = scconx->icnum[j];
1623 j++;
1624 }
1625 }
1626
1627 scconx = scconx->next;
1628 last_dcconx = dcconx;
1629 }
1630
1631 return cconx;
1632 }
1633
1634
cconx_list(int okey,int omode,int ocnum)1635 char *cconx_list(int okey, int omode, int ocnum) {
1636 char *st1 = lives_strdup(""), *st2;
1637 lives_cconnect_t *cconx = mainw->cconx;
1638 int totcons = 0;
1639
1640 while (cconx) {
1641 if (cconx->okey == okey && cconx->omode == omode) {
1642 for (int i = 0; i < cconx->nchans; i++) {
1643 if (cconx->chans[i] == ocnum) {
1644 for (int j = totcons; j < totcons + cconx->nconns[i]; j++) {
1645 if (!*st1) st2 = lives_strdup_printf("%d %d %d", cconx->ikey[j] + 1, cconx->imode[j] + 1, cconx->icnum[j]);
1646 else
1647 st2 = lives_strdup_printf("%s %d %d %d", st1, cconx->ikey[j] + 1, cconx->imode[j] + 1, cconx->icnum[j]);
1648 lives_free(st1);
1649 st1 = st2;
1650 }
1651 return st1;
1652 }
1653 totcons += cconx->nconns[i];
1654 }
1655 return st1;
1656 }
1657 cconx = cconx->next;
1658 }
1659 return st1;
1660 }
1661
1662
cconx_delete(int okey,int omode,int ocnum,int ikey,int imode,int icnum)1663 void cconx_delete(int okey, int omode, int ocnum, int ikey, int imode, int icnum) {
1664 lives_cconnect_t *cconx = mainw->cconx, *cconx_next, *cconx_prev = NULL;
1665
1666 register int i, j = 0, k;
1667
1668 int totcons = 0, maxcons = 0;
1669
1670 while (cconx) {
1671 cconx_next = cconx->next;
1672 if (okey == FX_DATA_WILDCARD || (cconx->okey == okey && cconx->omode == omode)) {
1673 if (ikey == FX_DATA_WILDCARD) {
1674 // delete entire node
1675 lives_free(cconx->chans); lives_free(cconx->nconns); lives_free(cconx->ikey);
1676 lives_free(cconx->imode); lives_free(cconx->icnum); lives_free(cconx);
1677 if (mainw->cconx == cconx) mainw->cconx = cconx_next;
1678 else cconx_prev->next = cconx_next;
1679 return;
1680 }
1681
1682 maxcons = 0;
1683 totcons = 0;
1684 j = 0;
1685
1686 for (i = 0; i < cconx->nchans; i++) {
1687 maxcons += cconx->nconns[i];
1688 }
1689
1690 for (i = 0; cconx && i < cconx->nchans; i++) {
1691 totcons += cconx->nconns[i];
1692
1693 if (okey != FX_DATA_WILDCARD && cconx->chans[i] != ocnum) {
1694 j = totcons;
1695 continue;
1696 }
1697
1698 for (; j < totcons; j++) {
1699 if (cconx->ikey[j] == ikey && cconx->imode[j] == imode && (icnum == FX_DATA_WILDCARD || cconx->icnum[j] == icnum)) {
1700 maxcons--;
1701 for (k = j; k < maxcons; k++) {
1702 cconx->ikey[k] = cconx->ikey[k + 1];
1703 cconx->imode[k] = cconx->imode[k + 1];
1704 cconx->icnum[k] = cconx->icnum[k + 1];
1705 }
1706
1707 cconx->ikey = (int *)lives_realloc(cconx->ikey, maxcons * sizint);
1708 cconx->imode = (int *)lives_realloc(cconx->imode, maxcons * sizint);
1709 cconx->icnum = (int *)lives_realloc(cconx->icnum, maxcons * sizint);
1710
1711 cconx->nconns[i]--;
1712
1713 if (cconx->nconns[i] == 0) {
1714 cconx->nchans--;
1715 for (k = i; k < cconx->nchans; k++) {
1716 cconx->chans[k] = cconx->chans[k + 1];
1717 cconx->nconns[k] = cconx->nconns[k + 1];
1718 }
1719
1720 if (cconx->nchans == 0) {
1721 // delete entire node
1722 lives_free(cconx->chans); lives_free(cconx->nconns); lives_free(cconx->ikey);
1723 lives_free(cconx->imode); lives_free(cconx->icnum); lives_free(cconx);
1724 if (mainw->cconx == cconx) {
1725 mainw->cconx = cconx_next;
1726 cconx = NULL;
1727 } else {
1728 cconx = cconx_prev;
1729 cconx->next = cconx_next;
1730 }
1731 } else {
1732 cconx->nconns = (int *)lives_realloc(cconx->nconns, cconx->nchans * sizint);
1733 }
1734 // *INDENT-OFF*
1735 }}}}}
1736 // *INDENT-ON*
1737
1738 cconx_prev = cconx;
1739 cconx = cconx_next;
1740 }
1741 }
1742
1743
cconx_remap_mode(int key,int omode,int nmode)1744 void cconx_remap_mode(int key, int omode, int nmode) {
1745 lives_cconnect_t *cconx = mainw->cconx;
1746
1747 register int i, j, totcons;
1748
1749 while (cconx) {
1750 if (cconx->okey == key && cconx->omode == omode) {
1751 cconx->omode = nmode;
1752 }
1753 j = 0;
1754 totcons = 0;
1755 for (i = 0; i < cconx->nchans; i++) {
1756 totcons += cconx->nconns[i];
1757 for (; j < totcons; j++) {
1758 if (cconx->ikey[j] == key && cconx->imode[j] == omode) {
1759 cconx->imode[j] = nmode;
1760 }
1761 }
1762 }
1763 cconx = cconx->next;
1764 }
1765 }
1766
1767
cconx_append(lives_cconnect_t * cconx)1768 static void cconx_append(lives_cconnect_t *cconx) {
1769 lives_cconnect_t *occonx = mainw->cconx;
1770 lives_cconnect_t *last_cconx = occonx;
1771
1772 while (occonx) {
1773 last_cconx = occonx;
1774 occonx = occonx->next;
1775 }
1776
1777 if (last_cconx) last_cconx->next = cconx;
1778 if (!mainw->cconx) mainw->cconx = cconx;
1779 }
1780
1781
cconx_find(int okey,int omode)1782 static lives_cconnect_t *cconx_find(int okey, int omode) {
1783 lives_cconnect_t *cconx = mainw->cconx;
1784 while (cconx) {
1785 if (cconx->okey == okey && cconx->omode == omode) {
1786 return cconx;
1787 }
1788 cconx = cconx->next;
1789 }
1790 return NULL;
1791 }
1792
1793
cconx_get_numcons(lives_conx_w * conxwp,int cnum)1794 static int cconx_get_numcons(lives_conx_w * conxwp, int cnum) {
1795 // get displayed number
1796 int totcons = 0;
1797
1798 register int j;
1799
1800 if (cnum != FX_DATA_WILDCARD) return conxwp->dispc[cnum];
1801
1802 for (j = 0; j < conxwp->num_alpha; j++) {
1803 totcons += conxwp->dispc[j];
1804 }
1805
1806 return totcons;
1807 }
1808
1809
cconx_get_nconns(lives_cconnect_t * cconx,int cnum)1810 static int cconx_get_nconns(lives_cconnect_t *cconx, int cnum) {
1811 // get actual number of connections
1812
1813 int totcons = 0, j;
1814
1815 if (!cconx) return 0;
1816
1817 for (j = 0; j < cconx->nchans; j++) {
1818 if (cnum != FX_DATA_WILDCARD) {
1819 if (cconx->chans[j] == cnum) return cconx->nconns[j];
1820 } else totcons += cconx->nconns[j];
1821 }
1822 return totcons;
1823 }
1824
1825
cconx_add_connection_private(int okey,int omode,int ocnum,int ikey,int imode,int icnum)1826 static lives_cconnect_t *cconx_add_connection_private(int okey, int omode, int ocnum, int ikey, int imode, int icnum) {
1827 lives_cconnect_t *cconx;
1828 int posn = 0, totcons = 0, i, j;
1829
1830 // delete any existing connection to the input channel
1831 cconx_delete(FX_DATA_WILDCARD, 0, 0, ikey, imode, icnum);
1832 cconx = cconx_find(okey, omode);
1833
1834 if (!cconx) {
1835 // add whole new node
1836 cconx = cconx_new(okey, omode);
1837 cconx_append(cconx);
1838 } else {
1839 // see if already in chans
1840
1841 for (i = 0; i < cconx->nchans; i++) {
1842
1843 if (cconx->chans[i] == ocnum) {
1844 // add connection to existing
1845
1846 for (j = 0; j < cconx->nchans; j++) {
1847 if (j < i) {
1848 // calc posn
1849 posn += cconx->nconns[j];
1850 }
1851 totcons += cconx->nconns[j];
1852 }
1853
1854 // if already there, do not add again
1855 for (j = posn; j < posn + cconx->nconns[i]; j++) {
1856 if (cconx->ikey[j] == ikey && cconx->imode[j] == imode && cconx->icnum[j] == icnum) {
1857 return cconx;
1858 }
1859
1860 // add in order key/mode/chan
1861 if (cconx->ikey[j] > ikey || (cconx->ikey[j] == ikey && cconx->imode[j] > imode) ||
1862 (cconx->ikey[j] == ikey && cconx->imode[j] == imode && cconx->icnum[j] > icnum)) break;
1863 }
1864
1865 posn = j; // we will insert here
1866 cconx->nconns[i]++;
1867 totcons++;
1868
1869 // make space for new
1870 cconx->ikey = (int *)lives_realloc(cconx->ikey, totcons * sizint);
1871 cconx->imode = (int *)lives_realloc(cconx->imode, totcons * sizint);
1872 cconx->icnum = (int *)lives_realloc(cconx->icnum, totcons * sizint);
1873
1874 // move up 1
1875 for (j = totcons - 1; j > posn; j--) {
1876 cconx->ikey[j] = cconx->ikey[j - 1];
1877 cconx->imode[j] = cconx->imode[j - 1];
1878 cconx->icnum[j] = cconx->icnum[j - 1];
1879 }
1880
1881 // insert at posn
1882 cconx->ikey[posn] = ikey;
1883 cconx->imode[posn] = imode;
1884 cconx->icnum[posn] = icnum;
1885
1886 return cconx;
1887 }
1888 }
1889
1890 // so, we have data for key/mode but this is a new channel to be mapped
1891
1892 for (i = 0; i < cconx->nchans; i++) {
1893 totcons += cconx->nconns[i];
1894 }
1895
1896 totcons++;
1897
1898 cconx->nchans++;
1899 posn = cconx->nchans;
1900
1901 // make space for new
1902 cconx->nconns = (int *)lives_realloc(cconx->nconns, posn * sizint);
1903 cconx->chans = (int *)lives_realloc(cconx->chans, posn * sizint);
1904
1905 cconx->ikey = (int *)lives_realloc(cconx->ikey, totcons * sizint);
1906 cconx->imode = (int *)lives_realloc(cconx->imode, totcons * sizint);
1907 cconx->icnum = (int *)lives_realloc(cconx->icnum, totcons * sizint);
1908
1909 cconx->chans[posn - 1] = ocnum;
1910
1911 cconx->nconns[posn - 1] = 1;
1912
1913 posn = totcons - 1;
1914
1915 // insert at posn
1916 cconx->ikey[posn] = ikey;
1917 cconx->imode[posn] = imode;
1918 cconx->icnum[posn] = icnum;
1919
1920 #ifdef DEBUG_CCONX
1921 g_print("added another cconx from %d %d %d to %d %d %d\n", okey, omode, ocnum, ikey, imode, icnum);
1922 #endif
1923
1924 return cconx;
1925 }
1926
1927 // add new
1928
1929 totcons = cconx_get_nconns(cconx, FX_DATA_WILDCARD) + 1;
1930 cconx->nchans++;
1931
1932 cconx->nconns = (int *)lives_realloc(cconx->chans, cconx->nchans * sizint);
1933 cconx->nconns[cconx->nchans - 1] = 1;
1934
1935 cconx->chans = (int *)lives_realloc(cconx->chans, cconx->nchans * sizint);
1936 cconx->chans[cconx->nchans - 1] = ocnum;
1937
1938 cconx->ikey = (int *)lives_realloc(cconx->ikey, totcons * sizint);
1939 cconx->ikey[totcons - 1] = ikey;
1940
1941 cconx->imode = (int *)lives_realloc(cconx->imode, totcons * sizint);
1942 cconx->imode[totcons - 1] = imode;
1943
1944 cconx->icnum = (int *)lives_realloc(cconx->icnum, totcons * sizint);
1945 cconx->icnum[totcons - 1] = icnum;
1946
1947 #ifdef DEBUG_CCONX
1948 g_print("added new cconx from %d %d %d to %d %d %d\n", okey, omode, ocnum, ikey, imode, icnum);
1949 #endif
1950 return cconx;
1951 }
1952
1953
cconx_add_connection(int okey,int omode,int ocnum,int ikey,int imode,int icnum)1954 void cconx_add_connection(int okey, int omode, int ocnum, int ikey, int imode, int icnum) {
1955 cconx_add_connection_private(okey, omode, ocnum, ikey, imode, icnum);
1956 }
1957
1958
cconx_get_out_alpha(boolean use_filt,int ikey,int imode,int icnum,int * okey,int * omode,int * ocnum)1959 static weed_plant_t *cconx_get_out_alpha(boolean use_filt, int ikey, int imode, int icnum, int *okey, int *omode, int *ocnum) {
1960 // walk all cconx and find one which has ikey/imode/icnum as destination
1961 // then all we need do is convert the pixel_data
1962
1963 lives_cconnect_t *cconx = mainw->cconx;
1964 weed_plant_t *inst = NULL, *filter = NULL, *orig_inst = NULL;
1965 int totcons, i, j;
1966
1967 while (cconx) {
1968 if (!use_filt) {
1969 if (mainw->is_rendering) {
1970 inst = get_new_inst_for_keymode(cconx->okey, cconx->omode);
1971 } else {
1972 inst = rte_keymode_get_instance(cconx->okey + 1, cconx->omode);
1973 }
1974 if (!inst) {
1975 cconx = cconx->next;
1976 continue;
1977 }
1978 filter = weed_instance_get_filter(inst, TRUE);
1979 } else {
1980 inst = NULL;
1981 filter = rte_keymode_get_filter(cconx->okey + 1, cconx->omode);
1982 if (!filter) {
1983 cconx = cconx->next;
1984 continue;
1985 }
1986 }
1987 if (!weed_plant_has_leaf(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES)) {
1988 if (inst) weed_instance_unref(inst);
1989 cconx = cconx->next;
1990 continue;
1991 }
1992 orig_inst = inst;
1993 totcons = 0;
1994 j = 0;
1995 for (i = 0; i < cconx->nchans; i++) {
1996 totcons += cconx->nconns[i];
1997 for (; j < totcons; j++) {
1998 if (cconx->ikey[j] == ikey && cconx->imode[j] == imode && cconx->icnum[j] == icnum) {
1999 weed_plant_t **outchans;
2000 weed_plant_t *channel = NULL;
2001 if (use_filt) {
2002 outchans = weed_get_plantptr_array(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, NULL);
2003 if (cconx->chans[i] < weed_leaf_num_elements(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES)) {
2004 channel = outchans[cconx->chans[i]];
2005 }
2006 } else {
2007 while (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) inst = weed_get_plantptr_value(inst,
2008 WEED_LEAF_HOST_NEXT_INSTANCE, NULL);
2009 outchans = weed_get_plantptr_array(inst, WEED_LEAF_OUT_CHANNELS, NULL);
2010 if (cconx->chans[i] < weed_leaf_num_elements(inst, WEED_LEAF_OUT_CHANNELS)) {
2011 channel = outchans[cconx->chans[i]];
2012 }
2013 }
2014 lives_free(outchans);
2015 if (okey) *okey = cconx->okey;
2016 if (omode) *omode = cconx->omode;
2017 if (ocnum) *ocnum = cconx->chans[i];
2018 if (orig_inst) weed_instance_unref(orig_inst);
2019 return channel;
2020 }
2021 }
2022 }
2023 cconx = cconx->next;
2024 weed_instance_unref(inst);
2025 }
2026
2027 return NULL;
2028 }
2029
2030
cconx_convert_pixel_data(weed_plant_t * dchan,weed_plant_t * schan)2031 boolean cconx_convert_pixel_data(weed_plant_t *dchan, weed_plant_t *schan) {
2032 // convert pixel_data by possibly converting the type (palette)
2033
2034 // return TRUE if we need to reinit the instance (because channel palette changed)
2035
2036 // we set boolean "host_orig_pdata" if we steal the schan pdata (so do not free....)
2037
2038 int iwidth, iheight, ipal, irow;
2039 int owidth, oheight, opal, orow, oflags;
2040 boolean pal_ok, needs_reinit = FALSE;
2041
2042 weed_plant_t *dtmpl = weed_get_plantptr_value(dchan, WEED_LEAF_TEMPLATE, NULL);
2043
2044 uint8_t *spdata, *dpdata;
2045
2046 int i;
2047
2048 ipal = weed_get_int_value(schan, WEED_LEAF_CURRENT_PALETTE, NULL);
2049 if (!weed_palette_is_alpha(ipal)) return FALSE;
2050
2051 iwidth = weed_get_int_value(schan, WEED_LEAF_WIDTH, NULL);
2052 iheight = weed_get_int_value(schan, WEED_LEAF_HEIGHT, NULL);
2053 irow = weed_get_int_value(schan, WEED_LEAF_ROWSTRIDES, NULL);
2054
2055 owidth = weed_get_int_value(dchan, WEED_LEAF_WIDTH, NULL);
2056 oheight = weed_get_int_value(dchan, WEED_LEAF_HEIGHT, NULL);
2057 opal = weed_get_int_value(dchan, WEED_LEAF_CURRENT_PALETTE, NULL);
2058 orow = weed_get_int_value(dchan, WEED_LEAF_ROWSTRIDES, NULL);
2059
2060 spdata = (uint8_t *)weed_get_voidptr_value(schan, WEED_LEAF_PIXEL_DATA, NULL);
2061
2062 #ifdef DEBUG_CCONX
2063 g_print("spd is %p %d %d %d %d %d %d %d %d\n", spdata, ipal, opal, iwidth, owidth, iheight, oheight, irow, orow);
2064 if (spdata) g_print("spd2 is %p %d\n", spdata, spdata[0]);
2065 #endif
2066 if (ipal == opal && iwidth == owidth && iheight == oheight && irow == orow) {
2067 /// everything matches - we can just do a steal
2068 weed_set_voidptr_value(dchan, WEED_LEAF_PIXEL_DATA, spdata);
2069 /// caller - do not free in dchan
2070 weed_set_boolean_value(dchan, WEED_LEAF_HOST_ORIG_PDATA, WEED_TRUE);
2071 return FALSE;
2072 }
2073
2074 /// check first if we can set the in-channel palette to match
2075 if (ipal == opal) pal_ok = TRUE;
2076 else {
2077 /// see if dest chan supports the source chan palette
2078 int num_palettes = weed_leaf_num_elements(dtmpl, WEED_LEAF_PALETTE_LIST);
2079 int *palettes = weed_get_int_array(dtmpl, WEED_LEAF_PALETTE_LIST, NULL);
2080 if (best_palette_match(palettes, num_palettes, ipal) == ipal) pal_ok = TRUE; ///< yes
2081 else pal_ok = FALSE; ///<no
2082 oflags = weed_get_int_value(dtmpl, WEED_LEAF_FLAGS, NULL);
2083 if (ipal != opal && (oflags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE)) needs_reinit = TRUE;
2084 lives_free(palettes);
2085 }
2086
2087 weed_layer_pixel_data_free(dchan);
2088
2089 weed_set_int_value(dchan, WEED_LEAF_WIDTH, iwidth);
2090 weed_set_int_value(dchan, WEED_LEAF_HEIGHT, iheight);
2091 weed_set_int_value(dchan, WEED_LEAF_CURRENT_PALETTE, ipal);
2092
2093 if (pal_ok) {
2094 weed_set_voidptr_value(dchan, WEED_LEAF_PIXEL_DATA, (void *)spdata);
2095 weed_set_int_value(dchan, WEED_LEAF_ROWSTRIDES, irow);
2096
2097 /// caller - do not free in dchan
2098 weed_set_boolean_value(dchan, WEED_LEAF_HOST_ORIG_PDATA, WEED_TRUE);
2099 #ifdef DEBUG_CCONX
2100 if (spdata) g_print("spd3 is %p %d\n", spdata, spdata[0]);
2101 #endif
2102 return FALSE;
2103 }
2104
2105 create_empty_pixel_data(dchan, FALSE, TRUE);
2106 dpdata = (uint8_t *)weed_get_voidptr_value(dchan, WEED_LEAF_PIXEL_DATA, NULL);
2107
2108 orow = weed_get_int_value(dchan, WEED_LEAF_ROWSTRIDES, NULL);
2109
2110 if (irow == orow) {
2111 lives_memcpy((void *)dpdata, (void *)spdata, irow * iheight);
2112 } else {
2113 int ipwidth = iwidth * weed_palette_get_bits_per_macropixel(ipal) / 8;
2114 for (i = 0; i < iheight; i++) {
2115 lives_memcpy((void *)dpdata, (void *)spdata, ipwidth);
2116 spdata += irow;
2117 dpdata += orow;
2118 }
2119 }
2120
2121 convert_layer_palette(dchan, opal, 0);
2122
2123 if (needs_reinit) return TRUE;
2124
2125 return FALSE;
2126 }
2127
2128
cconx_chain_data(int key,int mode)2129 boolean cconx_chain_data(int key, int mode) {
2130 // ret TRUE if we should reinit inst (because of palette change)
2131
2132 weed_plant_t *ichan, *ochan;
2133 weed_plant_t *inst = NULL;
2134
2135 boolean needs_reinit = FALSE;
2136
2137 int i = 0;
2138
2139 if (key > -1) {
2140 if (mainw->is_rendering) {
2141 if ((inst = get_new_inst_for_keymode(key, mode)) == NULL) {
2142 return FALSE; ///< dest effect is not found
2143 }
2144 } else {
2145 if ((inst = rte_keymode_get_instance(key + 1, mode)) == NULL) {
2146 return FALSE; ///< dest effect is not enabled
2147 }
2148 }
2149 } else if (key == FX_DATA_KEY_PLAYBACK_PLUGIN) {
2150 if (!mainw->vpp || mainw->vpp->num_alpha_chans == 0) return FALSE;
2151 }
2152
2153 while ((ichan = (key == FX_DATA_KEY_PLAYBACK_PLUGIN ? (weed_plant_t *)pp_get_chan(mainw->vpp->play_params, i)
2154 : get_enabled_channel(inst, i, TRUE))) != NULL) {
2155 if ((ochan = cconx_get_out_alpha(FALSE, key, mode, i++, NULL, NULL, NULL))) {
2156 filter_mutex_lock(key);
2157 if (cconx_convert_pixel_data(ichan, ochan)) needs_reinit = TRUE;
2158 filter_mutex_unlock(key);
2159 }
2160 }
2161 //if (inst) weed_instance_unref(inst);
2162 return needs_reinit;
2163 }
2164
2165
cconx_chain_data_internal(weed_plant_t * ichan)2166 boolean cconx_chain_data_internal(weed_plant_t *ichan) {
2167 // special version for compound fx internal connections
2168 boolean needs_reinit = FALSE;
2169
2170 if (weed_plant_has_leaf(ichan, WEED_LEAF_HOST_INTERNAL_CONNECTION)) {
2171 weed_plant_t *ochan = weed_get_plantptr_value(ichan, WEED_LEAF_HOST_INTERNAL_CONNECTION, NULL);
2172 if (cconx_convert_pixel_data(ichan, ochan)) needs_reinit = TRUE;
2173 }
2174 return needs_reinit;
2175 }
2176
2177
feeds_to_video_filters(int okey,int omode)2178 boolean feeds_to_video_filters(int okey, int omode) {
2179 weed_plant_t *filter;
2180 char **array;
2181 char *chlist;
2182 int nparams, niparams;
2183 int ikey, imode, i, j;
2184
2185 filter = rte_keymode_get_filter(okey + 1, omode);
2186
2187 nparams = num_out_params(filter);
2188
2189 for (i = 0; i < nparams; i++) {
2190 chlist = pconx_list(okey, omode, i);
2191 niparams = get_token_count(chlist, ' ') / 4;
2192 array = lives_strsplit(chlist, " ", niparams * 4);
2193 for (j = 0; j < niparams; j += 4) {
2194 ikey = atoi(array[j]);
2195 imode = atoi(array[j + 1]);
2196 if (imode != rte_key_getmode(ikey + 1)) continue;
2197 filter = rte_keymode_get_filter(ikey + 1, imode);
2198 if (has_video_chans_in(filter, TRUE) || has_video_chans_out(filter, TRUE)) {
2199 lives_strfreev(array);
2200 lives_free(chlist);
2201 return TRUE;
2202 }
2203 }
2204 lives_strfreev(array);
2205 lives_free(chlist);
2206 }
2207
2208 for (i = 0; i < nparams; i++) {
2209 chlist = cconx_list(okey, omode, i);
2210 niparams = get_token_count(chlist, ' ') / 3;
2211 array = lives_strsplit(chlist, " ", niparams * 3);
2212 for (j = 0; j < niparams; j += 3) {
2213 ikey = atoi(array[j]);
2214 imode = atoi(array[j + 1]);
2215 if (imode != rte_key_getmode(ikey + 1)) continue;
2216 lives_strfreev(array);
2217 lives_free(chlist);
2218 return TRUE;
2219 }
2220 lives_strfreev(array);
2221 lives_free(chlist);
2222 }
2223
2224 return FALSE;
2225 }
2226
2227
feeds_to_audio_filters(int okey,int omode)2228 boolean feeds_to_audio_filters(int okey, int omode) {
2229 weed_plant_t *filter;
2230 char **array;
2231 char *chlist;
2232 int nparams, niparams;
2233 int ikey, imode;
2234 int i, j;
2235
2236 filter = rte_keymode_get_filter(okey + 1, omode);
2237
2238 nparams = num_out_params(filter);
2239
2240 for (i = 0; i < nparams; i++) {
2241 chlist = pconx_list(okey, omode, i);
2242 niparams = get_token_count(chlist, ' ') / 4;
2243 array = lives_strsplit(chlist, " ", niparams * 4);
2244 for (j = 0; j < niparams; j += 4) {
2245 ikey = atoi(array[j]);
2246 if (ikey < 0) continue;
2247 imode = atoi(array[j + 1]);
2248 if (imode != rte_key_getmode(ikey + 1)) continue;
2249 filter = rte_keymode_get_filter(ikey + 1, imode);
2250 if (has_audio_chans_in(filter, TRUE) || has_audio_chans_out(filter, TRUE)) {
2251 lives_strfreev(array);
2252 lives_free(chlist);
2253 return TRUE;
2254 }
2255 }
2256 lives_strfreev(array);
2257 lives_free(chlist);
2258 }
2259
2260 for (i = 0; i < nparams; i++) {
2261 chlist = cconx_list(okey, omode, i);
2262 niparams = get_token_count(chlist, ' ') / 3;
2263 array = lives_strsplit(chlist, " ", niparams * 3);
2264 for (j = 0; j < niparams; j += 3) {
2265 ikey = atoi(array[j]);
2266 if (ikey < 0) continue;
2267 imode = atoi(array[j + 1]);
2268 if (imode != rte_key_getmode(ikey + 1)) continue;
2269 filter = rte_keymode_get_filter(ikey + 1, imode);
2270 if (has_audio_chans_in(filter, TRUE) || has_audio_chans_out(filter, TRUE)) {
2271 lives_strfreev(array);
2272 lives_free(chlist);
2273 return TRUE;
2274 }
2275 }
2276 lives_strfreev(array);
2277 lives_free(chlist);
2278 }
2279
2280 return FALSE;
2281 }
2282
2283
2284 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2285
2286 // channel/param connection window
2287
2288 enum {
2289 KEY_COLUMN,
2290 NAME_COLUMN,
2291 KEYVAL_COLUMN,
2292 MODEVAL_COLUMN,
2293 EFD_NUM_COLUMNS
2294 };
2295
2296
disconbutton_clicked(LiVESButton * button,livespointer user_data)2297 static void disconbutton_clicked(LiVESButton * button, livespointer user_data) {
2298 // disconnect all channels/params
2299 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2300
2301 int totparams, totchans;
2302 int pidx, pidx_last, cidx, cidx_last;
2303
2304 register int i;
2305
2306 totparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2307 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2308
2309 for (i = 0; i < totchans; i++) {
2310 lives_combo_set_active_index(LIVES_COMBO(conxwp->cfxcombo[i]), 0);
2311
2312 if (i == 0) lives_widget_set_sensitive(conxwp->del_button[i], FALSE);
2313 else {
2314 cidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->ccombo[i]), "cidx"));
2315 cidx_last = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->ccombo[i - 1]), "cidx"));
2316 lives_widget_set_sensitive(conxwp->del_button[i], cidx == cidx_last);
2317 }
2318 }
2319
2320 for (i = 0; i < totparams; i++) {
2321 lives_combo_set_active_index(LIVES_COMBO(conxwp->pfxcombo[i]), 0);
2322
2323 if (i == 0) lives_widget_set_sensitive(conxwp->del_button[i + totchans], FALSE);
2324 else {
2325 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[i]), "pidx"));
2326 pidx_last = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[i - 1]), "pidx"));
2327 lives_widget_set_sensitive(conxwp->del_button[i + totchans], pidx == pidx_last);
2328 }
2329 }
2330 }
2331
2332
apbutton_clicked(LiVESButton * button,livespointer user_data)2333 static void apbutton_clicked(LiVESButton * button, livespointer user_data) {
2334 // autoconnect each param with a compatible one in the target
2335 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2336
2337 LiVESWidget *combo;
2338
2339 LiVESTreeIter iter;
2340 LiVESTreeModel *model;
2341 LiVESTreePath *tpath;
2342
2343 weed_plant_t **iparams, **oparams;
2344 weed_plant_t *filter, *param, *oparam;
2345
2346 int fidx, key, mode, totchans;
2347 int niparams, ours, addn, stparam;
2348
2349 int i, k = 1;
2350
2351 // get filter from last connection from first parameter
2352
2353 ours = pconx_get_numcons(conxwp, -EXTRA_PARAMS_OUT) + pconx_get_numcons(conxwp, 0) - 1;
2354
2355 combo = (LiVESWidget *)conxwp->pfxcombo[ours];
2356
2357 if (!lives_combo_get_active_iter(LIVES_COMBO(combo), &iter)) return;
2358 model = lives_combo_get_model(LIVES_COMBO(combo));
2359
2360 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
2361
2362 if (key == FX_DATA_KEY_OMC_MACRO) {
2363 // match with OMC macro
2364 //
2365 //
2366 return;
2367 }
2368
2369 fidx = rte_keymode_get_filter_idx(key, mode);
2370
2371 if (fidx == -1) return;
2372
2373 tpath = lives_tree_model_get_path(model, &iter);
2374 lives_tree_model_get_iter(model, &iter, tpath);
2375
2376 // find the receiving filter/instance
2377 filter = get_weed_filter(fidx);
2378
2379 iparams = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL);
2380 niparams = weed_leaf_num_elements(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES);
2381
2382 #ifdef COMBO_LIST_LIMIT
2383 if (niparams + EXTRA_PARAMS_IN > COMBO_LIST_LIMIT) {
2384 niparams = COMBO_LIST_LIMIT - EXTRA_PARAMS_IN;
2385 }
2386 #endif
2387
2388 oparams = weed_get_plantptr_array(rte_keymode_get_filter(conxwp->okey + 1, conxwp->omode),
2389 WEED_LEAF_OUT_PARAMETER_TEMPLATES, NULL);
2390
2391 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2392
2393 // get first param connected
2394 stparam = conxwp->idx[totchans + ours];
2395
2396 if (conxwp->ikeys[totchans + ours] < 0) {
2397 // first out not connected, we will add this back in
2398 ours -= pconx_get_numcons(conxwp, 0);
2399 k = 0;
2400 } else stparam++;
2401
2402 // set all pcombo with params
2403 for (i = stparam; i < niparams; i++) {
2404
2405 param = iparams[i];
2406
2407 if (weed_plant_has_leaf(param, WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
2408
2409 if (pconx_get_out_param(TRUE, key - 1, mode, i, NULL, NULL, NULL, NULL)) continue;
2410
2411 oparam = oparams[k];
2412
2413 if (!params_compatible(oparam, param)) continue;
2414
2415 addn = pconx_get_numcons(conxwp, k);
2416
2417 ours += addn;
2418
2419 combo = conxwp->pcombo[ours];
2420
2421 if (conxwp->ikeys[ours + totchans] >= 0) {
2422 // add another if needed
2423 padd_clicked(conxwp->add_button[ours + totchans], (livespointer)conxwp);
2424 ours++;
2425 }
2426
2427 combo = conxwp->pfxcombo[ours];
2428 model = lives_combo_get_model(LIVES_COMBO(combo));
2429 lives_tree_model_get_iter(model, &iter, tpath);
2430 lives_combo_set_active_iter(LIVES_COMBO(combo), &iter);
2431 lives_widget_context_update();
2432
2433 lives_combo_set_active_index(LIVES_COMBO(conxwp->pcombo[ours]), i + EXTRA_PARAMS_IN);
2434
2435 if (++k >= conxwp->num_params - EXTRA_PARAMS_OUT) break;
2436 }
2437
2438 lives_tree_path_free(tpath);
2439
2440 lives_free(iparams);
2441 lives_free(oparams);
2442 }
2443
2444
acbutton_clicked(LiVESButton * button,livespointer user_data)2445 static void acbutton_clicked(LiVESButton * button, livespointer user_data) {
2446 // autoconnect each channel with a compatible one in the target
2447 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2448
2449 LiVESWidget *combo;
2450
2451 LiVESTreeIter iter;
2452 LiVESTreeModel *model;
2453 LiVESTreePath *tpath;
2454
2455 weed_plant_t **ichans, **ochans;
2456 weed_plant_t *filter, *chan, *ochan;
2457
2458 int fidx, key, mode;
2459 int nichans, nochans, ours, addn, stchan;
2460
2461 int i, j = 0, k = 1;
2462
2463 // get filter from last connection from first parameter
2464
2465 ours = cconx_get_numcons(conxwp, 0) - 1;
2466
2467 combo = (LiVESWidget *)conxwp->cfxcombo[ours];
2468
2469 if (!lives_combo_get_active_iter(LIVES_COMBO(combo), &iter)) return;
2470 model = lives_combo_get_model(LIVES_COMBO(combo));
2471
2472 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
2473 fidx = rte_keymode_get_filter_idx(key, mode);
2474
2475 if (fidx == -1) return;
2476
2477 tpath = lives_tree_model_get_path(model, &iter);
2478 lives_tree_model_get_iter(model, &iter, tpath);
2479
2480 // find the receiving filter/instance
2481 filter = get_weed_filter(fidx);
2482
2483 ichans = weed_get_plantptr_array(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, NULL);
2484 nichans = weed_leaf_num_elements(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES);
2485
2486 ochans = weed_get_plantptr_array(rte_keymode_get_filter(conxwp->okey + 1, conxwp->omode),
2487 WEED_LEAF_OUT_CHANNEL_TEMPLATES, NULL);
2488 nochans = weed_leaf_num_elements(rte_keymode_get_filter(conxwp->okey + 1, conxwp->omode),
2489 WEED_LEAF_OUT_CHANNEL_TEMPLATES);
2490
2491 // get first param connected
2492 stchan = conxwp->idx[ours];
2493
2494 if (conxwp->ikeys[ours] < 0) {
2495 // first out not connected, we will add this back in
2496 ours -= cconx_get_numcons(conxwp, 0);
2497 k = 0;
2498 } else {
2499 stchan++;
2500
2501 for (i = 0; i < nichans; i++) {
2502 j++;
2503 chan = ichans[i];
2504 if (!has_alpha_palette(chan, filter)) continue;
2505 if (i == conxwp->idx[ours]) break;
2506 }
2507 }
2508
2509 // set all ccombo with chans
2510 for (i = stchan; i < nichans; i++) {
2511
2512 chan = ichans[i];
2513
2514 if (!has_alpha_palette(chan, filter)) continue;
2515
2516 if (cconx_get_out_alpha(TRUE, key - 1, mode, i, NULL, NULL, NULL)) continue;
2517
2518 ochan = ochans[k];
2519
2520 if (!has_alpha_palette(ochan, filter)) {
2521 if (++k >= nochans) break;
2522 continue;
2523 }
2524
2525 addn = cconx_get_numcons(conxwp, k);
2526
2527 ours += addn;
2528
2529 combo = conxwp->ccombo[ours];
2530
2531 if (conxwp->ikeys[ours] >= 0) {
2532 // add another if needed
2533 cadd_clicked(conxwp->add_button[ours], (livespointer)conxwp);
2534 ours++;
2535 }
2536
2537 combo = conxwp->cfxcombo[ours];
2538 model = lives_combo_get_model(LIVES_COMBO(combo));
2539 lives_tree_model_get_iter(model, &iter, tpath);
2540 lives_combo_set_active_iter(LIVES_COMBO(combo), &iter);
2541 lives_widget_context_update();
2542
2543 lives_combo_set_active_index(LIVES_COMBO(conxwp->ccombo[ours]), j++);
2544
2545 if (++k >= nochans) break;
2546 }
2547
2548 lives_tree_path_free(tpath);
2549
2550 lives_free(ichans);
2551 lives_free(ochans);
2552 }
2553
2554
padd_clicked(LiVESWidget * button,livespointer user_data)2555 static void padd_clicked(LiVESWidget * button, livespointer user_data) {
2556 // add another param row below the add button
2557 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2558
2559 int totparams, totchans;
2560 int ours = -1, pidx;
2561 #if LIVES_TABLE_IS_GRID
2562 int trows;
2563 #else
2564 LiVESWidget *hbox[5], *hboxb[5], *achbox, *comhbox;
2565 #endif
2566
2567 int i;
2568
2569 totparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2570 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2571
2572 for (i = 0; i < totparams; i++) {
2573 if (conxwp->add_button[i + totchans] == button) {
2574 ours = i;
2575 break;
2576 }
2577 }
2578
2579 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[ours]), "pidx"));
2580
2581 totparams++;
2582
2583 conxwp->pclabel = (LiVESWidget **)lives_realloc(conxwp->pclabel, (totchans + totparams) * sizeof(LiVESWidget *));
2584
2585 conxwp->add_button = (LiVESWidget **)lives_realloc(conxwp->add_button, (totchans + totparams) * sizeof(LiVESWidget *));
2586 conxwp->del_button = (LiVESWidget **)lives_realloc(conxwp->del_button, (totchans + totparams) * sizeof(LiVESWidget *));
2587 conxwp->clabel = (LiVESWidget **)lives_realloc(conxwp->clabel, (totchans + totparams) * sizeof(LiVESWidget *));
2588
2589 conxwp->ikeys = (int *)lives_realloc(conxwp->ikeys, (totchans + totparams) * sizint);
2590 conxwp->imodes = (int *)lives_realloc(conxwp->imodes, (totchans + totparams) * sizint);
2591 conxwp->idx = (int *)lives_realloc(conxwp->idx, (totchans + totparams) * sizint);
2592
2593 conxwp->pfxcombo = (LiVESWidget **)lives_realloc(conxwp->pfxcombo, totparams * sizeof(LiVESWidget *));
2594 conxwp->pcombo = (LiVESWidget **)lives_realloc(conxwp->pcombo, totparams * sizeof(LiVESWidget *));
2595
2596 conxwp->dpp_func = (ulong *)lives_realloc(conxwp->dpp_func, totparams * sizeof(ulong));
2597 conxwp->acheck_func = (ulong *)lives_realloc(conxwp->acheck_func, totparams * sizeof(ulong));
2598
2599 conxwp->acheck = (LiVESWidget **)lives_realloc(conxwp->acheck, totparams * sizeof(LiVESWidget *));
2600
2601 conxwp->trowsp++;
2602
2603 for (i = conxwp->trowsp - 3; i > ours; i--) {
2604 conxwp->del_button[i + 1] = conxwp->del_button[i];
2605 conxwp->add_button[i + 1] = conxwp->add_button[i];
2606 conxwp->clabel[i + 1] = conxwp->clabel[i];
2607 }
2608
2609 #if !LIVES_TABLE_IS_GRID
2610 lives_table_resize(LIVES_TABLE(conxwp->tablep), conxwp->trowsp, 7);
2611
2612 // add parent widgets to new row
2613
2614 for (i = 0; i < 5; i++) {
2615 hbox[i] = lives_hbox_new(FALSE, 0);
2616
2617 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox[i], i, i + 1, conxwp->trowsp - 1, conxwp->trowsp,
2618 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
2619 (LiVESAttachOptions)(0), 0, 0);
2620
2621 }
2622
2623 ptable_row_add_standard_widgets(conxwp, totparams - 1);
2624 #else
2625 lives_grid_insert_row(LIVES_GRID(conxwp->tablep), ours + 2);
2626 trows = conxwp->trowsp;
2627 conxwp->trowsp = ours + 3;
2628 ptable_row_add_standard_widgets(conxwp, ours + 1);
2629 conxwp->trowsp = trows;
2630 #endif
2631
2632 // subtract 1 from trowsp because of title row
2633 for (i = conxwp->trowsp - 3; i > ours; i--) {
2634 #if !LIVES_TABLE_IS_GRID
2635
2636 // reparent widgets from row i to row i+1
2637 hboxb[0] = lives_widget_get_parent(conxwp->pclabel[i]);
2638 lives_widget_reparent(conxwp->pclabel[i], hbox[0]);
2639 hbox[0] = hboxb[0];
2640
2641 hboxb[2] = lives_widget_get_parent(conxwp->pfxcombo[i]);
2642 lives_widget_reparent(conxwp->pfxcombo[i], hbox[2]);
2643 hbox[2] = hboxb[2];
2644
2645 comhbox = lives_widget_get_parent(conxwp->pcombo[i]);
2646 hboxb[3] = lives_widget_get_parent(comhbox);
2647 lives_widget_reparent(comhbox, hbox[3]);
2648 hbox[3] = hboxb[3];
2649
2650 if (conxwp->acheck[i]) {
2651 achbox = lives_widget_get_parent(conxwp->acheck[i]);
2652 hboxb[4] = lives_widget_get_parent(achbox);
2653 lives_widget_reparent(achbox, hbox[4]);
2654 hbox[4] = hboxb[4];
2655 }
2656
2657 #endif
2658
2659 conxwp->pclabel[i + 1] = conxwp->pclabel[i];
2660
2661 conxwp->pfxcombo[i + 1] = conxwp->pfxcombo[i];
2662 conxwp->pcombo[i + 1] = conxwp->pcombo[i];
2663
2664 conxwp->acheck[i + 1] = conxwp->acheck[i];
2665 conxwp->acheck_func[i + 1] = conxwp->acheck_func[i];
2666
2667 conxwp->ikeys[i + 1] = conxwp->ikeys[i];
2668 conxwp->imodes[i + 1] = conxwp->imodes[i];
2669 conxwp->idx[i + 1] = conxwp->idx[i];
2670
2671 conxwp->dpp_func[i + 1] = conxwp->dpp_func[i];
2672 }
2673
2674 ptable_row_add_variable_widgets(conxwp, ours + 1, ours + 2, pidx);
2675
2676 conxwp->ikeys[ours + 1] = conxwp->imodes[ours + 1] = conxwp->idx[i + 1] = 0;
2677
2678 conxwp->dispp[pidx + EXTRA_PARAMS_OUT]++;
2679
2680 lives_widget_set_sensitive(conxwp->del_button[ours + 1], TRUE);
2681 lives_widget_set_sensitive(conxwp->add_button[ours], FALSE);
2682
2683 lives_widget_show_all(conxwp->tablep);
2684 }
2685
2686
pdel_clicked(LiVESWidget * button,livespointer user_data)2687 static void pdel_clicked(LiVESWidget * button, livespointer user_data) {
2688 // remove the param row at the del button
2689 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2690
2691 int totparams, totchans;
2692 int ours = -1, pidx;
2693
2694 #if !LIVES_TABLE_IS_GRID
2695 LiVESWidget *comhbox;
2696 LiVESWidget *hbox[4], *hboxb[4], *achbox;
2697 int pidx_next;
2698 #endif
2699
2700 register int i;
2701
2702 #if !LIVES_TABLE_IS_GRID
2703 hbox[3] = NULL;
2704 #endif
2705
2706 totparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2707 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2708
2709 for (i = 0; i < totparams; i++) {
2710 if (conxwp->del_button[i + totchans] == button) {
2711 ours = i;
2712 break;
2713 }
2714 }
2715
2716 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[ours]), "pidx"));
2717
2718 lives_combo_set_active_index(LIVES_COMBO(conxwp->pfxcombo[ours]), 0);
2719
2720 if (conxwp->dispp[pidx + EXTRA_PARAMS_OUT] <= 1) {
2721 // last one for this param, dont delete, just clear
2722 lives_widget_set_sensitive(conxwp->del_button[totchans + ours], FALSE);
2723 return;
2724 }
2725
2726 if (ours > 0) {
2727 if (lives_widget_get_sensitive(conxwp->del_button[totchans + ours - 1])
2728 && lives_widget_get_sensitive(conxwp->add_button[totchans + ours])) {
2729 lives_widget_set_sensitive(conxwp->add_button[totchans + ours - 1], TRUE);
2730 }
2731 }
2732
2733 conxwp->dispp[pidx + EXTRA_PARAMS_OUT]--;
2734
2735 // force callback for pfxcombo before destroying it
2736 lives_widget_context_update();
2737 totparams--;
2738
2739 #if !LIVES_TABLE_IS_GRID
2740 hbox[0] = lives_widget_get_parent(conxwp->pclabel[totchans + ours]);
2741 hbox[1] = lives_widget_get_parent(conxwp->pfxcombo[ours]);
2742
2743 comhbox = lives_widget_get_parent(conxwp->pcombo[ours]);
2744 hbox[2] = lives_widget_get_parent(comhbox);
2745
2746 lives_widget_destroy(conxwp->pfxcombo[ours]);
2747 lives_widget_destroy(conxwp->pcombo[ours]);
2748 lives_widget_destroy(comhbox);
2749 #endif
2750
2751 conxwp->trowsp--;
2752
2753 // subtract 1 from trowsp because of title row
2754 for (i = ours; i < conxwp->trowsp - 1; i++) {
2755 #if !LIVES_TABLE_IS_GRID
2756
2757 // reparent widgets from row i to row i+1
2758
2759 hboxb[0] = lives_widget_get_parent(conxwp->pclabel[totchans + i + 1]);
2760
2761 if (i == ours) {
2762 pidx_next = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[i + 1]), "pidx"));
2763 if (pidx_next != pidx) {
2764 // secondary param
2765 lives_widget_destroy(conxwp->pclabel[totchans + i]);
2766 lives_widget_reparent(conxwp->pclabel[totchans + i + 1], hbox[0]);
2767 conxwp->pclabel[totchans + i] = conxwp->pclabel[totchans + i + 1];
2768 } else {
2769 // primary param
2770 lives_widget_destroy(conxwp->pclabel[totchans + i + 1]);
2771 }
2772 } else {
2773 lives_widget_reparent(conxwp->pclabel[totchans + i + 1], hbox[0]);
2774 conxwp->pclabel[totchans + i] = conxwp->pclabel[totchans + i + 1];
2775 }
2776
2777 hbox[0] = hboxb[0];
2778
2779 hboxb[1] = lives_widget_get_parent(conxwp->pfxcombo[i + 1]);
2780 lives_widget_reparent(conxwp->pfxcombo[i + 1], hbox[1]);
2781 hbox[1] = hboxb[1];
2782
2783 comhbox = lives_widget_get_parent(conxwp->pcombo[i + 1]);
2784 hboxb[2] = lives_widget_get_parent(comhbox);
2785 lives_widget_reparent(comhbox, hbox[2]);
2786 hbox[2] = hboxb[2];
2787
2788 if (conxwp->acheck[i]) {
2789 if (!hbox[3]) {
2790 achbox = lives_widget_get_parent(conxwp->acheck[i]);
2791 hbox[3] = lives_widget_get_parent(achbox);
2792 lives_widget_destroy(achbox);
2793 }
2794 achbox = lives_widget_get_parent(conxwp->acheck[i + 1]);
2795 hboxb[3] = lives_widget_get_parent(achbox);
2796 lives_widget_reparent(achbox, hbox[3]);
2797 hbox[3] = hboxb[3];
2798 }
2799
2800 lives_widget_set_sensitive(conxwp->del_button[totchans + i],
2801 lives_widget_get_sensitive(conxwp->del_button[totchans + i + 1]));
2802
2803 #else
2804 conxwp->add_button[i] = conxwp->add_button[i + 1];
2805 conxwp->del_button[i] = conxwp->del_button[i + 1];
2806 conxwp->clabel[i] = conxwp->clabel[i + 1];
2807 conxwp->pclabel[i] = conxwp->pclabel[i + 1];
2808
2809 if (i == ours) {
2810 widget_opts.mnemonic_label = FALSE;
2811 lives_label_set_text(LIVES_LABEL(conxwp->pclabel[i + 1]), lives_label_get_text(LIVES_LABEL(conxwp->pclabel[i])));
2812 widget_opts.mnemonic_label = TRUE;
2813 }
2814 #endif
2815 conxwp->pfxcombo[i] = conxwp->pfxcombo[i + 1];
2816 conxwp->pcombo[i] = conxwp->pcombo[i + 1];
2817
2818 conxwp->acheck[i] = conxwp->acheck[i + 1];
2819 conxwp->acheck_func[i] = conxwp->acheck_func[i + 1];
2820
2821 conxwp->ikeys[i] = conxwp->ikeys[i + 1];
2822 conxwp->imodes[i] = conxwp->imodes[i + 1];
2823 conxwp->idx[i] = conxwp->idx[i + 1];
2824
2825 conxwp->dpp_func[i] = conxwp->dpp_func[i + 1];
2826 }
2827
2828 #if !LIVES_TABLE_IS_GRID
2829 lives_widget_destroy(conxwp->clabel[conxwp->trowsp - 1 + totchans]);
2830 lives_widget_destroy(conxwp->add_button[conxwp->trowsp - 1 + totchans]);
2831 lives_widget_destroy(conxwp->del_button[conxwp->trowsp - 1 + totchans]);
2832
2833 // destroy (empty) last row parent widgets
2834 lives_widget_destroy(hbox[0]);
2835 lives_widget_destroy(hbox[1]);
2836 lives_widget_destroy(hbox[2]);
2837 lives_widget_destroy(hbox[3]);
2838
2839 lives_table_resize(LIVES_TABLE(conxwp->tablep), conxwp->trowsp, 7);
2840 #else
2841 lives_grid_remove_row(LIVES_GRID(conxwp->tablep), ours + 1);
2842 #endif
2843
2844 conxwp->pclabel = (LiVESWidget **)lives_realloc(conxwp->pclabel, (totchans + totparams) * sizeof(LiVESWidget *));
2845
2846 conxwp->add_button = (LiVESWidget **)lives_realloc(conxwp->add_button, (totchans + totparams) * sizeof(LiVESWidget *));
2847 conxwp->del_button = (LiVESWidget **)lives_realloc(conxwp->del_button, (totchans + totparams) * sizeof(LiVESWidget *));
2848 conxwp->clabel = (LiVESWidget **)lives_realloc(conxwp->clabel, (totchans + totparams) * sizeof(LiVESWidget *));
2849
2850 conxwp->ikeys = (int *)lives_realloc(conxwp->ikeys, (totchans + totparams) * sizint);
2851 conxwp->imodes = (int *)lives_realloc(conxwp->imodes, (totchans + totparams) * sizint);
2852 conxwp->idx = (int *)lives_realloc(conxwp->idx, (totchans + totparams) * sizint);
2853
2854 conxwp->pfxcombo = (LiVESWidget **)lives_realloc(conxwp->pfxcombo, totparams * sizeof(LiVESWidget *));
2855 conxwp->pcombo = (LiVESWidget **)lives_realloc(conxwp->pcombo, totparams * sizeof(LiVESWidget *));
2856
2857 conxwp->dpp_func = (ulong *)lives_realloc(conxwp->dpp_func, totparams * sizeof(ulong));
2858 conxwp->acheck_func = (ulong *)lives_realloc(conxwp->acheck_func, totparams * sizeof(ulong));
2859
2860 conxwp->acheck = (LiVESWidget **)lives_realloc(conxwp->acheck, totparams * sizeof(LiVESWidget *));
2861 }
2862
2863
cadd_clicked(LiVESWidget * button,livespointer user_data)2864 static void cadd_clicked(LiVESWidget * button, livespointer user_data) {
2865 // add another channel row below the add button
2866 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2867
2868 #if LIVES_TABLE_IS_GRID
2869 int trows;
2870 #else
2871 LiVESWidget *hbox[4], *hboxb[4], *comhbox;
2872 #endif
2873
2874 int totparams, totchans;
2875 int ours = -1, cidx;
2876
2877 register int i;
2878
2879 totparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2880 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
2881
2882 for (i = 0; i < totchans; i++) {
2883 if (conxwp->add_button[i] == button) {
2884 ours = i;
2885 break;
2886 }
2887 }
2888
2889 cidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->cfxcombo[ours]), "cidx"));
2890
2891 conxwp->dispc[cidx]++;
2892
2893 totchans++;
2894
2895 conxwp->pclabel = (LiVESWidget **)lives_realloc(conxwp->pclabel, (totchans + totparams) * sizeof(LiVESWidget *));
2896
2897 conxwp->add_button = (LiVESWidget **)lives_realloc(conxwp->add_button, (totchans + totparams) * sizeof(LiVESWidget *));
2898 conxwp->del_button = (LiVESWidget **)lives_realloc(conxwp->del_button, (totchans + totparams) * sizeof(LiVESWidget *));
2899 conxwp->clabel = (LiVESWidget **)lives_realloc(conxwp->clabel, (totchans + totparams) * sizeof(LiVESWidget *));
2900
2901 conxwp->ikeys = (int *)lives_realloc(conxwp->ikeys, (totchans + totparams) * sizint);
2902 conxwp->imodes = (int *)lives_realloc(conxwp->imodes, (totchans + totparams) * sizint);
2903 conxwp->idx = (int *)lives_realloc(conxwp->idx, (totchans + totparams) * sizint);
2904
2905 conxwp->cfxcombo = (LiVESWidget **)lives_realloc(conxwp->cfxcombo, totchans * sizeof(LiVESWidget *));
2906 conxwp->ccombo = (LiVESWidget **)lives_realloc(conxwp->ccombo, totchans * sizeof(LiVESWidget *));
2907
2908 conxwp->dpc_func = (ulong *)lives_realloc(conxwp->dpc_func, totchans * sizeof(ulong));
2909
2910 conxwp->trowsc++;
2911
2912 for (i = conxwp->trowsc - 3; i > ours; i--) {
2913 conxwp->del_button[i + 1] = conxwp->del_button[i];
2914 conxwp->add_button[i + 1] = conxwp->add_button[i];
2915 conxwp->clabel[i + 1] = conxwp->clabel[i];
2916 }
2917
2918 #if !LIVES_TABLE_IS_GRID
2919 lives_table_resize(LIVES_TABLE(conxwp->tablec), conxwp->trowsc, 6);
2920
2921 // add parent widgets to new row
2922
2923 for (i = 0; i < 4; i++) {
2924 hbox[i] = lives_hbox_new(FALSE, 0);
2925
2926 lives_table_attach(LIVES_TABLE(conxwp->tablec), hbox[i], i, i + 1, conxwp->trowsc - 1, conxwp->trowsc,
2927 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
2928 (LiVESAttachOptions)(0), 0, 0);
2929 }
2930
2931 ctable_row_add_standard_widgets(conxwp, totchans - 1);
2932 #else
2933 lives_grid_insert_row(LIVES_GRID(conxwp->tablec), ours + 2);
2934 trows = conxwp->trowsc;
2935 conxwp->trowsc = ours + 3;
2936 ctable_row_add_standard_widgets(conxwp, ours + 1);
2937 conxwp->trowsc = trows;
2938 #endif
2939
2940 // subtract 1 from trowsp because of title row
2941 for (i = conxwp->trowsc - 3; i > ours; i--) {
2942 #if !LIVES_TABLE_IS_GRID
2943
2944 // reparent widgets from row i to row i+1
2945 hboxb[0] = lives_widget_get_parent(conxwp->pclabel[i]);
2946 lives_widget_reparent(conxwp->pclabel[i], hbox[0]);
2947 hbox[0] = hboxb[0];
2948
2949 hboxb[2] = lives_widget_get_parent(conxwp->cfxcombo[i]);
2950 lives_widget_reparent(conxwp->cfxcombo[i], hbox[2]);
2951 hbox[2] = hboxb[2];
2952
2953 comhbox = lives_widget_get_parent(conxwp->ccombo[i]);
2954 hboxb[3] = lives_widget_get_parent(comhbox);
2955 lives_widget_reparent(comhbox, hbox[3]);
2956 hbox[3] = hboxb[3];
2957
2958 #endif
2959
2960 conxwp->pclabel[i + 1] = conxwp->pclabel[i];
2961
2962 conxwp->cfxcombo[i + 1] = conxwp->cfxcombo[i];
2963 conxwp->ccombo[i + 1] = conxwp->ccombo[i];
2964
2965 conxwp->ikeys[i + 1] = conxwp->ikeys[i];
2966 conxwp->imodes[i + 1] = conxwp->imodes[i];
2967 conxwp->idx[i + 1] = conxwp->idx[i];
2968
2969 conxwp->dpc_func[i + 1] = conxwp->dpc_func[i];
2970 }
2971
2972 ctable_row_add_variable_widgets(conxwp, ours + 1, ours + 2, cidx);
2973
2974 conxwp->ikeys[ours + 1] = -1;
2975 conxwp->imodes[ours + 1] = conxwp->idx[i + 1] = 0;
2976
2977 conxwp->dispc[cidx]++;
2978
2979 lives_widget_set_sensitive(conxwp->del_button[ours + 1], TRUE);
2980 lives_widget_set_sensitive(conxwp->add_button[ours], FALSE);
2981
2982 lives_widget_show_all(conxwp->tablec);
2983 }
2984
2985
cdel_clicked(LiVESWidget * button,livespointer user_data)2986 static void cdel_clicked(LiVESWidget * button, livespointer user_data) {
2987 // remove the channel row at the del button
2988 lives_conx_w *conxwp = (lives_conx_w *)user_data;
2989
2990 int totparams, totchans;
2991 int ours = -1, cidx;
2992
2993 #if !LIVES_TABLE_IS_GRID
2994 LiVESWidget *hbox[3], *comhbox;
2995 LiVESWidget *hboxb[3];
2996 int cidx_next;
2997 #endif
2998
2999 register int i;
3000
3001 totparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3002 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3003
3004 for (i = 0; i < totchans; i++) {
3005 if (conxwp->del_button[i] == button) {
3006 ours = i;
3007 break;
3008 }
3009 }
3010
3011 cidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->ccombo[ours]), "cidx"));
3012
3013 lives_combo_set_active_index(LIVES_COMBO(conxwp->cfxcombo[ours]), 0);
3014
3015 if (conxwp->dispc[cidx] <= 1) {
3016 // last one, dont delete, just clear
3017 lives_widget_set_sensitive(conxwp->del_button[ours], FALSE);
3018 return;
3019 }
3020
3021 // force callback for cfxcombo before destroying it
3022 lives_widget_context_update();
3023
3024 conxwp->dispc[cidx]--;
3025
3026 totchans--;
3027
3028 #if !LIVES_TABLE_IS_GRID
3029 hbox[0] = lives_widget_get_parent(conxwp->pclabel[ours]);
3030 hbox[1] = lives_widget_get_parent(conxwp->cfxcombo[ours]);
3031
3032 comhbox = lives_widget_get_parent(conxwp->ccombo[ours]);
3033 hbox[2] = lives_widget_get_parent(comhbox);
3034
3035 lives_widget_destroy(conxwp->cfxcombo[ours]);
3036 lives_widget_destroy(conxwp->ccombo[ours]);
3037 lives_widget_destroy(comhbox);
3038 #endif
3039
3040 conxwp->trowsc--;
3041
3042 // subtract 1 from trowsc because of title row
3043 for (i = ours; i < conxwp->trowsc - 1; i++) {
3044 #if !LIVES_TABLE_IS_GRID
3045
3046 // reparent widgets from row i to row i+1
3047
3048 hboxb[0] = lives_widget_get_parent(conxwp->pclabel[i + 1]);
3049
3050 if (i == ours) {
3051 cidx_next = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->ccombo[i + 1]), "cidx"));
3052 if (cidx_next != cidx) {
3053 // secondary chan
3054 lives_widget_destroy(conxwp->pclabel[i]);
3055 lives_widget_reparent(conxwp->pclabel[i + 1], hbox[0]);
3056 conxwp->pclabel[i] = conxwp->pclabel[i + 1];
3057 } else {
3058 // primary chan
3059 lives_widget_destroy(conxwp->pclabel[i + 1]);
3060 }
3061 } else {
3062 lives_widget_reparent(conxwp->pclabel[i + 1], hbox[0]);
3063 conxwp->pclabel[i] = conxwp->pclabel[i + 1];
3064 }
3065
3066 hbox[0] = hboxb[0];
3067
3068 hboxb[1] = lives_widget_get_parent(conxwp->cfxcombo[i + 1]);
3069 lives_widget_reparent(conxwp->cfxcombo[i + 1], hbox[1]);
3070 hbox[1] = hboxb[1];
3071
3072 comhbox = lives_widget_get_parent(conxwp->ccombo[i + 1]);
3073 hboxb[2] = lives_widget_get_parent(comhbox);
3074 lives_widget_reparent(comhbox, hbox[2]);
3075 hbox[2] = hboxb[2];
3076
3077 lives_widget_set_sensitive(conxwp->del_button[i],
3078 lives_widget_get_sensitive(conxwp->del_button[i + 1]));
3079
3080 #else
3081 conxwp->add_button[i] = conxwp->add_button[i + 1];
3082 conxwp->del_button[i] = conxwp->del_button[i + 1];
3083 conxwp->clabel[i] = conxwp->clabel[i + 1];
3084 conxwp->pclabel[i] = conxwp->pclabel[i + 1];
3085
3086 if (i == ours) {
3087 widget_opts.mnemonic_label = FALSE;
3088 lives_label_set_text(LIVES_LABEL(conxwp->pclabel[i + 1]), lives_label_get_text(LIVES_LABEL(conxwp->pclabel[i])));
3089 widget_opts.mnemonic_label = TRUE;
3090 }
3091 #endif
3092 conxwp->cfxcombo[i] = conxwp->cfxcombo[i + 1];
3093 conxwp->ccombo[i] = conxwp->ccombo[i + 1];
3094
3095 conxwp->ikeys[i] = conxwp->ikeys[i + 1];
3096 conxwp->imodes[i] = conxwp->imodes[i + 1];
3097 conxwp->idx[i] = conxwp->idx[i + 1];
3098
3099 conxwp->dpc_func[i] = conxwp->dpc_func[i + 1];
3100 }
3101
3102 #if !LIVES_TABLE_IS_GRID
3103 lives_widget_destroy(conxwp->clabel[conxwp->trowsc - 1]);
3104 lives_widget_destroy(conxwp->add_button[conxwp->trowsc - 1]);
3105 lives_widget_destroy(conxwp->del_button[conxwp->trowsc - 1]);
3106
3107 // destroy (empty) last row parent widgets
3108 lives_widget_destroy(hbox[0]);
3109 lives_widget_destroy(hbox[1]);
3110 lives_widget_destroy(hbox[2]);
3111
3112 lives_table_resize(LIVES_TABLE(conxwp->tablec), conxwp->trowsc, 6);
3113 #else
3114 lives_grid_remove_row(LIVES_GRID(conxwp->tablec), ours + 1);
3115 #endif
3116
3117 if (ours == totchans) {
3118 if (lives_widget_get_sensitive(conxwp->del_button[ours - 1]))
3119 lives_widget_set_sensitive(conxwp->add_button[ours - 1], TRUE);
3120 }
3121
3122 conxwp->pclabel = (LiVESWidget **)lives_realloc(conxwp->pclabel, (totchans + totparams) * sizeof(LiVESWidget *));
3123
3124 conxwp->add_button = (LiVESWidget **)lives_realloc(conxwp->add_button, (totchans + totparams) * sizeof(LiVESWidget *));
3125 conxwp->del_button = (LiVESWidget **)lives_realloc(conxwp->del_button, (totchans + totparams) * sizeof(LiVESWidget *));
3126 conxwp->clabel = (LiVESWidget **)lives_realloc(conxwp->clabel, (totchans + totparams) * sizeof(LiVESWidget *));
3127
3128 conxwp->ikeys = (int *)lives_realloc(conxwp->ikeys, (totchans + totparams) * sizint);
3129 conxwp->imodes = (int *)lives_realloc(conxwp->imodes, (totchans + totparams) * sizint);
3130 conxwp->idx = (int *)lives_realloc(conxwp->idx, (totchans + totparams) * sizint);
3131
3132 conxwp->cfxcombo = (LiVESWidget **)lives_realloc(conxwp->cfxcombo, totchans * sizeof(LiVESWidget *));
3133 conxwp->ccombo = (LiVESWidget **)lives_realloc(conxwp->ccombo, totchans * sizeof(LiVESWidget *));
3134
3135 conxwp->dpc_func = (ulong *)lives_realloc(conxwp->dpc_func, totchans * sizeof(ulong));
3136 }
3137
3138
dfxc_changed(LiVESWidget * combo,livespointer user_data)3139 static void dfxc_changed(LiVESWidget * combo, livespointer user_data) {
3140 lives_conx_w *conxw = (lives_conx_w *)user_data;
3141
3142 LiVESTreeIter iter;
3143 LiVESTreeModel *model;
3144
3145 weed_plant_t **ichans;
3146 weed_plant_t *filter, *chan;
3147
3148 LiVESList *clist = NULL;
3149
3150 char *channame;
3151
3152 int fidx, cidx, key, mode;
3153 int nichans, nchans, ours = -1;
3154
3155 int i, j = 0;
3156
3157 if (!lives_combo_get_active_iter(LIVES_COMBO(combo), &iter)) return;
3158 model = lives_combo_get_model(LIVES_COMBO(combo));
3159
3160 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
3161 fidx = rte_keymode_get_filter_idx(key, mode);
3162
3163 nchans = cconx_get_numcons(conxw, FX_DATA_WILDCARD);
3164
3165 for (i = 0; i < nchans; i++) {
3166 if (conxw->cfxcombo[i] == combo) {
3167 ours = i;
3168 break;
3169 }
3170 }
3171
3172 cidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(combo), "cidx"));
3173
3174 if (fidx == -1) {
3175 lives_combo_set_active_string(LIVES_COMBO(conxw->ccombo[ours]), "");
3176 lives_signal_handler_block(conxw->ccombo[ours], conxw->dpc_func[ours]);
3177 lives_combo_populate(LIVES_COMBO(conxw->ccombo[ours]), NULL);
3178 lives_signal_handler_unblock(conxw->ccombo[ours], conxw->dpc_func[ours]);
3179 if (conxw->acbutton && cconx_get_nconns(conxw->cconx, 0) == 0 && cidx == 0)
3180 lives_widget_set_sensitive(conxw->acbutton, FALSE);
3181 lives_widget_set_sensitive(conxw->ccombo[ours], FALSE);
3182 return;
3183 }
3184
3185 // find the receiving filter/instance
3186 filter = get_weed_filter(fidx);
3187
3188 ichans = weed_get_plantptr_array(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, NULL);
3189 nichans = weed_leaf_num_elements(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES);
3190
3191 // populate all ccombo with channels
3192 for (i = 0; i < nichans; i++) {
3193 chan = ichans[j++];
3194
3195 if (!has_alpha_palette(chan, filter)) continue;
3196
3197 channame = get_chan_name(chan, i, TRUE);
3198 clist = lives_list_append(clist, channame);
3199 }
3200
3201 lives_free(ichans);
3202
3203 lives_combo_set_active_string(LIVES_COMBO(conxw->ccombo[ours]), "");
3204 lives_signal_handler_block(conxw->ccombo[ours], conxw->dpc_func[ours]);
3205 lives_combo_populate(LIVES_COMBO(conxw->ccombo[ours]), clist);
3206 lives_signal_handler_unblock(conxw->ccombo[ours], conxw->dpc_func[ours]);
3207
3208 if (cidx == 0) if (conxw->acbutton) lives_widget_set_sensitive(conxw->acbutton, TRUE);
3209 lives_widget_set_sensitive(conxw->ccombo[ours], TRUE);
3210
3211 lives_list_free_all(&clist);
3212 }
3213
3214
dfxp_changed(LiVESWidget * combo,livespointer user_data)3215 static void dfxp_changed(LiVESWidget * combo, livespointer user_data) {
3216 // filter was changed
3217
3218 lives_conx_w *conxwp = (lives_conx_w *)user_data;
3219
3220 LiVESTreeIter iter;
3221 LiVESTreeModel *model;
3222
3223 weed_plant_t **iparams = NULL;
3224 weed_plant_t *filter, *param;
3225
3226 LiVESList *plist = NULL;
3227
3228 char *paramname;
3229
3230 char *ptype, *range;
3231 char *array_type, *text;
3232
3233 int defelems, pflags, stype;
3234 int fidx, key, mode, pidx;
3235 int niparams = 0, nparams;
3236 int ours = -1, i, j = 0;
3237
3238 if (!lives_combo_get_active_iter(LIVES_COMBO(combo), &iter)) {
3239 return;
3240 }
3241
3242 nparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3243
3244 for (i = 0; i < nparams; i++) {
3245 if (conxwp->pfxcombo[i] == combo) {
3246 ours = i;
3247 break;
3248 }
3249 }
3250
3251 model = lives_combo_get_model(LIVES_COMBO(combo));
3252
3253 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
3254
3255 if (key == FX_DATA_KEY_OMC_MACRO) {
3256 // match with OMC macro
3257 int nmatchparams = 0;
3258 weed_plant_t *ofilter;
3259 LiVESWidget *fxcombo = conxwp->pcombo[ours];
3260
3261 // get type for out_param
3262 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(fxcombo), "pidx"));
3263 ofilter = conxwp->filter;
3264
3265 if (pidx >= 0) {
3266 weed_plant_t **oparams = weed_get_plantptr_array(ofilter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, NULL);
3267 weed_plant_t *oparam = oparams[pidx];
3268 lives_free(oparams);
3269 stype = weed_leaf_seed_type(oparam, WEED_LEAF_DEFAULT);
3270 } else {
3271 // invent an "ACTIVATED" param
3272 stype = WEED_SEED_BOOLEAN;
3273 }
3274
3275 // check omc_macros[mode]; show all params with matching type
3276
3277 // TODO...
3278
3279 // if nothing matched, then
3280
3281 // if out is boolean, we can link to ACTIVATE, we can choose FALSE -> TRUE (TODO: or TRUE -> FALSE)
3282 //
3283 if (nmatchparams == 0 && stype == WEED_SEED_BOOLEAN) {
3284 text = lives_strdup_printf(_("False to True -> TRIGGER (%s)"), weed_seed_type_to_text(WEED_SEED_BOOLEAN));
3285 plist = lives_list_append(plist, text);
3286 }
3287 } else {
3288 fidx = rte_keymode_get_filter_idx(key, mode);
3289
3290 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(combo), "pidx"));
3291
3292 if (fidx == -1) {
3293 // connection deleted
3294 LiVESWidget *acheck = conxwp->acheck[ours];
3295 if (acheck) {
3296 lives_signal_handler_block(acheck, conxwp->acheck_func[ours]);
3297 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(acheck), FALSE);
3298 lives_widget_set_sensitive(acheck, FALSE);
3299 lives_signal_handler_unblock(acheck, conxwp->acheck_func[ours]);
3300 }
3301
3302 lives_combo_set_active_string(LIVES_COMBO(conxwp->pcombo[ours]), "");
3303 lives_signal_handler_block(conxwp->pcombo[ours], conxwp->dpp_func[ours]);
3304 lives_combo_populate(LIVES_COMBO(conxwp->pcombo[ours]), NULL);
3305 lives_signal_handler_unblock(conxwp->pcombo[ours], conxwp->dpp_func[ours]);
3306
3307 if (conxwp->apbutton && pconx_get_nconns(conxwp->pconx, 0) == 0 && pidx == 0)
3308 lives_widget_set_sensitive(conxwp->apbutton, FALSE);
3309
3310 lives_widget_set_sensitive(conxwp->pcombo[ours], FALSE);
3311
3312 return;
3313 }
3314
3315 // find the receiving filter/instance
3316 filter = get_weed_filter(fidx);
3317
3318 if (weed_plant_has_leaf(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES)) {
3319 iparams = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL);
3320 niparams = weed_leaf_num_elements(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES);
3321 #ifdef COMBO_LIST_LIMIT
3322 if (niparams + EXTRA_PARAMS_IN > COMBO_LIST_LIMIT) {
3323 niparams = COMBO_LIST_LIMIT - EXTRA_PARAMS_IN;
3324 }
3325 #endif
3326 }
3327
3328 // populate pcombo with all in params
3329 for (i = -EXTRA_PARAMS_IN; i < niparams; i++) {
3330 if (i == FX_DATA_PARAM_ACTIVE) {
3331 ptype = weed_seed_type_to_text(WEED_SEED_BOOLEAN);
3332 text = lives_strdup_printf(_("ACTIVATE (%s)"), ptype);
3333 } else {
3334 param = iparams[j++];
3335
3336 if (weed_plant_has_leaf(param, WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
3337
3338 if (weed_plant_has_leaf(param, WEED_LEAF_GROUP) && weed_get_int_value(param, WEED_LEAF_GROUP, NULL) != 0) continue;
3339
3340 paramname = get_param_name(param, j - 1, TRUE);
3341
3342 ptype = weed_seed_type_to_text((stype = weed_leaf_seed_type(param, WEED_LEAF_DEFAULT)));
3343
3344 pflags = weed_get_int_value(param, WEED_LEAF_FLAGS, NULL);
3345
3346 if (pflags & WEED_PARAMETER_VARIABLE_SIZE) array_type = lives_strdup("[]");
3347 else if ((defelems = weed_leaf_num_elements(param, WEED_LEAF_DEFAULT)) > 1)
3348 array_type = lives_strdup_printf("[%d]", defelems);
3349 else array_type = lives_strdup("");
3350
3351 if (weed_plant_has_leaf(param, WEED_LEAF_MAX) && weed_plant_has_leaf(param, WEED_LEAF_MIN)) {
3352 if (stype == WEED_SEED_INT) {
3353 range = lives_strdup_printf("Range: %d to %d",
3354 weed_get_int_value(param, WEED_LEAF_MIN, NULL), weed_get_int_value(param,
3355 WEED_LEAF_MAX, NULL));
3356 } else if (stype == WEED_SEED_DOUBLE) {
3357 range = lives_strdup_printf("Range: %f to %f",
3358 weed_get_double_value(param, WEED_LEAF_MIN, NULL), weed_get_double_value(param,
3359 WEED_LEAF_MAX, NULL));
3360 } else range = lives_strdup("");
3361 } else range = lives_strdup("");
3362
3363 text = lives_strdup_printf("%s\n (%s%s) %s", paramname, ptype, array_type, range);
3364 lives_free(paramname);
3365 lives_free(array_type);
3366 lives_free(range);
3367 }
3368 lives_free(ptype);
3369 plist = lives_list_append(plist, text);
3370 }
3371
3372 if (iparams) lives_free(iparams);
3373 }
3374
3375 lives_combo_set_active_string(LIVES_COMBO(conxwp->pcombo[ours]), "");
3376 lives_signal_handler_block(conxwp->pcombo[ours], conxwp->dpp_func[ours]);
3377 lives_combo_populate(LIVES_COMBO(conxwp->pcombo[ours]), plist);
3378 lives_signal_handler_unblock(conxwp->pcombo[ours], conxwp->dpp_func[ours]);
3379
3380 //lives_combo_set_active_string(LIVES_COMBO(conxwp->pcombo[ours]), "");
3381
3382 if (!pidx) if (conxwp->apbutton) lives_widget_set_sensitive(conxwp->apbutton, TRUE);
3383
3384 lives_widget_set_sensitive(conxwp->pcombo[ours], TRUE);
3385
3386 lives_list_free_all(&plist);
3387 }
3388
3389
pconx_check_connection(weed_plant_t * ofilter,int opnum,int ikey,int imode,int ipnum,boolean setup,weed_plant_t ** iparam_ret,int * idx_ret,int * okey,int * omode,int * oopnum)3390 int pconx_check_connection(weed_plant_t *ofilter, int opnum, int ikey, int imode, int ipnum, boolean setup,
3391 weed_plant_t **iparam_ret, int *idx_ret, int *okey, int *omode, int *oopnum) {
3392 weed_plant_t **oparams = NULL, **iparams;
3393 weed_plant_t *oparam, *iparam = NULL;
3394
3395 int niparams, idx, i, j = 0;
3396
3397 // TODO :: key FX_DATA_KEY_OMC_MACRO == OMC Macro
3398
3399 if (opnum >= 0) {
3400 oparams = weed_get_plantptr_array(ofilter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, NULL);
3401 oparam = oparams[opnum];
3402 lives_free(oparams);
3403 } else {
3404 // invent an "ACTIVATED" param
3405 pthread_mutex_lock(&mainw->fxd_active_mutex);
3406 if (active_dummy && WEED_PLANT_IS_PARAMETER(active_dummy)) {
3407 weed_plant_free(active_dummy);
3408 active_dummy = NULL;
3409 }
3410 if (!active_dummy) {
3411 active_dummy = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
3412 weed_set_boolean_value(active_dummy, WEED_LEAF_DEFAULT, WEED_FALSE);
3413 }
3414 oparam = active_dummy;
3415 pthread_mutex_unlock(&mainw->fxd_active_mutex);
3416 }
3417
3418 if (ipnum == FX_DATA_PARAM_ACTIVE) {
3419 // invent an "ACTIVATE" param
3420 pthread_mutex_lock(&mainw->fxd_active_mutex);
3421 if (active_dummy && WEED_PLANT_IS_PARAMETER(active_dummy)) {
3422 weed_plant_free(active_dummy);
3423 active_dummy = NULL;
3424 }
3425 if (!active_dummy) {
3426 active_dummy = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
3427 weed_set_boolean_value(active_dummy, WEED_LEAF_DEFAULT, WEED_FALSE);
3428 }
3429 idx = ipnum;
3430 iparam = active_dummy;
3431 pthread_mutex_unlock(&mainw->fxd_active_mutex);
3432 } else {
3433 // find the receiving filter/instance
3434 int fidx = rte_keymode_get_filter_idx(ikey, imode);
3435 weed_plant_t *filter = get_weed_filter(fidx);
3436
3437 iparams = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL);
3438 niparams = weed_leaf_num_elements(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES);
3439
3440 for (i = 0; i < niparams; i++) {
3441 iparam = iparams[i];
3442 if (weed_plant_has_leaf(iparam, WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
3443 if (weed_plant_has_leaf(iparam, WEED_LEAF_GROUP) && weed_get_int_value(iparam, WEED_LEAF_GROUP, NULL) != 0) continue;
3444 if (j == ipnum) break;
3445 j++;
3446 }
3447 idx = i;
3448 lives_free(iparams);
3449 }
3450
3451 if (iparam_ret) *iparam_ret = iparam;
3452 if (idx_ret) *idx_ret = idx;
3453
3454 if (!setup) {
3455 if (pconx_get_out_param(TRUE, ikey, imode, ipnum, okey, omode, oopnum, NULL)) {
3456 // dest param already has a connection
3457 return -1;
3458 }
3459 }
3460
3461 if (!params_compatible(oparam, iparam)) {
3462 return -2;
3463 }
3464
3465 return 0;
3466 }
3467
3468
dpp_changed(LiVESWidget * combo,livespointer user_data)3469 static void dpp_changed(LiVESWidget * combo, livespointer user_data) {
3470 // receiver param was set
3471
3472 // 1) check if compatible
3473
3474 // 2) maybe enable autoscale
3475
3476 // 3) set text to just param name
3477 weed_plant_t *iparam;
3478
3479 lives_conx_w *conxwp = (lives_conx_w *)user_data;
3480
3481 LiVESWidget *acheck = NULL;
3482 LiVESWidget *fxcombo;
3483
3484 LiVESTreeModel *model;
3485
3486 LiVESTreeIter iter;
3487
3488 char *paramname;
3489
3490 boolean hasone = FALSE;
3491 boolean setup = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(combo), "setup"));
3492
3493 int nparams, nchans;
3494 int okey, omode, opnum, ikey;
3495
3496 int pidx, key, mode, ours = -1, ret;
3497 int idx = lives_combo_get_active_index(LIVES_COMBO(combo));
3498 int i, j;
3499
3500 nparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3501 nchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3502
3503 for (i = 0; i < nparams; i++) {
3504 if (conxwp->pcombo[i] == combo) {
3505 ours = i;
3506 break;
3507 }
3508 }
3509
3510 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(combo), "pidx"));
3511
3512 if (idx == -1) {
3513 // connection deleted
3514 if (setup) return;
3515 for (i = 0; i < nchans; i++) {
3516 if (lives_combo_get_active_index(LIVES_COMBO(conxwp->ccombo[i])) > -1) {
3517 hasone = TRUE;
3518 break;
3519 }
3520 }
3521 if (!hasone) {
3522 for (i = 0; i < nparams; i++) {
3523 if (LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[i]), "idx")) > -1) {
3524 hasone = TRUE;
3525 break;
3526 }
3527 }
3528 }
3529
3530 if (!hasone) lives_widget_set_sensitive(conxwp->disconbutton, FALSE);
3531
3532 ikey = conxwp->ikeys[nchans + ours];
3533
3534 if (ikey >= 0) {
3535 //if (ikey > 0) ikey--;
3536 pconx_delete(conxwp->okey, conxwp->omode, pidx, ikey, conxwp->imodes[nchans + ours],
3537 conxwp->idx[nchans + ours]);
3538
3539 conxwp->pconx = pconx_find(conxwp->okey, conxwp->omode);
3540 }
3541 conxwp->ikeys[nchans + ours] = -1;
3542 conxwp->imodes[nchans + ours] = 0;
3543 conxwp->idx[nchans + ours] = 0;
3544
3545 lives_widget_set_sensitive(conxwp->del_button[nchans + ours], FALSE);
3546 lives_widget_set_sensitive(conxwp->add_button[nchans + ours], FALSE);
3547
3548 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(combo), "idx", LIVES_INT_TO_POINTER(idx));
3549
3550 return;
3551 }
3552
3553 fxcombo = conxwp->pfxcombo[ours];
3554
3555 if (!lives_combo_get_active_iter(LIVES_COMBO(fxcombo), &iter)) return;
3556
3557 model = lives_combo_get_model(LIVES_COMBO(fxcombo));
3558
3559 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
3560
3561 idx -= EXTRA_PARAMS_IN;
3562
3563 //// check if connection may be made
3564 ret = pconx_check_connection(conxwp->filter, pidx, key, mode, idx, setup, &iparam, &j, &okey, &omode, &opnum);
3565
3566 if (ret == -2) {
3567 do_param_incompatible_error(conxwp);
3568 lives_combo_set_active_string(LIVES_COMBO(combo), "");
3569 return;
3570 }
3571 if (ret == -1) {
3572 if (!do_param_connected_query(conxwp, okey, omode, opnum, conxwp->okey == okey)) {
3573 lives_combo_set_active_string(LIVES_COMBO(combo), "");
3574 return;
3575 } else {
3576 pconx_delete(okey, omode, opnum, key, mode, idx);
3577 }
3578 }
3579
3580 ///////////////////////////////////////////////////////////////////////////
3581
3582 idx += EXTRA_PARAMS_IN;
3583
3584 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(combo), "idx", LIVES_INT_TO_POINTER(idx));
3585
3586 acheck = conxwp->acheck[ours];
3587
3588 if (acheck) {
3589 boolean hasrange = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(acheck), "available"));
3590
3591 lives_signal_handler_block(acheck, conxwp->acheck_func[ours]);
3592 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(acheck), FALSE);
3593 lives_signal_handler_unblock(acheck, conxwp->acheck_func[ours]);
3594
3595 if (hasrange) {
3596 lives_widget_set_sensitive(acheck, TRUE);
3597 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(conxwp->allcheckc))) {
3598 lives_signal_handler_block(acheck, conxwp->acheck_func[ours]);
3599 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(acheck), TRUE);
3600 lives_signal_handler_unblock(acheck, conxwp->acheck_func[ours]);
3601 }
3602 }
3603 }
3604
3605 if (iparam == active_dummy) {
3606 if (key == FX_DATA_KEY_OMC_MACRO) paramname = (_("TRIGGER"));
3607 else paramname = (_("ACTIVATE"));
3608 } else paramname = get_param_name(iparam, idx - EXTRA_PARAMS_IN, TRUE);
3609
3610 lives_signal_handler_block(combo, conxwp->dpp_func[ours]);
3611 lives_combo_set_active_string(LIVES_COMBO(combo), paramname);
3612 lives_signal_handler_unblock(combo, conxwp->dpp_func[ours]);
3613
3614 lives_free(paramname);
3615
3616 lives_widget_set_sensitive(conxwp->del_button[nchans + ours], TRUE);
3617
3618 if (setup) return;
3619
3620 lives_widget_set_sensitive(conxwp->add_button[nchans + ours], TRUE);
3621
3622 conxwp->pconx = pconx_add_connection_private(conxwp->okey, conxwp->omode, pidx, key - 1, mode, j,
3623 acheck ? lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(acheck)) : FALSE);
3624
3625 conxwp->ikeys[nchans + ours] = key;
3626 conxwp->imodes[nchans + ours] = mode;
3627 conxwp->idx[nchans + ours] = j;
3628
3629 lives_widget_set_sensitive(conxwp->disconbutton, TRUE);
3630 }
3631
3632
cconx_check_connection(int ikey,int imode,int icnum,boolean setup,weed_plant_t ** ichan_ret,int * idx_ret,int * okey,int * omode,int * ocnum)3633 int cconx_check_connection(int ikey, int imode, int icnum, boolean setup, weed_plant_t **ichan_ret, int *idx_ret,
3634 int *okey, int *omode, int *ocnum) {
3635 weed_plant_t **ichans;
3636 weed_plant_t *filter, *ichan = NULL;
3637
3638 int fidx, idx, nichans, i, j = 0;
3639
3640 fidx = rte_keymode_get_filter_idx(ikey + 1, imode);
3641
3642 // find the receiving filter/instance
3643 filter = get_weed_filter(fidx);
3644
3645 ichans = weed_get_plantptr_array(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, NULL);
3646 nichans = weed_leaf_num_elements(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES);
3647
3648 // find actual in channel number from list of alpha channels
3649 for (i = 0; i < nichans; i++) {
3650 ichan = ichans[i];
3651 if (!has_alpha_palette(ichan, filter)) continue;
3652 if (j == icnum) break;
3653 j++;
3654 }
3655
3656 lives_free(ichans);
3657
3658 idx = i;
3659
3660 if (ichan_ret) *ichan_ret = ichan;
3661 if (idx_ret) *idx_ret = idx;
3662
3663 if (!setup) {
3664 if (cconx_get_out_alpha(TRUE, ikey, imode, i, okey, omode, ocnum)) {
3665 // dest chan already has a connection
3666 return -1;
3667 }
3668 }
3669 return 0;
3670 }
3671
3672
dpc_changed(LiVESWidget * combo,livespointer user_data)3673 static void dpc_changed(LiVESWidget * combo, livespointer user_data) {
3674 lives_conx_w *conxwp = (lives_conx_w *)user_data;
3675 weed_plant_t *ichan;
3676 LiVESTreeModel *model;
3677 LiVESTreeIter iter;
3678 LiVESWidget *fxcombo;
3679
3680 char *channame;
3681
3682 boolean hasone = FALSE;
3683 boolean setup = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(combo), "setup"));
3684
3685 int nchans, nparams;
3686 int key, mode, cidx, ours = -1, ret, j;
3687 int okey, omode, ocnum;
3688 int idx = lives_combo_get_active_index(LIVES_COMBO(combo));
3689 int i;
3690
3691 nchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3692 nparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3693
3694 for (i = 0; i < nchans; i++) {
3695 if (conxwp->ccombo[i] == combo) {
3696 ours = i;
3697 break;
3698 }
3699 }
3700
3701 cidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(combo), "cidx"));
3702
3703 if (idx == -1) {
3704 for (i = 0; i < nchans; i++) {
3705 if (lives_combo_get_active_index(LIVES_COMBO(conxwp->ccombo[i])) > -1) {
3706 hasone = TRUE;
3707 break;
3708 }
3709 }
3710 if (!hasone) for (i = 0; i < nparams; i++) {
3711 if (LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[i]), "idx")) > -1) {
3712 hasone = TRUE;
3713 break;
3714 }
3715 }
3716
3717 if (!hasone) lives_widget_set_sensitive(conxwp->disconbutton, FALSE);
3718
3719 if (conxwp->ikeys[ours] >= 0) cconx_delete(conxwp->okey, conxwp->omode, cidx,
3720 conxwp->ikeys[ours], conxwp->imodes[ours], conxwp->idx[ours]);
3721 conxwp->cconx = cconx_find(conxwp->okey, conxwp->omode);
3722
3723 conxwp->ikeys[ours] = -1;
3724 conxwp->imodes[ours] = 0;
3725 conxwp->idx[ours] = 0;
3726
3727 lives_widget_set_sensitive(conxwp->del_button[ours], FALSE);
3728
3729 return;
3730 }
3731
3732 fxcombo = conxwp->cfxcombo[ours];
3733
3734 if (!lives_combo_get_active_iter(LIVES_COMBO(fxcombo), &iter)) return;
3735
3736 model = lives_combo_get_model(LIVES_COMBO(fxcombo));
3737 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
3738
3739 // check if connection can be made
3740 ret = cconx_check_connection(key, mode, idx, setup, &ichan, &j, &okey, &omode, &ocnum);
3741
3742 if (ret == -1) {
3743 // dest chan already has a connection
3744 if (!do_chan_connected_query(conxwp, okey, omode, ocnum, conxwp->okey == okey)) {
3745 lives_combo_set_active_string(LIVES_COMBO(combo), "");
3746 return;
3747 } else {
3748 cconx_delete(okey, omode, ocnum, key, mode, idx);
3749 }
3750 }
3751
3752 lives_signal_handler_block(combo, conxwp->dpc_func[ours]);
3753 channame = get_chan_name(ichan, idx, TRUE);
3754 lives_combo_set_active_string(LIVES_COMBO(combo), channame);
3755 lives_signal_handler_unblock(combo, conxwp->dpc_func[ours]);
3756
3757 lives_free(channame);
3758
3759 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(combo), "idx", LIVES_INT_TO_POINTER(idx));
3760
3761 lives_widget_set_sensitive(conxwp->del_button[ours], TRUE);
3762
3763 if (setup) return;
3764
3765 conxwp->cconx = cconx_add_connection_private(conxwp->okey, conxwp->omode, cidx, key - 1, mode, j);
3766
3767 conxwp->ikeys[ours] = key;
3768 conxwp->imodes[ours] = mode;
3769 conxwp->idx[ours] = j;
3770
3771 lives_widget_set_sensitive(conxwp->disconbutton, TRUE);
3772 }
3773
3774
on_allcheck_toggled(LiVESToggleButton * button,livespointer user_data)3775 static void on_allcheck_toggled(LiVESToggleButton * button, livespointer user_data) {
3776 lives_conx_w *conxwp = (lives_conx_w *)user_data;
3777 boolean on = lives_toggle_button_get_active(button);
3778 int nparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3779
3780 for (int i = EXTRA_PARAMS_OUT; i < nparams; i++) {
3781 if (conxwp->acheck[i]) {
3782 if (lives_widget_is_sensitive(conxwp->acheck[i]))
3783 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(conxwp->acheck[i]), on);
3784 }
3785 }
3786 }
3787
3788
on_acheck_toggled(LiVESToggleButton * acheck,livespointer user_data)3789 static void on_acheck_toggled(LiVESToggleButton * acheck, livespointer user_data) {
3790 lives_conx_w *conxwp = (lives_conx_w *)user_data;
3791 weed_plant_t **iparams;
3792 weed_plant_t *param, *filter;
3793 LiVESTreeModel *model;
3794 LiVESTreeIter iter;
3795 LiVESWidget *fxcombo;
3796
3797 boolean on = lives_toggle_button_get_active(acheck);
3798 int ours = -1, fidx, key, mode, niparams, nparams, nchans, nx = 0;
3799 int idx, pidx, i, j = 0;
3800
3801 if (EXTRA_PARAMS_OUT > 0) nx = pconx_get_numcons(conxwp, -EXTRA_PARAMS_OUT);
3802
3803 nparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3804 nchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3805
3806 for (i = nx; i < nparams; i++) {
3807 if (conxwp->acheck[i] == (LiVESWidget *)acheck) {
3808 ours = i;
3809 break;
3810 }
3811 }
3812
3813 idx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[ours]), "idx"));
3814
3815 fxcombo = conxwp->pfxcombo[ours];
3816
3817 model = lives_combo_get_model(LIVES_COMBO(fxcombo));
3818 lives_combo_get_active_iter(LIVES_COMBO(fxcombo), &iter);
3819
3820 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
3821
3822 if (key < 0) return;
3823
3824 if (key == FX_DATA_KEY_OMC_MACRO) {
3825 // match with OMC macro
3826
3827
3828 return;
3829 } else {
3830 if (idx >= EXTRA_PARAMS_IN) {
3831 fidx = rte_keymode_get_filter_idx(key, mode);
3832
3833 // find the receiving filter/instance
3834 filter = get_weed_filter(fidx);
3835
3836 iparams = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL);
3837 niparams = weed_leaf_num_elements(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES);
3838
3839 #ifdef COMBO_LIST_LIMIT
3840 if (niparams + EXTRA_PARAMS_IN > COMBO_LIST_LIMIT) {
3841 niparams = COMBO_LIST_LIMIT - EXTRA_PARAMS_IN;
3842 }
3843 #endif
3844
3845 for (i = 0; i < niparams; i++) {
3846 param = iparams[j];
3847 if (weed_plant_has_leaf(param, WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
3848 if (j == idx) break;
3849 j++;
3850 }
3851
3852 j = i;
3853
3854 lives_free(iparams);
3855 } else j = idx - EXTRA_PARAMS_IN;
3856 }
3857
3858 pidx = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(acheck), "pidx"));
3859 conxwp->pconx = pconx_add_connection_private(conxwp->okey, conxwp->omode, pidx, key - 1, mode, j, on);
3860
3861 conxwp->ikeys[nchans + ours] = key;
3862 conxwp->imodes[nchans + ours] = mode;
3863 conxwp->idx[nchans + ours] = j;
3864 }
3865
3866
inparam_fx_model(boolean is_chans,int key)3867 static LiVESTreeModel *inparam_fx_model(boolean is_chans, int key) {
3868 LiVESTreeStore *tstore;
3869 LiVESTreeIter iter1, iter2;
3870 weed_plant_t *filter;
3871 char *fxname, *keystr, *text;
3872 boolean key_added;
3873 int idx, nmodes = rte_getmodespk(), i, j;
3874
3875 tstore = lives_tree_store_new(EFD_NUM_COLUMNS, LIVES_COL_TYPE_STRING, LIVES_COL_TYPE_STRING, LIVES_COL_TYPE_INT,
3876 LIVES_COL_TYPE_INT);
3877
3878 lives_tree_store_append(tstore, &iter1, NULL); /* Acquire an iterator */
3879 lives_tree_store_set(tstore, &iter1,
3880 KEY_COLUMN, mainw->string_constants[LIVES_STRING_CONSTANT_NONE],
3881 NAME_COLUMN, mainw->string_constants[LIVES_STRING_CONSTANT_NONE],
3882 KEYVAL_COLUMN, 0, MODEVAL_COLUMN, 0, -1);
3883
3884 if (!is_chans) {
3885 // add OMC Macros
3886 keystr = (_("OMC Macros"));
3887 lives_tree_store_append(tstore, &iter1, NULL); /* Acquire an iterator */
3888 lives_tree_store_set(tstore, &iter1, KEY_COLUMN, keystr, NAME_COLUMN, keystr, KEYVAL_COLUMN, 0, MODEVAL_COLUMN, 0, -1);
3889
3890 for (i = 0; get_omc_macro(i); i++) {
3891 if (i != OSC_NOTIFY) continue; // TODO
3892 text = get_omc_macro(i)->macro_text;
3893 lives_tree_store_append(tstore, &iter2, &iter1);
3894 lives_tree_store_set(tstore, &iter2, KEY_COLUMN, text, NAME_COLUMN, text,
3895 KEYVAL_COLUMN, FX_DATA_KEY_OMC_MACRO, MODEVAL_COLUMN, i, -1);
3896 }
3897
3898 lives_free(keystr);
3899 }
3900
3901 // go through all keys
3902 for (i = 1; i <= FX_KEYS_MAX_VIRTUAL; i++) {
3903 if (i == key + 1) continue;
3904
3905 key_added = FALSE;
3906 keystr = lives_strdup_printf(_("Key slot %d"), i);
3907
3908 for (j = 0; j < nmodes; j++) {
3909 if ((idx = rte_keymode_get_filter_idx(i, j)) == -1) continue;
3910
3911 filter = get_weed_filter(idx);
3912
3913 if (is_chans)
3914 if (num_alpha_channels(filter, FALSE) == 0) continue;
3915
3916 fxname = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
3917 text = lives_strdup_printf("(%d,%d) %s", i, j + 1, fxname);
3918
3919 if (!key_added) {
3920 // add key
3921 lives_tree_store_append(tstore, &iter1, NULL); /* Acquire an iterator */
3922 lives_tree_store_set(tstore, &iter1, KEY_COLUMN, keystr, NAME_COLUMN, keystr, KEYVAL_COLUMN, 0, MODEVAL_COLUMN, 0, -1);
3923 key_added = TRUE;
3924 }
3925 lives_tree_store_append(tstore, &iter2, &iter1);
3926 lives_tree_store_set(tstore, &iter2, KEY_COLUMN, text, NAME_COLUMN, text, KEYVAL_COLUMN, i, MODEVAL_COLUMN, j, -1);
3927
3928 lives_free(fxname);
3929 lives_free(text);
3930 }
3931
3932 lives_free(keystr);
3933 }
3934
3935 return (LiVESTreeModel *)tstore;
3936 }
3937
3938
ptable_row_add_variable_widgets(lives_conx_w * conxwp,int idx,int row,int pidx)3939 static void ptable_row_add_variable_widgets(lives_conx_w * conxwp, int idx, int row, int pidx) {
3940 weed_plant_t **oparams, *param;
3941
3942 LiVESWidget *hbox, *hbox2;
3943 LiVESWidget *fx_entry;
3944
3945 boolean hasrange = FALSE;
3946
3947 int stype, totchans;
3948
3949 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
3950
3951 hbox = lives_hbox_new(FALSE, 0);
3952
3953 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 0, 1, row, row + 1,
3954 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
3955 (LiVESAttachOptions)(0), 0, 0);
3956
3957 conxwp->pclabel[idx + totchans] = lives_standard_label_new(NULL);
3958 lives_box_pack_start(LIVES_BOX(hbox), conxwp->pclabel[idx + totchans], FALSE, FALSE, widget_opts.packing_width);
3959
3960 hbox = lives_hbox_new(FALSE, 0);
3961
3962 conxwp->pfxcombo[idx] = lives_standard_combo_new_with_model(pmodel, LIVES_BOX(hbox));
3963
3964 lives_combo_set_entry_text_column(LIVES_COMBO(conxwp->pfxcombo[idx]), NAME_COLUMN);
3965
3966 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 2, 3, row, row + 1,
3967 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
3968 (LiVESAttachOptions)(0), 0, 0);
3969
3970 fx_entry = lives_combo_get_entry(LIVES_COMBO(conxwp->pfxcombo[idx]));
3971 lives_entry_set_width_chars(LIVES_ENTRY(fx_entry), SHORTER_ENTRY_WIDTH);
3972 lives_entry_set_text(LIVES_ENTRY(fx_entry), mainw->string_constants[LIVES_STRING_CONSTANT_NONE]);
3973 lives_entry_set_editable(LIVES_ENTRY(fx_entry), FALSE);
3974
3975 hbox = lives_hbox_new(FALSE, 0);
3976
3977 hbox2 = lives_hbox_new(FALSE, 0);
3978 lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, FALSE, 0);
3979
3980 conxwp->pcombo[idx] = lives_standard_combo_new("", NULL, LIVES_BOX(hbox2), NULL);
3981 lives_entry_set_width_chars(LIVES_ENTRY(lives_combo_get_entry(LIVES_COMBO(conxwp->pcombo[idx]))), SHORTER_ENTRY_WIDTH);
3982 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[idx]), "idx", LIVES_INT_TO_POINTER(-1));
3983 lives_widget_set_sensitive(conxwp->pcombo[idx], FALSE);
3984
3985 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 3, 4, row, row + 1,
3986 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
3987 (LiVESAttachOptions)(0), 0, 0);
3988
3989 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->pfxcombo[idx]), LIVES_WIDGET_CHANGED_SIGNAL,
3990 LIVES_GUI_CALLBACK(dfxp_changed), (livespointer)conxwp);
3991
3992 conxwp->dpp_func[idx] = lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->pcombo[idx]), LIVES_WIDGET_CHANGED_SIGNAL,
3993 LIVES_GUI_CALLBACK(dpp_changed), (livespointer)conxwp);
3994
3995 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(conxwp->pcombo[idx]), "pidx", LIVES_INT_TO_POINTER(pidx));
3996
3997 if (pidx < 0) {
3998 conxwp->acheck[idx] = NULL;
3999 } else {
4000 if (weed_plant_has_leaf(conxwp->filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES)) {
4001 oparams = weed_get_plantptr_array(conxwp->filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, NULL);
4002
4003 param = oparams[pidx];
4004 stype = weed_leaf_seed_type(param, WEED_LEAF_DEFAULT);
4005
4006 if (weed_plant_has_leaf(param, WEED_LEAF_MAX) && weed_plant_has_leaf(param, WEED_LEAF_MIN) && (stype == WEED_SEED_INT ||
4007 stype == WEED_SEED_DOUBLE))
4008 hasrange = TRUE;
4009
4010 lives_free(oparams);
4011 }
4012
4013 hbox = lives_hbox_new(FALSE, 0);
4014
4015 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 4, 5, row, row + 1,
4016 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
4017 (LiVESAttachOptions)(0), 0, 0);
4018
4019 hbox2 = lives_hbox_new(FALSE, 0);
4020 lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, FALSE, 0);
4021
4022 conxwp->acheck[idx] = lives_standard_check_button_new(_("Autoscale"), FALSE, LIVES_BOX(hbox2), NULL);
4023
4024 lives_widget_set_sensitive(conxwp->acheck[idx], FALSE);
4025 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(conxwp->acheck[idx]), "available", LIVES_INT_TO_POINTER(hasrange));
4026
4027 conxwp->acheck_func[idx] = lives_signal_sync_connect_after(LIVES_GUI_OBJECT(conxwp->acheck[idx]), LIVES_WIDGET_TOGGLED_SIGNAL,
4028 LIVES_GUI_CALLBACK(on_acheck_toggled), (livespointer)conxwp);
4029
4030 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(conxwp->acheck[idx]), "pidx", LIVES_INT_TO_POINTER(pidx));
4031 }
4032 }
4033
4034
ctable_row_add_variable_widgets(lives_conx_w * conxwp,int idx,int row,int cidx)4035 static void ctable_row_add_variable_widgets(lives_conx_w * conxwp, int idx, int row, int cidx) {
4036 LiVESWidget *hbox, *hbox2;
4037 LiVESWidget *fx_entry;
4038
4039 hbox = lives_hbox_new(FALSE, 0);
4040
4041 lives_table_attach(LIVES_TABLE(conxwp->tablec), hbox, 0, 1, row, row + 1,
4042 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
4043 (LiVESAttachOptions)(0), 0, 0);
4044
4045 conxwp->pclabel[idx] = lives_standard_label_new(NULL);
4046 lives_box_pack_start(LIVES_BOX(hbox), conxwp->pclabel[idx], FALSE, FALSE, widget_opts.packing_width);
4047
4048 hbox = lives_hbox_new(FALSE, 0);
4049
4050 conxwp->cfxcombo[idx] = lives_standard_combo_new_with_model(cmodel, LIVES_BOX(hbox));
4051
4052 lives_combo_set_entry_text_column(LIVES_COMBO(conxwp->cfxcombo[idx]), NAME_COLUMN);
4053
4054 lives_table_attach(LIVES_TABLE(conxwp->tablec), hbox, 2, 3, row, row + 1,
4055 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
4056 (LiVESAttachOptions)(0), 0, 0);
4057
4058 fx_entry = lives_combo_get_entry(LIVES_COMBO(conxwp->cfxcombo[idx]));
4059 lives_entry_set_width_chars(LIVES_ENTRY(fx_entry), SHORTER_ENTRY_WIDTH);
4060 lives_entry_set_text(LIVES_ENTRY(fx_entry), mainw->string_constants[LIVES_STRING_CONSTANT_NONE]);
4061 lives_entry_set_editable(LIVES_ENTRY(fx_entry), FALSE);
4062
4063 hbox = lives_hbox_new(FALSE, 0);
4064
4065 hbox2 = lives_hbox_new(FALSE, 0);
4066 lives_box_pack_start(LIVES_BOX(hbox), hbox2, FALSE, FALSE, 0);
4067
4068 conxwp->ccombo[idx] = lives_standard_combo_new("", NULL, LIVES_BOX(hbox2), NULL);
4069 lives_entry_set_width_chars(LIVES_ENTRY(lives_combo_get_entry(LIVES_COMBO(conxwp->ccombo[idx]))), SHORTER_ENTRY_WIDTH);
4070 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(conxwp->ccombo[idx]), "idx", LIVES_INT_TO_POINTER(-1));
4071 lives_widget_set_sensitive(conxwp->ccombo[idx], FALSE);
4072
4073 lives_table_attach(LIVES_TABLE(conxwp->tablec), hbox, 3, 4, row, row + 1,
4074 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
4075 (LiVESAttachOptions)(0), 0, 0);
4076
4077 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->cfxcombo[idx]), LIVES_WIDGET_CHANGED_SIGNAL,
4078 LIVES_GUI_CALLBACK(dfxc_changed), (livespointer)conxwp);
4079
4080 conxwp->dpc_func[idx] = lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->ccombo[idx]), LIVES_WIDGET_CHANGED_SIGNAL,
4081 LIVES_GUI_CALLBACK(dpc_changed), (livespointer)conxwp);
4082
4083 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(conxwp->ccombo[idx]), "cidx", LIVES_INT_TO_POINTER(cidx));
4084 }
4085
4086
ptable_row_add_standard_widgets(lives_conx_w * conxwp,int idx)4087 static void ptable_row_add_standard_widgets(lives_conx_w * conxwp, int idx) {
4088 LiVESWidget *hbox;
4089
4090 hbox = lives_hbox_new(FALSE, 0);
4091
4092 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 1, 2, conxwp->trowsp - 1, conxwp->trowsp,
4093 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND), (LiVESAttachOptions)(0), 0, 0);
4094
4095 conxwp->clabel[idx] = lives_standard_label_new(lctext);
4096 lives_box_pack_start(LIVES_BOX(hbox), conxwp->clabel[idx], FALSE, FALSE, widget_opts.packing_width);
4097
4098 conxwp->add_button[idx] = lives_standard_button_new_from_stock(LIVES_STOCK_ADD, NULL, BW, BH);
4099 lives_widget_set_tooltip_text(conxwp->add_button[idx],
4100 _("Add another connection for this output parameter"));
4101 lives_widget_set_sensitive(conxwp->add_button[idx], FALSE);
4102
4103 lives_table_attach(LIVES_TABLE(conxwp->tablep), conxwp->add_button[idx], 6, 7, conxwp->trowsp - 1,
4104 conxwp->trowsp, (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
4105
4106 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->add_button[idx]), LIVES_WIDGET_CLICKED_SIGNAL,
4107 LIVES_GUI_CALLBACK(padd_clicked), (livespointer)conxwp);
4108
4109 conxwp->del_button[idx] = lives_standard_button_new_from_stock(LIVES_STOCK_REMOVE, NULL, BW, BH);
4110 lives_widget_set_tooltip_text(conxwp->del_button[idx], _("Delete this connection"));
4111
4112 hbox = lives_hbox_new(FALSE, 0);
4113
4114 lives_box_pack_start(LIVES_BOX(hbox), conxwp->del_button[idx], FALSE, FALSE, 0);
4115
4116 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 5, 6, conxwp->trowsp - 1, conxwp->trowsp,
4117 (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
4118
4119 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->del_button[idx]), LIVES_WIDGET_CLICKED_SIGNAL,
4120 LIVES_GUI_CALLBACK(pdel_clicked), (livespointer)conxwp);
4121
4122 lives_widget_set_sensitive(conxwp->del_button[idx], FALSE);
4123 }
4124
4125
ctable_row_add_standard_widgets(lives_conx_w * conxwp,int idx)4126 static void ctable_row_add_standard_widgets(lives_conx_w * conxwp, int idx) {
4127 LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
4128
4129 lives_table_attach(LIVES_TABLE(conxwp->tablec), hbox, 1, 2, conxwp->trowsc - 1, conxwp->trowsc,
4130 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND), (LiVESAttachOptions)(0), 0, 0);
4131
4132 conxwp->clabel[idx] = lives_standard_label_new(lctext);
4133 lives_box_pack_start(LIVES_BOX(hbox), conxwp->clabel[idx], FALSE, FALSE, widget_opts.packing_width);
4134
4135 conxwp->add_button[idx] = lives_standard_button_new_from_stock(LIVES_STOCK_ADD, NULL, BW, BH);
4136 lives_widget_set_tooltip_text(conxwp->add_button[idx], _("Add another connection for this output channel"));
4137
4138 lives_table_attach(LIVES_TABLE(conxwp->tablec), conxwp->add_button[idx], 5, 6, conxwp->trowsc - 1, conxwp->trowsc,
4139 (LiVESAttachOptions)(0), (LiVESAttachOptions)(0), 0, 0);
4140
4141 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->add_button[idx]), LIVES_WIDGET_CLICKED_SIGNAL,
4142 LIVES_GUI_CALLBACK(cadd_clicked), (livespointer)conxwp);
4143
4144 conxwp->del_button[idx] = lives_standard_button_new_from_stock(LIVES_STOCK_REMOVE, NULL, BW, BH);
4145 lives_widget_set_tooltip_text(conxwp->del_button[idx], _("Delete this connection"));
4146
4147 hbox = lives_hbox_new(FALSE, 0);
4148
4149 lives_box_pack_start(LIVES_BOX(hbox), conxwp->del_button[idx], FALSE, FALSE, 0);
4150
4151 lives_table_attach(LIVES_TABLE(conxwp->tablec), hbox, 4, 5, conxwp->trowsc - 1, conxwp->trowsc,
4152 (LiVESAttachOptions)(0),
4153 (LiVESAttachOptions)(0), 0, 0);
4154
4155 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxwp->del_button[idx]), LIVES_WIDGET_CLICKED_SIGNAL,
4156 LIVES_GUI_CALLBACK(cdel_clicked), (livespointer)conxwp);
4157
4158 lives_widget_set_sensitive(conxwp->del_button[idx], FALSE);
4159 }
4160
4161
conx_scroll_new(lives_conx_w * conxwp)4162 static LiVESWidget *conx_scroll_new(lives_conx_w * conxwp) {
4163 weed_plant_t *chan, *param;
4164
4165 LiVESWidget *label;
4166 LiVESWidget *top_vbox;
4167 LiVESWidget *hbox;
4168 LiVESWidget *scrolledwindow;
4169
4170 char *channame, *pname, *fname;
4171 char *ptype, *range;
4172 char *array_type, *text, *tmp;
4173
4174 boolean isfirst;
4175
4176 int defelems, pflags, stype;
4177
4178 int totchans, totparams, nconns;
4179
4180 register int i, j = 0, x = 0;
4181
4182 for (i = 0; i < conxwp->num_alpha; i++) {
4183 nconns = cconx_get_nconns(conxwp->cconx, i);
4184 if (nconns == 0) nconns = 1;
4185 conxwp->dispc[i] = nconns;
4186 }
4187
4188 for (i = -EXTRA_PARAMS_OUT; i < conxwp->num_params - EXTRA_PARAMS_OUT; i++) {
4189 nconns = pconx_get_nconns(conxwp->pconx, i);
4190 if (nconns == 0) nconns = 1;
4191 conxwp->dispp[i + EXTRA_PARAMS_OUT] = nconns;
4192 }
4193
4194 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
4195 totparams = pconx_get_numcons(conxwp, FX_DATA_WILDCARD);
4196
4197 conxwp->add_button = (LiVESWidget **)lives_malloc((totchans + totparams) * sizeof(LiVESWidget *));
4198 conxwp->del_button = (LiVESWidget **)lives_malloc((totchans + totparams) * sizeof(LiVESWidget *));
4199 conxwp->clabel = (LiVESWidget **)lives_malloc((totchans + totparams) * sizeof(LiVESWidget *));
4200 conxwp->pclabel = (LiVESWidget **)lives_malloc((totchans + totparams) * sizeof(LiVESWidget *));
4201
4202 conxwp->cfxcombo = conxwp->ccombo = conxwp->pcombo = conxwp->pfxcombo = conxwp->acheck = NULL;
4203 conxwp->dpp_func = conxwp->dpc_func = conxwp->acheck_func = NULL;
4204
4205 conxwp->ikeys = (int *)lives_malloc((totchans + totparams) * sizint);
4206 conxwp->imodes = (int *)lives_malloc((totchans + totparams) * sizint);
4207 conxwp->idx = (int *)lives_malloc((totchans + totparams) * sizint);
4208
4209 for (i = 0; i < totchans + totparams; i++) {
4210 conxwp->ikeys[i] = -1;
4211 conxwp->imodes[i] = conxwp->idx[i] = 0;
4212 }
4213
4214 lctext = (_("Connected to -->"));
4215
4216 top_vbox = lives_vbox_new(FALSE, 0);
4217
4218 scrolledwindow = lives_standard_scrolled_window_new(-1, -1, top_vbox);
4219
4220 conxwp->trowsc = conxwp->trowsp = 0;
4221
4222 fname = weed_get_string_value(conxwp->filter, WEED_LEAF_NAME, NULL);
4223
4224 if (conxwp->num_alpha > 0) {
4225 weed_plant_t **ochans = weed_get_plantptr_array(conxwp->filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, NULL);
4226
4227 conxwp->dpc_func = (ulong *)lives_malloc(totchans * sizeof(ulong));
4228
4229 conxwp->cfxcombo = (LiVESWidget **)lives_malloc(totchans * sizeof(LiVESWidget *));
4230
4231 conxwp->ccombo = (LiVESWidget **)lives_malloc(totchans * sizeof(LiVESWidget *));
4232
4233 tmp = lives_big_and_bold("%s - Alpha Channel Connections", fname);
4234
4235 widget_opts.use_markup = TRUE;
4236 widget_opts.justify = LIVES_JUSTIFY_CENTER;
4237 label = lives_standard_label_new(tmp);
4238 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
4239 widget_opts.use_markup = FALSE;
4240 lives_free(tmp);
4241
4242 lives_box_pack_start(LIVES_BOX(top_vbox), label, FALSE, FALSE, widget_opts.packing_height);
4243
4244 conxwp->tablec = lives_table_new(0, 6, FALSE);
4245 lives_table_set_row_spacings(LIVES_TABLE(conxwp->tablec), widget_opts.packing_height);
4246 lives_table_set_col_spacings(LIVES_TABLE(conxwp->tablec), widget_opts.packing_width);
4247 lives_box_pack_start(LIVES_BOX(top_vbox), conxwp->tablec, FALSE, FALSE, widget_opts.packing_height);
4248
4249 conxwp->trowsc = 1;
4250
4251 cmodel = inparam_fx_model(TRUE, conxwp->okey);
4252
4253 for (i = 0; i < conxwp->num_alpha; i++) {
4254 chan = ochans[j++];
4255
4256 if (!has_alpha_palette(chan, conxwp->filter)) {
4257 i--;
4258 continue;
4259 }
4260
4261 lives_table_resize(LIVES_TABLE(conxwp->tablec), ++conxwp->trowsc, 6);
4262
4263 nconns = conxwp->dispc[i];
4264
4265 isfirst = TRUE;
4266
4267 do {
4268 ctable_row_add_variable_widgets(conxwp, x, conxwp->trowsc - 1, i);
4269 ctable_row_add_standard_widgets(conxwp, x);
4270
4271 if (isfirst) {
4272 channame = get_chan_name(chan, j - 1, FALSE);
4273 widget_opts.mnemonic_label = FALSE;
4274 lives_label_set_text(LIVES_LABEL(conxwp->pclabel[x]), channame);
4275 widget_opts.mnemonic_label = TRUE;
4276 lives_free(channame);
4277 isfirst = FALSE;
4278 }
4279
4280 x++;
4281
4282 if (nconns > 1) {
4283 lives_table_resize(LIVES_TABLE(conxwp->tablec), ++conxwp->trowsc, 6);
4284 }
4285
4286 } while (--nconns > 0);
4287 }
4288
4289 lives_free(ochans);
4290 }
4291
4292 if (conxwp->num_alpha > 0 && conxwp->num_params > 0) {
4293 add_hsep_to_box(LIVES_BOX(top_vbox));
4294 }
4295
4296 if (conxwp->num_params > 0) {
4297 weed_plant_t **oparams = NULL;
4298
4299 pmodel = inparam_fx_model(FALSE, conxwp->okey);
4300
4301 if (weed_plant_has_leaf(conxwp->filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES))
4302 oparams = weed_get_plantptr_array(conxwp->filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, NULL);
4303
4304 conxwp->pfxcombo = (LiVESWidget **)lives_malloc(totparams * sizeof(LiVESWidget *));
4305 conxwp->pcombo = (LiVESWidget **)lives_malloc(totparams * sizeof(LiVESWidget *));
4306
4307 conxwp->dpp_func = (ulong *)lives_malloc(totparams * sizeof(ulong));
4308 conxwp->acheck_func = (ulong *)lives_malloc(totparams * sizeof(ulong));
4309
4310 conxwp->acheck = (LiVESWidget **)lives_malloc(totparams * sizeof(LiVESWidget *));
4311
4312 tmp = lives_big_and_bold("%s - Parameter Data Connections", fname);
4313
4314 widget_opts.use_markup = TRUE;
4315 widget_opts.justify = LIVES_JUSTIFY_CENTER;
4316 label = lives_standard_label_new(tmp);
4317 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
4318 widget_opts.use_markup = FALSE;
4319 lives_free(tmp);
4320
4321 lives_box_pack_start(LIVES_BOX(top_vbox), label, FALSE, FALSE, widget_opts.packing_height);
4322
4323 conxwp->tablep = lives_table_new(1, 7, FALSE);
4324 lives_table_set_row_spacings(LIVES_TABLE(conxwp->tablep), widget_opts.packing_height);
4325 lives_table_set_col_spacings(LIVES_TABLE(conxwp->tablep), widget_opts.packing_width);
4326 lives_box_pack_start(LIVES_BOX(top_vbox), conxwp->tablep, FALSE, FALSE, widget_opts.packing_height);
4327
4328 conxwp->trowsp = 1;
4329 x = 0;
4330
4331 hbox = lives_hbox_new(FALSE, 0);
4332
4333 lives_table_attach(LIVES_TABLE(conxwp->tablep), hbox, 4, 5, 0, 1,
4334 (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
4335 (LiVESAttachOptions)(0), 0, 0);
4336
4337 conxwp->allcheckc = lives_standard_check_button_new(_("Autoscale All"), TRUE, LIVES_BOX(hbox), NULL);
4338 conxwp->allcheck_label = widget_opts.last_label;
4339
4340 lives_signal_sync_connect_after(LIVES_GUI_OBJECT(conxwp->allcheckc), LIVES_WIDGET_TOGGLED_SIGNAL,
4341 LIVES_GUI_CALLBACK(on_allcheck_toggled),
4342 (livespointer)conxwp);
4343
4344 if (EXTRA_PARAMS_OUT > 0) {
4345 lives_table_resize(LIVES_TABLE(conxwp->tablep), ++conxwp->trowsp, 7);
4346
4347 nconns = conxwp->dispp[0];
4348
4349 isfirst = TRUE;
4350
4351 do {
4352 // TODO: for OMC, adjust the pmodel for each oparam type
4353
4354 ptable_row_add_variable_widgets(conxwp, x, conxwp->trowsp - 1, -EXTRA_PARAMS_OUT);
4355 ptable_row_add_standard_widgets(conxwp, x + totchans);
4356
4357 //lives_widget_set_sensitive(conxwp->add_button[x + totchans], FALSE);
4358
4359 if (isfirst) {
4360 /* TRANSLATORS - as in "Effect ACTIVATED" */
4361 pname = (_("ACTIVATED"));
4362 ptype = weed_seed_type_to_text(WEED_SEED_BOOLEAN);
4363
4364 text = lives_strdup_printf("%s (%s)", pname, ptype);
4365 widget_opts.mnemonic_label = FALSE;
4366 lives_label_set_text(LIVES_LABEL(conxwp->pclabel[x + totchans]), text);
4367 widget_opts.mnemonic_label = TRUE;
4368 lives_free(text);
4369 lives_free(pname);
4370 lives_free(ptype);
4371
4372 isfirst = FALSE;
4373 }
4374
4375 x++;
4376
4377 if (nconns > 1) {
4378 lives_table_resize(LIVES_TABLE(conxwp->tablep), ++conxwp->trowsp, 7);
4379 }
4380 } while (--nconns > 0);
4381 }
4382
4383 for (i = 0; i < conxwp->num_params - EXTRA_PARAMS_OUT; i++) {
4384 lives_table_resize(LIVES_TABLE(conxwp->tablep), ++conxwp->trowsp, 7);
4385
4386 nconns = conxwp->dispp[i + EXTRA_PARAMS_OUT];
4387
4388 isfirst = TRUE;
4389
4390 do {
4391 ptable_row_add_variable_widgets(conxwp, x, conxwp->trowsp - 1, i);
4392 ptable_row_add_standard_widgets(conxwp, x + totchans);
4393
4394 if (isfirst) {
4395 param = oparams[i];
4396
4397 pname = get_param_name(param, i, FALSE);
4398
4399 ptype = weed_seed_type_to_text((stype = weed_leaf_seed_type(param, WEED_LEAF_DEFAULT)));
4400
4401 pflags = weed_get_int_value(param, WEED_LEAF_FLAGS, NULL);
4402
4403 if (pflags & WEED_PARAMETER_VARIABLE_SIZE) array_type = lives_strdup("[]");
4404 else if ((defelems = weed_leaf_num_elements(param, WEED_LEAF_DEFAULT)) > 1)
4405 array_type = lives_strdup_printf("[%d]", defelems);
4406 else array_type = lives_strdup("");
4407
4408 if (weed_plant_has_leaf(param, WEED_LEAF_MAX) && weed_plant_has_leaf(param, WEED_LEAF_MIN)) {
4409 if (stype == WEED_SEED_INT) {
4410 range = lives_strdup_printf("Range: %d to %d", weed_get_int_value(param, WEED_LEAF_MIN, NULL),
4411 weed_get_int_value(param,
4412 WEED_LEAF_MAX,
4413 NULL));
4414 } else if (stype == WEED_SEED_DOUBLE) {
4415 range = lives_strdup_printf("Range: %f to %f", weed_get_double_value(param, WEED_LEAF_MIN, NULL),
4416 weed_get_double_value(param,
4417 WEED_LEAF_MAX,
4418 NULL));
4419 } else range = lives_strdup("");
4420 } else range = lives_strdup("");
4421
4422 text = lives_strdup_printf("%s\n (%s%s) %s", pname, ptype, array_type, range);
4423 widget_opts.mnemonic_label = FALSE;
4424 lives_label_set_text(LIVES_LABEL(conxwp->pclabel[x + totchans]), text);
4425 widget_opts.mnemonic_label = TRUE;
4426 lives_free(text);
4427 lives_free(pname);
4428 lives_free(ptype);
4429
4430 isfirst = FALSE;
4431 }
4432
4433 x++;
4434
4435 if (nconns > 1) {
4436 lives_table_resize(LIVES_TABLE(conxwp->tablep), ++conxwp->trowsp, 7);
4437 }
4438 } while (--nconns > 0);
4439 }
4440
4441 lives_free(oparams);
4442 }
4443
4444 lives_free(fname);
4445
4446 return scrolledwindow;
4447 }
4448
4449
conxw_cancel_clicked(LiVESWidget * button,livespointer user_data)4450 static void conxw_cancel_clicked(LiVESWidget * button, livespointer user_data) {
4451 lives_conx_w *conxwp = (lives_conx_w *)user_data;
4452
4453 /// TODO - consider the benefits of using LSD
4454 if (conxwp->pclabel) lives_free(conxwp->pclabel);
4455 if (conxwp->clabel) lives_free(conxwp->clabel);
4456 if (conxwp->cfxcombo) lives_free(conxwp->cfxcombo);
4457 if (conxwp->ccombo) lives_free(conxwp->ccombo);
4458 if (conxwp->pfxcombo) lives_free(conxwp->pfxcombo);
4459 if (conxwp->pcombo) lives_free(conxwp->pcombo);
4460 if (conxwp->acheck) lives_free(conxwp->acheck);
4461 if (conxwp->add_button) lives_free(conxwp->add_button);
4462 if (conxwp->del_button) lives_free(conxwp->del_button);
4463 if (conxwp->dpp_func) lives_free(conxwp->dpp_func);
4464 if (conxwp->dpc_func) lives_free(conxwp->dpc_func);
4465 if (conxwp->acheck_func) lives_free(conxwp->acheck_func);
4466
4467 if (conxwp->dispp) lives_free(conxwp->dispp);
4468 if (conxwp->dispc) lives_free(conxwp->dispc);
4469
4470 lives_free(conxwp->ikeys);
4471 lives_free(conxwp->imodes);
4472 lives_free(conxwp->idx);
4473
4474 lives_free(lctext);
4475
4476 pconx_delete_all();
4477 cconx_delete_all();
4478
4479 if (!button) return;
4480
4481 // restore old values
4482 mainw->pconx = spconx;
4483 mainw->cconx = scconx;
4484
4485 lives_general_button_clicked(LIVES_BUTTON(button), NULL);
4486 }
4487
4488
conxw_ok_clicked(LiVESWidget * button,livespointer user_data)4489 static void conxw_ok_clicked(LiVESWidget * button, livespointer user_data) {
4490 lives_cconnect_t *cconx_bak = mainw->cconx;
4491 lives_pconnect_t *pconx_bak = mainw->pconx;
4492
4493 // let backup copy be freed
4494 mainw->pconx = spconx;
4495 mainw->cconx = scconx;
4496
4497 conxw_cancel_clicked(NULL, user_data);
4498
4499 mainw->cconx = cconx_bak;
4500 mainw->pconx = pconx_bak;
4501
4502 lives_general_button_clicked(LIVES_BUTTON(button), NULL);
4503 }
4504
4505
set_to_keymode_vals(LiVESCombo * combo,int xkey,int xmode)4506 static void set_to_keymode_vals(LiVESCombo * combo, int xkey, int xmode) {
4507 LiVESTreeIter iter, piter;
4508 LiVESTreeModel *model;
4509
4510 int key, mode;
4511
4512 model = lives_combo_get_model(combo);
4513 if (!lives_tree_model_get_iter_first(model, &piter)) return;
4514
4515 do {
4516 if (lives_tree_model_iter_children(model, &iter, &piter)) {
4517 do {
4518 lives_tree_model_get(model, &iter, KEYVAL_COLUMN, &key, MODEVAL_COLUMN, &mode, -1);
4519 if (key == (key > -0 ? xkey + 1 : key) && mode == xmode) goto iter_found;
4520 } while (lives_tree_model_iter_next(model, &iter));
4521 }
4522 } while (lives_tree_model_iter_next(model, &piter));
4523
4524 iter_found:
4525 lives_combo_set_active_iter(combo, &iter);
4526
4527 }
4528
4529
show_existing(lives_conx_w * conxwp)4530 static boolean show_existing(lives_conx_w * conxwp) {
4531 lives_cconnect_t *cconx = conxwp->cconx;
4532 lives_pconnect_t *pconx = conxwp->pconx;
4533
4534 LiVESWidget *cfxcombo, *ccombo;
4535 LiVESWidget *pfxcombo, *pcombo;
4536 LiVESWidget *acheck;
4537
4538 weed_plant_t **ochans, **ichans;
4539 weed_plant_t **iparams;
4540 weed_plant_t *ofilter = conxwp->filter, *filter;
4541 weed_plant_t *chan, *param;
4542
4543 int ikey, imode, icnum, ipnum, nichans, niparams;
4544 int posn = 0, cidx, pidx, totchans = 0;
4545 int i, j, k, l;
4546
4547 if (!cconx) goto show_ex_params;
4548
4549 totchans = cconx_get_numcons(conxwp, FX_DATA_WILDCARD);
4550
4551 ochans = weed_get_plantptr_array(ofilter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, NULL);
4552
4553 for (i = 0; i < cconx->nchans; i++) {
4554 // find the row
4555 l = 0;
4556
4557 // total out channel connections (display order) up to here
4558 for (k = 0; k < i; k++) {
4559 chan = ochans[j++];
4560 if (!has_alpha_palette(chan, ofilter)) {
4561 k--;
4562 continue;
4563 }
4564 l += cconx_get_numcons(conxwp, k);
4565 }
4566
4567 cidx = cconx->chans[i];
4568 for (j = posn; j < posn + cconx->nconns[i]; j++) {
4569 ikey = cconx->ikey[j];
4570 imode = cconx->imode[j];
4571
4572 // row is l
4573 cfxcombo = conxwp->cfxcombo[l];
4574
4575 // set it to the value which has ikey/imode
4576 set_to_keymode_vals(LIVES_COMBO(cfxcombo), ikey, imode);
4577
4578 // set channel
4579 ccombo = conxwp->ccombo[l];
4580 icnum = cconx->icnum[j];
4581
4582 filter = rte_keymode_get_filter(ikey + 1, imode);
4583 ichans = weed_get_plantptr_array(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, NULL);
4584 nichans = weed_leaf_num_elements(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES);
4585
4586 cidx = 0;
4587
4588 // find combo list index for ichan
4589 for (k = 0; k < nichans; k++) {
4590 chan = ichans[k];
4591 if (!has_alpha_palette(chan, filter)) continue;
4592 if (k == icnum) break;
4593 cidx++;
4594 }
4595
4596 lives_free(ichans);
4597
4598 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(ccombo), "setup", LIVES_INT_TO_POINTER(TRUE));
4599
4600 lives_signal_handler_block(ccombo, conxwp->dpc_func[l]);
4601 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(ccombo), "idx", LIVES_INT_TO_POINTER(cidx));
4602 lives_combo_set_active_index(LIVES_COMBO(ccombo), cidx);
4603 lives_signal_handler_unblock(ccombo, conxwp->dpc_func[l]);
4604
4605 conxwp->ikeys[l] = ikey;
4606 conxwp->imodes[l] = imode;
4607 conxwp->idx[l] = icnum;
4608
4609 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(ccombo), "setup", LIVES_INT_TO_POINTER(FALSE));
4610 lives_widget_set_sensitive(conxwp->disconbutton, TRUE);
4611 lives_widget_set_sensitive(ccombo, TRUE);
4612
4613 l++;
4614 }
4615
4616 posn += cconx->nconns[i];
4617 }
4618
4619 lives_free(ochans);
4620
4621 show_ex_params:
4622
4623 if (!pconx) goto show_ex_done;
4624
4625 posn = 0;
4626
4627 for (i = 0; i < pconx->nparams; i++) {
4628 pidx = pconx->params[i];
4629
4630 // find the row
4631 l = 0;
4632
4633 // total out param connections (display order) up to here
4634 for (k = -EXTRA_PARAMS_OUT; k < pidx; k++) {
4635 l += pconx_get_numcons(conxwp, k);
4636 }
4637
4638 for (j = posn; j < posn + pconx->nconns[i]; j++) {
4639 ikey = pconx->ikey[j];
4640 imode = pconx->imode[j];
4641
4642 // row is l
4643 pfxcombo = conxwp->pfxcombo[l];
4644
4645 // set it to the value which has ikey/imode
4646 set_to_keymode_vals(LIVES_COMBO(pfxcombo), ikey, imode);
4647
4648 // set parameter
4649 pcombo = conxwp->pcombo[l];
4650 acheck = conxwp->acheck[l];
4651
4652 if (j == posn + pconx->nconns[i] - 1)
4653 lives_widget_set_sensitive(conxwp->add_button[l], TRUE);
4654
4655 if (acheck) {
4656 boolean hasrange = LIVES_POINTER_TO_INT(lives_widget_object_get_data(LIVES_WIDGET_OBJECT(acheck), "available"));
4657 if (hasrange) {
4658 lives_widget_set_sensitive(acheck, TRUE);
4659 lives_signal_handler_block(acheck, conxwp->acheck_func[l]);
4660 lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(acheck), pconx->autoscale[j]);
4661 lives_signal_handler_unblock(acheck, conxwp->acheck_func[l]);
4662 }
4663 }
4664
4665 ipnum = pconx->ipnum[j];
4666
4667 // TODO ****: OMC
4668
4669 if (ipnum == FX_DATA_PARAM_ACTIVE) {
4670 pidx = FX_DATA_PARAM_ACTIVE;
4671 } else {
4672 filter = rte_keymode_get_filter(ikey + 1, imode);
4673 iparams = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL);
4674 niparams = weed_leaf_num_elements(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES);
4675
4676 #ifdef COMBO_LIST_LIMIT
4677 if (niparams + EXTRA_PARAMS_IN > COMBO_LIST_LIMIT) {
4678 niparams = COMBO_LIST_LIMIT - EXTRA_PARAMS_IN;
4679 }
4680 #endif
4681 pidx = 0;
4682
4683 // find combo list index for iparam
4684 for (k = 0; k < niparams; k++) {
4685 param = iparams[k];
4686 if (weed_plant_has_leaf(param, WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
4687 if (k == ipnum) break;
4688 pidx++;
4689 }
4690
4691 lives_free(iparams);
4692 }
4693
4694 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pcombo), "setup", LIVES_INT_TO_POINTER(TRUE));
4695
4696 conxwp->ikeys[totchans + l] = ikey;
4697 conxwp->imodes[totchans + l] = imode;
4698 conxwp->idx[totchans + l] = ipnum;
4699
4700 //lives_signal_handler_block(pcombo,conxwp->dpp_func[pidx]);
4701 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pcombo), "idx", LIVES_INT_TO_POINTER(pidx + EXTRA_PARAMS_IN));
4702 lives_combo_set_active_index(LIVES_COMBO(pcombo), pidx + EXTRA_PARAMS_IN);
4703 //lives_signal_handler_unblock(pcombo,conxwp->dpp_func[pidx]);
4704
4705 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(pcombo), "setup", LIVES_INT_TO_POINTER(FALSE));
4706
4707 lives_widget_set_sensitive(conxwp->disconbutton, TRUE);
4708 lives_widget_set_sensitive(pcombo, TRUE);
4709
4710 l++;
4711 }
4712
4713 posn += pconx->nconns[i];
4714 }
4715
4716 show_ex_done:
4717
4718 return FALSE;
4719 }
4720
4721
make_datacon_window(int key,int mode)4722 LiVESWidget *make_datacon_window(int key, int mode) {
4723 static lives_conx_w conxw;
4724
4725 LiVESWidget *cbox, *abox;
4726 LiVESWidget *scrolledwindow;
4727
4728 LiVESWidget *cancelbutton;
4729 LiVESWidget *okbutton;
4730
4731 LiVESAccelGroup *accel_group;
4732
4733 int winsize_h;
4734 int winsize_v;
4735
4736 conxw.filter = rte_keymode_get_filter(key + 1, mode);
4737
4738 if (!conxw.filter) return NULL;
4739
4740 conxw.acbutton = conxw.apbutton = NULL;
4741
4742 conxw.dispp = conxw.dispc = NULL;
4743
4744 // save unaltered values
4745 spconx = pconx_copy(mainw->pconx);
4746 scconx = cconx_copy(mainw->cconx);
4747
4748 conxw.cconx = cconx_find(key, mode);
4749 conxw.pconx = pconx_find(key, mode);
4750
4751 conxw.okey = key;
4752 conxw.omode = mode;
4753
4754 conxw.num_alpha = num_alpha_channels(conxw.filter, TRUE);
4755 conxw.num_params = weed_leaf_num_elements(conxw.filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES);
4756
4757 conxw.num_params += EXTRA_PARAMS_OUT;
4758
4759 if (conxw.num_params > 0)
4760 conxw.dispp = (int *)lives_malloc(conxw.num_params * sizint);
4761
4762 conxw.ntabs = 0;
4763
4764 winsize_h = GUI_SCREEN_WIDTH - SCR_WIDTH_SAFETY * 2;
4765 winsize_v = GUI_SCREEN_HEIGHT - SCR_HEIGHT_SAFETY;
4766
4767 conxw.conx_dialog = lives_standard_dialog_new(_("Parameter and Alpha Channel Connections"), FALSE, winsize_h, winsize_v);
4768
4769 accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
4770 lives_window_add_accel_group(LIVES_WINDOW(conxw.conx_dialog), accel_group);
4771
4772 if (conxw.num_alpha > 0) {
4773 conxw.dispc = (int *)lives_malloc(conxw.num_alpha * sizint);
4774
4775 conxw.acbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(conxw.conx_dialog), NULL, _("Auto Connect Channels"),
4776 LIVES_RESPONSE_NONE);
4777 lives_widget_set_sensitive(conxw.acbutton, FALSE);
4778 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxw.acbutton), LIVES_WIDGET_CLICKED_SIGNAL,
4779 LIVES_GUI_CALLBACK(acbutton_clicked), (livespointer)&conxw);
4780 }
4781
4782 if (conxw.num_params > EXTRA_PARAMS_OUT) {
4783 conxw.apbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(conxw.conx_dialog), NULL, _("Auto Connect Parameters"),
4784 LIVES_RESPONSE_NONE);
4785 lives_widget_set_sensitive(conxw.apbutton, FALSE);
4786 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxw.apbutton), LIVES_WIDGET_CLICKED_SIGNAL,
4787 LIVES_GUI_CALLBACK(apbutton_clicked), (livespointer)&conxw);
4788 }
4789
4790 conxw.disconbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(conxw.conx_dialog), NULL, _("_Disconnect All"),
4791 LIVES_RESPONSE_NONE);
4792 //lives_container_set_border_width(LIVES_CONTAINER(conxw.disconbutton), widget_opts.border_width);
4793 //!! dont - causes other buttons to exp. vert in gtk2
4794 lives_widget_set_sensitive(conxw.disconbutton, FALSE);
4795
4796 lives_signal_sync_connect(LIVES_GUI_OBJECT(conxw.disconbutton), LIVES_WIDGET_CLICKED_SIGNAL,
4797 LIVES_GUI_CALLBACK(disconbutton_clicked), (livespointer)&conxw);
4798
4799 abox = lives_dialog_get_action_area(LIVES_DIALOG(conxw.conx_dialog));
4800 if (LIVES_IS_BOX(abox) && (conxw.num_alpha > 0 || conxw.num_params > 0)) add_fill_to_box(LIVES_BOX(abox));
4801
4802 cbox = lives_dialog_get_content_area(LIVES_DIALOG(conxw.conx_dialog));
4803
4804 scrolledwindow = conx_scroll_new(&conxw);
4805 show_existing(&conxw);
4806
4807 lives_box_pack_start(LIVES_BOX(cbox), scrolledwindow, TRUE, TRUE, 0);
4808
4809 if (conxw.num_params > EXTRA_PARAMS_OUT) {
4810 if (conxw.apbutton && pconx_get_nconns(conxw.pconx, 0) > 0)
4811 lives_widget_set_sensitive(conxw.apbutton, TRUE);
4812 }
4813 if (conxw.num_alpha > 0) {
4814 if (conxw.acbutton && cconx_get_nconns(conxw.cconx, 0) > 0)
4815 lives_widget_set_sensitive(conxw.acbutton, TRUE);
4816 }
4817
4818 cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(conxw.conx_dialog), LIVES_STOCK_CANCEL, NULL,
4819 LIVES_RESPONSE_CANCEL);
4820
4821 okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(conxw.conx_dialog), LIVES_STOCK_OK, NULL,
4822 LIVES_RESPONSE_OK);
4823
4824 lives_button_grab_default_special(okbutton);
4825
4826 lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
4827 LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
4828
4829 lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
4830 LIVES_GUI_CALLBACK(conxw_cancel_clicked),
4831 (livespointer)&conxw);
4832
4833 lives_signal_sync_connect(LIVES_GUI_OBJECT(okbutton), LIVES_WIDGET_CLICKED_SIGNAL,
4834 LIVES_GUI_CALLBACK(conxw_ok_clicked),
4835 (livespointer)&conxw);
4836
4837 lives_widget_show_all(conxw.conx_dialog);
4838
4839 if (conxw.num_params == EXTRA_PARAMS_OUT && EXTRA_PARAMS_OUT > 0) {
4840 lives_widget_set_no_show_all(conxw.allcheckc, TRUE);
4841 lives_widget_hide(conxw.allcheckc);
4842 lives_widget_set_no_show_all(conxw.allcheck_label, TRUE);
4843 lives_widget_hide(conxw.allcheck_label);
4844 }
4845
4846 return conxw.conx_dialog;
4847 }
4848
4849
do_chan_connected_query(lives_conx_w * conxwp,int key,int mode,int cnum,boolean is_same)4850 static boolean do_chan_connected_query(lives_conx_w * conxwp, int key, int mode, int cnum, boolean is_same) {
4851 weed_plant_t *filter = rte_keymode_get_filter(key + 1, mode);
4852 weed_plant_t *ctmpl, **ochans;
4853 char *cname, *msg, *fname = weed_filter_get_name(filter);
4854 boolean resp = FALSE;
4855 ochans = weed_get_plantptr_array(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, NULL);
4856 ctmpl = ochans[cnum];
4857 lives_free(ochans);
4858 cname = get_chan_name(ctmpl, cnum, TRUE);
4859 widget_opts.transient = LIVES_WINDOW(conxwp->conx_dialog);
4860 msg = lives_strdup_printf(_("Input channel is already connected from key %d, mode %d\n\n(%s:%s)\n\n"),
4861 key + 1, mode, fname, cname);
4862 if (!is_same)
4863 resp = do_yesno_dialogf(_("%sWould you like to replace the existing connection ?\n\n"), msg);
4864
4865 else
4866 do_error_dialogf(_("%sYou need to remove this connection first before adding another.\n\n"), msg);
4867 widget_opts.transient = NULL;
4868 lives_free(msg); lives_free(cname); lives_free(fname);
4869 return resp;
4870 }
4871
4872
do_param_connected_query(lives_conx_w * conxwp,int key,int mode,int pnum,boolean is_same)4873 static boolean do_param_connected_query(lives_conx_w * conxwp, int key, int mode, int pnum, boolean is_same) {
4874 weed_plant_t *filter = rte_keymode_get_filter(key + 1, mode);
4875 char *pname, *msg, *fname = weed_filter_get_name(filter);
4876 boolean resp = FALSE;
4877 if (pnum >= 0) {
4878 weed_plant_t *ptmpl = weed_filter_out_paramtmpl(filter, pnum);
4879 pname = get_param_name(ptmpl, pnum, TRUE);
4880 } else pname = (_("ACTIVATED"));
4881 widget_opts.transient = LIVES_WINDOW(conxwp->conx_dialog);
4882 msg = lives_strdup_printf(_("Input parameter is already connected from key %d, mode %d\n\n(%s:%s)\n\n"),
4883 key + 1, mode, fname, pname);
4884 if (!is_same)
4885 resp = do_yesno_dialogf(_("%sWould you like to replace the existing connection ?\n\n"), msg);
4886
4887 else
4888 do_error_dialogf(_("%sYou need to remove this connection first before adding another.\n\n"), msg);
4889 widget_opts.transient = NULL;
4890 lives_free(msg); lives_free(pname); lives_free(fname);
4891 return resp;
4892 }
4893
4894
do_param_incompatible_error(lives_conx_w * conxwp)4895 static void do_param_incompatible_error(lives_conx_w * conxwp) {
4896 widget_opts.transient = LIVES_WINDOW(conxwp->conx_dialog);
4897 do_error_dialog(_("Input and output parameters are not compatible"));
4898 widget_opts.transient = NULL;
4899 }
4900
4901